The purpose of this module is to provide for duplicate email addresses checking for domains that allow extraneous characters to be placed inside usernames and be treated as different email addresses. For example:

abdulaziz@gmail.com
a.bdulaziz@gmail.com
ab.dulaziz@gmail.com

Dots don't matter in Gmail addresses

Project link

https://www.drupal.org/project/unwanted_email_registration

Git instructions

git clone --branch '1.0.x' https://git.drupalcode.org/project/unwanted_email_registration.git

PAReview checklist

http://pareview.net/r/250

Comments

abdulaziz1zaid created an issue. See original summary.

abdulaziz zaid’s picture

Title: [D9]Unwanted Email Registration » [D9] Unwanted Email Registration
rajeshreeputra’s picture

The code looks good and works as well. No issue found.

3ssom’s picture

Status: Active » Reviewed & tested by the community

I think this is a RTBC.

avpaderno’s picture

Issue summary: View changes
Status: Reviewed & tested by the community » Needs work
Issue tags: +PAreview: project created less than ten days ago
  • What follows is a quick review of the project; it doesn't mean to be complete
  • For every point, I didn't make a complete list of where the files should be fixed, but an example of what is wrong
  • The review points report what should be changed to follow the Drupal coding standards, correctly use the Drupal API, or avoid any (possible) security issue; if a review point isn't about one of those topics, the point makes that clear
  /**
   * {@inheritdoc}
   */
  public function __construct(ConfigFactoryInterface $config_factory) {
    parent::__construct($config_factory);
    $this->configFactory = $config_factory;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('config.factory'),
    );
  }

Setting $this->configFactory is already done from the parent class. Neither of those methods are necessary, in a class extending ConfigFormBase.

    $form = parent::buildForm($form, $form_state);
    $config = $this->config('unwanted_email_registration.settings');
    $form['unwanted_email_registration_settings'] = [
      '#type' => 'vertical_tabs',
    ];

    $form['unwanted_email_registration_settings']['settings'] = [
      '#type' => 'details',
      '#title' => $this->t('Settings'),
      '#collapsible' => TRUE,
      '#collapsed' => TRUE,
      '#group' => 'unwanted_email_registration_settings',
      '#weight' => 0,
    ];

    $form['unwanted_email_registration_settings']['settings']['filter_chars'] = [
      '#type' => 'textarea',
      '#title' => $this->t('Filter Chars'),
      '#default_value' => $config->get('filter_chars'),
      '#required' => TRUE,
      '#description' => $this->t('Characters to prevent email registration with. Separated by comma.'),
    ];

    $form['unwanted_email_registration_settings']['settings']['email_domains'] = [
      '#type' => 'textarea',
      '#title' => $this->t('Domains'),
      '#default_value' => $config->get('email_domains'),
      '#required' => TRUE,
      '#description' => $this->t('Enter domain names of email addresses to apply this rule. One domain on each line.'),
    ];

    return parent::buildForm($form, $form_state);

Either parent::buildForm() isn't called at the end of the method, or it's isn't called at the beginning of the method. I would look at the code used from Drupal core classes that extend ConfigFormBase to understand when parent::buildForm() should be called.

    $config = $this->configFactory->getEditable('unwanted_email_registration.settings');
    $config->set('filter_chars', $form_state->getValue('filter_chars'))->save();
    $config->set('email_domains', $form_state->getValue('email_domains'))->save();
    $this->config('unwanted_email_registration.settings')->save();

$this->configFactory->getEditable('unwanted_email_registration.settings') must be replaced from $this->config('unwanted_email_registration.settings') which already returns an editable configuration object.
The second call to $this->config('unwanted_email_registration.settings') isn't necessary. (Since the code already obtained an editable configuration object, it doesn't need another editable configuration object for the same configuration.)

/**
 * Class Unwanted Email Registration Service.
 */
class UnwantedEmailRegistrationService {

The documentation comment for a class should not just repeat the class name. Also, the class name used to implement a service, in Drupal core, doesn't end with Service.

  /**
   * Constructs a new CustomService object.
   */
  public function __construct(ConfigFactoryInterface $config_factory, Connection $connection, MessengerInterface $messenger) {
    $this->config = $config_factory->get('unwanted_email_registration.settings');
    $this->connection = $connection;
    $this->messenger = $messenger;
  }

The documentation comment for a method needs to document its parameters. It is also not correct, as CustomService isn't the class name.

The messenger service isn't used from the service and it should not be one of its parameters.

  /**
   * {@inheritdoc}
   */
  public function validateEmail($email) {

Since that class doesn't extend another class, nor does it implement an interface, the documentation comment for the method cannot just contain {@inheritdoc} as that isn't an inherit method.

      /* Check if the domain is in our list. */
      if (!in_array($domain, $allowed)) {
        // Not allowed.
        return TRUE;
      }
      // Check to see if our domain is in the configured list.
      if (in_array($domain, $allowed)) {

This is could be either a wrong variable name or wrong logic used from the code. From the array name, it seems that $allowed contains the allowed domain names. If this is the case, why is the code returning TRUE which means the email is valid?

if (in_array($domain, $allowed)) { isn't really necessary, as the method exits when the value $domain isn't contained in the $allowed array.

        $query = $this->connection->select('users_field_data', 'u')
          ->fields('u', ['mail']);
        $results = $query->execute()->fetchAllAssoc('mail');

Modules should never directly query the database table for an entity. Drupal has a class to query the entity values in the database.

abdulaziz zaid’s picture

Dear apaderno,

Thank you for your testing.

 /* Check if the domain is in our list. */
      if (!in_array($domain, $allowed)) {
        // Not allowed.
        return TRUE;
      }
      // Check to see if our domain is in the configured list.
      if (in_array($domain, $allowed)) {

This is could be either a wrong variable name or wrong logic used from the code. From the array name, it seems that $allowed contains the allowed domain names. If this is the case, why is the code returning TRUE which means the email is valid?

if (in_array($domain, $allowed)) { isn't really necessary, as the method exits when the value $domain isn't contained in the $allowed array.

Return TRUE, if not exists Email to continue registration.
Return FALSE, if Email exists.

Drupal has a class to query the entity values in the database.

What is the class? gave me an example.

marijan gudelj’s picture

I think he is referring to the clas EntityQuery

\Drupal::entityQuery('user')
  ->condition('mail', $email)
  ->execute();
rajeshreeputra’s picture

avpaderno’s picture

avpaderno’s picture

Priority: Normal » Minor
      /* Check if the domain is in our list. */
      /* Line 1 */
      if (!in_array($domain, $allowed)) {
        // Not allowed.
        return TRUE;
      }
      // Check to see if our domain is in the configured list.
      /* Line 2 */
      if (in_array($domain, $allowed)) {

Line 1 checks the $domain value is not in the $allowed array; if it isn't, it returns TRUE. This means that when line 2 is executed, the $domain value is surely in the $allowed array and checking it is in the array is useless.

abdulaziz zaid’s picture

Status: Needs work » Needs review
avpaderno’s picture

Assigned: Unassigned » avpaderno
Priority: Minor » Normal
Status: Needs review » Fixed

Thank you for your contribution! I am going to update your account.

These are some recommended readings to help with excellent maintainership:

You can find more contributors chatting on the IRC #drupal-contribute channel. So, come hang out and stay involved.
Thank you, also, for your patience with the review process.
Anyone is welcome to participate in the review process. Please consider reviewing other projects that are pending review. I encourage you to learn more about that process and join the group of reviewers.

I thank all the dedicated reviewers as well.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.