If the user is registered, it asks for the existing password.
If the user is not registered, why doesn't this module let them set a password?

Comments

IckZ’s picture

subscribe++

Robin Millette’s picture

Status: Active » Closed (duplicate)
versatil’s picture

Status: Closed (duplicate) » Active

I don't think this is a duplicate.

The Issue @ http://drupal.org/node/1425148 is specifically for requiring the password field for existing users. Not only was that implemented there, it was also implemented arguably better in the patches provided by Tommy Kaneko here: http://drupal.org/node/1414608

I believe kevin.klikka is asking why aren't the password fields made available for account creation purposes. By default the password is blank and an e-mail is sent out via a default Rule/Action with a one time login link. (See: Accounts created with "Create new accout for anonymous order" Checkout rule have blank password.)

I'd be interested but I'm okay with the one time login in the meantime.

versatil’s picture

Okay so I needed to implement this but I can't make a patch atm because my code is all over the place for all the features I was trying to implement (very hack-like).

It took me a while to figure out how to even do this, the idea is add password fields and leave them somewhere for people to apply during their business logic. Being new to Drupal I had no idea how to do this, why form hooks weren't working, etc.

I figured we can make an invisible Pane that has its own checkout_form callback that looks up the account details, the password would have to be saved in the Commerce Order's data serial (should it be removed after business logic is executed)?

I don't have time to clean up, put stuff into callbacks, etc. and make a patch, on a very tight deadline, just wanted to share for those who might be in a similar position:

/**
 * Implements hook_commerce_checkout_pane_info()
 * 
 * We need a pane in order to do custom form submission stuff.
 */
function commerce_checkout_login_commerce_checkout_pane_info() {
  $panes = array();
  $panes['login_information'] = array(
    'title' => t('Account Registration/Login Information'),
    'base' => 'commerce_checkout_login_information',
    'page' => 'checkout',
    'enabled' => TRUE,
    'weight' => -50,
    'review' => FALSE,
    'fieldset' => FALSE,
//    'file' => 'includes/commerce_registration.checkout_pane.inc',
  );
  return $panes;
}

/**
 * Simple function for applying password to the Commerce Order
 * 
 * This function assumes nothing about your business logic, however.
 * 
 * I.e. the password is stored in the Commerce Order Data but isn't used.
 * To apply it one could execute the following PHP Code as an Action in the
 * "Create a new account for an anonymous order" Rule (modify the send e-mail!):
 *   //watchdog('debug', 'commerce order pass? '.print_r($commerce_order, true), array('0'), WATCHDOG_DEBUG);
 *   if (!empty($commerce_order->data['pass'])) {
 *     $account_created->pass = $commerce_order->data['pass'];
 *   }
 * 
 * Should the Commerce Order then be modified to remove the password?
 */
function commerce_checkout_login_information_checkout_form_submit($form, $form_state, $checkout_page, &$order) {
  global $user;
  
  // Assume this has been validated
  if (!empty($form_state['values']['account']['login']['pass'])
    && empty($user->uid)) {
    if (!function_exists('user_hash_password')) {
      require_once DRUPAL_ROOT . '/includes/password.inc';
    }
    $order->data['pass'] = user_hash_password($form_state['values']['account']['login']['pass']);
  }
}

