2

I'm trying to POST an email address to the password_reset Services endpoint so that it generates and sends a password reset email for a user. When I post the uid to the endpoint, it does this successfully. That said, I want to post the user's email to the endpoint (e.g. they type in their email to retrieve their password recovery email). How can I change the below in order to allow this? I tried changing user_load($uid) to user_load_by_mail($uid), but this didn't work.

Endpoint format:

mydomain.com/myendpoint/user/[email protected]/password_reset_email

user_resource.inc

  $definition = array(
  'user' => array(
  'operations' => array(
  'actions' => array( 
    'help' => 'Send forgot password email',
    'callback' => '_user_resource_password_reset_email',
    'access callback' => 'services_access_menu',
    'args' => array(
      array(
        'name' => 'email',
        'optional' => FALSE,
          'source' => array('data' => 'email'),
        'type' => 'string',
        'description' => 'The email address of the user whose password should be reset.',
      ),
      ),
    ),
    ),
    ),
  ),

       function _user_resource_password_reset_email($data) {
  global $language;


  $mail = _services_arg_value($data, 'data');
  $account = user_load_by_mail($mail);

  if (empty($account)) {
    return services_error(t('There is no user with email @email.', array('@email' => $mail)), 404);
  }

  // Mail one time login URL and instructions using current language.
  $mail = _user_mail_notify('password_reset_email', $account, $language);
  if (!empty($mail)) {
    watchdog('user', 'Password reset instructions mailed to %name at %email.', array('%name' => $account->name, '%email' => $account->mail));
  }
  else {
    watchdog('user', 'There was an error re-sending password reset instructions mailed to %name at %email', array('%name' => $account->name, '%email' => $account->mail));
}

  $result = "success";
  return $result;
}

Obj-C

ViewController.m

- (IBAction)sendButton:(id)sender {

[DIOSUser userSendPasswordRecoveryEmailWithEmailAddress:self.forgotField.text
                                                            success:^(AFHTTPRequestOperation *operation, id responseObject) {

                                                                NSLog(@"Password being sent!");

                                                                UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Retrieving Password"
                                                                                                                message:@"We're helping you retrieve your password! Please check your email in a few minutes for a rescue link."
                                                                                                               delegate:self
                                                                                                      cancelButtonTitle:@"OK"
                                                                                                      otherButtonTitles:nil];
    [alert show];


      }failure:^( AFHTTPRequestOperation *operation , NSError *error ){

      if(!error){

     }
      }];


        }

DIOSUser.m

 + (void)userSendPasswordRecoveryEmailWithEmailAddress: (NSString*)email
                                              success:(void (^)(AFHTTPRequestOperation *operation, id responseObject)) success
                                              failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error)) failure {

   NSString *path = [NSString stringWithFormat:@"user/%@/request_new_password", email];

    [[DIOSSession sharedSession] sendRequestWithPath:path method:@"POST" params:nil success:success failure:failure];
}

3 Answers 3

1

It would be better if this was externalised into a custom module instead of 'hacking' the services module.

This is fine on my system

