Jump to content

preventing duplicate user emails


valan
 Share

Recommended Posts

There is a need to prevent duplicate user emails, e.g. ensure that users have unique emails.

This requires email uniqueness checks to be performed each time email field is going to be saved.

Please could you help with right hook for that and get/set methods in function call? E.g. how to get "old" and "new" email values. How to skip saving OR save if email is unique? Simple piece of code is preferred over words.) Thanks!

P.S. Also, it would be good it admin gets error notification when tries to save user page with duplicate email.

Link to comment
Share on other sites

Andrey,

With adapted code stolen from Soma here: https://processwire.com/talk/topic/4476-validating-field-before-page-save/ (post #2), you can do something like below in an autoload module. Be sure to read Soma's explanations as well in that post/thread.

<?php

class ValidateEmail extends WireData implements Module {
	
	/**
	 * Return information about this module (required).
	 *
	 *	@access public
	 *	@return array module info
	 *
	 */
	public static function getModuleInfo() {
	
		return array(
			'title' => 'Validate Unique Email',
			'summary' => 'Ensure Uniqueness of Emails across site',
			'author' => 'Kongondo, Soma',
			'version' => 001,
			'singular' => true, 
			'autoload' => true,

		);

	}

	public function init(){
	  	$this->addHookAfter("InputfieldEmail::processInput", $this, "validEmail");
	}

	public function validEmail($event){
		
		$field = $event->object;

		if($field->name == 'mail'){
			$page = $this->modules->ProcessPageEdit->getPage();
			
			$oldEmail = $page->get($field->name);
			$newEmail = $field->value;
			
			#$this->message("old value: $oldEmail");
			#$this->message("new value: $newEmail");
			
			$existEmail = $this->wire('pages')->get("id!=$page->id, template=basic-page, mail=$newEmail, mail!=''");
			if($existEmail && $existEmail->id > 0) {
				$field->value = $oldEmail;
                                $field->error($this->_("That email $newEmail is already taken mate; go fishing! :-)"));	
			}			

		}
	}

}

This will save if unique, keep old value if not unique and show error. I am not sure what you mean by admin gets error notification; you mean send them an email or log the error? I'll let you Google that  ;)

Edited by kongondo
  • Like 3
Link to comment
Share on other sites

  • 9 months later...

@kongondo

 or anybody else:

If I want to check only the email address of users on duplicates, would it then be safe to say that the template must be "user"

Thus not:

$existEmail = $this->wire('pages')->get("id!=$page->id, template=basic-page, mail=$newEmail, mail!=''");

But:

$existEmail = $this->wire('pages')->get("id!=$page->id, template=user, mail=$newEmail, mail!=''");

 

NEVER MIND,
I found it myself.

EDIT: but with one more issue (see below)

 

<?php namespace ProcessWire;

class ValidateEmail extends WireData implements Module {
	
	/**
	 * Return information about this module (required).
	 *
	 *	@access public
	 *	@return array module info
	 *
	 */
	public static function getModuleInfo() {
	
		return array(
			'title' => 'Validate Email module',
			'summary' => 'Ensure Uniqueness of Emails across site',
			'author' => 'Kongondo, Soma',
			'version' => 001,
			'singular' => true, 
			'autoload' => true,
		);

	}

	public function init(){
	  	$this->addHookAfter("InputfieldEmail::processInput", $this, "validEmail");
	}

	public function validEmail($event){
		
		$field = $event->object;

		if($field->name == 'email'){ // edited to my field
			$page = $this->modules->ProcessPageEdit->getPage();
			
			$oldEmail = $page->get($field->name);
			$newEmail = $field->value;
			
			#$this->message("old value: $oldEmail");
			#$this->message("new value: $newEmail");
			
			$existEmail = $this->wire('pages')->get("id!=$page->id, template=user, email=$newEmail, email!=''"); // edited to my field
			if($existEmail && $existEmail->id > 0) {
				$field->value = $oldEmail;
                                $field->error($this->_("That email $newEmail is already taken mate; go fishing! :-)"));	
			}			

		}
	}

}

 

Link to comment
Share on other sites

This is the code which gives the error: 

$page = $this->modules->ProcessPageEdit->getPage();

It gives an error because in my case the users in role 'clients' have only permission to 'profile-edit' and not to 'page-edit'.  Superuser has all the permissions, so that's why the module works as admin, but not as user.

So I tried with following code: 

$page = $this->modules->ProcessProfile->getPage();

With the latter the user can edit the email field, but then the superuser gave errors.  (I don't understand why)

So, for now I have this workaround (which I don't really like): 

if ($this->user->hasRole('clients')) {
	$page = $this->modules->ProcessProfile->getPage();
}else{
	$page = $this->modules->ProcessPageEdit->getPage();		
}

Feel free to comment.  I'm sure there must be a better way.

Edited by KarlvonKarton
typo
Link to comment
Share on other sites

Sorry wasn't really checking through everything properly. Take a look at how I am doing it for InputfieldPassword::render

https://github.com/adrianbj/EmailNewUser/blob/master/EmailNewUser.module#L50

        $process = $this->wire('process');
        if($process instanceof WirePageEditor) {
            $userpage = $process->getPage();
            if($userpage->is(Page::statusUnpublished)) $event->object->notes = 'NB: Because you chose to automatically generate the password for new users, you can leave these blank. However, if you do enter a password here, it will override the generated one.';
        }

 

  • Like 2
Link to comment
Share on other sites

Sorry, I shouldn't give advice without really checking into it. This is what you need:

$event->arguments[0]->id

That will get you the id of the user/page.

BTW, the way I figured this out was to bd($event) inside the validEmail() function. With TracyDebugger installed I see this:

bd($event, '$event', array('maxDepth' => 5));

Screen Shot 2016-09-06 at 3.11.03 PM.png


Then to confirm, I did this:

bd($event->arguments[0]->id);

and got this:

Screen Shot 2016-09-06 at 3.12.35 PM.png

 

With the ID you can get the full user object like this:

        $uid = $event->arguments[0]->id;
        bd(wire('users')->get($uid));

Screen Shot 2016-09-06 at 7.33.08 PM.png

See all the user fields under "settings"

 

  • Like 3
Link to comment
Share on other sites

I am not sure what you're trying to do with that. 

$event->arguments[0]->id

returns the ID of the user page.

You don't want to override the $page object ever. Given that we are talking about a user, the convention is often to use $u.

$u = wire('users')->get($event->arguments[0]->id);

but that is basically what I showed you up above.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...