after the secondmail patch (http://drupal.org/node/1442494#comment-5609926)

        $form['account']['login']['secondmail'] = array(
          '#type' => 'textfield',
          '#title' => t('Enter E-mail address again'),
          '#required' => TRUE,
          '#description' => t('Please enter your email address again for validation purposes'),
          '#element_validate' => array('commerce_checkout_login_secondmail_validate'),
        );
        
        $form['account']['login']['pass'] = array(
          '#type' => 'password_confirm',
          '#size' => 25,
          '#description' => t('Provide a password for the new account in both fields.'),
          '#required' => TRUE,
          '#after_build' => array('commerce_checkout_login_pass_after_build'),
        );

validation functions (FULL CREDIT to Logintoboggan module):

/**
 * Append our own validation to the password_confirm field
 *
 * This is useful for respecting one's module of choice for password policy
 */
function commerce_checkout_login_pass_after_build($element, &$form_state) {
  $element['#element_validate'][] = 'commerce_checkout_login_pass_validate';
  return $element;
}

/**
 * Validates the pass field
 *
 * Validate the new account's password. Respect popular policies.
 */
function commerce_checkout_login_pass_validate($element, &$form_state) {
  $pass = $form_state['values']['account']['login']['pass'];
  $pass_err = FALSE;
  
  // @todo Password Policy module respect?
  
  // Respect Login Toboggan settings
  if (module_exists('logintoboggan')) {
    if (!variable_get('user_email_verification', TRUE)) {
      $pass_err = logintoboggan_validate_pass($pass);
    }
  } else {
    // Borrowing from LoginToboggan directly
    // @see logintoboggan_validate_pass() 
    // it is that function verbatim albeit without length
    if (!strlen($pass)) $pass_err = t('You must enter a password.');
    if (preg_match('/[\x{80}-\x{A0}'.          // Non-printable ISO-8859-1 + NBSP
                     '\x{A1}-\x{F7}'.          // Latin punctuations
                     '\x{AD}'.                 // Soft-hyphen
                     '\x{2000}-\x{200F}'.      // Various space characters
                     '\x{2028}-\x{202F}'.      // Bidirectional text overrides
                     '\x{205F}-\x{206F}'.      // Various text hinting characters
                     '\x{FEFF}'.               // Byte order mark
                     '\x{FF01}-\x{FF60}'.      // Full-width latin
                     '\x{FFF9}-\x{FFFD}]/u',   // Replacement characters
                     $pass)) {
      $pass_err = t('The password contains an illegal character.');
    }
  }
  
  if ($pass_err) {
    form_set_error('account][login][pass', $pass_err);
  }  
}

Put the following action in the "Create a new account for an anonymous order" before Save Entity (note you may have to enable PHP Evaluation/Code in your Modules to have PHP as an action, cannot use Set data value as User Entity isn't provided a "pass" (for good reason I bet!)):

if (!empty($commerce_order->data['pass'])) {
  $account_created->pass = $commerce_order->data['pass'];
}

i would have liked to somehow respect whatever system for user registration... but i dont have time for all that and just came across logintoboggan in the process. i wouldnt have any idea where to start lol.

good luck!

if I have time (unlikely in the next 2 weeks) i'll come back and try to offer a patch or something

edited: April 4th 2012 7:30AM EST,

- use password_confirm form element so it does the password strength checking in javascript in realtime, there's a new function after_build and the pass2_validate is removed, no use for it as Drupal does this natively now.
- also changed the form_submit function, dunno how I had it working when I said !empty($user->uid) ... that would be FALSE when there is no user logged in...
- seems I forgot to post the Rules Action snippet

yanniboi’s picture

Thanks versatil!! I really need this right now..

I'm working on a File Download based commerce site and atm anonymous users that don't check their emails don't know why they can't see their files... duh!

Not really ever done any coding work before, but I'm gonna have to start at some point so I'l give it a try and then post how well I got on.

versatil’s picture

edit: check my original comment as i've updated the code

Ah. I spent a good deal of time getting further acquainted with Git before I started up on Drupal again (it has been years). It makes it easier on me because I can make my own code without worrying too much about affecting what the original authors are working on. It wouldn't be easy to figure out how to do that from scratch, could take a few hours, maybe a few weeks to get it all sorted out, but it's an investment that pays for itself.

As for coding... yeah even as a "coder" I try to stay away from code, but it seems Drupal esp. Drupal Commerce really shines once you're not shy of hacking away at some code. Making a module is super easy, don't know why I shy away from just making modules for customizations instead of trying to get existing modules to do things they weren't designed to do.

anywho, yeah, i'm still figuring things out myself so I would only use the code above if you're like me and seriously pressed for time. i don't know what's right, better, secure, etc. and the above lacks testing. so if things break i can't really support.

Before I worked on the password stuff I made a Rule to automatically log a user in. Probably a very risky thing to do, but from a user experience standpoint I wanted the user to be logged in when he's given links to his order, instead of leading to an access denied page they can see their order. I also made a custom one-time-login-url link that forces a logout as by default Drupal would have had the user's password to blank, so if they were logged in and visited the reset link they would not be able to change their password as they'd have to confirm their current password, which they can't because it's blank (and passwords can't be blank). So the solution I came up with before working on password entry was to have a link that forces logout then takes them to the reset url.

Here's the rules.inc (commerce_checkout_login.rules.inc):

<?php

/**
 * @file
 * Adds/Modifies Rules for Commerce Modules and Commerce Checkout Login
 */


/**
 * Implements hook_rules_action_info()
 *
 * Actions for Commerce and Comemrce Checkout Login
 */
function commerce_checkout_login_rules_action_info() {
  $actions = array(
    'commerce_checkout_login_action_login_new_user' => array(
      'label' => t('Automatically log a user in'),
      'group' => t('Commerce Checkout Login'),
      'parameter' => array(
        'account' => array(
          'type' => 'user',
          'label' => t('User to Login e.g. [commerce-order:owner] or [account-created]'),
        ),
      ),
    ),
  );  
  
  return $actions;
}

/**
 * Rules action: Login a User
 *
 * Use with great caution. Assuming this will never happen except in the case
 * of the user being newly created. If the user existed before they should be
 * prompted to login according to your own business logic.
 *
 * @param $account
 *   The User Account to login, selected in the Rules configuration.
 */
function commerce_checkout_login_action_login_new_user($account) {
  global $user;

  // Load the specified user into the global $user variable.
  $user = user_load($account->uid);

  // "Finalize" the login by triggering the appropriate system messages, IP
  // address and login timestamp logging, and user login hook.
  user_login_finalize();
}

You would add this Rule after you've 1) marked the order as complete, 2) created the new user and applied the Order to the new account (modify the e-mail as necessary!), this Rule relies on the owner of the order and current user being different meaning the order is assigned to the new user but the user is still anonymous (0):

export/import code:

{ "rules_when_new_user_purchases_login_and_email" : {
    "LABEL" : "When new user purchases, login and email",
    "PLUGIN" : "reaction rule",
    "WEIGHT" : "6",
    "TAGS" : [ "checkout" ],
    "REQUIRES" : [ "rules", "commerce_checkout_login", "commerce_checkout" ],
    "ON" : [ "commerce_checkout_complete" ],
    "IF" : [
      { "data_is" : { "data" : [ "commerce-order:state" ], "value" : "completed" } },
      { "NOT data_is" : { "data" : [ "commerce-order:owner" ], "value" : [ "site:current-user" ] } }
    ],
    "DO" : [
      { "commerce_checkout_login_action_login_new_user" : { "account" : [ "commerce-order:owner" ] } },
      { "send_account_email" : {
          "account" : [ "commerce-order:owner" ],
          "email_type" : "register_no_approval_required"
        }
      }
    ]
  }
}

again i bet the above poses serious problems and wouldn't put it in production without review unless you're super pressed for time like myself

yanniboi’s picture

Right so I've been messing around with the password transfer (from the commerce_checkout_pane to the user account) and I can't seem to be getting it to work. I've read through your instructions and there are two bits I dont understand. Don't worry about trying to explain it all to me because I know you're on a deadline and havn't got the time, but I do wonder what the "includes/commerce_registration.checkout_pane.inc" file does/why you edited it out.. It seems I'm either not getting the password out of the checkout_pane or the pane itself isn't getting the data.

It doesn't help that I'm not really sure how to go about debugging. As far as time is concerned, I definitely would rather be working on this (because its cool!) but I'm thinking if I could just find a way to get logintobbogan to redirect unauthenticated users to sign in before allowing them to proceed with checkout that would do the trick (for now....)

Any ideas? (do you IRC?)

versatil’s picture

I do wonder what the "includes/commerce_registration.checkout_pane.inc" file does/why you edited it out

The commented out file key is because I probably borrowed the pane stuff directly from somewhere else and there was no need for a whole file to refer to. I'm not exactly sure how the file key works probably Drupal refers to that file for functions related to that pane.

The way it works is that it saves the password as part of the order data, so you have to use a Rule action (Configuration->Workflow->Rules) to extract that data and apply it to the new user. Here's the modified version of the existing Rule:

{ "rules_create_a_new_account_for_an_anonymous_order_no_email_" : {
    "LABEL" : "Create a new account for an anonymous order (no email)",
    "PLUGIN" : "reaction rule",
    "WEIGHT" : "3",
    "REQUIRES" : [ "rules", "commerce_checkout", "php" ],
    "ON" : [ "commerce_checkout_complete" ],
    "IF" : [
      { "data_is" : { "data" : [ "commerce-order:uid" ], "value" : "0" } },
      { "NOT entity_exists" : {
          "type" : "user",
          "property" : "mail",
          "value" : [ "commerce-order:mail" ]
        }
      },
      { "data_is" : { "data" : [ "commerce-order:type" ], "value" : "commerce_order" } }
    ],
    "DO" : [
      { "entity_create" : {
          "USING" : {
            "type" : "user",
            "param_name" : [ "commerce-order:mail" ],
            "param_mail" : [ "commerce-order:mail" ]
          },
          "PROVIDE" : { "entity_created" : { "account_created" : "Created account" } }
        }
      },
      { "data_set" : { "data" : [ "account-created:status" ], "value" : 1 } },
      { "php_eval" : { "code" : "\/\/watchdog(\u0027debug\u0027, \u0027commerce order pass? \u0027.print_r($commerce_order, true), array(\u00270\u0027), WATCHDOG_DEBUG);\r\nif (!empty($commerce_order-\u003Edata[\u0027pass\u0027])) {\r\n  $account_created-\u003Epass = $commerce_order-\u003Edata[\u0027pass\u0027];\r\n}" } },
      { "entity_save" : { "data" : [ "account-created" ], "immediate" : 1 } },
      { "entity_query" : {
          "USING" : {
            "type" : "user",
            "property" : "mail",
            "value" : [ "commerce-order:mail" ],
            "limit" : 1
          },
          "PROVIDE" : { "entity_fetched" : { "account_fetched" : "Fetched account" } }
        }
      },
      { "LOOP" : {
          "USING" : { "list" : [ "account-fetched" ] },
          "ITEM" : { "list_item" : "Current list item" },
          "DO" : [
            { "data_set" : { "data" : [ "commerce-order:uid" ], "value" : [ "list-item:uid" ] } },
            { "data_set" : {
                "data" : [ "commerce-order:commerce-customer-billing:uid" ],
                "value" : [ "list-item:uid" ]
              }
            }
          ]
        }
      }
    ]
  }
}
if I could just find a way to get logintobbogan to redirect unauthenticated users to sign in before allowing them to proceed with checkout

You should be able to use Rules for that. E.g. using the events Before Add to Cart, After Add to Cart, something like that, check if the [site:current-user]'s uid is 0, if it is then redirect to the login page with a message (both should be under the System optgroup). Actually, without all the password stuff I added that's how the checkout should work, you get to the checkout page and you can't proceed unless you login first.

I just want to minimize the steps it takes for the user to get from the product to the purchase, even though my employer really wanted to enforce login, I decided to cut out a whole part of the project to get the user creation stuff above working. Unfortunately using the Auth.net module for DC required I had to have another page for the credit card form. The cc info doesn't get saved anywhere (good thing, we don't want to have anything to do with your cc info) so there's no way to carry it through a Review page, i.e. it gets processed immediately even while you're login stuff is trying to sort itself out. That's a major recipe for disaster, but pushing it to a review page was all that really could be done.

