Drupal Answers is a question and answer site for Drupal developers and administrators. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

As a courtesy to registered users on my website, I require all users who send private messages to have a profile picture.

I already have system messages throughout the site to encourage them to upload such a picture (for example, when they log in, or visit a user's profile) with a link to their account edit page where they can upload such a picture.

But how do I block them (without banning them of course) from sending a private message if they do not have a picture (in other words BEFORE the message is sent?)

Fall back scenario: If I cannot stop the action before it happens, how do I prevent the message from being delivered, with the appropriate warning to the sender of course?

The message is sent by the Privatemsg module, not the Rules module.

Any idea?


UPDATE

I have tried both solutions proposed below (jeroen and Pierre Vriens) and both did the job.

Pierre's solution below works well and is easiest to implement.

For those who need guidance in implementing it, here are the steps:

1 - Create a new role. I called mine "can send private messages"

2 - Give this new role the "send privatemsg permission" only. Remove the same permission from the authenticated user permission (and other roles that have it and shouldn't.) At this stage, only those users who have the new role will be able to send private messages. The others will be sent to a "you do not have permission to access..." page.

3 - Create the first rule: Give it a name and select, under User, "an account is created." Save it. Create a second event and, still under User, select when an "account is updated." You now have two events in the same rule.

4 - Create the condition: Select "Data value is empty." Then drill down and select the name of the field that should contain the main picture (in my case, it is "site:current-user:field-user-image".) Below that, check the Negate box. This means the rule will check if the field is NOT empty.

5 - Create the action: You want the role to be granted if the field is not empty. So select "Add user role" under User. Data selector is "account" and select the value of the role (it's the name you gave to the new role.)

And that's it. To make the user lose the role if he removes the picture, you need to create a new rule, albeit a little less complicated. I called mine "disable private messages send." It only has one event: "After updating an existing user account" The condition is, again, "Data value is empty" but DO NOT check the Negate box. For the action, it's pretty straightforward. Like for the first rule but select the remove role instead.

For this rule to work the user must go into his account and click the save button. This is ok with new accounts but it may be a drawback if your site already has many users. But eventually, they will all update their account one way or another and the rules will be implemented then. If only a few users, the administrator (user #1) can go into their accounts and click on the new role box to grant the role.

See my second update below.

Again, thank you to Pierre for his insightful approach.

share|improve this question
    
It's a good question and I have thought about it. The reason I have not given you the "accepted" checkmark is because, like I say in my comment below your post, your solution does not allow for the posting of a system message when the user tries to send a message. So he may wonder why he can't send a private message. Although I find your approach very insightful, and the best for those who have no knowledge of php, @Jeroven proposed solution is the one I have adopted for now because it allows the posting of a message. It's not your fault, (continued on next comment.) – user14666 Feb 6 at 21:34
    
but an error message generally is possible after an event has happened. Like you said yourself, your solution prevents an event from happening. So, the system cannot know ahead of time if the user is going to attempt sending a message or not. However, I am still working on this issue and if I find the solution to get a system error or warning message posted on the .../messages/new" page I'd gladly review the rating. – user14666 Feb 6 at 21:34
up vote 4 down vote accepted

Have a look at the community documentation about Privatemsg-Rules Integration, especially the child page about Introduction to Privatemsg-Rules: it lists the various Rules Events, Conditions and Actions you have available. I don't think there is anything in it you can take advantage of to do what you are asking for, and it won't help to implement your fall back scenario either.

But, as an alternative to "trying to solve a problem", you could use an approach to "prevent the problem from happening" ... here is what, pretty sure, should work:

  1. Create a role like "PrivateMsgOk" (call it whatever you want).
  2. Only grant access to private messages for role "PrivateMsgOk".
  3. Use Rules to automatically assign role "PrivateMsgOk" after they uploaded their picture (and remove it again if they somehow can "remove" that picture afterwards).

The disadvantage of the above approach is that it does not permit the posting of a system message to notify (inform) the users (that are not allowed) to explain why such users cannot send a message. However here is a variation (enhanced version) of it in which you can make that work:

  1. Create a role like "PictureUploadOk" (call it whatever you want).
  2. DO NOT limit access to private messages to only those who have role "PictureUploadOk". Instead give that access to anybody you'd want to be able to "see" the private message functionality. But for those where their profile picture is missing they, they'll be interrupted when they try to send a private message, as explained below.
  3. Create a 1st rule (using the Rules module) to automatically assign role "PictureUploadOk" after they uploaded their picture (and remove it again if they somehow can "remove" that picture afterwards).
  4. Create a 2nd rule (using the Rules module) which is a variation of the rule included in my answer to "How to specify a Rules condition like 'Before creating new content'?". Here are the details of this 2nd rule:

    • Use (System) Rules Event "Drupal is initializing".
    • Use a 1st Rules Condition like "Does NOT have the role 'PictureUploadOk'".
    • Use a 2nd Rules Condition that must also be true (so combined with the 1st Rules condition via an "AND") and which is like either of the text_matches that corresponds to an url like (say) /messages/new (assuming that's the URL to send a private message).
    • Within the Rules Action set your "system message to notify (inform) the users (that are not allowed) to explain why such users cannot send a message". Make sure to make it of type "Error" (not just "warning").
share|improve this answer
    
The only problem I have with this approach is that the Rules/Privatemsg combination does not permit the posting of a system message.notifying the user why he can't send a message.. – user14666 Feb 6 at 15:23
1  
You could use Rules Conditional module. Then add action of Diplay system message. – No Sssweat Feb 8 at 10:36
1  
@NoSssweat : you're absolutely right, that's exactly what I had in mind also when posting my last comment below the question. But I haven't had time "yet" to first QA-test my upcoming answer enhancement (which I do quite often for such kind of "yes you can" answers). But guess what: I also found a 2nd alternative (I think) which will still use/require Rules, but no extra module ... Did I make y'all curious enough now? Hang on a bit please to my upcoming answer enhancement ... – Pierre.Vriens Feb 8 at 10:42
    
OK, I think I found the easiest way to get it to work with such "system message" also (which only uses the Rules module, no need for Rules Conditional). – Pierre.Vriens Feb 14 at 20:22

I don't think you can use the Rules module directly for this, because the only action that is provided by Privatemsg is called when a message has been sent. Therefore, I suggest you write an easy piece of code.

When a user hasn't set a profile picture yet, the field is empty or displays the default picture if you picked one in your configuration. In both cases, $user->picture has value 0. You could use this fact by hiding the sending form for a private message with the following code in a custom module:

function MYMODULE_form_privatemsg_new_alter(&$form, &$form_state, $form_id) {
  global $user;
  if ($user->picture==0) {
    hide($form);
  }
}

As suggested in the comment below, you can also use $form['#access'] = FALSE; instead of hide($form);. You can add a line of code that, for example, displays a message Please add a profile picture! or whatever you want in the if statement.

share|improve this answer
1  
I like @Jeroen's general approach, although there are security issues with using hide() (see api.drupal.org/api/drupal/includes%21common.inc/function/hide/7). But you can get the same effect w/o the security issue by replacing hide($form); with $form['#access'] = FALSE;. The difference is that something will end up in the HTML of the web page with hide(), but the '#access' solution won't render any HTML at all. – Torenware Networks Feb 5 at 0:02

Ok. Thanks again to Pierre.Viriens who provided the perfect answer. I wasn't too familiar with the "Drupal is initializing" event but it did the trick and the link he provided How to specify a Rules condition before creating new content was very helpful. Of course, I had to play with it and adapt it to my own circumstances to make it work. For those who are interested, I am reproducing the export of the final rule below:

{ "rules_private_messages_send_authorization_check" : {
    "LABEL" : "Private messages send authorization check",
    "PLUGIN" : "reaction rule",
    "OWNER" : "rules",
    "REQUIRES" : [ "rules" ],
    "ON" : { "init" : [] },
    "IF" : [
      { "text_matches" : { "text" : [ "site:current-page:url" ], "match" : "messages\/new" } },
      { "AND" : [] },
      { "data_is_empty" : { "data" : [ "site:current-user:field-user-image" ] } },
      { "AND" : [] },
      { "NOT data_is" : {
          "data" : [ "site:current-user:roles" ],
          "value" : { "value" : { "9" : "9" } }
        }
      }
    ],
    "DO" : [ { "redirect" : { "url" : "message\/new" } } ]
  }
}

Note the two similar paths. The first one ("messages/new") is the Privatemsg module path for accessing the new message page (notice "messages" is plural.) The second "message/new" (singular) is the path of the node (article or page) I created. It is on this node that I can enter any message I want (and even include pictures and graphics too.)

If a user who does NOT have a profile picture tries to beat the system and adds an "s" to make the path read "messages/new" on the URL address bar he is redirected to a "You are not authorized to access...." default error page.

The value of "9" in the rule is assigned by the Rules module and corresponds to the name of new role I created for users who do not have a profile picture (see UPDATE above.)

All of this results in the user being sent to the module's "messages/new" page where he can send a message if he has a profile image or to the "message/new" page if he doesn't. Once there, he can't send a message and is informed why this is so.

I have thoroughly tested this rule and it operates flawlessly. The three conditions are necessary in my case.

Thanks you @Pierre.Viriens.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.