foldershare-8.x-1.2/src/Controller/UserAutocompleteController.php

src/Controller/UserAutocompleteController.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
<?php
 
namespace Drupal\foldershare\Controller;
 
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Controller\ControllerBase;
 
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
 
use Drupal\foldershare\Settings;
use Drupal\foldershare\Utilities\UserUtilities;
 
/**
 * Provides a user name autocomplete service.
 *
 * The user name autocomplete service is intended for use by forms that
 * require the user to type in a user or account name in order to
 * select a user. There are two primary forms that may use this:
 * - The change owner form that prompts for the account of the new owner
 *   of a selected item.
 * - The share form that prompts for the account of a user to be granted
 *   shared access to a file or folder.
 *
 * This autocomplete service is available on the route
 * "entity.foldershare.userautocomplete", defined in the module's routing file.
 *
 * Required URL arguments include:
 * - 'q=NAMEFRAGMENT' to provide a string to look up as part of a user's
 *   account name, display name, or email address.
 *
 * Optional URL arguments include:
 * - 'excludeUids=UIDLIST' to provide a comma-separated list of integer user IDs
 *   to NOT include in the returned autocomplete results. This may be used to
 *   exclude users in a 'Share' form that have already been granted access.
 * - 'excludeBlocked=1' to to prevent the returned list from including blocked
 *   users.
 *
 * The returned user list always excludes users with IDs in the 'excludeUids'
 * list, if any.
 *
 * The return list optionally excludes blocked users, if 'excludeBlocked' is 1.
 *
 * The returned user list is empty if:
 * - User autocomplete has been disabled for the module.
 * - The name fragment is empty.
 * - The name fragment does not match anything.
 *
 * The returned list is an array, formatted as JSON, sorted by user name.
 * Each entry is an array with 'value' and 'label' fields. The 'value' field
 * is the user account name, and the 'label' a label to show in an
 * autocomplete menu. Labels have one of these forms:
 * - Name only.
 * - Name with email address.
 * - Name with masked email address.
 *
 * The label style is determined by a module setting.
 *
 * The name is the account display name, and the email address the account's
 * email address (if any). When the masked form is used, the email address
 * is masked with '*'s for all name field characters, except the first and
 * last (e.g. "e*****e@example.com").
 *
 * @ingroup foldershare
 */
class UserAutocompleteController extends ControllerBase {
 
  /*---------------------------------------------------------------------
   *
   * Constants.
   *
   *---------------------------------------------------------------------*/
 
  /**
   * The default maximum number of results to return.
   *
   * @var int
   */
  const MAXIMUM_NUMBER_OF_RESULTS = 10;
 
  /*--------------------------------------------------------------------
   *
   * Fields - dependency injection.
   *
   *--------------------------------------------------------------------*/
 
  /**
   * The User entity storage manager, set at construction time.
   *
   * @var \Drupal\Core\Entity\EntityStorageInterface
   */
  protected $userStorage;
 
  /*--------------------------------------------------------------------
   *
   * Construction.
   *
   *--------------------------------------------------------------------*/
 
