Projet

Général

Profil

Paste
Télécharger (14 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / privatemsg / pm_block_user / pm_block_user.module @ 13755f8d

1
<?php
2

    
3
/**
4
 * @file
5
 * Allows users to block other users from sending them any messages
6
 */
7

    
8
/**
9
 * Disallow blocking private messages from a user.
10
 */
11
define('PM_BLOCK_USER_DISALLOW_BLOCKING', 0);
12

    
13
/**
14
 * Disallow sending private messages to a user.
15
 */
16
define('PM_BLOCK_USER_DISALLOW_SENDING', 1);
17

    
18
/**
19
 * Implements hook_help().
20
 */
21
function pm_block_user_help($path) {
22
  switch ($path) {
23
    case 'admin/settings/messages/block':
24
      return '<p>' . t('This area is used to define user blocking rules for the Privatemsg module. Rules allow control of who may block messages from whom. By default all users are allowed to block messages from anyone else. However, a site may have groups of users that need to contact or get information to others, for example: the site may have administrative staff or be a forum with moderators. Groups of users are defined by roles, which can be managed on the <a href="@roles">roles configuration page</a>.', array('@roles' => url('admin/user/roles'))) . '</p>';
25
  }
26
}
27

    
28
/**
29
 * Implements hook_menu().
30
 */
31
function pm_block_user_menu() {
32
  $items['messages/block/%user'] = array(
33
    'title'            => 'Block user messages',
34
    'page callback'    => 'drupal_get_form',
35
    'page arguments'   => array('pm_block_user_form', 2),
36
    'file'             => 'pm_block_user.pages.inc',
37
    'access callback'  => '_pm_block_user_access',
38
    'access arguments' => array(2),
39
    'type'             => MENU_CALLBACK,
40
    'weight'           => -10,
41
  );
42

    
43
  $items['messages/blocked'] = array(
44
    'title'            => 'Blocked users',
45
    'page callback'    => 'drupal_get_form',
46
    'page arguments'    => array('pm_block_user_list'),
47
    'file'             => 'pm_block_user.pages.inc',
48
    'access callback'  => 'privatemsg_user_access',
49
    'access arguments' => array('read privatemsg'),
50
    'type'             => MENU_LOCAL_TASK,
51
    'weight'           => 10,
52
  );
53

    
54
  $items['admin/config/messaging/privatemsg/block'] = array(
55
    'title'            => 'User blocking rules',
56
    'description'      => 'Configure rules for which users may block each other.',
57
    'page callback'    => 'drupal_get_form',
58
    'page arguments'   => array('pm_block_user_settings'),
59
    'file'             => 'pm_block_user.admin.inc',
60
    'access arguments' => array('administer privatemsg settings'),
61
    'type'             => MENU_LOCAL_TASK,
62
  );
63
  
64
  $items['messages/block/js'] = array(
65
    'title'            => 'Javascript block actions form',
66
    'page callback'    => 'pm_block_user_js',
67
    'file'             => 'pm_block_user.admin.inc',
68
    'access arguments' => array('administer privatemsg settings'),
69
    'type'             => MENU_CALLBACK,
70
  );
71

    
72
  $items['messages/user/autocomplete'] = array(
73
    'page callback'    => 'privatemsg_autocomplete',
74
    'file'             => 'privatemsg.pages.inc',
75
    'file path'        => drupal_get_path('module', 'privatemsg'),
76
    'access callback'  => 'privatemsg_user_access',
77
    'access arguments' => array('write privatemsg'),
78
    'type'             => MENU_CALLBACK,
79
  );
80

    
81
  return $items;
82
}
83

    
84
/**
85
 * Implements hook_theme().
86
 */
87
function pm_block_user_theme() {
88
  return array(
89
    'pm_block_user_list' => array(
90
      'render element' => 'form',
91
      'file'      => 'pm_block_user.pages.inc',
92
    ),
93
    'pm_block_user_actions' => array(
94
      'render element' => 'form',
95
      'file'      => 'pm_block_user.admin.inc',
96
    ),
97
  );
98
}
99

    
100
function pm_block_user_privatemsg_autocomplete_alter(&$matches, $names, $fragment) {
101
  // Remove all types other than user if accessed through
102
  // messages/user/autocomplete.
103
  if (arg(1) == 'user') {
104
    foreach ($matches as $id => $match) {
105
      if ($match->type != 'user') {
106
        unset($matches[$id]);
107
      }
108
    }
109
  }
110
}
111

    
112
/**
113
 * Theme the user actions form.
114
 *
115
 * @ingroup themeable
116
 */
117
function theme_pm_block_user_actions($form) {
118
  // @todo: Something is wrong, remove this hack.
119
  $form = $form['form'];
120

    
121
  $rows = array();
122
  $headers = array(
123
    t('If the author has the role'),
124
    t('And the recipient has the role'),
125
    t('Action'),
126
    t('Enabled'),
127
    '',
128
  );
129
  $form_data = element_children($form);
130

    
131
  foreach ($form_data as $key) {
132
    // Build the table row.
133
    $row = array(
134
      'data' => array(
135
        array('data' => drupal_render($form[$key]['author'])),
136
        array('data' => drupal_render($form[$key]['recipient'])),
137
        array('data' => drupal_render($form[$key]['action'])),
138
        array('data' => drupal_render($form[$key]['enabled'])),
139
        array('data' => drupal_render($form[$key]['remove'])),
140
      ),
141
    );
142

    
143
    // Add additional attributes to the row, such as a class for this row.
144
    if (isset($form[$key]['#attributes'])) {
145
      $row = array_merge($row, $form[$key]['#attributes']);
146
    }
147
    $rows[] = $row;
148
  }
149

    
150
  // If there are no rows, output some instructions for the user.
151
  if (empty($form_data)) {
152
    $rows[] = array(
153
      array(
154
        'data' => t("No rules have been added. All users may block private messages from each other. To limit which users may be blocked, click 'Add new rule'."),
155
        'colspan' => '5',
156
      ),
157
    );
158
  }
159

    
160
  $output = theme('table', array(
161
    'header' => $headers,
162
    'rows' => $rows
163
  ));
164
  $output .= drupal_render_children($form);
165

    
166
  return $output;
167
}
168

    
169
/**
170
 * Provides access argument for blocking user menu item.
171
 *
172
 * @param $account
173
 *   User object representing the account the menu item will block private
174
 *   messages from.
175
 *
176
 * @return
177
 *   TRUE if the user is allowed to block $account, or FALSE if not.
178
 */
179
function _pm_block_user_access($account) {
180
  global $user;
181
  if (!privatemsg_user_access('read privatemsg', $user)) {
182
    return FALSE;
183
  }
184
  // Allow to unblock users that are already blocked but the user is now not
185
  // allowed to block anymore.
186
  if (_pm_block_user_rule_exists($account, $user, PM_BLOCK_USER_DISALLOW_BLOCKING) && !pm_block_user_has_blocked($account, $user)) {
187
    return FALSE;
188
  }
189
  return TRUE;
190
}
191

    
192
/**
193
 * Checks if author is blocked by the recipient.
194
 *
195
 * @param $author
196
 *   The user that would send a message.
197
 * @param $recipient
198
 *   The user that would receive the message.
199
 * @return
200
 *   TRUE if the recipient has blocked the author.
201
 */
202
function pm_block_user_has_blocked($author, $recipient) {
203
  return db_query('SELECT 1 FROM {pm_block_user} WHERE author = :author AND recipient = :recipient', array(':author' => $author->uid, ':recipient' => $recipient->uid))->fetchField();
204
}
205

    
206
/**
207
 * Checks whether a rule exists for a given author, recipient and action.
208
 *
209
 * For example: if this is passed User A (who has the admin role), User B (who
210
 * has the authenticated user role) and PM_BLOCK_USER_DISALLOW_BLOCKING
211
 * parameters, and a rule is configured that disallows authenticated users
212
 * blocking admins then this function will return TRUE.
213
 *
214
 * @param $author
215
 *   Author user object to check.
216
 * @param $recipient
217
 *   Receiver user object to check.
218
 * @param $action
219
 *   The action to be taken, defaults to PM_BLOCK_USER_DISALLOW_BLOCKING.
220
 *
221
 * @return
222
 *   TRUE if a rule exists for the combination of author recipient and action.
223
 */
224
function _pm_block_user_rule_exists($author, $recipient, $action = PM_BLOCK_USER_DISALLOW_BLOCKING) {
225
  $block_actions = variable_get('pm_block_user_actions', array());
226
  foreach ($block_actions as $details) {
227
    // If this rule doesn't relate to $action, or it's disabled
228
    // ignore it and go to next loop iteration.
229
    if ($details['action'] != $action || !$details['enabled']) {
230
      continue;
231
    }
232
    // There are no rules governing user one, but user one may have roles that
233
    // affect other users, so these exceptions are narrow in scope.
234
    // Disallow sending affects private message authors.
235
    if ($author->uid == 1 && $action == PM_BLOCK_USER_DISALLOW_SENDING) {
236
      continue;
237
    }
238
    // Disallow blocking affects private message recipients.
239
    if ($recipient->uid == 1 && $action == PM_BLOCK_USER_DISALLOW_BLOCKING) {
240
      continue;
241
    }
242
    // The author has a role matching the rule and so does the recipient.
243
    if (isset($author->roles[$details['author']]) && isset($recipient->roles[$details['recipient']])) {
244
      return TRUE;
245
    }
246
  }
247
  return FALSE;
248
}
249

    
250
/**
251
 * Implements hook_privatemsg_block_message.
252
 */
253
function pm_block_user_privatemsg_block_message($author, $recipients, $context = array()) {
254
  $blocked = array();
255
  // Loop through each recipient and ensure there is no rule blocking this
256
  // author from sending them private messages. Use a reference, so when
257
  // privatemsg_user_load_multiple() is needed here the array is updated, to
258
  // avoid additional checks.
259
  foreach (array_keys($recipients) as $id) {
260
    // Only recipients of type user are currently supported.
261
    if (isset($recipients[$id]->type) && $recipients[$id]->type != 'user') {
262
      continue;
263
    }
264
    // Ensure we have a recipient user object which includes roles.
265
    if (!isset($recipients[$id]->roles)) {
266
      $uid = str_replace('user_', '', $id);
267
      $recipients[$id] = array_shift(privatemsg_user_load_multiple($uid));
268
    }
269
    // Note: this is checks whether the author may send the message (see third
270
    // parameter). Further below is a check whether the recipient may block it.
271
    if (_pm_block_user_rule_exists($author, $recipients[$id], PM_BLOCK_USER_DISALLOW_SENDING)) {
272
      $blocked[] = array(
273
        'recipient' => $id,
274
        'message' => t('You are not permitted to send messages to !user.', array('!user' => privatemsg_recipient_format($recipients[$id]))),
275
      );
276
    }
277
  }
278

    
279
  // Only user recipients are supported for now, remove others.
280
  $user_recipients = array();
281
  foreach ($recipients as $recipient) {
282
    if (empty($recipient->type)) {
283
      $recipient->type = 'user';
284
      $recipient->recipient = $recipient->uid;
285
    }
286
    if ($recipient->type == 'user') {
287
      $user_recipients[$recipient->recipient] = $recipient;
288
    }
289
  }
290

    
291
  if (empty($user_recipients)) {
292
    return $blocked;
293
  }
294

    
295
  $args = array(
296
    ':author' => $author->uid,
297
    ':recipients' => array_keys($user_recipients)
298
  );
299
  $result = db_query('SELECT recipient FROM {pm_block_user} WHERE author = :author AND recipient IN (:recipients) GROUP BY recipient', $args);
300
  foreach ($result as $row) {
301
    $recipient = $user_recipients[$row->recipient];
302
    // If there's a rule disallowing blocking of this message, send it anyway.
303
    if (_pm_block_user_rule_exists($author, $recipient, PM_BLOCK_USER_DISALLOW_BLOCKING)) {
304
      continue;
305
    }
306
    $blocked[] = array(
307
      'recipient' => privatemsg_recipient_key($recipient),
308
      'message' => t('%name has chosen to block messages from you.', array('%name' => privatemsg_recipient_format($recipient, array('plain' => TRUE))))
309
    );
310
  }
311
  return $blocked;
312
}
313

    
314
function pm_block_user_query_privatemsg_message_load_multiple_alter($query) {
315
  $query->addField('pmbu', 'recipient', 'is_blocked');
316
  $query->leftJoin('pm_block_user', 'pmbu', "base.author = pmbu.author AND pmi.recipient = pmbu.recipient AND pmi.type IN ('user', 'hidden')");
317
}
318

    
319
/**
320
 * Implements hook_privatemsg_message_view_alter.
321
 */
322
function pm_block_user_privatemsg_message_view_alter(&$vars) {
323
  global $user;
324

    
325
  // @todo: weird, figure out why it is below #message.
326
  $author = $vars['message']->author;
327
  if (_pm_block_user_rule_exists($author, $user, PM_BLOCK_USER_DISALLOW_BLOCKING)) {
328
    return;
329
  }
330
  if (!isset($vars['message']->thread_id)) {
331
    // No thread id, this is probably only a preview
332
    return;
333
  }
334
  $thread_id = $vars['message']->thread_id;
335

    
336
  if ($user->uid <> $author->uid) {
337
    if ($vars['message']->is_blocked) {
338
      $vars['message_actions']['unblock_author'] = array('title' => t('Unblock'), 'href' => 'messages/block/' . $author->uid, 'query' => array('destination' => 'messages/view/' . $thread_id));
339
    }
340
    else {
341
      $vars['message_actions']['block_author'] = array('title' => t('Block'), 'href' => 'messages/block/' . $author->uid, 'query' => array('destination' => 'messages/view/' . $thread_id));
342
    }
343
  }
344
}
345

    
346
/**
347
 * Implements hook_user_cancel().
348
 */
349
function pm_block_user_user_cancel($edit, $account, $method) {
350
  // Always delete, we don't need to keepy anonymous blocking rules.
351
  db_delete('pm_block_user')
352
    ->condition(db_or()
353
      ->condition('author', $account->uid)
354
      ->condition('recipient', $account->uid)
355
    )
356
    ->execute();
357
}
358

    
359
/**
360
 * Implements hook_query_TAG_alter().
361
 *
362
 * Remove blocked users.
363
 */
364
function pm_block_user_query_privatemsg_autocomplete_alter($query) {
365
  global $user;
366

    
367
  // Assume the users don't have blocked more than a few dozen other users
368
  // but there can be hundreds of thousands of users and make the subquery
369
  // unrelated.
370

    
371
  // Create a subquery that gets all users which have blocked the current user.
372
  $blocked = db_select('pm_block_user', 'pmbu')
373
    ->fields('pmbu', array('recipient'))
374
    ->condition('pmbu.author', $user->uid);
375

    
376
  // Exclude these from the possible recipients.
377
  $query->condition('u.uid', $blocked, 'NOT IN');
378

    
379
  // Block role configurations.
380
  if ($user->uid != 1) {
381
    $rids = array();
382
    $block_actions = variable_get('pm_block_user_actions', array());
383
    foreach ($block_actions as $details) {
384
      // Only continue if the rule is enabled and is a disallow sending rule.
385
      if ($details['action'] != PM_BLOCK_USER_DISALLOW_SENDING || !$details['enabled']) {
386
        continue;
387
      }
388
      // The author (current user) does have a matching role.
389
      if (isset($user->roles[$details['author']])) {
390
        // authenticated user role is not stored in the database but all users
391
        // have it so there can be no valid recipients. Add a condition that is
392
        // always false and bail out because no other rules need to be checked.
393
        if ($details['recipient'] == DRUPAL_AUTHENTICATED_RID) {
394
          $query->addExpression('1 = 0');
395
          return;
396
        }
397
        // Keep role id, will be added to the query later on.
398
        $rids[] = $details['recipient'];;
399
      }
400
    }
401
    // If there are any, add role limitation to the query.
402
    if (!empty($rids)) {
403
      $join_alias = $query->leftJoin('users_roles', 'ur', 'u.uid = ur.uid');
404
      $query->condition(db_or()
405
        ->condition($join_alias . '.rid', $rids, 'NOT IN')
406
        ->isNull($join_alias . '.rid')
407
      );
408
    }
409
  }
410
}