Your IP : 216.73.217.68


Current Path : /home/wuectly/www/03cbe/
Upload File :
Current File : /home/wuectly/www/03cbe/com_privacy.zip

PK)r!]�b�ggg
config.xmlnu&1i�<?xml version="1.0" encoding="utf-8"?>
<config>
	<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>
PK)r!]�r�JJprivacy.phpnu&1i�<?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;

// Only super user can access here
if (!JFactory::getUser()->authorise('core.admin'))
{
	throw new JAccessExceptionNotallowed(JText::_('JERROR_ALERTNOAUTHOR'), 403);
}

$controller = JControllerLegacy::getInstance('Privacy');
$controller->execute(JFactory::getApplication()->input->get('task'));
$controller->redirect();
PK)r!]��$JJprivacy.xmlnu&1i�<?xml version="1.0" encoding="utf-8"?>
<extension type="component" version="3.9" method="upgrade">
	<name>com_privacy</name>
	<author>Joomla! Project</author>
	<creationDate>May 2018</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>
	<files folder="site">
		<filename>controller.php</filename>
		<filename>privacy.php</filename>
		<filename>router.php</filename>
		<folder>controllers</folder>
		<folder>models</folder>
		<folder>views</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>controller.php</filename>
			<filename>privacy.php</filename>
			<folder>controllers</folder>
			<folder>helpers</folder>
			<folder>models</folder>
			<folder>tables</folder>
			<folder>views</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>
</extension>

PK)r!]Nj���helpers/plugin.phpnu&1i�<?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;

JLoader::register('PrivacyExportDomain', __DIR__ . '/export/domain.php');
JLoader::register('PrivacyExportField', __DIR__ . '/export/field.php');
JLoader::register('PrivacyExportItem', __DIR__ . '/export/item.php');
JLoader::register('FieldsHelper', JPATH_ADMINISTRATOR . '/components/com_fields/helpers/fields.php');

/**
 * Base class for privacy plugins
 *
 * @since  3.9.0
 */
abstract class PrivacyPlugin extends JPlugin
{
	/**
	 * Database object
	 *
	 * @var    JDatabaseDriver
	 * @since  3.9.0
	 */
	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  PrivacyExportDomain
	 *
	 * @since   3.9.0
	 */
	protected function createDomain($name, $description = '')
	{
		$domain              = new PrivacyExportDomain;
		$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  PrivacyExportItem
	 *
	 * @since   3.9.0
	 */
	protected function createItemFromArray(array $data, $itemId = null)
	{
		$item = new PrivacyExportItem;
		$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 PrivacyExportField;
			$field->name  = $key;
			$field->value = $value;

			$item->addField($field);
		}

		return $item;
	}

	/**
	 * Create an item object for a JTable object
	 *
	 * @param   JTable  $table  The JTable object to convert
	 *
	 * @return  PrivacyExportItem
	 *
	 * @since   3.9.0
	 */
	protected function createItemForTable($table)
	{
		$data = array();

		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  PrivacyExportDomain
	 *
	 * @since   3.9.0
	 */
	protected function createCustomFieldsDomain($context, $items = array())
	{
		if (!is_array($items))
		{
			$items = array($items);
		}

		$parts = FieldsHelper::extract($context);

		if (!$parts)
		{
			return array();
		}

		$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 = array(
					$type . '_id' => $item->id,
					'field_name'  => $field->name,
					'field_title' => $field->title,
					'field_value' => $fieldValue,
				);

				$domain->addItem($this->createItemFromArray($data));
			}
		}

		return $domain;
	}
}
PK)r!]�P�helpers/export/domain.phpnu&1i�<?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;

JLoader::register('PrivacyExportItem', __DIR__ . '/item.php');

/**
 * 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 PrivacyExportDomain
{
	/**
	 * 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    PrivacyExportItem[]
	 * @since  3.9.0
	 */
	protected $items = array();

	/**
	 * Add an item to the domain
	 *
	 * @param   PrivacyExportItem  $item  The item to add
	 *
	 * @return  void
	 *
	 * @since  3.9.0
	 */
	public function addItem(PrivacyExportItem $item)
	{
		$this->items[] = $item;
	}

	/**
	 * Get the domain's items
	 *
	 * @return  PrivacyExportItem[]
	 *
	 * @since  3.9.0
	 */
	public function getItems()
	{
		return $this->items;
	}
}
PK)r!]�H8���helpers/export/item.phpnu&1i�<?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;

JLoader::register('PrivacyExportField', __DIR__ . '/field.php');

/**
 * 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 PrivacyExportItem
{
	/**
	 * 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    PrivacyExportField[]
	 * @since  3.9.0
	 */
	protected $fields = array();

	/**
	 * Add a field to the item
	 *
	 * @param   PrivacyExportField  $field  The field to add
	 *
	 * @return  void
	 *
	 * @since  3.9.0
	 */
	public function addField(PrivacyExportField $field)
	{
		$this->fields[] = $field;
	}

	/**
	 * Get the item's fields
	 *
	 * @return  PrivacyExportField[]
	 *
	 * @since  3.9.0
	 */
	public function getFields()
	{
		return $this->fields;
	}
}
PK)r!]y��,,helpers/export/field.phpnu&1i�<?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;

/**
 * Data object representing a field within an item.
 *
 * @since  3.9.0
 */
class PrivacyExportField
{
	/**
	 * 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;
}
PK)r!]=*Nhelpers/html/helper.phpnu&1i�<?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;

/**
 * Privacy component HTML helper.
 *
 * @since  3.9.0
 */
class PrivacyHtmlHelper
{
	/**
	 * Render a status label
	 *
	 * @param   integer  $status  The item status
	 *
	 * @return  string
	 *
	 * @since   3.9.0
	 */
	public static function statusLabel($status)
	{
		switch ($status)
		{
			case 2:
				return '<span class="label label-success">' . JText::_('COM_PRIVACY_STATUS_COMPLETED') . '</span>';

			case 1:
				return '<span class="label label-info">' . JText::_('COM_PRIVACY_STATUS_CONFIRMED') . '</span>';

			case -1:
				return '<span class="label label-important">' . JText::_('COM_PRIVACY_STATUS_INVALID') . '</span>';

			default:
			case 0:
				return '<span class="label label-warning">' . JText::_('COM_PRIVACY_STATUS_PENDING') . '</span>';
		}
	}
}
PK)r!]�:�<<helpers/removal/status.phpnu&1i�<?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;

/**
 * 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 PrivacyRemovalStatus
{
	/**
	 * 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;
}
PK)r!]�7�helpers/privacy.phpnu&1i�<?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\Factory;

/**
 * Privacy component helper.
 *
 * @since  3.9.0
 */
class PrivacyHelper extends JHelperContent
{
	/**
	 * Configure the Linkbar.
	 *
	 * @param   string  $vName  The name of the active view.
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public static function addSubmenu($vName)
	{
		JHtmlSidebar::addEntry(
			JText::_('COM_PRIVACY_SUBMENU_DASHBOARD'),
			'index.php?option=com_privacy&view=dashboard',
			$vName === 'dashboard'
		);

		JHtmlSidebar::addEntry(
			JText::_('COM_PRIVACY_SUBMENU_REQUESTS'),
			'index.php?option=com_privacy&view=requests',
			$vName === 'requests'
		);

		JHtmlSidebar::addEntry(
			JText::_('COM_PRIVACY_SUBMENU_CAPABILITIES'),
			'index.php?option=com_privacy&view=capabilities',
			$vName === 'capabilities'
		);

		JHtmlSidebar::addEntry(
			JText::_('COM_PRIVACY_SUBMENU_CONSENTS'),
			'index.php?option=com_privacy&view=consents',
			$vName === 'consents'
		);
	}

	/**
	 * Render the data request as a XML document.
	 *
	 * @param   PrivacyExportDomain[]  $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);

		try
		{
			$result = (int) $db->loadResult();
		}
		catch (RuntimeException $e)
		{
			JError::raiseWarning(500, $e->getMessage());
		}

		return $result;
	}
}
PK)r!]Q�FRRcontrollers/request.xml.phpnu&1i�<?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;

/**
 * Request management controller class.
 *
 * @since  3.9.0
 */
class PrivacyControllerRequest extends JControllerLegacy
{
	/**
	 * 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();
	}
}
PK)r!]�J$�zzcontrollers/consents.phpnu&1i�<?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;

/**
 * Consents management controller class.
 *
 * @since  3.9.0
 */
class PrivacyControllerConsents extends JControllerForm
{
	/**
	 * Method to invalidate specific consents.
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 */
	public function invalidate($key = null, $urlVar = null)
	{
		// Check for request forgeries
		JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN'));

		$ids = (array) $this->input->get('cid', array(), 'int');

		// Remove zero values resulting from input filter
		$ids = array_filter($ids);

		if (empty($ids))
		{
			$message = JText::_('JERROR_NO_ITEMS_SELECTED');

			$this->setError($message);
		}
		else
		{
			// Get the model.
			/** @var PrivacyModelConsents $model */
			$model = $this->getModel();

			// Publish the items.
			if (!$model->invalidate($ids))
			{
				$this->setError($model->getError());
			}

			$message = JText::plural('COM_PRIVACY_N_CONSENTS_INVALIDATED', count($ids));
		}

		$this->setRedirect(JRoute::_('index.php?option=com_privacy&view=consents', false), $message);
	}

	/**
	 * Method to invalidate all consents of a specific subject.
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 */
	public function invalidateAll()
	{
		// Check for request forgeries
		JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN'));

		$filters = $this->input->get('filter', array(), 'array');

		if (isset($filters['subject']) && $filters['subject'] != '')
		{
			$subject = $filters['subject'];
		}
		else
		{
			$this->setError(JText::_('JERROR_NO_ITEMS_SELECTED'));
		}

		// Get the model.
		/** @var PrivacyModelConsents $model */
		$model = $this->getModel();

		// Publish the items.
		if (!$model->invalidateAll($subject))
		{
			$this->setError($model->getError());
		}

		$message = JText::_('COM_PRIVACY_CONSENTS_INVALIDATED_ALL');

		$this->setRedirect(JRoute::_('index.php?option=com_privacy&view=consents', false), $message);
	}
}
PK)r!])��WF&F&controllers/request.phpnu&1i�<?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;

/**
 * Request management controller class.
 *
 * @since  3.9.0
 */
class PrivacyControllerRequest extends JControllerForm
{
	/**
	 * 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.
		JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN'));

		/** @var PrivacyModelRequest $model */
		$model = $this->getModel();

		/** @var PrivacyTableRequest $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->setError(\JText::_('COM_PRIVACY_ERROR_COMPLETE_TRANSITION_NOT_PERMITTED'));
			$this->setMessage($this->getError(), 'error');

			$this->setRedirect(
				\JRoute::_(
					'index.php?option=com_privacy&view=request&id=' . $recordId, false
				)
			);

			return false;
		}

		// Build the data array for the update
		$data = array(
			$key     => $recordId,
			'status' => '2',
		);

		// Access check.
		if (!$this->allowSave($data, $key))
		{
			$this->setError(\JText::_('JLIB_APPLICATION_ERROR_SAVE_NOT_PERMITTED'));
			$this->setMessage($this->getError(), 'error');

			$this->setRedirect(
				\JRoute::_(
					'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->setError(\JText::sprintf('JLIB_APPLICATION_ERROR_SAVE_FAILED', $model->getError()));
			$this->setMessage($this->getError(), 'error');

			$this->setRedirect(
				\JRoute::_(
					'index.php?option=com_privacy&view=request&id=' . $recordId, false
				)
			);

			return false;
		}

		// Log the request completed
		$model->logRequestCompleted($recordId);

		$this->setMessage(\JText::_('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) && \JUri::isInternal(base64_decode($return)))
		{
			$url = base64_decode($return);
		}

		// Redirect to the list screen.
		$this->setRedirect(\JRoute::_($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 PrivacyModelExport $model */
		$model = $this->getModel('Export');

		$recordId = $this->input->getUint('id');