  /**
   * Constructs a new page.
   */
  public function __construct(
    EntityStorageInterface $userStorage) {
    $this->userStorage = $userStorage;
  }
 
  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('entity_type.manager')->getStorage('user'));
  }
 
  /*---------------------------------------------------------------------
   *
   * Autocomplete.
   *
   *---------------------------------------------------------------------*/
 
  /**
   * Responds to a text field's autocomplete request using a user name fragment.
   *
   * Auto-complete uses the given user name fragment to find all user names
   * that are similar to the name. If configured using the FolderShare admin
   * settings form, auto-complete may also look at email addresses to find
   * a good match.
   *
   * The returned list is intended for the 'Share' form to indicate users
   * with which to share content. There may already be users listed in the
   * form, and returning them in the auto-complete would be redundant. To
   * skip those users, an optional excludeUids list omits them from the returned
   * results.
   *
   * @param \Symfony\Component\HttpFoundation\Request $request
   *   The HTTP request, including two parameters:
   *   - 'q' has the text field input to auto-complete.
   *   - 'excludeUids' has a list of integer UIDs to exclude.
   *   - 'excludeBlocked' is 0 (FALSE) or 1 (TRUE) to indicate whether blocked
   *     user accounts should be excluded.
   *
   * @return \Symfony\Component\HttpFoundation\JsonResponse
   *   The JSON response that contains an array of autocomplete content. Each
   *   entry in the JSON array is for a user. Each user entry is itself an
   *   array with 'value' and 'label' string values. The label is intended to
   *   be shown in an autocomplete menu, and the value is the value for that
   *   label.
   */
  public function autocomplete(Request $request) {
    //
    // Get parameters.
    // ---------------
    // 'q' is the query input from the text field. It must not be empty.
    // 'excludeUids' is the optional list of user IDs to skip in the returned
    // results. It can be missing or empty.
    $userNameFragment = $request->get('q', NULL);
    $excludeUids      = $request->get('excludeUids', []);
    $excludeBlocked   = $request->get('excludeBlocked', FALSE);
 
    $excludeBlocked = boolval($excludeBlocked);
 
    if (empty($userNameFragment) === TRUE) {
      // No user name fragment given. Return an empty response.
      return new JsonResponse([]);
    }
 
    //
    // Get auto-complete style.
    // ------------------------
    // The following styles are recognized:
    // - 'none'.
    // - 'name-only'.
    // - 'name-email'.
    // - 'name-masked-email'.
    $autocompleteStyle = Settings::getUserAutocompleteStyle();
 
    if ($autocompleteStyle === 'none') {
      // Auto-complete disabled. Return an empty response.
      return new JsonResponse([]);
    }
 
    $matchEmail = FALSE;
    if ($autocompleteStyle === 'name-email' ||
        $autocompleteStyle === 'name-masked-email') {
      $matchEmail = TRUE;
    }
 
    //
    // Get a list of similar users.
    // ----------------------------
    // Match the given name fragment against user account names and user
    // display names, if possible. Optionally match against user email
    // addresses. Optionally exclude the given list of user IDs and
    // blocked users.
    $uids = UserUtilities::findSimilarUsers(
      $userNameFragment,
      $matchEmail,
      $excludeBlocked,
      $excludeUids,
      self::MAXIMUM_NUMBER_OF_RESULTS);
 
    if (empty($uids) === TRUE) {
      // No match.
      return new JsonResponse([]);
    }
 
    //
    // Build returned JSON.
    // --------------------
    // Loop through the returned UIDs. For each one, we need:
    // - the display name.
    // - the email address (for appropriate auto-complete styles).
    //
    // If needed, the email address must be masked.
    $results = [];
    foreach ($uids as $uid) {
      // Load the user.
      $user = $this->userStorage->load($uid);
      if ($user === NULL) {
        // Invalid user.
        continue;
      }
 
      // Get the user's display name. If there is no full name, this falls
      // back to the account name.
      $userDisplayName = $user->getDisplayName();
 
      // Get the user's email address, if needed. Mask it, if needed.
      if ($autocompleteStyle === 'name-email' ||
          $autocompleteStyle === 'name-masked-email') {
        $userEmail = $user->getEmail();
 
        if ($autocompleteStyle === 'name-masked-email' &&
            empty($userEmail) === FALSE) {
          $userEmail = $this->maskEmail($userEmail);
        }
 
        if (empty($userEmail) === TRUE) {
          // The account has no email address, or it is malformed.
          // Skip it.
          $label = $this->t(
            '@userDisplayName',
            [
              '@userDisplayName' => $userDisplayName,
            ]);
        }
        else {
          $label = $this->t(
            '@userDisplayName (@userEmail)',
            [
              '@userDisplayName' => $userDisplayName,
              '@userEmail'       => $userEmail,
            ]);
        }
      }
      else {
        $label = $this->t(
          '@userDisplayName',
          [
            '@userDisplayName' => $userDisplayName,
          ]);
      }
 
      $results[] = [
        'value' => $user->getAccountName(),
        'label' => $label,
      ];
 
      unset($user);
    }
 
    return new JsonResponse($results);
  }
 
  /**
   * Returns a masked version of a given email address.
   *
   * Masking keeps the first and last characters of the name portion of
   * the email address, and all of the rest of the email address. The
   * intervening letters are replaced with '*'.
   *
   * @param string $email
   *   The email address to mask.
   *
   * @return string
   *   Returns the masked email address.
   */
  private function maskEmail(string $email) {
    if (empty($email) === TRUE) {
      // Missing email address.
      return '';
    }
 
    // Email addresses are UTF-8 strings that may include non-ASCII characters
    // in both the name and domain parts of the address. Proper string handling
    // then requires that we use the PHP mb_* functions for multi-byte strings.
    //
    // Split the address into name and domain parts.
    $parts = mb_split('@', $email);
    if (count($parts) !== 2) {
      // Malformed email address either has no '@' or too many.
      // Masking is not defined in this case, so return nothing.
      return '';
    }
 
    // Create a masked name with the original first and last characters,
    // and the rest replaced with '*'.
    $masked = mb_substr($email, 0, 1);
    $len = mb_strlen($parts[0]) - 2;
    for ($i = 0; $i < $len; $i++) {
      $masked .= '*';
    }
    $masked .= mb_substr($email, $len + 1, 1);
 
    return $masked . '@' . $parts[1];
  }
 
}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc