Hi LoginToboggan,

This is in regards to: http://drupal.org/node/1431696

Basically, the Services module has a User Login resource that allows a user to login with a user name and password. The LoginToboggan module of course lets a user login with an e-mail address and password.

It would be great if this was also possible with the Services module through LoginToboggan with an implementation of a new resource through the Services API.

I am familiar with creating resources using the Services API and would be happy to implement this extension for LoginTobboggan. Please let me know if this is something you are interested in, thanks!

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Jon Pugh’s picture

So, you already have a patch for this? We need the same thing, would you mind posting it?

tyler.frankenstein’s picture

I have the patch for the user_resource.inc, but I'll hold off on posting it. I am waiting for the OK to make an actual Service Resource for this though.

In the mean time, just place this line of code in the _user_resource_login function (D6), just before the call to user_authenticate(...):

if (valid_email_address($username)) { $username = db_result(db_query(" SELECT name FROM {users} WHERE mail = '%s' ",$username)); }

This allows the user login service resource to be used in the exact same way, just pass an e-mail address in place of the user name.

For example, do a POST to http://localhost/my_drupal_site/my_services_endpoint/user/login.json with the following args:

username=foo@foo.com&password=TacoTuesday

The D7 version should be very similar, it would just require a few tweaks for the new database API calls in D7.

stevecowie’s picture

I'm not too familiar with the services module. Can you explain a bit more about the use case so I can think about it. It's unlikely to be honest, as we only undertake to keep LT operational with nothing installed other than core so don't want to create dependencies.

tyler.frankenstein’s picture

Basically the Services module can create and expose a RESTful server on a Drupal site. Then for example, an HTML5 mobile application can make calls to resources available through Services. One common resource to use is the 'user login' resource provided by Services. By using this resource, a mobile app can login a user to a Drupal site and subsequently use other service resources that user has permission to do (create content, post comments, etc.).

The user login resource requires a user name and password (just like a normal login). However, it would be fantastic if LT's login with e-mail address feature could be exposed to this as well. That way a user can login with their e-mail and password from a mobile app.

I understand that this may be out of LT's scope. If so, no worries, I'll start a sandbox module to allow this, thanks!

Jon Pugh’s picture

Assigned: Unassigned » Jon Pugh
Status: Active » Needs review
FileSize
2.62 KB

Here's a patch that adds a whole new module to the /contrib folder: logintoboggan_services.

In the meantime, I am going to add a new project on d.o for this just because. Will keep tabs on this issue to see if it gets rolled into logintoboggan.

Jon Pugh’s picture

oops, forgot to make it relative.

tyler.frankenstein’s picture

Nice job Jon Pugh! Thanks for the quick turn around. Please send a link to the Sandbox module when it is ready and I can review it for you.

stevecowie’s picture

careernerd, just been reviewing this, and I can see a case for having this as an LT contrib module. My point at #3 is nonsense as there's already rules and variable modules in LT Contrib, and both of those have dependencies.

D34dMan’s picture

Status: Needs review » Needs work

As there is already a resource which have been declared for the purpose of user login action i've created a patch for the same action in services issue queue. Here is the link - Using Email to log in instead of user name..

Reviewing the code in #6 shows a striking similarity in the approach. I am sure the Jon Pugh's approach should work.

But if you are creating a module as a contrib for LT i would strongly suggest you respect variable_get('user_email_verification', TRUE) somewhere in your module to check if site administrator really wants to use that feature. (This is the main reason why am putting this to needs work.)

DamienMcKenna’s picture

Version: 7.x-1.3 » 7.x-1.x-dev
Issue summary: View changes
DamienMcKenna’s picture

Version: 7.x-1.x-dev » 6.x-1.x-dev
Status: Needs work » Needs review
FileSize
1.1 KB

This is a patch for D6 that implements hook_services_resources_alter() to override the callback for the user login action, and then in the replacement callback it uses the same query from logintoboggan_user_login_validate to see if the user can be matched by email address. Simple stuff, and it's only a few lines of code so should IMHO be considered for inclusion in the main module.

JoeRobertsPhotography’s picture

What ever happened with this? Did it get added into drupal 7 version? Just curious. Thanks.

info.amit.dahiya’s picture

This is not working for drupal 7. while enabling service module it is breaking.

DamienMcKenna’s picture

Version: 6.x-1.x-dev » 7.x-1.x-dev
Status: Needs review » Patch (to be ported)

So someone needs to port the patch to the D7 branch.

housser’s picture