Another thing if you're like me and new to all this is that... when the user logs in... even if all you have is one link on the site... if they log in and see their user page instead of the product or service they were looking for... they might still manage to miss it. It's incredible. But that's what happened. Repeatedly. I was afraid to play with login redirect rules because I didn't know if it would affect this Checkout Login module and I didn't really have time to look into how to change the landing page when a user logs in.

Just sharing some of my experiences, might save others time/headache.

versatil’s picture

(do you IRC?)

Nope. Should I? It's been forever since I've used it, but if it's an excellent resource for drupal devs then I'll have to look into it. I have like no chat applications, maybe 1 but just for ease of us in office between machines/colleagues (sending links and stuff).

marcoka’s picture

letting them directly set a password? what if that is disabled and the password is mailed, confirmation link?

brianlp’s picture

Is there any update on this? I couldn't get it to work, there is no password field showing up. :(

I'd be more than happy to have a sreamline checkout process since I get a considerable amount of negative feedback from my download site. People are used to get easy access to their stuff.

luksak’s picture

We should try to get this fixed...

The code posted #4 is not the proper way.

Why do we need this password validation code? This could be handeled by Drupal Core, right?

We have to take Drupal Core user account settings into consideration as mentioned in #10.

Someone with the required knowledge about security has to review this: Is the password being removed from the form data saved to the database?

