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' ); } } } |