$definition = array(
  'user' => array(
    'operations' => array(
       ...
       'actions' => array( 
          ...
         'password_reset_email' => array(
         'access callback' => 'services_access_menu',
         'callback' => '_user_resource_password_reset_email',
         'args' => array(
          array(
                'name' => 'email',
                'optional' => FALSE,
                'source' => array('data' => 'email'),
                'type' => 'string',
                'description' => 'The email of the user whose password to reset.',
        ),
    ),

Function is

function _user_resource_password_reset_email($data) {
  global $language;


  $mail = _services_arg_value($data, 'data');
  $account = user_load_by_mail($mail);

  if (empty($account)) {
    return services_error(t('There is no user with email @email.', array('@email' => $mail)), 404);
  }

  // Mail one time login URL and instructions using current language.
  $mail = _user_mail_notify('password_reset', $account, $language);
  if (!empty($mail)) {
    watchdog('user', 'Password reset instructions mailed to %name at %email.', array('%name' => $account->name, '%email' => $account->mail));
  }
  else {
    watchdog('user', 'There was an error re-sending password reset instructions mailed to %name at %email', array('%name' => $account->name, '%email' => $account->mail));
}

  $result = "success";
  return $result;
}
6
  • Implemented the above, and I receive this error: ----- Error ----- Request failed: not found (404)
    – Brittany
    Mar 31, 2017 at 5:51
  • My obvious thought is that caches need to be reset. The menu needs to be rebuilt. It is in the 'actions' array underneath user_pass_reset & request_new_password?
    – Interlated
    Mar 31, 2017 at 6:29
  • Are you talking about this (it was located underneath of user_pass_reset &? If so, can you let me know what should be changed? Caches were cleared! If this is not the array you're talking about, can you show me an example of how it should look (sorry, newb where this is concerned!) $definition['user']['actions']['register'] = array_merge($definition['user']['operations']['create'], array( 'help' => 'Register a user', )); return $definition; }
    – Brittany
    Mar 31, 2017 at 6:36
  • No -merge it into $definition['user']['actions']
    – Interlated
    Mar 31, 2017 at 6:59
  • I'm confused - can you merge that into your above answer? E.g. not sure where exactly you're referring to?
    – Brittany
    Mar 31, 2017 at 7:06
1

I Think this is existing in the services module, As per the below question and provided answer, you only need to send to the correct resource "?q=rest/user/request_new_password.json"

Below answer is copied

This feature was added with the resolution of this issue:

https://www.drupal.org/node/1303400 To use this resource, make a POST to:

?q=rest/user/request_new_password.json ...and send along a name

name=john ...or e-mail address:

[email protected]

You can see the original question and answer here:

Requesting a new password via services

I tested it with HTTPRequester Plugin with below JSON sample and it worked by posting to q=rest-mobile/user/request_new_password

But do not forget to activate this resource as in below screen shot

enter image description here

And this is a shot of how it is sent as JSON request

{"name":"user1"} or {"name":"[email protected]"}

enter image description here

11
  • I'm 99.9% sure that you're right - but how should the URL look when I'm posting to the endpoint? E.g. should it be www.mydomain.com/endpoint/user/request_new_password.json/[email protected]/ ? When I do it this way now, I get a "Not Found 404" error returned.
    – Brittany
    Apr 3, 2017 at 23:55
  • The username or email should be passed as part of the json encoded body to this url "q=rest-mobile/user/request_new_password" and not as part of the url itself
    – Sherif
    Apr 4, 2017 at 6:55
  • You can also get the exact url for this resource by going to services definition in drupal (admin/structure/services/list/rest/definition) and this will show you the correct URL at your side and the parameters to pass, I will also update the question with screen shot from my HTTPRequester
    – Sherif
    Apr 4, 2017 at 7:02
  • I am posting the email as apart of the JSON, but for some reason when I post to the end point request_new_password, I'm still getting the 404 not found error (and yes, I remembered to enable the endpoint in Services). I'm so stumped. That said, by the looks of your code above, I should be posting to ?q=endpoint/user/request_new_password, and not replacing "user" with the email address? I'll try it out... Stand by and pray for me ha ha ha ha!
    – Brittany
    Apr 5, 2017 at 2:21
  • In some scenarios, you may find that your URL is different for the same service, so i advice to ensure the correct URL in the service definition section which will show you the exact url to post to in addition to the parameters and their description, you can check it here : admin/structure/services/list/<your service name>/definition
    – Sherif
    Apr 5, 2017 at 7:20
0

Drupal 7

Since you have tagged 7 I presume you are working on Drupal 7. I remember having done something like this last year. If you are using hook_services_request_preprocess_alter() to alter the incoming parameters for your password reset request. You can use the hook to implement the following logic:

  • Check if it is a password reset request;
  • If it is a password reset request, then see if an email address has been passed as an argument. You can do this by checking if the argument is a number or if it is a string resembling an email with an @ sign, etc.
  • If the argument is an email, then read the relevant user ID from the database and replace the argument with the user ID.

This should be a clean solution. I had done it this way for a project last year. Unfortunately, I do not have the code. Hope this algo helps.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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