luksak’s picture

anyone?

jennypanighetti’s picture

Nobody has managed to implement this cleaner?? This seems like SUCH an important component to a working Drupal site...

mrpeanut’s picture

I'd really like to see this implemented as well. For now, I have created an extra pane with a simple Boolean checkbox for "Create account." If they check that, then Rules sends the "Create a new account" mail.

If they don't check it, then the rule doesn't fire. Not very pretty, but it essentially achieves the same result.

Horroshow’s picture

+1

It would be a good workaround for the one time login URL problem (see links below). It would help the user set a password instead of emailing them a link.

Ideally it would have to work with CAPTCHA to avoid spammer.

http://drupal.org/node/1430694
http://drupal.org/node/1289898
https://drupal.org/node/2076647

Horroshow’s picture

Issue summary: View changes

Is there an update on this issue? Thanks guys.

Stathes’s picture

ok so this module doesnt provide any out of the box way to login in anonymous users? This post has a picture of literally the exact functionality and points to this module? Am i missing something?
https://drupalcommerce.org/extensions/sandbox/project/commerce-checkout-...

capfive’s picture

Stathes that is a sandbox project that adds on the functionality to this module, would probably be brought out as a submodule when it is completed, you should download it and then report in that thread if it is working or not to help speed the process of launching it :) that's what i am doing right now.

This functionality needs to be implemented!

capfive’s picture

Just a quick update, that modules works VERY well https://www.drupal.org/sandbox/purushothaman.drupalgeeks/2115745 I think there is a solution that is coming :) everyone should help these guys out and get it into dev/production!

legolasbo’s picture

Status: Active » Closed (duplicate)
Related issues: +#2009986: Add capability to require login for existing and new users

The last patch (#60) in #2009986: Add capability to require login for existing and new users solves this problem and I will therefor close this as a duplicate.