Реализация метода revoke для моделей и таблиц

This commit is contained in:
Artem Vasilev 2024-03-06 15:01:57 +03:00
parent 1daec613d4
commit 7cd246e6c8
6 changed files with 289 additions and 7 deletions

View File

@ -6,9 +6,10 @@ use Joomla\CMS\Factory;
use Joomla\CMS\Form\Form; use Joomla\CMS\Form\Form;
use Joomla\CMS\MVC\Model\AdminModel; use Joomla\CMS\MVC\Model\AdminModel;
class AccessTokenModel extends AdminModel class AccessTokenModel extends AdminModel implements RevokedModelInterface
{ {
use GetItemByIdentifierTrait; use GetItemByIdentifierTrait;
use RevokedModelTrait;
public function getForm($data = [], $loadData = true): Form|bool public function getForm($data = [], $loadData = true): Form|bool
{ {

View File

@ -0,0 +1,8 @@
<?php
namespace Webmasterskaya\Component\OauthServer\Administrator\Model;
interface RevokedModelInterface
{
public function revoke(&$identifiers): bool;
}

View File

@ -0,0 +1,116 @@
<?php
namespace Webmasterskaya\Component\OauthServer\Administrator\Model;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\User\User;
trait RevokedModelTrait
{
/**
* @var string
* @since version
* @noinspection PhpMissingFieldTypeInspection
*/
protected $option;
/**
* @var string
* @since version
* @noinspection PhpMissingFieldTypeInspection
*/
protected $name;
/**
* @var array
* @since version
* @noinspection PhpMissingFieldTypeInspection
*/
protected $events_map;
/**
* @var string
* @since version
* @noinspection PhpMissingFieldTypeInspection
*/
protected $event_before_change_state;
/**
* @var string
* @since version
* @noinspection PhpMissingFieldTypeInspection
*/
protected $event_change_state;
abstract public function getTable($name = '', $prefix = '', $options = []);
abstract protected function getCurrentUser(): User;
abstract public function setError($error);
abstract protected function cleanCache($group = null);
public function revoke(&$identifiers): bool
{
$user = $this->getCurrentUser();
/** @var \Joomla\CMS\Table\Table $table */
$table = $this->getTable();
$identifiers = (array)$identifiers;
$pks = [];
$context = $this->option . '.' . $this->name;
// Include the plugins for the change of state event.
PluginHelper::importPlugin($this->events_map['change_state']);
foreach ($identifiers as $i => $identifier) {
$table->reset();
if ($table->load(['identifier' => $identifier])) {
$revokedColumnName = $table->getColumnAlias('revoked');
if (property_exists($table, $revokedColumnName) && $table->get($revokedColumnName, 1) == 0) {
unset($identifier[$i]);
} else {
$pks[] = $table->get('id');
}
}
}
// Check if there are items to change
if (!\count($pks)) {
return true;
}
// Trigger the before change state event.
$result = Factory::getApplication()->triggerEvent($this->event_before_change_state, [$context, $pks, 0]);
if (\in_array(false, $result, true)) {
$this->setError($table->getError());
return false;
}
// Attempt to change the state of the records.
if (!$table->revoke($pks, $user->id)) {
$this->setError($table->getError());
return false;
}
// Trigger the change state event.
$result = Factory::getApplication()->triggerEvent($this->event_change_state, [$context, $pks, 0]);
if (\in_array(false, $result, true)) {
$this->setError($table->getError());
return false;
}
// Clear the component's cache
$this->cleanCache();
return true;
}
}

View File

@ -2,16 +2,24 @@
namespace Webmasterskaya\Component\OauthServer\Administrator\Table; namespace Webmasterskaya\Component\OauthServer\Administrator\Table;
use DateTimeImmutable;
use Joomla\CMS\Table\Table; use Joomla\CMS\Table\Table;
use Joomla\Database\DatabaseDriver; use Joomla\Database\DatabaseDriver;
use League\OAuth2\Server\CryptKey;
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
use League\OAuth2\Server\Entities\ClientEntityInterface;
use League\OAuth2\Server\Entities\ScopeEntityInterface;
class AccessTokenTable extends Table /**
* @property int $id
* @property string $identifier
* @property \DateTimeImmutable|\DateTime|string $expiry
* @property ?int $user_id
* @property string|array|null $scopes
* @property int $client_id
* @property int $revoked
*
* @since version
*/
class AccessTokenTable extends Table implements RevokedTableInterface
{ {
use RevokedTableTrait;
/** /**
* Indicates that columns fully support the NULL value in the database * Indicates that columns fully support the NULL value in the database
* *

View File

@ -0,0 +1,8 @@
<?php
namespace Webmasterskaya\Component\OauthServer\Administrator\Table;
interface RevokedTableInterface
{
public function revoke($pks = null, $userId = 0): bool;
}

View File

@ -0,0 +1,141 @@
<?php
namespace Webmasterskaya\Component\OauthServer\Administrator\Table;
use Joomla\CMS\Event\AbstractEvent;
use Joomla\CMS\Language\Text;
trait RevokedTableTrait
{
/**
* @var string
* @since version
* @noinspection PhpMissingFieldTypeInspection
*/
protected $_tbl = '';
/**
* @var string
* @since version
* @noinspection PhpMissingFieldTypeInspection
*/
protected $_tbl_key = '';
/**
* @var array
* @since version
* @noinspection PhpMissingFieldTypeInspection
*/
protected $_tbl_keys = [];
/**
* @var \Joomla\Database\DatabaseDriver
* @since version
* @noinspection PhpMissingFieldTypeInspection
*/
protected $_db;
abstract public function getDispatcher();
abstract public function setError($error);
abstract public function getColumnAlias($column);
abstract public function getDbo();
abstract public function appendPrimaryKeys($query, $pk = null);
public function revoke($pks = null, $userId = 0): bool
{
// Sanitize input
$userId = (int)$userId;
// Pre-processing by observers
$event = AbstractEvent::create(
'onTableBeforeRevoke',
[
'subject' => $this,
'pks' => $pks,
]
);
$this->getDispatcher()->dispatch('onTableBeforeRevoke', $event);
if (!\is_null($pks)) {
if (!\is_array($pks)) {
$pks = [$pks];
}
foreach ($pks as $key => $pk) {
if (!\is_array($pk)) {
$pks[$key] = [$this->_tbl_key => $pk];
}
}
}
// If there are no primary keys set check to see if the instance key is set.
if (empty($pks)) {
$pk = [];
foreach ($this->_tbl_keys as $key) {
if ($this->$key) {
$pk[$key] = $this->$key;
} else {
// We don't have a full primary key - return false
$this->setError(Text::_('JLIB_DATABASE_ERROR_NO_ROWS_SELECTED'));
return false;
}
}
$pks = [$pk];
}
$revokedField = $this->getColumnAlias('revoked');
foreach ($pks as $pk) {
$query = $this->_db->getQuery(true)
->update($this->_db->quoteName($this->_tbl))
->set($this->_db->quoteName($revokedField) . ' = 0');
// Build the WHERE clause for the primary keys.
$this->appendPrimaryKeys($query, $pk);
$this->_db->setQuery($query);
try {
$this->_db->execute();
} catch (\RuntimeException $e) {
$this->setError($e->getMessage());
return false;
}
// If the Table instance value is in the list of primary keys that were set, set the instance.
$ours = true;
foreach ($this->_tbl_keys as $key) {
if ($this->$key != $pk[$key]) {
$ours = false;
}
}
if ($ours) {
$this->$revokedField = 0;
}
}
$this->setError('');
// Pre-processing by observers
$event = AbstractEvent::create(
'onTableAfterRevoke',
[
'subject' => $this,
'pks' => $pks
]
);
$this->getDispatcher()->dispatch('onTableAfterRevoke', $event);
return true;
}
}