foldershare-8.x-1.2/src/Plugin/FolderShareCommand/Share.php
src/Plugin/FolderShareCommand/Share.php
<?php
namespace Drupal\foldershare\Plugin\FolderShareCommand;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Url;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Form\FormStateInterface;
use Drupal\user\Entity\User;
use Drupal\foldershare\Constants;
use Drupal\foldershare\Settings;
use Drupal\foldershare\Utilities\UserUtilities;
use Drupal\foldershare\Entity\FolderShare;
use Drupal\foldershare\Entity\FolderShareAccessControlHandler;
/**
* Defines a command plugin to change share grants on a root item.
*
* The command sets the access grants for the root item of the selected
* entity. Access grants enable/disable view and author access for
* individual users.
*
* Configuration parameters:
* - 'parentId': the parent folder, if any.
* - 'selectionIds': selected entity who's root item is shared.
* - 'grants': the new access grants.
*
* @ingroup foldershare
*
* @FolderShareCommand(
* id = "foldersharecommand_share",
* label = @Translation("Share"),
* menuNameDefault = @Translation("Share..."),
* menuName = @Translation("Share..."),
* description = @Translation("Share selected top-level files and folders, and their contents."),
* category = "settings",
* weight = 10,
* userConstraints = {
* "authenticated",
* },
* parentConstraints = {
* "kinds" = {
* "rootlist",
* },
* "access" = "view",
* },
* selectionConstraints = {
* "types" = {
* "one",
* },
* "kinds" = {
* "any",
* },
* "access" = "share",
* },
* )
*/
class Share extends FolderShareCommandBase {
/*--------------------------------------------------------------------
*
* Configuration.
*
*--------------------------------------------------------------------*/
/**
* {@inheritdoc}
*/
public function defaultConfiguration() {
// Include room for the new grants in the configuration.
$config = parent::defaultConfiguration();
$config['grants'] = [];
return $config;
}
/*--------------------------------------------------------------------
*
* Configuration form setup.
*
*--------------------------------------------------------------------*/
/**
* {@inheritdoc}
*/
public function hasConfigurationForm() {
return TRUE;
}
/**
* {@inheritdoc}
*/
public function getDescription(bool $forPage) {
// The description varies for page vs. dialog:
//
// - Dialog: The description is longer and has the form "Grant shared
// access to NAME and its contents."
//
// - Page: The description is as for a dialog, except the name is not
// included because it is already in the title.
$selectionIds = $this->getSelectionIds();
$item = FolderShare::load(reset($selectionIds));
$description = [];
if ($forPage === TRUE) {
// Page description. The page title already gives the name of the
// item. Don't include the item's name again here.
if ($item->isFolder() === TRUE) {
$description[] = t(
'Grant shared access to this folder and its contents.',
[
'@name' => $item->getName(),
]);
}
else {
$description[] = t(
'Grant shared access to @operand.',
[
'@operand' => FolderShare::translateKind($item->getKind()),
]);
}
}
else {
// Dialog description. Include the name of the item to be changed.
if ($item->isFolder() === TRUE) {
$description[] = t(
'Grant shared access to "@name" and its contents.',
[
'@name' => $item->getName(),
]);
}
else {
$description[] = t(
'Grant shared access to "@name".',
[
'@name' => $item->getName(),
]);
}
}
$description[] = t(
'%view access allows users to view, copy, and download. %author access also allows users to edit, delete, move, and upload.',
[
'%view' => t('View'),
'%author' => t('Author'),
]);
return $description;
}
/**
* {@inheritdoc}
*/
public function getTitle(bool $forPage) {
// The title varies for page vs. dialog:
//
// - Dialog: The title is short and has the form "Share OPERAND",
// where OPERAND is the kind of item (e.g. "file"). By not putting
// the item's name in the title, we keep the dialog title short and
// avoid cropping or wrapping.
//
// - Page: The title is longer and has the form "Share "NAME"?"
// This follows Drupal convention.
$selectionIds = $this->getSelectionIds();
$item = FolderShare::load(reset($selectionIds));
if ($forPage === TRUE) {
// Page title. Include the name of the item.
return t(
'Share "@name"',
[
'@name' => $item->getName(),
]);
}
// Dialog title. Include the operand kind.
return t(
'Share @operand',
[
'@operand' => FolderShare::translateKind($item->getKind()),
]);
}
/**
* {@inheritdoc}
*/
public function getSubmitButtonName() {
return t('Save');
}
/*--------------------------------------------------------------------
*
* Configuration form.
*
*--------------------------------------------------------------------*/
/**
* {@inheritdoc}
*/
public function buildConfigurationForm(
array $form,
FormStateInterface $formState) {
//
// Define form element names/classes.
// ----------------------------------
// Most form elements have specific names/classes. Names enable values
// to be retreived easily. Classes enable custom styling.
$shareForm = Constants::MODULE . '_share_form';
$shareFormWrapper = Constants::MODULE . '_share_form_wrapper';
$shareTable = Constants::MODULE . '_share_table';
$addUserForm = Constants::MODULE . '_share_add_user';
$addUserField = Constants::MODULE . '_share_add_user_name';
$addUserFieldAndButton = Constants::MODULE . '_share_add_user_name_and_button';
$addUserButton = Constants::MODULE . '_share_add_user_button';
$addUserDescription = Constants::MODULE . '_share_add_user_description';
$addUserMessages = Constants::MODULE . '_share_add_user_messages';
$formInput = $formState->getUserInput();
//
// Get current user permissions.
// -----------------------------
// Does the current user have permission to share with other users
// and/or share with the public?
$currentUser = \Drupal::currentUser();
$hasShareWithUsersPermission = AccessResult::allowedIfHasPermission(
$currentUser,
Constants::SHARE_PERMISSION)->isAllowed();
$hasShareWithPublicPermission = AccessResult::allowedIfHasPermission(
$currentUser,
Constants::SHARE_PUBLIC_PERMISSION)->isAllowed();
// If the current user doesn't have permission to share content with
// other users or with the public, then the share form should not have
// been presented. Since it has been, show an error message.
if ($hasShareWithUsersPermission === FALSE &&
$hasShareWithPublicPermission === FALSE) {
$form['nopermission'] = [
'#type' => 'html_tag',
'#tag' => 'p',
'#value' => t('You do not have permission to share files and folders with other users or the public.'),
];
unset($form['actions']['submit']);
return $form;
}
//
// Get user info.
// --------------
// On the first form build, get the list of grants from the selected
// item. On subsequent calls, use a saved list that's been updated with
// added and removed users.
//
// The list has UID keys and values that are arrays with one
// or more of:
//
// '' = no grants.
// 'view' = granted view access.
// 'author' = granted author access.
//
// The returned array cannot be empty. It always contains at least
// the owner of the folder, who always has 'view' and 'author' access.
$selectionIds = $this->getSelectionIds();
$item = FolderShare::load(reset($selectionIds));
$grants = $formState->get('grants');
if (empty($grants) === TRUE) {
$grants = $item->getAccessGrants();
$formState->set('grants', $grants);
}
// Load all referenced users. We need their display names for the
// form's list of users. Add the users into an array keyed by
// the display name, then sort on those keys so that we can create
// a sorted list in the form.
$loadedUsers = User::loadMultiple(array_keys($grants));
$users = [];
foreach ($loadedUsers as $user) {
if ($user === NULL) {
// User cannot be loaded. The item's grants list probably references
// a user ID for an account that has been deleted. Silently ignore
// the deleted user.
continue;
}
$users[$user->getDisplayName()] = $user;
}
ksort($users, SORT_NATURAL);
// Get the anonymous user.
$anonymousUser = User::getAnonymousUser();
// Get the user ID of the special primary site admin. There can be
// additional site admins, and it is even possible to delete the primary
// site admin (though that is not advised).
$siteAdminId = 1;
// Save the root folder for use when the form is submitted later.
$this->entity = $item;
// Get the item's owner.
$ownerId = $item->getOwnerId();
$owner = User::load($ownerId);
//
// Table of users and grants.
// --------------------------
// Create a table that has a first column showing user names, and a
// second column showing access grants.
$form[$shareForm] = [
'#type' => 'container',
'#name' => $shareForm,
'#prefix' => '<div id="' . $shareFormWrapper . '">',
'#suffix' => '</div>',
'#attributes' => [
'class' => [$shareForm],
],
$shareTable => [
'#type' => 'table',
'#name' => $shareTable,
'#attributes' => [
'class' => [$shareTable],
],
'#responsive' => FALSE,
'#sticky' => TRUE,
'#header' => [
t('User'),
t(
'<span>@none</span><span>@view</span><span>@author</span>',
[
'@none' => t('None'),
'@view' => t('View'),
'@author' => t('Author'),
]),
],
],
];
$rows = [];
$uids = [];
//
// Add row for anonymous.
// ----------------------
// If Sharing with anonymous is allowed for this user, include a row
// to do so at the top of the table.
if ($hasShareWithPublicPermission === TRUE) {
if (isset($grants[(int) $anonymousUser->id()]) === FALSE) {
// There is no entry yet for anonymous. Create one, but with neither
// view or author access.
$grants[0] = [];
}
$r = $this->buildRow(
$anonymousUser,
$owner,
$grants[(int) $anonymousUser->id()]);
// buildRow() can return an empty array if the anonymous user has not
// been given view permission for files and folders.
if (empty($r) === FALSE) {
$rows[] = $r;
}
}
//
// Add rows for users granted access.
// ----------------------------------
// If sharing with other users is allowed for this user, include a list
// of users currently granted access.
if ($hasShareWithUsersPermission === TRUE) {
foreach ($users as $user) {
$uid = (int) $user->id();
// Do not add table rows for:
// - Anonymous.
// - Blocked accounts.
// - The primary site admin.
// - The file/folder owner.
//
// Anonymous access is already handled above and requires a separate
// permission.
//
// Blocked accounts can be on a grants list if the account was blocked
// recently. But once blocked, this form no longer shows the account
// and the account is silently removed from the grants list when the
// form is saved.
//
// The primary site admin always had access, so they don't have to be
// on a share list. Adding them looks odd, so they are silently skipped.
//
// The owner always has access to their content, so they don't need
// to be listed here.
if ($user->isAnonymous() === TRUE ||
$user->isBlocked() === TRUE ||
$uid === $siteAdminId ||
$uid === $ownerId) {
continue;
}
// Add the row.
$r = $this->buildRow(
$user,
$owner,
$grants[$uid]);
if (empty($r) === FALSE) {
$rows[] = $r;
$uids[] = $uid;
}
}
}
// If the above code did not add any rows, then there is currently no one
// granted shared access. Say so.
//
// If the above code added rows, excluding anonymous, then add a table
// description.
if (count($rows) <= 0) {
$rows[] = [
'User' => [
'#markup' => t('No users have shared access.'),
'#wrapper_attributes' => [
'colspan' => 2,
],
],
];
}
elseif ($hasShareWithUsersPermission === TRUE) {
$form[$shareForm]['description'] = [
'#type' => 'html_tag',
'#tag' => 'p',
'#value' => t(
'Users with "%none" selected are automatically removed from this list when the form is saved.',
[
'%none' => t('None'),
]),
'#attributes' => [
'class' => ['description'],
],
];
}
if (count($rows) != 0) {
$form[$shareForm][$shareTable] = array_merge(
$form[$shareForm][$shareTable],
$rows);
}
//
// Add user autocomplete field and button.
// ---------------------------------------
// If sharing with other users is allowed for this user, include an
// 'Add a user' autocomplete field used to add users to the share list.
if ($hasShareWithUsersPermission === TRUE) {
// If the text field is empty, the 'Add' user button is disabled by
// Javascript attached to the form.
$routeParameters =
$form['actions']['submit']['#ajax']['url']->getRouteParameters()['encoded'];
$description = '';
switch (Settings::getUserAutocompleteStyle()) {
default:
case 'none':
case 'name-only':
$description = t('Enter the account name of a user.');
break;
case 'name-email':
case 'name-masked-email':
$description = t('Enter the account name or email address of a user.');
break;
}
$defaultUser = '';
if (isset($formInput[$addUserField]) === TRUE) {
$defaultUser = $formInput[$addUserField];
}
$form[$shareForm][$addUserForm] = [
'#type' => 'container',
'#tree' => TRUE,
'#name' => $addUserForm,
'#attributes' => [
'class' => [$addUserForm],
],
'label' => [
'#type' => 'label',
'#title' => t('Add a user'),
],
$addUserFieldAndButton => [
'#type' => 'container',
'#attributes' => [
'class' => [$addUserFieldAndButton],
],
$addUserField => [
'#type' => 'textfield',
'#maxlength' => 256,
'#default_value' => $defaultUser,
'#required' => FALSE,
'#name' => $addUserField,
'#attributes' => [
'autofocus' => 'autofocus',
'spellcheck' => 'false',
'class' => [$addUserField],
],
],
$addUserButton => [
'#type' => 'button',
'#value' => t('Add'),
'#name' => $addUserButton,
'#attributes' => [
'class' => [$addUserButton],
],
'#ajax' => [
'callback' => [$this, 'refreshConfigurationForm'],
'event' => 'click',
'wrapper' => $shareFormWrapper,
'url' => Url::fromRoute(
'entity.foldersharecommand.plugin',
[
'encoded' => $routeParameters,
]),
'options' => [
'query' => [
'ajax_form' => 1,
],
],
],
],
],
$addUserDescription => [
'#type' => 'html_tag',
'#tag' => 'p',
'#value' => $description,
'#attributes' => [
'class' => [
'description',
$addUserDescription,
],
],
],
$addUserMessages => [
'#type' => 'status_messages',
],
];
// If the site allows user autocomplete, set up the text field. Include
// a list of users culled to skip:
// - All users already with shared access.
// - The current user, who always has access.
// - Anonymous, who has a special row above.
// - The primary site admin, who always has access.
$autocompleteStyle = Settings::getUserAutocompleteStyle();
if ($autocompleteStyle !== 'none') {
$excludeUids = $uids;
$excludeUids[] = (int) $currentUser->id();
$excludeUids[] = (int) $anonymousUser->id();
$excludeUids[] = $siteAdminId;
$form[$shareForm][$addUserForm][$addUserFieldAndButton][$addUserField]['#autocomplete_route_name'] =
'entity.foldershare.userautocomplete';
$form[$shareForm][$addUserForm][$addUserFieldAndButton][$addUserField]['#autocomplete_route_parameters'] = [
'excludeUids' => $excludeUids,
'excludeBlocked' => 1,
];
}
}
return $form;
}
/**
* Builds and returns a form row for a user.
*
* The form has three columns:
* - User name.
* - Access choice.
* - Actions.
*
* The user name is the account's display name.
*
* The access choice is a pair of radio buttons for "view" and "access".
*
* If the given user does not have appropriate module permissions, they
* cannot have either "view" or "access" and an empty array is returned.
*
* @param \Drupal\user\Entity\User $user
* The user for whom to build the row.
* @param \Drupal\user\Entity\User $owner
* The owner of the current root item.
* @param array $grant
* The access grants for the user.
*
* @return array
* The form table row description for the user, or an empty row if the
* user cannot be granted access because their account is blocked, they
* don't have module permissions, or they are the item's owner.
*/
private function buildRow(
User $user,
User $owner,
array $grant) {
//
// Get account attributes.
// -----------------------
// Watch for special users.
$rowIsForAnonymous = $user->isAnonymous();
$rowIsForBlockedUser = $user->isBlocked();
$rowIsForRootOwner = ((int) $user->id() === (int) $owner->id());
if ($rowIsForBlockedUser === TRUE && $rowIsForAnonymous === FALSE) {
// Blocked non-anonymous users cannot be granted shared access.
// Do not list them.
return [];
}
if ($rowIsForRootOwner === TRUE) {
// The owner always has access. Do not list them.
return [];
}
//
// Check row user permissions.
// ---------------------------
// Get what the row user is permitted to do based on permissions alone.
$permittedToView =
FolderShareAccessControlHandler::mayAccess('view', $user);
$permittedToAuthor =
FolderShareAccessControlHandler::mayAccess('update', $user);
if ($permittedToView === FALSE) {
// The user has not been given view access for the module's content.
// They cannot be granted shared access then.
return [];
}
//
// Get grants for this root.
// -------------------------
// Check the access grants on the root item and see what the row user
// has been granted to do, if anything.
$currentlyGrantedView = in_array('view', $grant);
$currentlyGrantedAuthor = in_array('author', $grant);
// If the user is explicitly granted author access, then automatically
// include view access.
if ($currentlyGrantedAuthor === TRUE) {
$currentlyGrantedView = TRUE;
}
if ($permittedToAuthor === FALSE) {
// The row user doesn't have author permission, so any author grant
// they have on the row's root is irrelevant.
$currentlyGrantedAuthor = FALSE;
}
//
// Build row
// ---------
// Start by creating the radio button options array based upon the grants.
$radios = ['none' => ''];
$default = 'none';
if ($permittedToView === TRUE) {
// User has view permissions, so allow a 'view' choice.
$radios['view'] = '';
}
if ($permittedToAuthor === TRUE) {
// User has author permissions, so allow a 'author' choice.
$radios['author'] = '';
}
if ($currentlyGrantedView === TRUE) {
// User has been granted view access.
$default = 'view';
}
if ($currentlyGrantedAuthor === TRUE) {
// User has been granted author access (which for our purposes
// includes view access).
$default = 'author';
}
// Create an annotated user name.
$name = $user->getDisplayName();
if ($rowIsForAnonymous === TRUE) {
$nameMarkup = t('Everyone that can access this website');
}
else {
$nameMarkup = t(
'@name',
[
'@name' => $name,
]);
}
// Create the row. Provide the user's UID as the row value, which we'll
// use later during validation and submit handling. Show a link to the
// user's profile.
$shareTableRow = Constants::MODULE . '_share_table_row';
$shareTableRowUser = Constants::MODULE . '_share_table_row_user';
$shareTableRowAccess = Constants::MODULE . '_share_table_row_access';
return [
'User' => [
'#type' => 'item',
'#value' => $user->id(),
'#markup' => $nameMarkup,
'#attributes' => [
'class' => [$shareTableRowUser],
],
],
// Disable the row if the user has no permissions.
'Access' => [
'#type' => 'radios',
'#options' => $radios,
'#default_value' => $default,
'#attributes' => [
'class' => [$shareTableRowAccess],
],
],
'#attributes' => [
'class' => [$shareTableRow],
],
];
}
/**
* {@inheritdoc}
*/
public function validateConfigurationForm(
array &$form,
FormStateInterface $formState) {
//
// Setup.
// ------
// Get user input.
$trigger = $formState->getTriggeringElement();
$formInput = $formState->getUserInput();
$shareForm = Constants::MODULE . '_share_form';
$shareTable = Constants::MODULE . '_share_table';
$addUserForm = Constants::MODULE . '_share_add_user';
$addUserFieldAndButton = Constants::MODULE . '_share_add_user_name_and_button';
$addUserField = Constants::MODULE . '_share_add_user_name';
$addUserButton = Constants::MODULE . '_share_add_user_button';
// Get the selection, which is always a single root list item.
$selectionIds = $this->getSelectionIds();
$item = FolderShare::load(reset($selectionIds));
$ownerId = $item->getOwnerId();
//
// Determine reason validation was called.
// ---------------------------------------
// Validation is called on a 'Save' button click to submit the form,
// or on an 'Add' button click to add a new user.
$formIsForAdd = FALSE;
if ($trigger['#name'] === $addUserButton) {
$formIsForAdd = TRUE;
}
//
// Validate current grants.
// ------------------------
// Whether or not the user has clicked 'Save' to submit changes to
// the grant list, we still need to validate them and save them into
// the form's configuration.
//
// Get the form's grants. These may differ from the item's original
// grants in two ways:
// - Added users will have an entry.
// - Removed users will not have an entry.
//
// All entries that are not for added users will have the view/author
// grants originally granted. Below we'll adjust those grants based upon
// the radio buttons in the form.
$grants = $formState->get('grants');
// Get the original grants too.
$originalGrants = $item->getAccessGrants($item);
// Copy the owner's own original grants forward. The owner always has
// access and should not have been listed in the form, but be safe.
if (isset($originalGrants[$ownerId]) === TRUE) {
$grants[$ownerId] = $originalGrants[$ownerId];
}
// Get the current list of users from the table.
$entries = $formState->getValue($shareForm)[$shareTable];
if (empty($entries) === FALSE) {
if ($formIsForAdd === TRUE) {
// The form has been submitted by clicking 'Add' to add a new user.
// The form's table of users and grants is not final yet, so it is
// premature to validate it.
foreach ($entries as $entry) {
$uid = $entry['User'];
switch ($entry['Access']) {
case 'view':
$grants[$uid] = ['view'];
break;
case 'author':
$grants[$uid] = [
'view',
'author',
];
break;
case 'none':
$grants[$uid] = [];
break;
default:
break;
}
}
}
else {
// Validate that the new grants make sense.
//
// Loop through the form's table of users and access grants. For each
// user, see if 'none', 'view', or 'author' radio buttons are set
// and create the associated grant in a user-grant array.
foreach ($entries as $entry) {
$uid = $entry['User'];
// Ignore any row for the root item owner. This shouldn't have been in
// the table in the first place.
if ($uid === $ownerId) {
continue;
}
// Ignore blocked accounts that aren't anonymous. Blocked accounts
// should not have been in the table in the first place.
$user = User::load($uid);
if ($user === NULL ||
($user->isBlocked() === TRUE && $user->isAnonymous() === FALSE)) {
continue;
}
switch ($entry['Access']) {
case 'view':
// Make sure the user has view permission.
if (FolderShareAccessControlHandler::mayAccess('view', $user) === TRUE) {
$grants[$uid] = ['view'];
}
break;
case 'author':
// Make sure the user has author permission.
if (FolderShareAccessControlHandler::mayAccess('update', $user) === TRUE) {
// Author grants ALWAYS include view grants.
$grants[$uid] = [
'view',
'author',
];
}
break;
case 'none':
// Remove any user that has not been granted any permission.
unset($grants[$uid]);
break;
default:
break;
}
}
}
}
// Save the updated grants back into the form and into the command's
// configuration.
$formState->set('grants', $grants);
$this->configuration['grants'] = $grants;
//
// Handle add user.
// ----------------
// When the trigger is the add user button, get the entered text for
// a user to add. The text can be an account name or email address.
// Add the user to the grants list, then rebuild the form.
if ($formIsForAdd === TRUE) {
// Get the entered text for the user to add.
$name = $formInput[$addUserField];
// Remove leading white space.
$cleanedName = mb_ereg_replace('^\s+', '', $name);
if ($cleanedName !== FALSE) {
$name = $cleanedName;
}
// Remove trailing white space.
$cleanedName = mb_ereg_replace('\s+$', '', $name);
if ($cleanedName !== FALSE) {
$name = $cleanedName;
}
if (empty($name) === TRUE) {
// Empty user. Intentionally use an empty error message. This will
// highlight the form field but not show a message. Such a message
// would be redundant and just say "Enter an account name", which
// is what the description under the field already says.
$formState->setErrorByName(
$shareForm,
'');
// Clear the name field.
// Since a validation error does not rebuild the form, updating the
// form's state does not work to insure the form name field is empty.
$form[$shareForm][$addUserForm][$addUserFieldAndButton][$addUserField]['#value'] = '';
$formState->setRebuild();
return;
}
//
// Look up the user.
// -----------------
// Use the given name to find a user then add them to the grants list.
$uid = UserUtilities::findUser($name);
if ($uid === -1) {
// Unknown user.
$formState->setErrorByName(
$shareForm,
t(
'"%name" is not a recognized account at this site.',
[
'%name' => $name,
]));
// Insure the name field has the cleaned name.
// Since a validation error does not rebuild the form, updating the
// form's state does not work to insure the form is showing the cleaned
// name. Set it into the form directly.
$form[$shareForm][$addUserForm][$addUserFieldAndButton][$addUserField]['#value'] = $name;
$formState->setRebuild();
return;
}
//
// Validate user.
// --------------
// User's must be:
// - Not the owner.
// - Not the administrator.
// - Not blocked.
// - Have at least view permission on FolderShare content.
// - Not already on the grants list.
if ((int) $this->entity->getOwnerId() === $uid) {
// Owner.
if ((int) \Drupal::currentUser()->id() === $uid) {
// The current user is the owner. Tell them they don't have to be
// added to the list.
$formState->setErrorByName(
$shareForm,
t('As the owner, you always have access and do not need to be added to the list.'));
}
else {
// The current user is not the owner, but has permission to change
// sharing on the item. They are probably an administrator. Tell
// them they don't need to add the owner to the list.
$formState->setErrorByName(
$shareForm,
t(
'"%name" is the @kind owner, who always has access. They do not need to be added to the list.',
[
'%name' => $name,
'@kind' => FolderShare::translateKind($this->entity->getKind()),
]));
}
// Clear the name field.
// Since a validation error does not rebuild the form, updating the
// form's state does not work to insure the form name field is empty.
$form[$shareForm][$addUserForm][$addUserFieldAndButton][$addUserField]['#value'] = '';
$formState->setRebuild();
return;
}
if ($uid === 1) {
// Primary site admin.
$formState->setErrorByName(
$shareForm,
t(
'"%name" account is the site administrator, who always has access for administrative purposes. They cannot be added to the list.',
[
'%name' => $name,
]));
// Clear the name field.
// Since a validation error does not rebuild the form, updating the
// form's state does not work to insure the form name field is empty.
$form[$shareForm][$addUserForm][$addUserFieldAndButton][$addUserField]['#value'] = '';
$formState->setRebuild();
return;
}
$user = User::load($uid);
if ($user->isBlocked() === TRUE && $user->isAnonymous() === FALSE) {
// Blocked user that is not anonymous.
$formState->setErrorByName(
$shareForm,
t(
'The "%name" account is disabled and cannot be added to the list.',
[
'%name' => $name,
]));
// Clear the name field.
// Since a validation error does not rebuild the form, updating the
// form's state does not work to insure the form name field is empty.
$form[$shareForm][$addUserForm][$addUserFieldAndButton][$addUserField]['#value'] = '';
$formState->setRebuild();
return;
}
if (FolderShareAccessControlHandler::mayAccess('view', $user) === FALSE) {
// User without view permission.
if ($uid === 0) {
// Anonymous.
$formState->setErrorByName(
$shareForm,
t('Public visitors to the web site do not have permission to use files and folders. They cannot be added to the list.'));
}
else {
$formState->setErrorByName(
$shareForm,
t(
'"%name" does not have permission to use files and folders. They cannot be added to the list.',
[
'%name' => $name,
]));
}
// Clear the name field.
// Since a validation error does not rebuild the form, updating the
// form's state does not work to insure the form name field is empty.
$form[$shareForm][$addUserForm][$addUserFieldAndButton][$addUserField]['#value'] = '';
$formState->setRebuild();
return;
}
$grants = $formState->get('grants');
if (isset($grants[$uid]) === TRUE) {
// User already on list.
$formState->setErrorByName(
$shareForm,
t(
'"%name" is already on the list.',
[
'%name' => $name,
]));
// Clear the name field.
// Since a validation error does not rebuild the form, updating the
// form's state does not work to insure the form name field is empty.
$form[$shareForm][$addUserForm][$addUserFieldAndButton][$addUserField]['#value'] = '';
$formState->setRebuild();
return;
}
//
// Add user to pending grants.
// ---------------------------
// Add the user's ID to the list of pending grants. Default the user
// to no granted access.
$grants[$uid] = [];
$formState->set('grants', $grants);
$this->configuration['grants'] = $grants;
// Clear the current form's saved radio button state because the number
// of table rows in that state no longer matches the number or order of
// grants. If we don't reset the form's input, the wrong radio button
// values will be assigned to the newly ordered users and we get a mess.
$formInput[$addUserField] = '';
unset($formInput[$shareForm][$shareTable]);
$formState->setUserInput($formInput);
// Clear the name field.
// Since a validation error does not rebuild the form, updating the
// form's state does not work to insure the form name field is empty.
$form[$shareForm][$addUserForm][$addUserFieldAndButton][$addUserField]['#value'] = '';
$formState->setRebuild();
return;
}
//
// Finish.
// -------
// At this point, the grants have been updated to match the form. The
// user has clicked 'Save'. Validate everything to be sure.
try {
$this->validateParameters();
}
catch (\Exception $e) {
$formState->setErrorByName(
$shareTable,
$e->getMessage());
return;
}
}
/**
* {@inheritdoc}
*/
public function submitConfigurationForm(
array &$form,
FormStateInterface $formState) {
$this->configuration['grants'] = $formState->get('grants');
$this->execute();
}
/**
* Refreshes the configuration form after an AJAX request.
*
* @param array $form
* The configuration form.
* @param \Drupal\Core\Form\FormStateInterface $formState
* The form state.
*
* @return array
* Returns the share form portion of the form.
*/
public function refreshConfigurationForm(
array &$form,
FormStateInterface $formState) {
$shareForm = Constants::MODULE . '_share_form';
return $form[$shareForm];
}
/*--------------------------------------------------------------------
*
* Execute.
*
*--------------------------------------------------------------------*/
/**
* {@inheritdoc}
*/
public function execute() {
// Always a selection that is a root item.
$selectionIds = $this->getSelectionIds();
$item = FolderShare::load(reset($selectionIds));
try {
$item->share($this->configuration['grants']);
}
catch (\Exception $e) {
\Drupal::messenger()->addMessage($e->getMessage(), 'error');
}
// Flush the render cache because sharing may have changed what
// content is viewable throughout the folder tree under this root.
Cache::invalidateTags(['rendered']);
if (Settings::getCommandNormalCompletionReportEnable() === TRUE) {
\Drupal::messenger()->addMessage(
t("The shared access configuration has been updated."),
'status');
}
}
}
