Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[5.2] Delete user access level - check for levels in use #43223

Merged
merged 17 commits into from
Aug 8, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 82 additions & 58 deletions administrator/components/com_users/src/Model/LevelModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,89 @@
class LevelModel extends AdminModel
{
/**
* @var array A list of the access levels in use.
* @since 1.6
* Method to delete one or more access levels.
*
* @param array $pks An array of record primary keys.
chmst marked this conversation as resolved.
Show resolved Hide resolved
*
* @return boolean True if successful, false if an error occurs.
*
* @since __DEPLOY_VERSION__
*/
protected $levelsInUse = null;
public function delete(&$pks)
{
$pks = (array) $pks;
$table = $this->getTable();

$itemsInUse = [];
chmst marked this conversation as resolved.
Show resolved Hide resolved

// Iterate the items to delete each one.
foreach ($pks as $i => $pk) {
if ($table->load($pk)) {

// Check if the access level is being used by any content.
chmst marked this conversation as resolved.
Show resolved Hide resolved
$db = $this->getDatabase();
$query = $db->getQuery(true)
->select('DISTINCT access');

// Get all tabels that have the access field
chmst marked this conversation as resolved.
Show resolved Hide resolved
$checkTables = $db->getTableList();
$prefix = $db->getPrefix();

$itemsInUse[$pk] = [];
foreach ($checkTables as $checktable) {

// Get all of the columns in the table
$fields = $db->getTableColumns($checktable);

/**
* We are looking for the access field. If custom tables are using something other
* than the 'access' field they are on their own unfortunately.
* Also make sure the table prefix matches the live db prefix (eg, it is not a "bak_" table)
*/
if (strpos($checktable, $prefix) === 0 && isset($fields['access'])) {
// Lookup the distinct values of the field.
$query->clear('from')
->from($db->quoteName($checktable));
$db->setQuery($query);

try {
$values = $db->loadColumn();
} catch (\RuntimeException $e) {
$this->setError($e->getMessage());

return false;
}

// Check if the table uses this access level
if (\in_array($pk, $values)) {

// Add the table to the list of tables that use this access level
$levelsInUse[$pk][] = $checktable;

// Remove the access level from the list of items to delete
unset($pks[$i]);
}
}
}
}
}

if (!empty($levelsInUse)) {
$msg = Text::_('COM_USERS_ERROR_VIEW_LEVEL_IN_USE');
$msg .= '<ul>';

foreach ($levelsInUse as $levelId => $usedIn) {
$text = Text::sprintf('COM_USERS_ERROR_VIEW_LEVEL_IN_USE_DETAILS', $levelId, implode(', ', $usedIn));
$msg .= '<li>' . $text . '</li>';
}

$msg .= '</ul>';

Factory::getApplication()->enqueueMessage($msg, 'error');
}

return parent::delete($pks);
}

/**
* Method to test whether a record can be deleted.
Expand Down Expand Up @@ -65,61 +144,6 @@ protected function canDelete($record)
}
}

// Check if the access level is being used by any content.
if ($this->levelsInUse === null) {
// Populate the list once.
$this->levelsInUse = [];

$db = $this->getDatabase();
$query = $db->getQuery(true)
->select('DISTINCT access');

// Get all the tables and the prefix
$tables = $db->getTableList();
$prefix = $db->getPrefix();

foreach ($tables as $table) {
// Get all of the columns in the table
$fields = $db->getTableColumns($table);

/**
* We are looking for the access field. If custom tables are using something other
* than the 'access' field they are on their own unfortunately.
* Also make sure the table prefix matches the live db prefix (eg, it is not a "bak_" table)
*/
if (strpos($table, $prefix) === 0 && isset($fields['access'])) {
// Lookup the distinct values of the field.
$query->clear('from')
->from($db->quoteName($table));
$db->setQuery($query);

try {
$values = $db->loadColumn();
} catch (\RuntimeException $e) {
$this->setError($e->getMessage());

return false;
}

$this->levelsInUse = array_merge($this->levelsInUse, $values);

// @todo Could assemble an array of the tables used by each view level list those,
// giving the user a clue in the error where to look.
}
}

// Get uniques.
$this->levelsInUse = array_unique($this->levelsInUse);

// Ok, after all that we are ready to check the record :)
}

if (\in_array($record->id, $this->levelsInUse)) {
$this->setError(Text::sprintf('COM_USERS_ERROR_VIEW_LEVEL_IN_USE', $record->id, $record->title));

return false;
}

return parent::canDelete($record);
}

Expand Down
3 changes: 2 additions & 1 deletion administrator/language/en-GB/com_users.ini
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ COM_USERS_ERROR_LEVELS_NOLEVELS_SELECTED="No View Permission Level(s) selected."
COM_USERS_ERROR_NO_ADDITIONS="The selected user(s) are already assigned to the selected group."
COM_USERS_ERROR_NOT_IN_GROUP="The selected user(s) are not in the selected group."
COM_USERS_ERROR_ONLY_ONE_GROUP="A user must belong to at least one group."
COM_USERS_ERROR_VIEW_LEVEL_IN_USE="You can't delete the view access level '%d:%s' because it is being used by content."
COM_USERS_ERROR_VIEW_LEVEL_IN_USE="You can't delete the view access level(s)"
COM_USERS_ERROR_VIEW_LEVEL_IN_USE_DETAILS="Level with ID %d is being used in the database tables: %s."
chmst marked this conversation as resolved.
Show resolved Hide resolved
COM_USERS_FIELDS_USER_FIELDS_TITLE="Users: Fields"
COM_USERS_FIELDS_USER_FIELD_ADD_TITLE="Users: New Field"
COM_USERS_FIELDS_USER_FIELD_EDIT_TITLE="Users: Edit Field"
Expand Down