		if (!$model->emailDataExport($recordId))
		{
			// Redirect back to the edit screen.
			$this->setError(\JText::sprintf('COM_PRIVACY_ERROR_EXPORT_EMAIL_FAILED', $model->getError()));
			$this->setMessage($this->getError(), 'error');
		}
		else
		{
			$this->setMessage(\JText::_('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) && \JUri::isInternal(base64_decode($return)))
		{
			$url = base64_decode($return);
		}

		// Redirect to the list screen.
		$this->setRedirect(\JRoute::_($url, false));

		return true;
	}

	/**
	 * 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.
		JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN'));

		/** @var PrivacyModelRequest $model */
		$model = $this->getModel();

		/** @var PrivacyTableRequest $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->setError(\JText::_('COM_PRIVACY_ERROR_INVALID_TRANSITION_NOT_PERMITTED'));
			$this->setMessage($this->getError(), 'error');

			$this->setRedirect(
				\JRoute::_(
					'index.php?option=com_privacy&view=request&id=' . $recordId, false
				)
			);

			return false;
		}

		// Build the data array for the update
		$data = array(
			$key     => $recordId,
			'status' => '-1',
		);

		// Access check.
		if (!$this->allowSave($data, $key))
		{
			$this->setError(\JText::_('JLIB_APPLICATION_ERROR_SAVE_NOT_PERMITTED'));
			$this->setMessage($this->getError(), 'error');

			$this->setRedirect(
				\JRoute::_(
					'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->setError(\JText::sprintf('JLIB_APPLICATION_ERROR_SAVE_FAILED', $model->getError()));
			$this->setMessage($this->getError(), 'error');

			$this->setRedirect(
				\JRoute::_(
					'index.php?option=com_privacy&view=request&id=' . $recordId, false
				)
			);

			return false;
		}

		// Log the request invalidated
		$model->logRequestInvalidated($recordId);

		$this->setMessage(\JText::_('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) && \JUri::isInternal(base64_decode($return)))
		{
			$url = base64_decode($return);
		}

		// Redirect to the list screen.
		$this->setRedirect(\JRoute::_($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 PrivacyModelRemove $model */
		$model = $this->getModel('Remove');

		$recordId = $this->input->getUint('id');

		if (!$model->removeDataForRequest($recordId))
		{
			// Redirect back to the edit screen.
			$this->setError(\JText::sprintf('COM_PRIVACY_ERROR_REMOVE_DATA_FAILED', $model->getError()));
			$this->setMessage($this->getError(), 'error');

			$this->setRedirect(
				\JRoute::_(
					'index.php?option=com_privacy&view=request&id=' . $recordId, false
				)
			);

			return false;
		}

		$this->setMessage(\JText::_('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) && \JUri::isInternal(base64_decode($return)))
		{
			$url = base64_decode($return);
		}

		// Redirect to the list screen.
		$this->setRedirect(\JRoute::_($url, false));

		return true;
	}

	/**
	 * Function that allows child controller access to model data after the data has been saved.
	 *
	 * @param   \JModelLegacy  $model      The data model object.
	 * @param   array          $validData  The validated data.
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	protected function postSaveHook(\JModelLegacy $model, $validData = array())
	{
		// 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())
			{
				JFactory::getApplication()->enqueueMessage($error, 'warning');
			}
		}

		if (!$model->notifyUserAdminCreatedRequest($model->getState($model->getName() . '.id')))
		{
			if ($error = $model->getError())
			{
				JFactory::getApplication()->enqueueMessage($error, 'warning');
			}
		}
		else
		{
			JFactory::getApplication()->enqueueMessage(JText::_('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, array('-1', '2'), true);

			// 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
			case '-1':
			case '2':
			default:
				return false;
		}
	}
}
PK)r!]��B��controllers/requests.phpnu&1i�<?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;

/**
 * Requests management controller class.
 *
 * @since  3.9.0
 */
class PrivacyControllerRequests extends JControllerAdmin
{
	/**
	 * 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  JModelLegacy|boolean  Model object on success; otherwise false on failure.
	 *
	 * @since   3.9.0
	 */
	public function getModel($name = 'Request', $prefix = 'PrivacyModel', $config = array('ignore_request' => true))
	{
		return parent::getModel($name, $prefix, $config);
	}
}
PK)r!]Z�y==tables/request.phpnu&1i�<?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;

/**
 * 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 PrivacyTableRequest extends JTable
{
	/**
	 * The class constructor.
	 *
	 * @param   JDatabaseDriver  $db  JDatabaseDriver connector object.
	 *
	 * @since   3.9.0
	 */
	public function __construct(JDatabaseDriver $db)
	{
		parent::__construct('#__privacy_requests', 'id', $db);
	}

	/**
	 * 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 = JFactory::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();
			}
		}

		return parent::store($updateNulls);
	}
}
PK)r!]<X����tables/consent.phpnu&1i�<?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;

/**
 * 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 PrivacyTableConsent extends JTable
{
	/**
	 * The class constructor.
	 *
	 * @param   JDatabaseDriver  $db  JDatabaseDriver connector object.
	 *
	 * @since   3.9.0
	 */
	public function __construct(JDatabaseDriver $db)
	{
		parent::__construct('#__privacy_consents', 'id', $db);
	}

	/**
	 * 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 = JFactory::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);
	}
}
PK)r!]��>���models/remove.phpnu&1i�<?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;

JLoader::register('PrivacyHelper', JPATH_ADMINISTRATOR . '/components/com_privacy/helpers/privacy.php');
JLoader::register('PrivacyRemovalStatus', JPATH_ADMINISTRATOR . '/components/com_privacy/helpers/removal/status.php');

/**
 * Remove model class.
 *
 * @since  3.9.0
 */
class PrivacyModelRemove extends JModelLegacy
{
	/**
	 * 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(JText::_('COM_PRIVACY_ERROR_REQUEST_ID_REQUIRED_FOR_REMOVE'));

			return false;
		}

		/** @var PrivacyTableRequest $table */
		$table = $this->getTable();

		if (!$table->load($id))
		{
			$this->setError($table->getError());

			return false;
		}

		if ($table->request_type !== 'remove')
		{
			$this->setError(JText::_('COM_PRIVACY_ERROR_REQUEST_TYPE_NOT_REMOVE'));

			return false;
		}

		if ($table->status != 1)
		{
			$this->setError(JText::_('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->getDbo();

		$userId = (int) $db->setQuery(
			$db->getQuery(true)
				->select('id')
				->from($db->quoteName('#__users'))
				->where('LOWER(' . $db->quoteName('email') . ') = LOWER(' . $db->quote($table->email) . ')'),
			0,
			1
		)->loadResult();

		$user = $userId ? JUser::getInstance($userId) : null;

		$canRemove = true;

		JPluginHelper::importPlugin('privacy');

		/** @var PrivacyRemovalStatus[] $pluginResults */
		$pluginResults = JFactory::getApplication()->triggerEvent('onPrivacyCanRemoveData', array($table, $user));

		foreach ($pluginResults as $status)
		{
			if (!$status->canRemove)
			{
				$this->setError($status->reason ?: JText::_('COM_PRIVACY_ERROR_CANNOT_REMOVE_DATA'));

				$canRemove = false;
			}
		}

		if (!$canRemove)
		{
			$this->logRemoveBlocked($table, $this->getErrors());

			return false;
		}

		// Log the removal
		$this->logRemove($table);

		JFactory::getApplication()->triggerEvent('onPrivacyRemoveData', array($table, $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  JTable  A JTable object
	 *
	 * @since   3.9.0
	 * @throws  \Exception
	 */
	public function getTable($name = 'Request', $prefix = 'PrivacyTable', $options = array())
	{
		return parent::getTable($name, $prefix, $options);
	}

	/**
	 * Log the data removal to the action log system.
	 *
	 * @param   PrivacyTableRequest  $request  The request record being processed
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function logRemove(PrivacyTableRequest $request)
	{
		JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_actionlogs/models', 'ActionlogsModel');

		$user = JFactory::getUser();

		$message = array(
			'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,
		);

		/** @var ActionlogsModelActionlog $model */
		$model = JModelLegacy::getInstance('Actionlog', 'ActionlogsModel');
		$model->addLog(array($message), 'COM_PRIVACY_ACTION_LOG_REMOVE', 'com_privacy.request', $user->id);
	}

	/**
	 * Log the data removal being blocked to the action log system.
	 *
	 * @param   PrivacyTableRequest  $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(PrivacyTableRequest $request, array $reasons)
	{
		JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_actionlogs/models', 'ActionlogsModel');

		$user = JFactory::getUser();

		$message = array(
			'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),
		);

		/** @var ActionlogsModelActionlog $model */
		$model = JModelLegacy::getInstance('Actionlog', 'ActionlogsModel');
		$model->addLog(array($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', JFactory::getApplication()->input->getUint('id'));

		// Load the parameters.
		$this->setState('params', JComponentHelper::getParams('com_privacy'));
	}
}
PK)r!]�˾RR models/forms/filter_requests.xmlnu&1i�<?xml version="1.0" encoding="utf-8"?>
<form>
	<fieldset addfieldpath="/administrator/components/com_privacy/models/fields" />

	<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="privacy.requeststatus"
			label="COM_PRIVACY_FILTER_STATUS"
			description="COM_PRIVACY_FILTER_STATUS_DESC"
			onchange="this.form.submit();"
			>
			<option value="">JOPTION_SELECT_PUBLISHED</option>
		</field>

		<field
			name="request_type"
			type="privacy.requesttype"
			label="COM_PRIVACY_FILTER_REQUEST_TYPE"
			description="COM_PRIVACY_FILTER_REQUEST_TYPE_DESC"
			onchange="this.form.submit();"
			>
			<option value="">COM_PRIVACY_SELECT_REQUEST_TYPE</option>
		</field>
	</fields>

	<fields name="list">
		<field
			name="fullordering"
			type="list"
			label="JGLOBAL_SORT_BY"
			description="JGLOBAL_SORT_BY"
			onchange="this.form.submit();"
			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"
			class="input-mini"
			default="25"
			onchange="this.form.submit();"
		/>
	</fields>
</form>
PK)r!]��		 models/forms/filter_consents.xmlnu&1i�<?xml version="1.0" encoding="utf-8"?>
<form>
	<fieldset addfieldpath="/administrator/components/com_privacy/models/fields" />

	<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"
			onchange="this.form.submit();"
			>
			<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"
			onchange="this.form.submit();"
			>
			<option value="">COM_PRIVACY_CONSENTS_SUBJECT_DEFAULT</option>
		</field>
	</fields>

	<fields name="list">
		<field
			name="fullordering"
			type="list"
			label="JGLOBAL_SORT_BY"
			description="JGLOBAL_SORT_BY"
			onchange="this.form.submit();"
			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.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"
			class="input-mini"
			default="25"
			onchange="this.form.submit();"
		/>
	</fields>
</form>
PK)r!]�Q/models/forms/request.xmlnu&1i�<?xml version="1.0" encoding="utf-8"?>
<form>
	<fieldset addfieldpath="/administrator/components/com_privacy/models/fields">
		<field
			name="email"
			type="email"
			label="JGLOBAL_EMAIL"
			description="COM_PRIVACY_USER_FIELD_EMAIL_DESC"
			required="true"
			size="30"
			validate="email"
		/>

		<field
			name="status"
			type="list"
			label="JSTATUS"
			description="COM_PRIVACY_FIELD_STATUS_DESC"
			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"
			description="COM_PRIVACY_FIELD_REQUEST_TYPE_DESC"
			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>
PK)r!]_�Զ"�"models/export.phpnu&1i�<?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;

JLoader::register('PrivacyHelper', JPATH_ADMINISTRATOR . '/components/com_privacy/helpers/privacy.php');

/**
 * Export model class.
 *
 * @since  3.9.0
 */
class PrivacyModelExport extends JModelLegacy
{
	/**
	 * Create the export document for an information request.
	 *
	 * @param   integer  $id  The request ID to process
	 *
	 * @return  PrivacyExportDomain[]|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(JText::_('COM_PRIVACY_ERROR_REQUEST_ID_REQUIRED_FOR_EXPORT'));

			return false;
		}

		/** @var PrivacyTableRequest $table */
		$table = $this->getTable();

		if (!$table->load($id))
		{
			$this->setError($table->getError());

			return false;
		}

		if ($table->request_type !== 'export')
		{
			$this->setError(JText::_('COM_PRIVACY_ERROR_REQUEST_TYPE_NOT_EXPORT'));

			return false;
		}