I found the module defined in #6 seems to work just fine for me, Drupal 7.39, LoginToboggan 1.5.

falcon03’s picture

Any update on this? What would need to be done to get the patch in a stable release soon?

DamienMcKenna’s picture

@falcon03: Someone needs to port the patch to the D7 version of the module.

tyler.frankenstein’s picture

Here's how it can be done with a custom Drupal module:

sites/all/modules/custom/example/example.module


/**
 * Implements hook_services_resources_alter().
 */
function example_services_resources_alter(&$resources, &$endpoint) {
  // For Login Toboggan support, add this to the condition below.
  // variable_get('logintoboggan_login_with_email', 0)

  // Override the normal user login callback.
  if (isset($resources['user']['actions']['login']['callback'])) {
    $resources['user']['actions']['login']['callback'] = '_example_user_resource_login';
    $resources['user']['actions']['login']['file']['module'] = 'example';
    $resources['user']['actions']['login']['file']['name'] = 'resources/resource.user-login';
  }
}


sites/all/modules/custom/example/resources/resource.user-login.inc


/**
 * @see _user_resource_login().
 * @see https://drupal.org/node/1431724
 */
function _example_user_resource_login($username, $password) {

  // For Login Toboggan support, add this to the condition below.
  //variable_get('logintoboggan_login_with_email', 0)

  // If an e-mail address was provided, look up its user name and use it if possible.
  if (valid_email_address($username)) {
    $query = db_select('users', 'u')
      ->fields('u', array('name'))
      ->condition('u.mail', $username)
      ->range(0, 1)
      ->execute();
    $result = $query->fetchObject();
    if (isset($result->name)) { $username = $result->name; }
  }

  // Call the default Services User Login Resource.
  module_load_include('inc', 'services', 'resources/user_resource');
  return _user_resource_login($username, $password);
}

D34dMan’s picture

I have done something similar as mentioned by @tyler.frankenstein, but while using user_load_by_mail function. instead of query.

scarer’s picture

I tried implementing a new module and enabling it. It still doesn't work when I use:

POST

http://mywebsite.com/user/login?_format=json

Body (raw):

{"mail":"user@user.com","pass":"user"}

It returns:
{"message":"Missing credentials.name."}

When I change the body to:

{"name":"user@user.com","pass":"user"}

It returns:

{"message":"Sorry, unrecognized username or password."}

I created a custom module called 'loaduserbyemail' with a directory/file structure in the custom folder in modules:

loaduserbyemail/loaduserbyemail.info.yml
loaduserbyemail/loaduserbyemail.module
loaduserbyemail/resources/resource.user-login.inc

loaduserbyemail.info.yml

name: User login by Email Module and Resource
description: Creates a resource for Drupal services to log in users by email.
package: Custom

type: module
core: 8.x

loaduserbyemail.module


/**
 * Implements hook_services_resources_alter().
 */
function loaduserbyemail_services_resources_alter(&$resources, &$endpoint) {
  // For Login Toboggan support, add this to the condition below.
  // variable_get('logintoboggan_login_with_email', 0)

  // Override the normal user login callback.
  if (isset($resources['user']['actions']['login']['callback'])) {
    $resources['user']['actions']['login']['callback'] = '_loaduserbyemail_user_resource_login';
    $resources['user']['actions']['login']['file']['module'] = 'loaduserbyemail';
    $resources['user']['actions']['login']['file']['name'] = 'resources/resource.user-login';
  }
}

resource.user-login.inc


/**
 * @see _user_resource_login().
 * @see https://drupal.org/node/1431724
 */
function _loaduserbyemail_user_resource_login($username, $password) {

  // For Login Toboggan support, add this to the condition below.
  //variable_get('logintoboggan_login_with_email', 0)

  // If an e-mail address was provided, look up its user name and use it if possible.
  if (valid_email_address($username)) {
    $query = db_select('users', 'u')
      ->fields('u', array('name'))
      ->condition('u.mail', $username)
      ->range(0, 1)
      ->execute();
    $result = $query->fetchObject();
    if (isset($result->name)) { $username = $result->name; }
  }

  // Call the default Services User Login Resource.
  module_load_include('inc', 'services', 'resources/user_resource');
  return _user_resource_login($username, $password);
}

However when I use the browser and go to the user login form I can use the email in the form field with the password for that user.

tyler.frankenstein’s picture

> http://mywebsite.com/user/login?_format=json

This is a path you'd use for Drupal 8 core's REST. You should use this path for Drupal 7 Services:

http://mywebsite.com/[my-endpoint-path]/user/login.json