Enforce unique email addresses with user save service
emosbaugh - March 19, 2009 - 21:51
| Project: | Services |
| Version: | 6.x-2.x-dev |
| Component: | Code |
| Category: | bug report |
| Priority: | critical |
| Assigned: | Unassigned |
| Status: | needs review |
Description
Is this currently possible? If not, wouldn't this be a good feature, or at least a way to check if you are entering a duplicate. Or do I have to write a custom service?
thanks

#1
The user.save service simply calls Drupal's user_save() function, and that function checks for email address uniqueness. When this fails services will return an error (although this error is kind of vague.) Generally services try and work simply as passthroughs to core functions, and since this is how core works it is probably how services should work as well.
#2
I just tested this and unfortunately, when a user is registered through services, email conflicts do not appear to be checked for. I was able to register two users with the same email. When doing so through the normal Drupal web interface, this is caught.
#3
Wow that is really weird, one of us should take a look soon, that should definitely be caught.
#4
I thought maybe it was because I was using Login Toboggan , but nope. I will tell you that I'm using AMFPHP and Flex, for what it's worth, along with the March 31 dev version.
Any idea where the email checking function is? I couldn't see anything obvious in user.module but it seems like it should live in there.
#5
So the email address checking is done in _user_edit_validate() in user.module. Unfortunately this is only called when users are registered through the Drupal admin interface (through a hook called by the validate handler.) Services is just calling user_save(), so this is all bypassed. This should be fixed to use drupal_execute() just like the node.save service does.
#6
I encountered this problem too. Is it going to be fixed?
#7
Raising priority as it affects all user registration functions eg email. However we should keep the existing user save service and add a new user register service as they exist for different cases. User save should error if a user doesn't currently exist as part of this change.
#8
Subscribing.
#9
Subs
#10
Sorry to bump....but any news on this? (I hope I am not coming accros as rude, as I know this an open-source project, with real people, with real lives behind this :-), so a big thank you for all the work already done.)
#11
I have made a small service call to check for username and email. Maybe it can be added to user services.
It is very basic with no access check, but yet again, all it dose is check for validation and if anyone else is using the username or emails address.
Replace xxxxx with your custom service call module name, and don't forget your .info so you can turn it on. Also remember to edit your key to allow it to use the call.
pretty much taken from _user_edit_validate()
<?php
// $Id$
/**
* @file
* Service Calls used by xxxxx
*/
function xxxxx_service() {
return array(
//Check if user or email exists
array(
'#method' => 'xxxxxx.usercheck',
'#callback' => 'user_check',
'#args' => array(
array(
'#name' => 'User Name',
'#type' => 'string',
'#description' => t('new username')),
array(
'#name' => 'User Email',
'#type' => 'string',
'#description' => t('new user email'))),
'#return' => 'array'
),
);
}
function user_check($username_in, $email_in) {
//Check UserName
if ($error = user_validate_name($username_in)) {
return array(error => TRUE, message => $error);
}
else if (db_result(db_query("SELECT COUNT(*) FROM {users} WHERE LOWER(name) = LOWER('%s')", $username_in)) > 0) {
return array(error => TRUE, message => t('The name '. $username_in .' is already taken.'));
}
else if (drupal_is_denied('user', $username_in)) {
return array(error => TRUE, message => t('The name '. $username_in .' has been denied access.'));
}
//Check email
else if ($error = user_validate_mail($email_in)) {
return array(error => TRUE, message => t('The e-mail address '. $email_in .'is not valid.'));
}
else if (db_result(db_query("SELECT COUNT(*) FROM {users} WHERE LOWER(mail) = LOWER('%s')", $email_in)) > 0) {
return array(error => TRUE, message => t('The e-mail address '. $email_in .' already exists'));
}
else {
return array(error => FALSE, message => 'no error');
}
}
#12
I am not a fan of this solution, because it repeats code from core. If this code ever gets patched as part of security or bug fix, we're left out in the cold. I'd rather figure out a way to exploit core's validation, or use drupal_execute() which is how it should really be done. Unfortunately this could very well break existing installations. Am playing with this now and hope to have a patch soon. This has been broken far too long.
#13
Attached is a patch that replaces the existing user.save() service with one that uses drupal_execute() and as such acknowledges all validation rules. It should work pretty much exactly the same as the old service, and the code should be 100% compatible. As an added bonus, this service can save user profile information through the addition of a 'category' key to the submitted data. If this means nothing to you don't worry about it.
Would love to see some testing of this patch so we can get it in. I've done some but it's pretty basic.
Thanks all.