		if ($table->status != 1)
		{
			$this->setError(JText::_('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->getDbo();

		$userId = (int) $db->setQuery(
			$db->getQuery(true)
				->select('id')
				->from($db->quoteName('#__users'))
				->where('LOWER(' . $db->quoteName('email') . ') = LOWER(' . $db->quote($table->email) . ')'),
			0,
			1
		)->loadResult();

		$user = $userId ? JUser::getInstance($userId) : null;

		// Log the export
		$this->logExport($table);

		JPluginHelper::importPlugin('privacy');

		$pluginResults = JFactory::getApplication()->triggerEvent('onPrivacyExportRequest', array($table, $user));

		$domains = array();

		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(JText::_('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 PrivacyTableRequest $table */
		$table = $this->getTable();

		if (!$table->load($id))
		{
			$this->setError($table->getError());

			return false;
		}

		if ($table->request_type !== 'export')
		{
			$this->setError(JText::_('COM_PRIVACY_ERROR_REQUEST_TYPE_NOT_EXPORT'));

			return false;
		}

		if ($table->status != 1)
		{
			$this->setError(JText::_('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 = JFactory::getLanguage();

		$db = $this->getDbo();

		$userId = (int) $db->setQuery(
			$db->getQuery(true)
				->select('id')
				->from($db->quoteName('#__users'))
				->where('LOWER(' . $db->quoteName('email') . ') = LOWER(' . $db->quote($table->email) . ')'),
			0,
			1
		)->loadResult();

		if ($userId)
		{
			$receiver = JUser::getInstance($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 = JLanguage::getInstance($langCode, $lang->getDebug());
		}

		// Ensure the right language files have been loaded
		$lang->load('com_privacy', JPATH_ADMINISTRATOR, null, false, true)
			|| $lang->load('com_privacy', JPATH_ADMINISTRATOR . '/components/com_privacy', null, false, true);

		// The mailer can be set to either throw Exceptions or return boolean false, account for both
		try
		{
			$app = JFactory::getApplication();

			$substitutions = array(
				'[SITENAME]' => $app->get('sitename'),
				'[URL]'      => JUri::root(),
				'\\n'        => "\n",
			);

			$emailSubject = $lang->_('COM_PRIVACY_EMAIL_DATA_EXPORT_COMPLETED_SUBJECT');
			$emailBody    = $lang->_('COM_PRIVACY_EMAIL_DATA_EXPORT_COMPLETED_BODY');

			foreach ($substitutions as $k => $v)
			{
				$emailSubject = str_replace($k, $v, $emailSubject);
				$emailBody    = str_replace($k, $v, $emailBody);
			}

			$mailer = JFactory::getMailer();
			$mailer->setSubject($emailSubject);
			$mailer->setBody($emailBody);
			$mailer->addRecipient($table->email);
			$mailer->addStringAttachment(
				PrivacyHelper::renderDataAsXml($exportData),
				'user-data_' . JUri::getInstance()->toString(array('host')) . '.xml'
			);

			$mailResult = $mailer->Send();

			if ($mailResult instanceof JException)
			{
				// JError was already called so we just need to return now
				return false;
			}
			elseif ($mailResult === false)
			{
				$this->setError($mailer->ErrorInfo);

				return false;
			}

			return true;
		}
		catch (phpmailerException $exception)
		{
			$this->setError($exception->getMessage());

			return false;
		}

		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  JTable  A JTable object
	 *
	 * @since   3.9.0
	 * @throws  \Exception
	 */
	public function getTable($name = 'Request', $prefix = 'PrivacyTable', $options = array())
	{
		return parent::getTable($name, $prefix, $options);
	}

	/**
	 * Log the data export to the action log system.
	 *
	 * @param   PrivacyTableRequest  $request  The request record being processed
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function logExport(PrivacyTableRequest $request)
	{
		JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_actionlogs/models', 'ActionlogsModel');

		$user = JFactory::getUser();

		$message = array(
			'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,
		);

		/** @var ActionlogsModelActionlog $model */
		$model = JModelLegacy::getInstance('Actionlog', 'ActionlogsModel');
		$model->addLog(array($message), 'COM_PRIVACY_ACTION_LOG_EXPORT', 'com_privacy.request', $user->id);
	}

	/**
	 * Log the data export email to the action log system.
	 *
	 * @param   PrivacyTableRequest  $request  The request record being processed
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function logExportEmailed(PrivacyTableRequest $request)
	{
		JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_actionlogs/models', 'ActionlogsModel');

		$user = JFactory::getUser();

		$message = array(
			'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,
		);

		/** @var ActionlogsModelActionlog $model */
		$model = JModelLegacy::getInstance('Actionlog', 'ActionlogsModel');
		$model->addLog(array($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', JFactory::getApplication()->input->getUint('id'));

		// Load the parameters.
		$this->setState('params', JComponentHelper::getParams('com_privacy'));
	}
}
PK)r!]�Y��;0;0models/request.phpnu&1i�<?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\Router\Route;

/**
 * Request item model class.
 *
 * @since  3.9.0
 */
class PrivacyModelRequest extends JModelAdmin
{
	/**
	 * Clean the cache
	 *
	 * @param   string   $group     The cache group
	 * @param   integer  $clientId  The ID of the client
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	protected function cleanCache($group = 'com_privacy', $clientId = 1)
	{
		parent::cleanCache('com_privacy', 1);
	}

	/**
	 * 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  JForm|boolean  A JForm object on success, false on failure
	 *
	 * @since   3.9.0
	 */
	public function getForm($data = array(), $loadData = true)
	{
		// Get the form.
		$form = $this->loadForm('com_privacy.request', 'request', array('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  JTable  A JTable object
	 *
	 * @since   3.9.0
	 * @throws  \Exception
	 */
	public function getTable($name = 'Request', $prefix = 'PrivacyTable', $options = array())
	{
		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 = JFactory::getApplication()->getUserState('com_privacy.edit.request.data', array());

		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 PrivacyTableRequest $table */
		$table = $this->getTable();

		if (!$table->load($id))
		{
			$this->setError($table->getError());

			return false;
		}

		JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_actionlogs/models', 'ActionlogsModel');

		$user = JFactory::getUser();

		$message = array(
			'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,
		);

		/** @var ActionlogsModelActionlog $model */
		$model = JModelLegacy::getInstance('Actionlog', 'ActionlogsModel');
		$model->addLog(array($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 PrivacyTableRequest $table */
		$table = $this->getTable();

		if (!$table->load($id))
		{
			$this->setError($table->getError());

			return false;
		}

		JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_actionlogs/models', 'ActionlogsModel');

		$user = JFactory::getUser();

		$message = array(
			'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,
		);

		/** @var ActionlogsModelActionlog $model */
		$model = JModelLegacy::getInstance('Actionlog', 'ActionlogsModel');
		$model->addLog(array($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 PrivacyTableRequest $table */
		$table = $this->getTable();

		if (!$table->load($id))
		{
			$this->setError($table->getError());

			return false;
		}

		JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_actionlogs/models', 'ActionlogsModel');

		$user = JFactory::getUser();

		$message = array(
			'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,
		);

		/** @var ActionlogsModelActionlog $model */
		$model = JModelLegacy::getInstance('Actionlog', 'ActionlogsModel');
		$model->addLog(array($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 PrivacyTableRequest $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 = JFactory::getLanguage();

		$db = $this->getDbo();

		$userId = (int) $db->setQuery(
			$db->getQuery(true)
				->select('id')
				->from($db->quoteName('#__users'))
				->where('LOWER(' . $db->quoteName('email') . ') = LOWER(' . $db->quote($table->email) . ')'),
			0,
			1
		)->loadResult();

		if ($userId)
		{
			$receiver = JUser::getInstance($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 = JLanguage::getInstance($langCode, $lang->getDebug());
		}

		// Ensure the right language files have been loaded
		$lang->load('com_privacy', JPATH_ADMINISTRATOR, null, false, true)
			|| $lang->load('com_privacy', JPATH_ADMINISTRATOR . '/components/com_privacy', null, false, true);

		// Regenerate the confirmation token
		$token       = JApplicationHelper::getHash(JUserHelper::genRandomPassword());
		$hashedToken = JUserHelper::hashPassword($token);

		$table->confirm_token            = $hashedToken;
		$table->confirm_token_created_at = JFactory::getDate()->toSql();

		try
		{
			$table->store();
		}
		catch (JDatabaseException $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 = JFactory::getApplication();

			$linkMode = $app->get('force_ssl', 0) == 2 ? Route::TLS_FORCE : Route::TLS_IGNORE;

			$substitutions = array(
				'[SITENAME]' => $app->get('sitename'),
				'[URL]'      => JUri::root(),
				'[TOKENURL]' => JRoute::link('site', 'index.php?option=com_privacy&view=confirm&confirm_token=' . $token, false, $linkMode, true),
				'[FORMURL]'  => JRoute::link('site', 'index.php?option=com_privacy&view=confirm', false, $linkMode, true),
				'[TOKEN]'    => $token,
				'\\n'        => "\n",
			);

			switch ($table->request_type)
			{
				case 'export':
					$emailSubject = $lang->_('COM_PRIVACY_EMAIL_ADMIN_REQUEST_SUBJECT_EXPORT_REQUEST');
					$emailBody    = $lang->_('COM_PRIVACY_EMAIL_ADMIN_REQUEST_BODY_EXPORT_REQUEST');

					break;

				case 'remove':
					$emailSubject = $lang->_('COM_PRIVACY_EMAIL_ADMIN_REQUEST_SUBJECT_REMOVE_REQUEST');
					$emailBody    = $lang->_('COM_PRIVACY_EMAIL_ADMIN_REQUEST_BODY_REMOVE_REQUEST');

					break;

				default:
					$this->setError(JText::_('COM_PRIVACY_ERROR_UNKNOWN_REQUEST_TYPE'));

					return false;
			}

			foreach ($substitutions as $k => $v)
			{
				$emailSubject = str_replace($k, $v, $emailSubject);
				$emailBody    = str_replace($k, $v, $emailBody);
			}

			$mailer = JFactory::getMailer();
			$mailer->setSubject($emailSubject);
			$mailer->setBody($emailBody);
			$mailer->addRecipient($table->email);

			$mailResult = $mailer->Send();

			if ($mailResult instanceof JException)
			{
				// JError was already called so we just need to return now
				return false;
			}
			elseif ($mailResult === false)
			{
				$this->setError($mailer->ErrorInfo);

				return false;
			}

			return true;
		}
		catch (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 && !JFactory::getConfig()->get('mailonline', 1))
		{
			$this->setError(JText::_('COM_PRIVACY_ERROR_CANNOT_CREATE_REQUEST_WHEN_SENDMAIL_DISABLED'));

			return false;
		}

		return parent::save($data);
	}

	/**
	 * Method to validate the form data.
	 *
	 * @param   JForm   $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     JFormRule
	 * @see     JFilterInput
	 * @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(JFactory::getUser()->email) === strtolower($validatedData['email']))
		{
			$this->setError(JText::_('COM_PRIVACY_ERROR_CANNOT_CREATE_REQUEST_FOR_SELF'));

			return false;
		}

		// Check for an active request for this email address
		$db = $this->getDbo();

		$query = $db->getQuery(true)
			->select('COUNT(id)')
			->from('#__privacy_requests')
			->where('email = ' . $db->quote($validatedData['email']))
			->where('request_type = ' . $db->quote($validatedData['request_type']))
			->where('status IN (0, 1)');

		$activeRequestCount = (int) $db->setQuery($query)->loadResult();

		if ($activeRequestCount > 0)
		{
			$this->setError(JText::_('COM_PRIVACY_ERROR_ACTIVE_REQUEST_FOR_EMAIL'));

			return false;
		}

		return $validatedData;
	}
}
PK)r!]��;��models/requests.phpnu&1i�<?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\Component\ComponentHelper;

/**
 * Requests management model class.
 *
 * @since  3.9.0
 */
class PrivacyModelRequests extends JModelList
{
	/**
	 * Constructor.
	 *
	 * @param   array  $config  An optional associative array of configuration settings.
	 *
	 * @since   3.9.0
	 */
	public function __construct($config = array())
	{
		if (empty($config['filter_fields']))
		{
			$config['filter_fields'] = array(
				'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 JDatabaseQuery object for retrieving the data set from a database.
	 *
	 * @return  JDatabaseQuery
	 *
	 * @since   3.9.0
	 */
	protected function getListQuery()
	{
		// Create a new query object.
		$db    = $this->getDbo();
		$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))
		{
			$query->where('a.status = ' . (int) $status);
		}

		// Filter by request type
		$requestType = $this->getState('filter.request_type', '');

		if ($requestType)
		{
			$query->where('a.request_type = ' . $db->quote($db->escape($requestType, true)));
		}

		// Filter by search in email
		$search = $this->getState('filter.search');

		if (!empty($search))
		{
			if (stripos($search, 'id:') === 0)
			{
				$query->where($db->quoteName('a.id') . ' = ' . (int) substr($search, 3));
			}
			else
			{
				$search = $db->quote('%' . $db->escape($search, true) . '%');
				$query->where('(' . $db->quoteName('a.email') . ' LIKE ' . $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 filter state.
		$this->setState(
			'filter.search',
			$this->getUserStateFromRequest($this->context . '.filter.search', 'filter_search')
		);

		$this->setState(
			'filter.status',
			$this->getUserStateFromRequest($this->context . '.filter.status', 'filter_status', '', 'int')
		);

		$this->setState(
			'filter.request_type',
			$this->getUserStateFromRequest($this->context . '.filter.request_type', 'filter_request_type', '', 'string')
		);

		// Load the parameters.
		$this->setState('params', JComponentHelper::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    = JFactory::getDate()->toSql();
		$period = '-' . $notify;

		$db    = $this->getDbo();
		$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();
	}
}
PK)r!]p8q

models/consents.phpnu&1i�<?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\Utilities\ArrayHelper;

/**
 * Consents management model class.
 *
 * @since  3.9.0
 */
class PrivacyModelConsents extends JModelList
{
	/**
	 * Constructor.
	 *
	 * @param   array  $config  An optional associative array of configuration settings.
	 *
	 * @since   3.9.0
	 */
	public function __construct($config = array())
	{
		if (empty($config['filter_fields']))
		{
			$config['filter_fields'] = array(
				'id', 'a.id', 
				'user_id', 'a.user_id',
				'subject', 'a.subject',
				'created', 'a.created',
				'username', 'u.username',
				'state', 'a.state'
			);
		}

		parent::__construct($config);
	}

	/**
	 * Method to get a JDatabaseQuery object for retrieving the data set from a database.
	 *
	 * @return  JDatabaseQuery
	 *
	 * @since   3.9.0
	 */
	protected function getListQuery()
	{
		// Create a new query object.
		$db    = $this->getDbo();
		$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.
		$query->select($db->quoteName('u.username', 'username'));
		$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)
			{
				$query->where($db->quoteName('a.id') . ' = ' . (int) substr($search, 3));
			}
			elseif (stripos($search, 'uid:') === 0)
			{
				$query->where($db->quoteName('a.user_id') . ' = ' . (int) substr($search, 4));
			}
			else
			{
				$search = $db->quote('%' . $db->escape($search, true) . '%');
				$query->where('(' . $db->quoteName('u.username') . ' LIKE ' . $search . ')');
			}
		}

		$state = $this->getState('filter.state');

		if ($state != '')
		{
			$query->where($db->quoteName('a.state') . ' = ' . (int) $state);
		}

		// 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 filter state.
		$this->setState(
			'filter.search',
			$this->getUserStateFromRequest($this->context . '.filter.search', 'filter_search')
		);

		$this->setState(
			'filter.subject',
			$this->getUserStateFromRequest($this->context . '.filter.subject', 'filter_subject')
		);

		$this->setState(
			'filter.state',
			$this->getUserStateFromRequest($this->context . '.filter.state', 'filter_state')
		);

		// Load the parameters.
		$this->setState('params', JComponentHelper::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->getDbo();
			$query = $db->getQuery(true)
				->update($db->quoteName('#__privacy_consents'))
				->set($db->quoteName('state') . ' = -1')
				->where($db->quoteName('id') . ' IN (' . implode(',', $pks) . ')')
				->where($db->quoteName('state') . ' = 1');
			$db->setQuery($query);
			$db->execute();
		}
		catch (JDatabaseExceptionExecuting $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->getDbo();
			$query = $db->getQuery(true)
				->update($db->quoteName('#__privacy_consents'))
				->set($db->quoteName('state') . ' = -1')
				->where($db->quoteName('subject') . ' = ' . $db->quote($subject))
				->where($db->quoteName('state') . ' = 1');
			$db->setQuery($query);
			$db->execute();
		}
		catch (JDatabaseExceptionExecuting $e)
		{
			$this->setError($e->getMessage());

			return false;
		}

		return true;
	}
}
PK)r!]�\��P
P
models/capabilities.phpnu&1i�<?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;

/**
 * Capabilities model class.
 *
 * @since  3.9.0
 */
class PrivacyModelCapabilities extends JModelLegacy
{
	/**
	 * Retrieve the extension capabilities.
	 *
	 * @return  array
	 *
	 * @since   3.9.0
	 */
	public function getCapabilities()
	{
		$app = JFactory::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 = array(
			JText::_('COM_PRIVACY_HEADING_CORE_CAPABILITIES') => array(
				JText::_('COM_PRIVACY_CORE_CAPABILITY_SESSION_IP_ADDRESS_AND_COOKIE'),
				JText::sprintf('COM_PRIVACY_CORE_CAPABILITY_LOGGING_IP_ADDRESS', $app->get('log_path', JPATH_ADMINISTRATOR . '/logs')),
				JText::_('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.
		 */

		JPluginHelper::importPlugin('authentication');
		JPluginHelper::importPlugin('captcha');
		JPluginHelper::importPlugin('installer');
		JPluginHelper::importPlugin('privacy');
		JPluginHelper::importPlugin('user');

		$pluginResults = $app->triggerEvent('onPrivacyCollectAdminCapabilities');

		// We are going to "cheat" here and include this component's capabilities without using a plugin
		$extensionCapabilities = array(
			JText::_('COM_PRIVACY') => array(
				JText::_('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', JComponentHelper::getParams('com_privacy'));
	}
}
PK)r!]��Y�UUmodels/fields/requeststatus.phpnu&1i�<?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;

JFormHelper::loadFieldClass('predefinedlist');

/**
 * Form Field to load a list of request statuses
 *
 * @since  3.9.0
 */
class PrivacyFormFieldRequeststatus extends JFormFieldPredefinedList
{
	/**
	 * The form field type.
	 *
	 * @var    string
	 * @since  3.9.0
	 */
	public $type = 'RequestStatus';

	/**
	 * Available statuses
	 *
	 * @var    array
	 * @since  3.9.0
	 */
	protected $predefinedOptions = array(
		'-1' => 'COM_PRIVACY_STATUS_INVALID',
		'0'  => 'COM_PRIVACY_STATUS_PENDING',
		'1'  => 'COM_PRIVACY_STATUS_CONFIRMED',
		'2'  => 'COM_PRIVACY_STATUS_COMPLETED',
	);
}
PK)r!]v�Z##models/fields/requesttype.phpnu&1i�<?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;

JFormHelper::loadFieldClass('predefinedlist');

/**
 * Form Field to load a list of request types
 *
 * @since  3.9.0
 */
class PrivacyFormFieldRequesttype extends JFormFieldPredefinedList
{
	/**
	 * The form field type.
	 *
	 * @var    string
	 * @since  3.9.0
	 */
	public $type = 'RequestType';

	/**
	 * Available types
	 *
	 * @var    array
	 * @since  3.9.0
	 */
	protected $predefinedOptions = array(
		'export' => 'COM_PRIVACY_HEADING_REQUEST_TYPE_TYPE_EXPORT',
		'remove' => 'COM_PRIVACY_HEADING_REQUEST_TYPE_TYPE_REMOVE',
	);
}
PK)r!]�@@models/dashboard.phpnu&1i�<?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\Router\Route;

/**
 * Dashboard model class.
 *
 * @since  3.9.0
 */
class PrivacyModelDashboard extends JModelLegacy
{
	/**
	 * Get the information about the published privacy policy
	 *
	 * @return  array  Array containing a status of whether a privacy policy is set and a link to the policy document for editing
	 *
	 * @since   3.9.0
	 */
	public function getPrivacyPolicyInfo()
	{
		$policy = array(
			'published'         => false,
			'articlePublished'  => false,
			'editLink'          => '',
		);

		/*
		 * Prior to 3.9.0 it was common for a plugin such as the User - Profile plugin to define a privacy policy or
		 * terms of service article, therefore we will also import the user plugin group to process this event.
		 */
		JPluginHelper::importPlugin('privacy');
		JPluginHelper::importPlugin('user');

		JFactory::getApplication()->triggerEvent('onPrivacyCheckPrivacyPolicyPublished', array(&$policy));

		return $policy;
	}

	/**
	 * Get a count of the active information requests grouped by type and status
	 *
	 * @return  array  Array containing site privacy requests
	 *
	 * @since   3.9.0
	 */
	public function getRequestCounts()
	{
		$db    = $this->getDbo();
		$query = $db->getQuery(true)
			->select(
				array(
					'COUNT(*) AS count',
					$db->quoteName('status'),
					$db->quoteName('request_type'),
				)
			)
			->from($db->quoteName('#__privacy_requests'))
			->group($db->quoteName('status'))
			->group($db->quoteName('request_type'));

		$db->setQuery($query);

		return $db->loadObjectList();
	}

	/**
	 * Check whether there is a menu item for the request form
	 *
	 * @return  array  Array containing a status of whether a menu is published for the request form and its current link
	 *
	 * @since   3.9.0
	 */
	public function getRequestFormPublished()
	{
		$status = array(
			'exists'    => false,
			'published' => false,
			'link'      => '',
		);

		$db    = $this->getDbo();
		$query = $db->getQuery(true)
			->select($db->quoteName('id') . ', ' . $db->quoteName('published') . ', ' . $db->quoteName('language'))
			->from($db->quoteName('#__menu'))
			->where($db->quoteName('client_id') . ' = 0')
			->where($db->quoteName('link') . ' = ' . $db->quote('index.php?option=com_privacy&view=request'));
		$db->setQuery($query);

		$menuItem = $db->loadObject();

		// Check if the menu item exists in database
		if ($menuItem)
		{
			$status['exists'] = true;

			// Check if the menu item is published
			if ($menuItem->published == 1)
			{
				$status['published'] = true;
			}

			// Add language to the url if the site is multilingual
			if (JLanguageMultilang::isEnabled() && $menuItem->language && $menuItem->language !== '*')
			{
				$lang = '&lang=' . $menuItem->language;
			}
			else
			{
				$lang = '';
			}
		}

		$linkMode = JFactory::getApplication()->get('force_ssl', 0) == 2 ? Route::TLS_FORCE : Route::TLS_IGNORE;

		if (!$menuItem)
		{
			if (JLanguageMultilang::isEnabled())
			{
				// Find the Itemid of the home menu item tagged to the site default language
				$params = JComponentHelper::getParams('com_languages');
				$defaultSiteLanguage = $params->get('site');

				$db    = $this->getDbo();
				$query = $db->getQuery(true)
					->select($db->quoteName('id'))
					->from($db->quoteName('#__menu'))
					->where($db->quoteName('client_id') . ' = 0')
					->where($db->quoteName('home') . ' = 1')
					->where($db->quoteName('language') . ' = ' . $db->quote($defaultSiteLanguage));
				$db->setQuery($query);

				$homeId = (int) $db->loadResult();
				$itemId = $homeId ? '&Itemid=' . $homeId : '';
			}
			else
			{
				$itemId = '';
			}

			$status['link'] = JRoute::link('site', 'index.php?option=com_privacy&view=request' . $itemId, true, $linkMode);
		}
		else
		{
			$status['link'] = JRoute::link('site', 'index.php?Itemid=' . $menuItem->id . $lang, true, $linkMode);
		}

		return $status;
	}
}
PK)r!]�
��++controller.phpnu&1i�<?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\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Response\JsonResponse;
use Joomla\CMS\Session\Session;

/**
 * Privacy Controller
 *
 * @since  3.9.0
 */
class PrivacyController extends JControllerLegacy
{
	/**
	 * The default view.
	 *
	 * @var    string
	 * @since  3.9.0
	 */
	protected $default_view = 'dashboard';

	/**
	 * 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, for valid values see {@link JFilterInput::clean()}.
	 *
	 * @return  $this
	 *
	 * @since   3.9.0
	 */
	public function display($cachable = false, $urlparams = array())
	{
		JLoader::register('PrivacyHelper', JPATH_ADMINISTRATOR . '/components/com_privacy/helpers/privacy.php');

		// Get the document object.
		$document = JFactory::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);

			// For the dashboard view, we need to also push the requests model into the view
			if ($vName === 'dashboard')
			{
				$requestsModel = $this->getModel('Requests');

				$view->setModel($requestsModel, false);
			}

			if ($vName === 'request')
			{
				// For the default layout, we need to also push the action logs model into the view
				if ($lName === 'default')
				{
					JLoader::register('ActionlogsHelper', JPATH_ADMINISTRATOR . '/components/com_actionlogs/helpers/actionlogs.php');
					JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_actionlogs/models', 'ActionlogsModel');

					$logsModel = $this->getModel('Actionlogs', 'ActionlogsModel');

					// 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' && !JFactory::getConfig()->get('mailonline', 1))
				{
					$this->setRedirect(
						JRoute::_('index.php?option=com_privacy&view=requests', false),
						JText::_('COM_PRIVACY_WARNING_CANNOT_CREATE_REQUEST_WHEN_SENDMAIL_DISABLED'),
						'warning'
					);

					return $this;
				}
			}

			$view->setLayout($lName);

			// Push document object into the view.
			$view->document = $document;

			// Load the submenu.
			PrivacyHelper::addSubmenu($this->input->get('view', $this->default_view));

			$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()
	{
		$app = Factory::getApplication();

		// Check for a valid token. If invalid, send a 403 with the error message.
		if (!Session::checkToken('get'))
		{
			$app->setHeader('status', 403, true);
			$app->sendHeaders();
			echo new JsonResponse(new \Exception(Text::_('JINVALID_TOKEN'), 403));
			$app->close();
		}

		/** @var PrivacyModelRequests $model */
		$model                = $this->getModel('requests');
		$numberUrgentRequests = $model->getNumberUrgentRequests();

		echo new JResponseJson(array('number_urgent_requests' => $numberUrgentRequests));

		$app->close();
	}
}
PK)r!]�cW5zzviews/consents/tmpl/default.phpnu&1i�<?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;

/** @var PrivacyViewConsent $this */

// Load the tooltip behavior.
JHtml::_('bootstrap.tooltip');
JHtml::_('behavior.multiselect');
JHtml::_('formbehavior.chosen', 'select');

$user       = JFactory::getUser();
$listOrder  = $this->escape($this->state->get('list.ordering'));
$listDirn   = $this->escape($this->state->get('list.direction'));
$now        = JFactory::getDate();
$stateIcons = array(-1 => 'trash', 0 => 'archive', 1 => 'publish');
$stateMsgs  = array(-1 => JText::_('COM_PRIVACY_CONSENTS_STATE_INVALIDATED'), 0 => JText::_('COM_PRIVACY_CONSENTS_STATE_OBSOLETE'), 1 => JText::_('COM_PRIVACY_CONSENTS_STATE_VALID'));

?>
<form action="<?php echo JRoute::_('index.php?option=com_privacy&view=consents'); ?>" method="post" name="adminForm" id="adminForm">
	<?php if (!empty($this->sidebar)) : ?>
		<div id="j-sidebar-container" class="span2">
			<?php echo $this->sidebar; ?>
		</div>
		<div id="j-main-container" class="span10">
	<?php else : ?>
		<div id="j-main-container">
	<?php endif; ?>
		<?php echo JLayoutHelper::render('joomla.searchtools.default', array('view' => $this)); ?>
		<div class="clearfix"> </div>
		<?php if (empty($this->items)) : ?>
			<div class="alert alert-no-items">
				<?php echo JText::_('COM_PRIVACY_MSG_CONSENTS_NO_CONSENTS'); ?>
			</div>
		<?php else : ?>
			<table class="table table-striped" id="consentList">
				<thead>
					<tr>
						<th width="1%" class="center">
							<?php echo JHtml::_('grid.checkall'); ?>
						</th>
						<th width="1%" class="nowrap center">
							<?php echo JHtml::_('searchtools.sort', 'JSTATUS', 'a.state', $listDirn, $listOrder); ?>
						</th>
						<th width="10%" class="nowrap">
							<?php echo JHtml::_('searchtools.sort', 'JGLOBAL_USERNAME', 'u.username', $listDirn, $listOrder); ?>
						</th>
						<th width="1%" class="nowrap">
							<?php echo JHtml::_('searchtools.sort', 'COM_PRIVACY_HEADING_USERID', 'a.user_id', $listDirn, $listOrder); ?>
						</th>
						<th width="10%" class="nowrap">
							<?php echo JHtml::_('searchtools.sort', 'COM_PRIVACY_HEADING_CONSENTS_SUBJECT', 'a.subject', $listDirn, $listOrder); ?>
						</th>
						<th class="nowrap">
							<?php echo JText::_('COM_PRIVACY_HEADING_CONSENTS_BODY'); ?>
						</th>
						<th width="15%" class="nowrap">
							<?php echo JHtml::_('searchtools.sort', 'COM_PRIVACY_HEADING_CONSENTS_CREATED', 'a.created', $listDirn, $listOrder); ?>
						</th>
						<th width="1%" class="nowrap hidden-phone">
							<?php echo JHtml::_('searchtools.sort', 'JGRID_HEADING_ID', 'a.id', $listDirn, $listOrder); ?>
						</th>
					</tr>
				</thead>
				<tfoot>
					<tr>
						<td colspan="9">
							<?php echo $this->pagination->getListFooter(); ?>
						</td>
					</tr>
				</tfoot>
				<tbody>
					<?php foreach ($this->items as $i => $item) : ?>
						<tr class="row<?php echo $i % 2; ?>">
							<td class="center">
								<?php echo JHtml::_('grid.id', $i, $item->id); ?>
							</td>
							<td>
								<span class="icon icon-<?php echo $stateIcons[$item->state]; ?>" title="<?php echo $stateMsgs[$item->state]; ?>"></span>
							</td>
							<td>
								<?php echo $item->username; ?>
							</td>
							<td>
								<?php echo $item->user_id; ?>
							</td>
							<td>
								<?php echo JText::_($item->subject); ?>
							</td>
							<td>
								<?php echo $item->body; ?>
							</td>
							<td class="break-word">
								<span class="hasTooltip" title="<?php echo JHtml::_('date', $item->created, JText::_('DATE_FORMAT_LC6')); ?>">
									<?php echo JHtml::_('date.relative', new JDate($item->created), null, $now); ?>
								</span>
							</td>
							<td class="hidden-phone">
								<?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 JHtml::_('form.token'); ?>
	</div>
</form>
PK)r!]�lz���views/consents/tmpl/default.xmlnu&1i�<?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>
PK)r!]C�dԱ�views/consents/view.html.phpnu&1i�<?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;

/**
 * Consents view class
 *
 * @since  3.9.0
 */
class PrivacyViewConsents extends JViewLegacy
{
	/**
	 * 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    JForm
	 * @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    JPagination
	 * @since  3.9.0
	 */
	protected $pagination;

	/**
	 * The HTML markup for the sidebar
	 *
	 * @var    string
	 * @since  3.9.0
	 */
	protected $sidebar;

	/**
	 * The state information
	 *
	 * @var    JObject
	 * @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  mixed  A string if successful, otherwise an Error object.
	 *
	 * @see     JViewLegacy::loadTemplate()
	 * @since   3.9.0
	 * @throws  Exception
	 */
	public function display($tpl = null)
	{
		// Initialise variables
		$this->items         = $this->get('Items');
		$this->pagination    = $this->get('Pagination');
		$this->state         = $this->get('State');
		$this->filterForm    = $this->get('FilterForm');
		$this->activeFilters = $this->get('ActiveFilters');

		// Check for errors.
		if (count($errors = $this->get('Errors')))
		{
			throw new Exception(implode("\n", $errors), 500);
		}

		$this->addToolbar();

		$this->sidebar = JHtmlSidebar::render();

		return parent::display($tpl);
	}

	/**
	 * Add the page title and toolbar.
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	protected function addToolbar()
	{
		JToolbarHelper::title(JText::_('COM_PRIVACY_VIEW_CONSENTS'), 'lock');

		$bar = JToolbar::getInstance('toolbar');

		// Add a button to invalidate a consent
		$bar->appendButton(
			'Confirm',
			'COM_PRIVACY_CONSENTS_TOOLBAR_INVALIDATE_CONFIRM_MSG',
			'trash',
			'COM_PRIVACY_CONSENTS_TOOLBAR_INVALIDATE',
			'consents.invalidate',
			true
		);

		// If the filter is restricted to a specific subject, show the "Invalidate all" button
		if ($this->state->get('filter.subject') != '')
		{
			$bar->appendButton(
				'Confirm',
				'COM_PRIVACY_CONSENTS_TOOLBAR_INVALIDATE_ALL_CONFIRM_MSG',
				'cancel',
				'COM_PRIVACY_CONSENTS_TOOLBAR_INVALIDATE_ALL',
				'consents.invalidateAll',
				false
			);
		}

		JToolbarHelper::preferences('com_privacy');

		JToolbarHelper::help('JHELP_COMPONENTS_PRIVACY_CONSENTS');
	}
}
PK)r!]JO����#views/capabilities/tmpl/default.phpnu&1i�<?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;

/** @var PrivacyViewCapabilities $this */

?>
<?php if (!empty($this->sidebar)) : ?>
	<div id="j-sidebar-container" class="span2">
		<?php echo $this->sidebar; ?>
	</div>
	<div id="j-main-container" class="span10">
<?php else : ?>
	<div id="j-main-container">
<?php endif; ?>
	<div class="alert alert-info">
		<h4 class="alert-heading"><?php echo JText::_('COM_PRIVACY_MSG_CAPABILITIES_ABOUT_THIS_INFORMATION'); ?></h4>
		<?php echo JText::_('COM_PRIVACY_MSG_CAPABILITIES_INTRODUCTION'); ?>
	</div>
	<?php if (empty($this->capabilities)) : ?>
		<div class="alert alert-no-items">
			<?php echo JText::_('COM_PRIVACY_MSG_CAPABILITIES_NO_CAPABILITIES'); ?>
		</div>
	<?php else : ?>
		<?php $i = 0; ?>
		<?php echo JHtml::_('bootstrap.startAccordion', 'slide-capabilities', array('active' => 'slide-0')); ?>

		<?php foreach ($this->capabilities as $extension => $capabilities) : ?>
			<?php echo JHtml::_('bootstrap.addSlide', 'slide-capabilities', $extension, 'slide-' . $i); ?>
				<?php if (empty($capabilities)) : ?>
					<div class="alert alert-no-items">
						<?php echo JText::_('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; ?>
			<?php echo JHtml::_('bootstrap.endSlide'); ?>
			<?php $i++; ?>
		<?php endforeach; ?>

		<?php echo JHtml::_('bootstrap.endAccordion'); ?>
	<?php endif; ?>
</div>
PK)r!]��_�� views/capabilities/view.html.phpnu&1i�<?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;

/**
 * Capabilities view class
 *
 * @since  3.9.0
 */
class PrivacyViewCapabilities extends JViewLegacy
{
	/**
	 * The reported extension capabilities
	 *
	 * @var    array
	 * @since  3.9.0
	 */
	protected $capabilities;

	/**
	 * The HTML markup for the sidebar
	 *
	 * @var    string
	 * @since  3.9.0
	 */
	protected $sidebar;

	/**
	 * The state information
	 *
	 * @var    JObject
	 * @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  mixed  A string if successful, otherwise an Error object.
	 *
	 * @see     JViewLegacy::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 Exception(implode("\n", $errors), 500);
		}

		$this->addToolbar();

		$this->sidebar = JHtmlSidebar::render();

		return parent::display($tpl);
	}

	/**
	 * Add the page title and toolbar.
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	protected function addToolbar()
	{
		JToolbarHelper::title(JText::_('COM_PRIVACY_VIEW_CAPABILITIES'), 'lock');

		JToolbarHelper::preferences('com_privacy');

		JToolbarHelper::help('JHELP_COMPONENTS_PRIVACY_CAPABILITIES');
	}
}
PK)r!]����views/requests/view.html.phpnu&1i�<?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;

/**
 * Requests view class
 *
 * @since  3.9.0
 */
class PrivacyViewRequests extends JViewLegacy
{
	/**
	 * 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    JForm
	 * @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    JPagination
	 * @since  3.9.0
	 */
	protected $pagination;

	/**
	 * Flag indicating the site supports sending email
	 *
	 * @var    boolean
	 * @since  3.9.0
	 */
	protected $sendMailEnabled;

	/**
	 * The HTML markup for the sidebar
	 *
	 * @var    string
	 * @since  3.9.0
	 */
	protected $sidebar;

	/**
	 * The state information
	 *
	 * @var    JObject
	 * @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  mixed  A string if successful, otherwise an Error object.
	 *
	 * @see     JViewLegacy::loadTemplate()
	 * @since   3.9.0
	 * @throws  Exception
	 */
	public function display($tpl = null)
	{
		// Initialise variables
		$this->items            = $this->get('Items');
		$this->pagination       = $this->get('Pagination');
		$this->state            = $this->get('State');
		$this->filterForm       = $this->get('FilterForm');
		$this->activeFilters    = $this->get('ActiveFilters');
		$this->urgentRequestAge = (int) JComponentHelper::getParams('com_privacy')->get('notify', 14);
		$this->sendMailEnabled  = (bool) JFactory::getConfig()->get('mailonline', 1);

		// Check for errors.
		if (count($errors = $this->get('Errors')))
		{
			throw new Exception(implode("\n", $errors), 500);
		}

		$this->addToolbar();

		$this->sidebar = JHtmlSidebar::render();

		return parent::display($tpl);
	}

	/**
	 * Add the page title and toolbar.
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	protected function addToolbar()
	{
		JToolbarHelper::title(JText::_('COM_PRIVACY_VIEW_REQUESTS'), 'lock');

		// Requests can only be created if mail sending is enabled
		if (JFactory::getConfig()->get('mailonline', 1))
		{
			JToolbarHelper::addNew('request.add');
		}

		JToolbarHelper::preferences('com_privacy');
		JToolbarHelper::help('JHELP_COMPONENTS_PRIVACY_REQUESTS');

	}
}
PK)r!]�A1���views/requests/tmpl/default.xmlnu&1i�<?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>
PK)r!]�}���views/requests/tmpl/default.phpnu&1i�<?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;

/** @var PrivacyViewRequests $this */

// Include the component HTML helpers.
JHtml::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_privacy/helpers/html');

// Load the tooltip behavior.
JHtml::_('bootstrap.tooltip');
JHtml::_('behavior.multiselect');
JHtml::_('formbehavior.chosen', 'select');

$user      = JFactory::getUser();
$listOrder = $this->escape($this->state->get('list.ordering'));
$listDirn  = $this->escape($this->state->get('list.direction'));
$now       = JFactory::getDate();

$urgentRequestDate= clone $now;
$urgentRequestDate->sub(new DateInterval('P' . $this->urgentRequestAge . 'D'));
?>
<form action="<?php echo JRoute::_('index.php?option=com_privacy&view=requests'); ?>" method="post" name="adminForm" id="adminForm">
	<?php if (!empty($this->sidebar)) : ?>
		<div id="j-sidebar-container" class="span2">
			<?php echo $this->sidebar; ?>
		</div>
		<div id="j-main-container" class="span10">
	<?php else : ?>
		<div id="j-main-container">
	<?php endif; ?>
		<?php echo JLayoutHelper::render('joomla.searchtools.default', array('view' => $this)); ?>
		<div class="clearfix"> </div>
		<?php if (empty($this->items)) : ?>
			<div class="alert alert-no-items">
				<?php echo JText::_('COM_PRIVACY_MSG_REQUESTS_NO_REQUESTS'); ?>
			</div>
		<?php else : ?>
			<table class="table table-striped" id="requestList">
				<thead>
					<tr>
						<th width="5%" class="nowrap center">
							<?php echo JText::_('COM_PRIVACY_HEADING_ACTIONS'); ?>
						</th>
						<th width="5%" class="nowrap center">
							<?php echo JText::_('JSTATUS'); ?>
						</th>
						<th class="nowrap">
							<?php echo JHtml::_('searchtools.sort', 'JGLOBAL_EMAIL', 'a.email', $listDirn, $listOrder); ?>
						</th>
						<th width="10%" class="nowrap">
							<?php echo JHtml::_('searchtools.sort', 'COM_PRIVACY_HEADING_REQUEST_TYPE', 'a.request_type', $listDirn, $listOrder); ?>
						</th>
						<th width="20%" class="nowrap">
							<?php echo JHtml::_('searchtools.sort', 'COM_PRIVACY_HEADING_REQUESTED_AT', 'a.requested_at', $listDirn, $listOrder); ?>
						</th>
						<th width="1%" class="nowrap hidden-phone">
							<?php echo JHtml::_('searchtools.sort', 'JGRID_HEADING_ID', 'a.id', $listDirn, $listOrder); ?>
						</th>
					</tr>
				</thead>
				<tfoot>
					<tr>
						<td colspan="7">
							<?php echo $this->pagination->getListFooter(); ?>
						</td>
					</tr>
				</tfoot>
				<tbody>
					<?php foreach ($this->items as $i => $item) : ?>
						<?php
						$itemRequestedAt = new JDate($item->requested_at);
						?>
						<tr class="row<?php echo $i % 2; ?>">
							<td class="center">
								<div class="btn-group">
									<?php if ($item->status == 1 && $item->request_type === 'export') : ?>
										<a class="btn btn-micro hasTooltip" href="<?php echo JRoute::_('index.php?option=com_privacy&task=request.export&format=xml&id=' . (int) $item->id); ?>" title="<?php echo JText::_('COM_PRIVACY_ACTION_EXPORT_DATA'); ?>"><span class="icon-download" aria-hidden="true"></span><span class="element-invisible"><?php echo JText::_('COM_PRIVACY_ACTION_EXPORT_DATA'); ?></span></a>
										<?php if ($this->sendMailEnabled) : ?>
											<a class="btn btn-micro hasTooltip" href="<?php echo JRoute::_('index.php?option=com_privacy&task=request.emailexport&id=' . (int) $item->id . '&' . JFactory::getSession()->getFormToken() . '=1'); ?>" title="<?php echo JText::_('COM_PRIVACY_ACTION_EMAIL_EXPORT_DATA'); ?>"><span class="icon-mail" aria-hidden="true"></span><span class="element-invisible"><?php echo JText::_('COM_PRIVACY_ACTION_EMAIL_EXPORT_DATA'); ?></span></a>
										<?php endif; ?>
									<?php endif; ?>
									<?php if ($item->status == 1 && $item->request_type === 'remove') : ?>
										<a class="btn btn-micro hasTooltip" href="<?php echo JRoute::_('index.php?option=com_privacy&task=request.remove&id=' . (int) $item->id . '&' . JFactory::getSession()->getFormToken() . '=1'); ?>" title="<?php echo JText::_('COM_PRIVACY_ACTION_DELETE_DATA'); ?>"><span class="icon-delete" aria-hidden="true"></span><span class="element-invisible"><?php echo JText::_('COM_PRIVACY_ACTION_DELETE_DATA'); ?></span></a>
									<?php endif; ?>
								</div>
							</td>
							<td class="center">
								<?php echo JHtml::_('PrivacyHtml.helper.statusLabel', $item->status); ?>
							</td>
							<td>
								<?php if ($item->status == 1 && $urgentRequestDate >= $itemRequestedAt) : ?>
									<span class="pull-right label label-important"><?php echo JText::_('COM_PRIVACY_BADGE_URGENT_REQUEST'); ?></span>
								<?php endif; ?>
								<a class="hasTooltip" href="<?php echo JRoute::_('index.php?option=com_privacy&view=request&id=' . (int) $item->id); ?>" title="<?php echo JText::_('COM_PRIVACY_ACTION_VIEW'); ?>">
									<?php echo JStringPunycode::emailToUTF8($this->escape($item->email)); ?>
								</a>
							</td>
							<td class="break-word">
								<?php echo JText::_('COM_PRIVACY_HEADING_REQUEST_TYPE_TYPE_' . $item->request_type); ?>
							</td>
							<td class="break-word">
								<span class="hasTooltip" title="<?php echo JHtml::_('date', $item->requested_at, JText::_('DATE_FORMAT_LC6')); ?>">
									<?php echo JHtml::_('date.relative', $itemRequestedAt, null, $now); ?>
								</span>
							</td>
							<td class="hidden-phone">
								<?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 JHtml::_('form.token'); ?>
	</div>
</form>
PK)r!]��))views/request/tmpl/edit.phpnu&1i�<?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;

/** @var PrivacyViewRequest $this */

JHtml::_('behavior.formvalidator');
JHtml::_('behavior.keepalive');
JHtml::_('formbehavior.chosen', 'select');

$js = <<< JS
Joomla.submitbutton = function(task) {
	if (task === 'request.cancel' || document.formvalidator.isValid(document.getElementById('item-form'))) {
		Joomla.submitform(task, document.getElementById('item-form'));
	}
};
JS;

JFactory::getDocument()->addScriptDeclaration($js);
?>

<form action="<?php echo JRoute::_('index.php?option=com_privacy&view=request&layout=edit&id=' . (int) $this->item->id); ?>" method="post" name="adminForm" id="item-form" class="form-validate">
	<div class="form-horizontal">
		<div class="row-fluid">
			<div class="span9">
				<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 JHtml::_('form.token'); ?>
	</div>
</form>
PK)r!]�Xllviews/request/tmpl/default.phpnu&1i�<?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;

/** @var PrivacyViewRequest $this */

// Include the component HTML helpers.
JHtml::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_privacy/helpers/html');

JHtml::_('behavior.formvalidator');
JHtml::_('behavior.keepalive');

$js = <<< JS
Joomla.submitbutton = function(task) {
	if (task === 'request.cancel' || document.formvalidator.isValid(document.getElementById('item-form'))) {
		Joomla.submitform(task, document.getElementById('item-form'));
	}
};
JS;

JFactory::getDocument()->addScriptDeclaration($js);
?>

<form action="<?php echo JRoute::_('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-fluid">
		<div class="span4">
			<h3><?php echo JText::_('COM_PRIVACY_HEADING_REQUEST_INFORMATION'); ?></h3>
			<dl class="dl-horizontal">
				<dt><?php echo JText::_('JGLOBAL_EMAIL'); ?>:</dt>
				<dd><?php echo $this->item->email; ?></dd>

				<dt><?php echo JText::_('JSTATUS'); ?>:</dt>
				<dd><?php echo JHtml::_('PrivacyHtml.helper.statusLabel', $this->item->status); ?></dd>

				<dt><?php echo JText::_('COM_PRIVACY_FIELD_REQUEST_TYPE_LABEL'); ?>:</dt>
				<dd><?php echo JText::_('COM_PRIVACY_HEADING_REQUEST_TYPE_TYPE_' . $this->item->request_type); ?></dd>

				<dt><?php echo JText::_('COM_PRIVACY_FIELD_REQUESTED_AT_LABEL'); ?>:</dt>
				<dd><?php echo JHtml::_('date', $this->item->requested_at, JText::_('DATE_FORMAT_LC6')); ?></dd>
			</dl>
		</div>
		<div class="span8">
			<h3><?php echo JText::_('COM_PRIVACY_HEADING_ACTION_LOG'); ?></h3>
			<?php if (empty($this->actionlogs)) : ?>
				<div class="alert alert-no-items">
					<?php echo JText::_('JGLOBAL_NO_MATCHING_RESULTS'); ?>
				</div>
			<?php else : ?>
				<table class="table table-striped table-hover">
					<thead>
						<th>
							<?php echo JText::_('COM_ACTIONLOGS_ACTION'); ?>
						</th>
						<th>
							<?php echo JText::_('COM_ACTIONLOGS_DATE'); ?>
						</th>
						<th>
							<?php echo JText::_('COM_ACTIONLOGS_NAME'); ?>
						</th>
					</thead>
					<tbody>
						<?php foreach ($this->actionlogs as $i => $item) : ?>
							<tr class="row<?php echo $i % 2; ?>">
								<td>
									<?php echo ActionlogsHelper::getHumanReadableLogMessage($item); ?>
								</td>
								<td>
									<?php echo JHtml::_('date', $item->log_date, JText::_('DATE_FORMAT_LC6')); ?>
								</td>
								<td>
									<?php echo $item->name; ?>
								</td>
							</tr>
						<?php endforeach; ?>
					</tbody>
				</table>
			<?php endif;?>
		</div>
	</div>

	<input type="hidden" name="task" value="" />
	<?php echo JHtml::_('form.token'); ?>
</form>
PK)r!]5�ӷ\\views/request/view.html.phpnu&1i�<?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;

/**
 * Request view class
 *
 * @since  3.9.0
 */
class PrivacyViewRequest extends JViewLegacy
{
	/**
	 * The action logs for the item
	 *
	 * @var    array
	 * @since  3.9.0
	 */
	protected $actionlogs;

	/**
	 * The form object
	 *
	 * @var    JForm
	 * @since  3.9.0
	 */
	protected $form;

	/**
	 * The item record
	 *
	 * @var    JObject
	 * @since  3.9.0
	 */
	protected $item;

	/**
	 * The state information
	 *
	 * @var    JObject
	 * @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  mixed  A string if successful, otherwise an Error object.
	 *
	 * @see     JViewLegacy::loadTemplate()
	 * @since   3.9.0
	 * @throws  Exception
	 */
	public function display($tpl = null)
	{
		// Initialise variables.
		$this->item  = $this->get('Item');
		$this->state = $this->get('State');

		// Variables only required for the default layout
		if ($this->getLayout() === 'default')
		{
			/** @var ActionlogsModelActionlogs $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 = JFactory::getLanguage();
			$lang->load('com_actionlogs', JPATH_ADMINISTRATOR, null, false, true)
				|| $lang->load('com_actionlogs', JPATH_ADMINISTRATOR . '/components/com_actionlogs', null, false, true);
		}

		// 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 Exception(implode("\n", $errors), 500);
		}

		$this->addToolbar();

		return parent::display($tpl);
	}

	/**
	 * Add the page title and toolbar.
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	protected function addToolbar()
	{
		JFactory::getApplication('administrator')->set('hidemainmenu', true);

		// Set the title and toolbar based on the layout
		if ($this->getLayout() === 'edit')
		{
			JToolbarHelper::title(JText::_('COM_PRIVACY_VIEW_REQUEST_ADD_REQUEST'), 'lock');

			JToolbarHelper::apply('request.save');
			JToolbarHelper::cancel('request.cancel');
			JToolbarHelper::help('JHELP_COMPONENTS_PRIVACY_REQUEST_EDIT');
		}
		else
		{
			JToolbarHelper::title(JText::_('COM_PRIVACY_VIEW_REQUEST_SHOW_REQUEST'), 'lock');

			$bar = JToolbar::getInstance('toolbar');

			// Add transition and action buttons based on item status
			switch ($this->item->status)
			{
				case '0':
					$bar->appendButton('Standard', 'cancel-circle', 'COM_PRIVACY_TOOLBAR_INVALIDATE', 'request.invalidate', false);

					break;

				case '1':
					$return = '&return=' . base64_encode('index.php?option=com_privacy&view=request&id=' . (int) $this->item->id);

					$bar->appendButton('Standard', 'apply', 'COM_PRIVACY_TOOLBAR_COMPLETE', 'request.complete', false);
					$bar->appendButton('Standard', 'cancel-circle', 'COM_PRIVACY_TOOLBAR_INVALIDATE', 'request.invalidate', false);

					if ($this->item->request_type === 'export')
					{
						JToolbarHelper::link(
							JRoute::_('index.php?option=com_privacy&task=request.export&format=xml&id=' . (int) $this->item->id . $return),
							'COM_PRIVACY_ACTION_EXPORT_DATA',
							'download'
						);

						if (JFactory::getConfig()->get('mailonline', 1))
						{
							JToolbarHelper::link(
								JRoute::_(
									'index.php?option=com_privacy&task=request.emailexport&id=' . (int) $this->item->id . $return
									. '&' . JSession::getFormToken() . '=1'
								),
								'COM_PRIVACY_ACTION_EMAIL_EXPORT_DATA',
								'mail'
							);
						}
					}

					if ($this->item->request_type === 'remove')
					{
						$bar->appendButton('Standard', 'delete', 'COM_PRIVACY_ACTION_DELETE_DATA', 'request.remove', false);
					}

					break;

				// Item is in a "locked" state and cannot transition
				default:
					break;
			}

			JToolbarHelper::cancel('request.cancel', 'JTOOLBAR_CLOSE');
			JToolbarHelper::help('JHELP_COMPONENTS_PRIVACY_REQUEST');
		}
	}
}
PK)r!]lg$M M  views/dashboard/tmpl/default.phpnu&1i�<?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;
use Joomla\CMS\Router\Route;

/** @var PrivacyViewDashboard $this */

// Include the component HTML helpers.
JHtml::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_privacy/helpers/html');

JHtml::_('bootstrap.tooltip');

$totalRequests  = 0;
$activeRequests = 0;

?>
<?php if (!empty($this->sidebar)) : ?>
	<div id="j-sidebar-container" class="span2">
		<?php echo $this->sidebar; ?>
	</div>
	<div id="j-main-container" class="span10">
<?php else : ?>
	<div id="j-main-container">
<?php endif; ?>
	<div class="row-fluid">
		<div class="span6">
			<div class="well well-small">
				<h3 class="module-title nav-header"><?php echo Text::_('COM_PRIVACY_DASHBOARD_HEADING_TOTAL_REQUEST_COUNT'); ?></h3>
				<div class="row-striped">
					<?php if (count($this->requestCounts)) : ?>
						<div class="row-fluid">
							<div class="span5"><strong><?php echo Text::_('COM_PRIVACY_DASHBOARD_HEADING_REQUEST_TYPE'); ?></strong></div>
							<div class="span5"><strong><?php echo Text::_('COM_PRIVACY_DASHBOARD_HEADING_REQUEST_STATUS'); ?></strong></div>
							<div class="span2"><strong><?php echo Text::_('COM_PRIVACY_DASHBOARD_HEADING_REQUEST_COUNT'); ?></strong></div>
						</div>
						<?php foreach ($this->requestCounts as $row) : ?>
							<div class="row-fluid">
								<div class="span5">
									<a class="hasTooltip" href="<?php echo JRoute::_('index.php?option=com_privacy&view=requests&filter[request_type]=' . $row->request_type . '&filter[status]=' . $row->status); ?>" data-original-title="<?php echo JText::_('COM_PRIVACY_DASHBOARD_VIEW_REQUESTS'); ?>">
										<strong><?php echo Text::_('COM_PRIVACY_HEADING_REQUEST_TYPE_TYPE_' . $row->request_type); ?></strong>
									</a>
								</div>
								<div class="span5"><?php echo JHtml::_('PrivacyHtml.helper.statusLabel', $row->status); ?></div>
								<div class="span2"><span class="badge badge-info"><?php echo $row->count; ?></span></div>
							</div>
							<?php if (in_array($row->status, array(0, 1))) : ?>
								<?php $activeRequests += $row->count; ?>
							<?php endif; ?>
							<?php $totalRequests += $row->count; ?>
						<?php endforeach; ?>
						<div class="row-fluid">
							<div class="span5"><?php echo Text::plural('COM_PRIVACY_DASHBOARD_BADGE_TOTAL_REQUESTS', $totalRequests); ?></div>
							<div class="span7"><?php echo Text::plural('COM_PRIVACY_DASHBOARD_BADGE_ACTIVE_REQUESTS', $activeRequests); ?></div>
						</div>
					<?php else : ?>
						<div class="row-fluid">
							<div class="span12">
								<div class="alert"><?php echo Text::_('COM_PRIVACY_DASHBOARD_NO_REQUESTS'); ?></div>
							</div>
						</div>
					<?php endif; ?>
				</div>
			</div>
		</div>
		<div class="span6">
			<div class="well well-small">
				<h3 class="module-title nav-header"><?php echo Text::_('COM_PRIVACY_DASHBOARD_HEADING_STATUS_CHECK'); ?></h3>
				<div class="row-striped">
					<div class="row-fluid">
						<div class="span3"><strong><?php echo Text::_('COM_PRIVACY_DASHBOARD_HEADING_STATUS'); ?></strong></div>
						<div class="span9"><strong><?php echo Text::_('COM_PRIVACY_DASHBOARD_HEADING_CHECK'); ?></strong></div>
					</div>
					<div class="row-fluid">
						<div class="span3">
							<?php if ($this->privacyPolicyInfo['published'] && $this->privacyPolicyInfo['articlePublished']) : ?>
								<span class="label label-success">
									<span class="icon-checkbox" aria-hidden="true"></span>
									<?php echo Text::_('JPUBLISHED'); ?>
								</span>
							<?php elseif ($this->privacyPolicyInfo['published'] && !$this->privacyPolicyInfo['articlePublished']) : ?>
								<span class="label label-warning">
									<span class="icon-warning" aria-hidden="true"></span>
									<?php echo Text::_('JUNPUBLISHED'); ?>
								</span>
							<?php else : ?>
								<span class="label label-warning">
									<span class="icon-warning" aria-hidden="true"></span>
									<?php echo Text::_('COM_PRIVACY_STATUS_CHECK_NOT_AVAILABLE'); ?>
								</span>
							<?php endif; ?>
						</div>
						<div class="span9">
							<div><?php echo Text::_('COM_PRIVACY_STATUS_CHECK_PRIVACY_POLICY_PUBLISHED'); ?></div>
							<?php if ($this->privacyPolicyInfo['editLink'] !== '') : ?>
								<small><a href="<?php echo $this->privacyPolicyInfo['editLink']; ?>"><?php echo Text::_('COM_PRIVACY_EDIT_PRIVACY_POLICY'); ?></a></small>
							<?php else : ?>
								<?php $link = Route::_('index.php?option=com_plugins&task=plugin.edit&extension_id=' . $this->privacyConsentPluginId); ?>
								<small><a href="<?php echo $link; ?>"><?php echo Text::_('COM_PRIVACY_EDIT_PRIVACY_CONSENT_PLUGIN'); ?></a></small>
							<?php endif; ?>
						</div>
					</div>
					<div class="row-fluid">
						<div class="span3">
							<?php if ($this->requestFormPublished['published'] && $this->requestFormPublished['exists']) : ?>
								<span class="label label-success">
									<span class="icon-checkbox" aria-hidden="true"></span>
									<?php echo Text::_('JPUBLISHED'); ?>
								</span>
							<?php elseif (!$this->requestFormPublished['published'] && $this->requestFormPublished['exists']) : ?>
								<span class="label label-warning">
									<span class="icon-warning" aria-hidden="true"></span>
									<?php echo Text::_('JUNPUBLISHED'); ?>
								</span>
							<?php else : ?>
								<span class="label label-warning">
									<span class="icon-warning" aria-hidden="true"></span>
									<?php echo Text::_('COM_PRIVACY_STATUS_CHECK_NOT_AVAILABLE'); ?>
								</span>
							<?php endif; ?>
						</div>
						<div class="span9">
							<div><?php echo Text::_('COM_PRIVACY_STATUS_CHECK_REQUEST_FORM_MENU_ITEM_PUBLISHED'); ?></div>
							<?php if ($this->requestFormPublished['link'] !== '') : ?>
								<small><a href="<?php echo $this->requestFormPublished['link']; ?>"><?php echo $this->requestFormPublished['link']; ?></a></small>
							<?php endif; ?>
						</div>
					</div>
					<div class="row-fluid">
						<div class="span3">
							<?php if ($this->numberOfUrgentRequests === 0) : ?>
								<span class="label label-success">
									<span class="icon-checkbox" aria-hidden="true"></span>
									<?php echo Text::_('JNONE'); ?>
								</span>
							<?php else : ?>
								<span class="label label-important">
									<span class="icon-warning" aria-hidden="true"></span>
									<?php echo Text::_('WARNING'); ?>
								</span>
							<?php endif; ?>
						</div>
						<div class="span9">
							<div><?php echo Text::_('COM_PRIVACY_STATUS_CHECK_OUTSTANDING_URGENT_REQUESTS'); ?></div>
							<small><?php echo Text::plural('COM_PRIVACY_STATUS_CHECK_OUTSTANDING_URGENT_REQUESTS_DESCRIPTION', $this->urgentRequestDays); ?></small>
							<?php if ($this->numberOfUrgentRequests > 0) : ?>
								<small><a href="<?php echo Route::_('index.php?option=com_privacy&view=requests&filter[status]=1&list[fullordering]=a.requested_at ASC'); ?>"><?php echo JText::_('COM_PRIVACY_SHOW_URGENT_REQUESTS'); ?></a></small>
							<?php endif; ?>
						</div>
					</div>
					<div class="row-fluid">
						<div class="span3">
							<?php if ($this->sendMailEnabled) : ?>
								<span class="label label-success">
									<span class="icon-checkbox" aria-hidden="true"></span>
									<?php echo Text::_('JENABLED'); ?>
								</span>
							<?php else : ?>
								<span class="label label-important">
									<span class="icon-warning" aria-hidden="true"></span>
									<?php echo Text::_('JDISABLED'); ?>
								</span>
							<?php endif; ?>
						</div>
						<div class="span9">
							<?php if (!$this->sendMailEnabled) : ?>
								<div><?php echo Text::_('COM_PRIVACY_STATUS_CHECK_SENDMAIL_DISABLED'); ?></div>
								<small><?php echo Text::_('COM_PRIVACY_STATUS_CHECK_SENDMAIL_DISABLED_DESCRIPTION'); ?></small>
							<?php else : ?>
								<div><?php echo Text::_('COM_PRIVACY_STATUS_CHECK_SENDMAIL_ENABLED'); ?></div>
							<?php endif; ?>
						</div>
					</div>
				</div>
			</div>
		</div>
	</div>
</div>
PK)r!]<ԧM�� views/dashboard/tmpl/default.xmlnu&1i�<?xml version="1.0" encoding="utf-8"?>
<metadata>
	<layout title="COM_PRIVACY_DASHBOARD_VIEW_DEFAULT_TITLE">
		<message>
			<![CDATA[COM_PRIVACY_DASHBOARD_VIEW_DEFAULT_DESC]]>
		</message>
	</layout>
</metadata>
PK)r!]uqp
��views/dashboard/view.html.phpnu&1i�<?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\Component\ComponentHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;

/**
 * Dashboard view class
 *
 * @since  3.9.0
 */
class PrivacyViewDashboard extends JViewLegacy
{
	/**
	 * Number of urgent requests based on the component configuration
	 *
	 * @var    integer
	 * @since  3.9.0
	 */
	protected $numberOfUrgentRequests;

	/**
	 * Information about whether a privacy policy is published
	 *
	 * @var    array
	 * @since  3.9.0
	 */
	protected $privacyPolicyInfo;

	/**
	 * The request counts
	 *
	 * @var    array
	 * @since  3.9.0
	 */
	protected $requestCounts;

	/**
	 * Information about whether a menu item for the request form is published
	 *
	 * @var    array
	 * @since  3.9.0
	 */
	protected $requestFormPublished;

	/**
	 * Flag indicating the site supports sending email
	 *
	 * @var    boolean
	 * @since  3.9.0
	 */
	protected $sendMailEnabled;

	/**
	 * The HTML markup for the sidebar
	 *
	 * @var    string
	 * @since  3.9.0
	 */
	protected $sidebar;

	/**
	 * Id of the system privacy consent plugin
	 *
	 * @var    integer
	 * @since  3.9.2
	 */
	protected $privacyConsentPluginId;

	/**
	 * Execute and display a template script.
	 *
	 * @param   string  $tpl  The name of the template file to parse; automatically searches through the template paths.
	 *
	 * @return  mixed  A string if successful, otherwise an Error object.
	 *
	 * @see     JViewLegacy::loadTemplate()
	 * @since   3.9.0
	 * @throws  Exception
	 */
	public function display($tpl = null)
	{
		// Initialise variables
		$this->privacyConsentPluginId = PrivacyHelper::getPrivacyConsentPluginId();
		$this->privacyPolicyInfo      = $this->get('PrivacyPolicyInfo');
		$this->requestCounts          = $this->get('RequestCounts');
		$this->requestFormPublished   = $this->get('RequestFormPublished');
		$this->sendMailEnabled        = (bool) Factory::getConfig()->get('mailonline', 1);

		/** @var PrivacyModelRequests $requestsModel */
		$requestsModel = $this->getModel('requests');

		$this->numberOfUrgentRequests = $requestsModel->getNumberUrgentRequests();

		// Check for errors.
		if (count($errors = $this->get('Errors')))
		{
			throw new Exception(implode("\n", $errors), 500);
		}

		$this->urgentRequestDays = (int) ComponentHelper::getParams('com_privacy')->get('notify', 14);

		$this->addToolbar();

		$this->sidebar = JHtmlSidebar::render();

		return parent::display($tpl);
	}

	/**
	 * Add the page title and toolbar.
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	protected function addToolbar()
	{
		JToolbarHelper::title(Text::_('COM_PRIVACY_VIEW_DASHBOARD'), 'lock');

		JToolbarHelper::preferences('com_privacy');

		JToolbarHelper::help('JHELP_COMPONENTS_PRIVACY_DASHBOARD');
	}
}
PK)r!]�e4��views/export/view.xml.phpnu&1i�<?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;

JLoader::register('PrivacyHelper', JPATH_ADMINISTRATOR . '/components/com_privacy/helpers/privacy.php');

/**
 * Export view class
 *
 * @since  3.9.0
 *
 * @property-read   \Joomla\CMS\Document\XmlDocument  $document
 */
class PrivacyViewExport extends JViewLegacy
{
	/**
	 * Execute and display a template script.
	 *
	 * @param   string  $tpl  The name of the template file to parse; automatically searches through the template paths.
	 *
	 * @return  mixed  A string if successful, otherwise an Error object.
	 *
	 * @see     JViewLegacy::loadTemplate()
	 * @since   3.9.0
	 * @throws  Exception
	 */
	public function display($tpl = null)
	{
		/** @var PrivacyModelExport $model */
		$model = $this->getModel();

		$exportData = $model->collectDataForExportRequest();

		// Check for errors.
		if (count($errors = $this->get('Errors')))
		{
			throw new Exception(implode("\n", $errors), 500);
		}

		$requestId = $model->getState($model->getName() . '.request_id');

		// This document should always be downloaded
		$this->document->setDownload(true);
		$this->document->setName('export-request-' . $requestId);

		echo PrivacyHelper::renderDataAsXml($exportData);
	}
}
PK�0"]zA��66views/confirm/tmpl/default.phpnu&1i�<?php
/**
 * @package     Joomla.Site
 * @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;

/** @var PrivacyViewConfirm $this */

JHtml::_('behavior.keepalive');
JHtml::_('behavior.formvalidator');

?>
<div class="request-confirm<?php echo $this->pageclass_sfx; ?>">
	<?php if ($this->params->get('show_page_heading')) : ?>
		<div class="page-header">
			<h1>
				<?php echo $this->escape($this->params->get('page_heading')); ?>
			</h1>
		</div>
	<?php endif; ?>
	<form action="<?php echo JRoute::_('index.php?option=com_privacy&task=request.confirm'); ?>" method="post" class="form-validate form-horizontal well">
		<?php foreach ($this->form->getFieldsets() as $fieldset) : ?>
			<fieldset>
				<?php if (!empty($fieldset->label)) : ?>
					<legend><?php echo JText::_($fieldset->label); ?></legend>
				<?php endif; ?>
				<?php echo $this->form->renderFieldset($fieldset->name); ?>
			</fieldset>
		<?php endforeach; ?>
		<div class="control-group">
			<div class="controls">
				<button type="submit" class="btn btn-primary validate">
					<?php echo JText::_('JSUBMIT'); ?>
				</button>
			</div>
		</div>
		<?php echo JHtml::_('form.token'); ?>
	</form>
</div>
PK�0"]���EEviews/confirm/tmpl/default.xmlnu&1i�<?xml version="1.0" encoding="utf-8"?>
<metadata>
	<layout title="COM_PRIVACY_CONFIRM_VIEW_DEFAULT_TITLE" option="COM_PRIVACY_CONFIRM_VIEW_DEFAULT_OPTION">
		<help
			key="JHELP_MENUS_MENU_ITEM_PRIVACY_CONFIRM_REQUEST"
		/>
		<message>
			<![CDATA[COM_PRIVACY_CONFIRM_VIEW_DEFAULT_DESC]]>
		</message>
	</layout>
</metadata>
PK�0"]�z�<��views/confirm/view.html.phpnu&1i�<?php
/**
 * @package     Joomla.Site
 * @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\Registry\Registry;

/**
 * Request confirmation view class
 *
 * @since  3.9.0
 */
class PrivacyViewConfirm extends JViewLegacy
{
	/**
	 * The form object
	 *
	 * @var    JForm
	 * @since  3.9.0
	 */
	protected $form;

	/**
	 * The CSS class suffix to append to the view container
	 *
	 * @var    string
	 * @since  3.9.0
	 */
	protected $pageclass_sfx;

	/**
	 * The view parameters
	 *
	 * @var    Registry
	 * @since  3.9.0
	 */
	protected $params;

	/**
	 * The state information
	 *
	 * @var    JObject
	 * @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  mixed  A string if successful, otherwise an Error object.
	 *
	 * @see     JViewLegacy::loadTemplate()
	 * @since   3.9.0
	 * @throws  Exception
	 */
	public function display($tpl = null)
	{
		// Initialise variables.
		$this->form   = $this->get('Form');
		$this->state  = $this->get('State');
		$this->params = $this->state->params;

		// Check for errors.
		if (count($errors = $this->get('Errors')))
		{
			throw new Exception(implode("\n", $errors), 500);
		}

		// Escape strings for HTML output
		$this->pageclass_sfx = htmlspecialchars($this->params->get('pageclass_sfx', ''), ENT_COMPAT, 'UTF-8');

		$this->prepareDocument();

		return parent::display($tpl);
	}

	/**
	 * Prepares the document.
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	protected function prepareDocument()
	{
		$app   = JFactory::getApplication();
		$menus = $app->getMenu();
		$title = null;

		// Because the application sets a default page title,
		// we need to get it from the menu item itself
		$menu = $menus->getActive();

		if ($menu)
		{
			$this->params->def('page_heading', $this->params->get('page_title', $menu->title));
		}
		else
		{
			$this->params->def('page_heading', JText::_('COM_PRIVACY_VIEW_CONFIRM_PAGE_TITLE'));
		}

		$title = $this->params->get('page_title', '');

		if (empty($title))
		{
			$title = $app->get('sitename');
		}
		elseif ($app->get('sitename_pagetitles', 0) == 1)
		{
			$title = JText::sprintf('JPAGETITLE', $app->get('sitename'), $title);
		}
		elseif ($app->get('sitename_pagetitles', 0) == 2)
		{
			$title = JText::sprintf('JPAGETITLE', $title, $app->get('sitename'));
		}

		$this->document->setTitle($title);

		if ($this->params->get('menu-meta_description'))
		{
			$this->document->setDescription($this->params->get('menu-meta_description'));
		}

		if ($this->params->get('menu-meta_keywords'))
		{
			$this->document->setMetadata('keywords', $this->params->get('menu-meta_keywords'));
		}

		if ($this->params->get('robots'))
		{
			$this->document->setMetadata('robots', $this->params->get('robots'));
		}
	}
}
PK�0"]
���DDviews/request/tmpl/default.xmlnu&1i�<?xml version="1.0" encoding="utf-8"?>
<metadata>
	<layout title="COM_PRIVACY_REQUEST_VIEW_DEFAULT_TITLE" option="COM_PRIVACY_REQUEST_VIEW_DEFAULT_OPTION">
		<help
			key="JHELP_MENUS_MENU_ITEM_PRIVACY_CREATE_REQUEST"
		/>
		<message>
			<![CDATA[COM_PRIVACY_REQUEST_VIEW_DEFAULT_DESC]]>
		</message>
	</layout>
</metadata>
PK�0"]`A��AAviews/remind/tmpl/default.xmlnu&1i�<?xml version="1.0" encoding="utf-8"?>
<metadata>
	<layout title="COM_PRIVACY_REMIND_VIEW_DEFAULT_TITLE" option="COM_PRIVACY_REMIND_VIEW_DEFAULT_OPTION">
		<help
			key="JHELP_MENUS_MENU_ITEM_PRIVACY_REMIND_REQUEST"
		/>
		<message>
			<![CDATA[COM_PRIVACY_REMIND_VIEW_DEFAULT_DESC]]>
		</message>
	</layout>
</metadata>
PK�0"]εd44views/remind/tmpl/default.phpnu&1i�<?php
/**
 * @package     Joomla.Site
 * @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;

/** @var PrivacyViewConfirm $this */

JHtml::_('behavior.keepalive');
JHtml::_('behavior.formvalidator');

?>
<div class="remind-confirm<?php echo $this->pageclass_sfx; ?>">
	<?php if ($this->params->get('show_page_heading')) : ?>
		<div class="page-header">
			<h1>
				<?php echo $this->escape($this->params->get('page_heading')); ?>
			</h1>
		</div>
	<?php endif; ?>
	<form action="<?php echo JRoute::_('index.php?option=com_privacy&task=request.remind'); ?>" method="post" class="form-validate form-horizontal well">
		<?php foreach ($this->form->getFieldsets() as $fieldset) : ?>
			<fieldset>
				<?php if (!empty($fieldset->label)) : ?>
					<legend><?php echo JText::_($fieldset->label); ?></legend>
				<?php endif; ?>
				<?php echo $this->form->renderFieldset($fieldset->name); ?>
			</fieldset>
		<?php endforeach; ?>
		<div class="control-group">
			<div class="controls">
				<button type="submit" class="btn btn-primary validate">
					<?php echo JText::_('JSUBMIT'); ?>
				</button>
			</div>
		</div>
		<?php echo JHtml::_('form.token'); ?>
	</form>
</div>
PK�0"]��i��views/remind/view.html.phpnu&1i�<?php
/**
 * @package     Joomla.Site
 * @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\Registry\Registry;

/**
 * Remind confirmation view class
 *
 * @since  3.9.0
 */
class PrivacyViewRemind extends JViewLegacy
{
	/**
	 * The form object
	 *
	 * @var    JForm
	 * @since  3.9.0
	 */
	protected $form;

	/**
	 * The CSS class suffix to append to the view container
	 *
	 * @var    string
	 * @since  3.9.0
	 */
	protected $pageclass_sfx;

	/**
	 * The view parameters
	 *
	 * @var    Registry
	 * @since  3.9.0
	 */
	protected $params;

	/**
	 * The state information
	 *
	 * @var    JObject
	 * @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  mixed  A string if successful, otherwise an Error object.
	 *
	 * @see     JViewLegacy::loadTemplate()
	 * @since   3.9.0
	 * @throws  Exception
	 */
	public function display($tpl = null)
	{
		// Initialise variables.
		$this->form   = $this->get('Form');
		$this->state  = $this->get('State');
		$this->params = $this->state->params;

		// Check for errors.
		if (count($errors = $this->get('Errors')))
		{
			throw new Exception(implode("\n", $errors), 500);
		}

		// Escape strings for HTML output
		$this->pageclass_sfx = htmlspecialchars($this->params->get('pageclass_sfx', ''), ENT_COMPAT, 'UTF-8');

		$this->prepareDocument();

		return parent::display($tpl);
	}

	/**
	 * Prepares the document.
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	protected function prepareDocument()
	{
		$app   = JFactory::getApplication();
		$menus = $app->getMenu();
		$title = null;

		// Because the application sets a default page title,
		// we need to get it from the menu item itself
		$menu = $menus->getActive();

		if ($menu)
		{
			$this->params->def('page_heading', $this->params->get('page_title', $menu->title));
		}
		else
		{
			$this->params->def('page_heading', JText::_('COM_PRIVACY_VIEW_REMIND_PAGE_TITLE'));
		}

		$title = $this->params->get('page_title', '');

		if (empty($title))
		{
			$title = $app->get('sitename');
		}
		elseif ($app->get('sitename_pagetitles', 0) == 1)
		{
			$title = JText::sprintf('JPAGETITLE', $app->get('sitename'), $title);
		}
		elseif ($app->get('sitename_pagetitles', 0) == 2)
		{
			$title = JText::sprintf('JPAGETITLE', $title, $app->get('sitename'));
		}

		$this->document->setTitle($title);

		if ($this->params->get('menu-meta_description'))
		{
			$this->document->setDescription($this->params->get('menu-meta_description'));
		}

		if ($this->params->get('menu-meta_keywords'))
		{
			$this->document->setMetadata('keywords', $this->params->get('menu-meta_keywords'));
		}

		if ($this->params->get('robots'))
		{
			$this->document->setMetadata('robots', $this->params->get('robots'));
		}
	}
}
PK�0"]@<�?��
router.phpnu&1i�<?php
/**
 * @package     Joomla.Site
 * @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;

/**
 * Routing class from com_privacy
 *
 * @since  3.9.0
 */
class PrivacyRouter extends JComponentRouterView
{
	/**
	 * Privacy Component router constructor
	 *
	 * @param   JApplicationCms  $app   The application object
	 * @param   JMenu            $menu  The menu object to work with
	 *
	 * @since   3.9.0
	 */
	public function __construct($app = null, $menu = null)
	{
		$this->registerView(new JComponentRouterViewconfiguration('confirm'));
		$this->registerView(new JComponentRouterViewconfiguration('request'));
		$this->registerView(new JComponentRouterViewconfiguration('remind'));

		parent::__construct($app, $menu);

		$this->attachRule(new JComponentRouterRulesMenu($this));
		$this->attachRule(new JComponentRouterRulesStandard($this));
		$this->attachRule(new JComponentRouterRulesNomenu($this));
	}
}

/**
 * Privacy router functions
 *
 * These functions are proxies for the new router interface
 * for old SEF extensions.
 *
 * @param   array  &$query  REQUEST query
 *
 * @return  array  Segments of the SEF url
 *
 * @since   3.9.0
 * @deprecated  4.0  Use Class based routers instead
 */
function privacyBuildRoute(&$query)
{
	$app = JFactory::getApplication();
	$router = new PrivacyRouter($app, $app->getMenu());

	return $router->build($query);
}

/**
 * Convert SEF URL segments into query variables
 *
 * @param   array  $segments  Segments in the current URL
 *
 * @return  array  Query variables
 *
 * @since   3.9.0
 * @deprecated  4.0  Use Class based routers instead
 */
function privacyParseRoute($segments)
{
	$app = JFactory::getApplication();
	$router = new PrivacyRouter($app, $app->getMenu());

	return $router->parse($segments);
}
PK�0"]�P�models/forms/remind.xmlnu&1i�<?xml version="1.0" encoding="utf-8"?>
<form>
	<fieldset name="default" label="COM_PRIVACY_REMIND_REQUEST_FIELDSET_LABEL">
		<field
			name="email"
			type="text"
			label="JGLOBAL_EMAIL"
			description="COM_PRIVACY_FIELD_CONFIRM_EMAIL_DESC"
			validate="email"
			required="true"
			size="30"
		/>

		<field
			name="remind_token"
			type="text"
			label="COM_PRIVACY_FIELD_REMIND_CONFIRM_TOKEN_LABEL"
			description="COM_PRIVACY_FIELD_REMIND_CONFIRM_TOKEN_DESC"
			filter="alnum"
			required="true"
			size="32"
		/>
	</fieldset>
</form>
PK�0"]��f$oomodels/forms/confirm.xmlnu&1i�<?xml version="1.0" encoding="utf-8"?>
<form>
	<fieldset name="default" label="COM_PRIVACY_CONFIRM_REQUEST_FIELDSET_LABEL">
		<field
			name="confirm_token"
			type="text"
			label="COM_PRIVACY_FIELD_CONFIRM_CONFIRM_TOKEN_LABEL"
			description="COM_PRIVACY_FIELD_CONFIRM_CONFIRM_TOKEN_DESC"
			filter="alnum"
			required="true"
			size="32"
		/>
	</fieldset>
</form>
PK�0"]��s�iimodels/confirm.phpnu&1i�<?php
/**
 * @package     Joomla.Site
 * @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;

/**
 * Request confirmation model class.
 *
 * @since  3.9.0
 */
class PrivacyModelConfirm extends JModelAdmin
{
	/**
	 * Confirms the information request.
	 *
	 * @param   array  $data  The data expected for the form.
	 *
	 * @return  mixed  Exception | JException | boolean
	 *
	 * @since   3.9.0
	 */
	public function confirmRequest($data)
	{
		// Get the form.
		$form = $this->getForm();

		// Check for an error.
		if ($form instanceof Exception)
		{
			return $form;
		}

		// Filter and validate the form data.
		$data = $form->filter($data);
		$return = $form->validate($data);

		// Check for an error.
		if ($return instanceof Exception)
		{
			return $return;
		}

		// Check the validation results.
		if ($return === false)
		{
			// Get the validation messages from the form.
			foreach ($form->getErrors() as $formError)
			{
				$this->setError($formError->getMessage());
			}

			return false;
		}

		// Get the user email address
		$data['email'] = JFactory::getUser()->email;

		// Search for the information request
		/** @var PrivacyTableRequest $table */
		$table = $this->getTable();

		if (!$table->load(array('email' => $data['email'], 'status' => 0)))
		{
			$this->setError(JText::_('COM_PRIVACY_ERROR_NO_PENDING_REQUESTS'));

			return false;
		}

		// A request can only be confirmed if it is in a pending status and has a confirmation token
		if ($table->status != '0' || !$table->confirm_token)
		{
			$this->setError(JText::_('COM_PRIVACY_ERROR_NO_PENDING_REQUESTS'));

			return false;
		}

		// A request can only be confirmed if the token is less than 24 hours old
		$confirmTokenCreatedAt = new JDate($table->confirm_token_created_at);
		$confirmTokenCreatedAt->add(new DateInterval('P1D'));

		$now = new JDate('now');

		if ($now > $confirmTokenCreatedAt)
		{
			// Invalidate the request
			$table->status = -1;
			$table->confirm_token = '';

			try
			{
				$table->store();
			}
			catch (JDatabaseException $exception)
			{
				// The error will be logged in the database API, we just need to catch it here to not let things fatal out
			}

			$this->setError(JText::_('COM_PRIVACY_ERROR_CONFIRM_TOKEN_EXPIRED'));

			return false;
		}

		// Verify the token
		if (!JUserHelper::verifyPassword($data['confirm_token'], $table->confirm_token))
		{
			$this->setError(JText::_('COM_PRIVACY_ERROR_NO_PENDING_REQUESTS'));

			return false;
		}

		// Everything is good to go, transition the request to confirmed
		$saved = $this->save(
			array(
				'id'     => $table->id,
				'status' => 1,
				'confirm_token' => '',
			)
		);

		if (!$saved)
		{
			// Error was set by the save method
			return false;
		}

		// Push a notification to the site's super users, deliberately ignoring if this process fails so the below message goes out
		JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_messages/models', 'MessagesModel');
		JTable::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_messages/tables');

		/** @var MessagesModelMessage $messageModel */
		$messageModel = JModelLegacy::getInstance('Message', 'MessagesModel');

		$messageModel->notifySuperUsers(
			JText::_('COM_PRIVACY_ADMIN_NOTIFICATION_USER_CONFIRMED_REQUEST_SUBJECT'),
			JText::sprintf('COM_PRIVACY_ADMIN_NOTIFICATION_USER_CONFIRMED_REQUEST_MESSAGE', $table->email)
		);

		JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_actionlogs/models', 'ActionlogsModel');

		$message = array(
			'action'       => 'request-confirmed',
			'subjectemail' => $table->email,
			'id'           => $table->id,
			'itemlink'     => 'index.php?option=com_privacy&view=request&id=' . $table->id,
		);

		/** @var ActionlogsModelActionlog $model */
		$model = JModelLegacy::getInstance('Actionlog', 'ActionlogsModel');
		$model->addLog(array($message), 'COM_PRIVACY_ACTION_LOG_CONFIRMED_REQUEST', 'com_privacy.request');

		return true;
	}

	/**
	 * 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  JForm|boolean  A JForm object on success, false on failure
	 *
	 * @since   3.9.0
	 */
	public function getForm($data = array(), $loadData = true)
	{
		// Get the form.
		$form = $this->loadForm('com_privacy.confirm', 'confirm', array('control' => 'jform'));

		if (empty($form))
		{
			return false;
		}

		$input = JFactory::getApplication()->input;

		if ($input->getMethod() === 'GET')
		{
			$form->setValue('confirm_token', '', $input->get->getAlnum('confirm_token'));
		}

		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  JTable  A JTable object
	 *
	 * @since   3.9.0
	 * @throws  \Exception
	 */
	public function getTable($name = 'Request', $prefix = 'PrivacyTable', $options = array())
	{
		return parent::getTable($name, $prefix, $options);
	}

	/**
	 * Method to auto-populate the model state.
	 *
	 * Note. Calling getState in this method will result in recursion.
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	protected function populateState()
	{
		// Get the application object.
		$params = JFactory::getApplication()->getParams('com_privacy');

		// Load the parameters.
		$this->setState('params', $params);
	}
}
PK�0"]��Ym--models/remind.phpnu&1i�<?php
/**
 * @package     Joomla.Site
 * @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;

/**
 * Remind confirmation model class.
 *
 * @since  3.9.0
 */
class PrivacyModelRemind extends JModelAdmin
{
	/**
	 * Confirms the remind request.
	 *
	 * @param   array  $data  The data expected for the form.
	 *
	 * @return  mixed  Exception | JException | boolean
	 *
	 * @since   3.9.0
	 */
	public function remindRequest($data)
	{
		// Get the form.
		$form = $this->getForm();
		$data['email'] = JStringPunycode::emailToPunycode($data['email']);

		// Check for an error.
		if ($form instanceof Exception)
		{
			return $form;
		}

		// Filter and validate the form data.
		$data = $form->filter($data);
		$return = $form->validate($data);

		// Check for an error.
		if ($return instanceof Exception)
		{
			return $return;
		}

		// Check the validation results.
		if ($return === false)
		{
			// Get the validation messages from the form.
			foreach ($form->getErrors() as $formError)
			{
				$this->setError($formError->getMessage());
			}

			return false;
		}

		/** @var PrivacyTableConsent $table */
		$table = $this->getTable();

		$db = $this->getDbo();
		$query = $db->getQuery(true)
			->select($db->quoteName(array('r.id', 'r.user_id', 'r.token')));
		$query->from($db->quoteName('#__privacy_consents', 'r'));
		$query->join('LEFT', $db->quoteName('#__users', 'u') . ' ON u.id = r.user_id');
		$query->where($db->quoteName('u.email') . ' = ' . $db->quote($data['email']));
		$query->where($db->quoteName('r.remind') . ' = 1');
		$db->setQuery($query);

		try
		{
			$remind = $db->loadObject();
		}
		catch (RuntimeException $e)
		{
			$this->setError(JText::_('COM_PRIVACY_ERROR_NO_PENDING_REMIND'));

			return false;
		}

		if (!$remind)
		{
			$this->setError(JText::_('COM_PRIVACY_ERROR_NO_PENDING_REMIND'));

			return false;
		}

		// Verify the token
		if (!JUserHelper::verifyPassword($data['remind_token'], $remind->token))
		{
			$this->setError(JText::_('COM_PRIVACY_ERROR_NO_REMIND_REQUESTS'));

			return false;
		}

		// Everything is good to go, transition the request to extended
		$saved = $this->save(
			array(
				'id'      => $remind->id,
				'remind'  => 0,
				'token'   => '',
				'created' => JFactory::getDate()->toSql(),
			)
		);

		if (!$saved)
		{
			// Error was set by the save method
			return false;
		}

		return true;
	}

	/**
	 * 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  JForm|boolean  A JForm object on success, false on failure
	 *
	 * @since   3.9.0
	 */
	public function getForm($data = array(), $loadData = true)
	{
		// Get the form.
		$form = $this->loadForm('com_privacy.remind', 'remind', array('control' => 'jform'));

		if (empty($form))
		{
			return false;
		}

		$input = JFactory::getApplication()->input;

		if ($input->getMethod() === 'GET')
		{
			$form->setValue('remind_token', '', $input->get->getAlnum('remind_token'));
		}

		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  JTable  A JTable object
	 *
	 * @since   3.9.0
	 * @throws  \Exception
	 */
	public function getTable($name = 'Consent', $prefix = 'PrivacyTable', $options = array())
	{
		return parent::getTable($name, $prefix, $options);
	}

	/**
	 * Method to auto-populate the model state.
	 *
	 * Note. Calling getState in this method will result in recursion.
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	protected function populateState()
	{
		// Get the application object.
		$params = JFactory::getApplication()->getParams('com_privacy');

		// Load the parameters.
		$this->setState('params', $params);
	}
}
PK)r!]�b�ggg
config.xmlnu&1i�PK)r!]�r�JJ�privacy.phpnu&1i�PK)r!]��$JJ&privacy.xmlnu&1i�PK)r!]Nj����	helpers/plugin.phpnu&1i�PK)r!]�P�helpers/export/domain.phpnu&1i�PK)r!]�H8����helpers/export/item.phpnu&1i�PK)r!]y��,,�"helpers/export/field.phpnu&1i�PK)r!]=*N3%helpers/html/helper.phpnu&1i�PK)r!]�:�<<�)helpers/removal/status.phpnu&1i�PK)r!]�7�-helpers/privacy.phpnu&1i�PK)r!]Q�FRRp8controllers/request.xml.phpnu&1i�PK)r!]�J$�zz
;controllers/consents.phpnu&1i�PK)r!])��WF&F&�Ccontrollers/request.phpnu&1i�PK)r!]��B��\jcontrollers/requests.phpnu&1i�PK)r!]Z�y==Ontables/request.phpnu&1i�PK)r!]<X�����utables/consent.phpnu&1i�PK)r!]��>���
|models/remove.phpnu&1i�PK)r!]�˾RR ۑmodels/forms/filter_requests.xmlnu&1i�PK)r!]��		 }�models/forms/filter_consents.xmlnu&1i�PK)r!]�Q/�models/forms/request.xmlnu&1i�PK)r!]_�Զ"�"D�models/export.phpnu&1i�PK)r!]�Y��;0;0;�models/request.phpnu&1i�PK)r!]��;����models/requests.phpnu&1i�PK)r!]p8q

}models/consents.phpnu&1i�PK)r!]�\��P
P
�#models/capabilities.phpnu&1i�PK)r!]��Y�UUd1models/fields/requeststatus.phpnu&1i�PK)r!]v�Z##5models/fields/requesttype.phpnu&1i�PK)r!]�@@x8models/dashboard.phpnu&1i�PK)r!]�
��++�Hcontroller.phpnu&1i�PK)r!]�cW5zzeXviews/consents/tmpl/default.phpnu&1i�PK)r!]�lz���.iviews/consents/tmpl/default.xmlnu&1i�PK)r!]C�dԱ�Ojviews/consents/view.html.phpnu&1i�PK)r!]JO����#Lvviews/capabilities/tmpl/default.phpnu&1i�PK)r!]��_�� �}views/capabilities/view.html.phpnu&1i�PK)r!]������views/requests/view.html.phpnu&1i�PK)r!]�A1�����views/requests/tmpl/default.xmlnu&1i�PK)r!]�}�����views/requests/tmpl/default.phpnu&1i�PK)r!]��))�views/request/tmpl/edit.phpnu&1i�PK)r!]�XllV�views/request/tmpl/default.phpnu&1i�PK)r!]5�ӷ\\�views/request/view.html.phpnu&1i�PK)r!]lg$M M  ��views/dashboard/tmpl/default.phpnu&1i�PK)r!]<ԧM�� T�views/dashboard/tmpl/default.xmlnu&1i�PK)r!]uqp
��x�views/dashboard/view.html.phpnu&1i�PK)r!]�e4��s�views/export/view.xml.phpnu&1i�PK�0"]zA��66\�views/confirm/tmpl/default.phpnu&1i�PK�0"]���EE�views/confirm/tmpl/default.xmlnu&1i�PK�0"]�z�<��sviews/confirm/view.html.phpnu&1i�PK�0"]
���DD�views/request/tmpl/default.xmlnu&1i�PK�0"]`A��AAEviews/remind/tmpl/default.xmlnu&1i�PK�0"]εd44�views/remind/tmpl/default.phpnu&1i�PK�0"]��i��Tviews/remind/view.html.phpnu&1i�PK�0"]@<�?��
�'router.phpnu&1i�PK�0"]�P�R/models/forms/remind.xmlnu&1i�PK�0"]��f$oo�1models/forms/confirm.xmlnu&1i�PK�0"]��s�iil3models/confirm.phpnu&1i�PK�0"]��Ym--Jmodels/remind.phpnu&1i�PK88Q�Z