0

As mentioned in the question here Using user_load() and user_save() to change the status of a logged out user, I want to be able to access the $user object of a logged out user based on a username and set the user status to active with user_save().

As advised, I put my code in a custom module and implemented hook_menu() with a page callback. However, I still don't fetch $user.

UPDATE: I've managed to get what I wanted: I'm indeed fetching the $user object by a username passed as a parameter and I manage to change the user's status. BUT, i'm not doing this the proper way. Here's the code inside mymodule.module:

<?php
function mymodule_user($op, &$edit, &$account, $category = NULL) {
  switch ($op) {
    // set user's status to blocked upon registration
    case 'insert' : {
      user_save($account, array('status' => 0));
      break;
    }
  }
}

function mymodule_init() {
  // needed due to Drupal's menu caching. Otherwise, mymodule_menu() won't be called
  menu_rebuild();
}

function mymodule_menu() {
  $account = user_load(array( 'name' => $_REQUEST['user'] ));
  user_save($account, array('status' => 1));    
}

As you can see, I implement hook_menu() but there's no page callback. A working page callback would solve me 2 issues:

  1. I would like the user activation functionality to be available only from a specific page in Drupal and i'd like to restrict access to that page.
  2. Performance - currently, the menu_rebuild() is called on each and every page request on Drupal.. not pleasant at all :)

When I tried putting a page callback in the mymodule_menu() function and debugged the code, I saw that the page callback wasn't even fired. Here's what my initial code looked like:

function mymodule_menu() {
  $account = user_load(array( 'name' => $_REQUEST['user'] ));
  $items['auth'] = array(
    'page callback' => 'mymodule_page',
    'page arguments' => array($account),
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
  );
  return $items;
}

function mymodule_page(&$account) {
  menu_rebuild();
  user_save($account, array('status' => 1));   
}

Why isn't my page callback function fired with this code? How can I tell Drupal to rebuild the menus or to clear the menus cache only for a certain page?

Avner

1

What is wrong in your code is that the implementation of hook_menu() is gathering the arguments for the callback, when that hook is only called in specific moments (as I reported in my previous answer).

Rather than doing as you do, I would rather use the following code:

function mymodule_menu() {
  $items['auth/%user'] = array(
    'page callback' => 'mymodule_page',
    'page arguments' => array(1),
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
  );
  return $items;
}

function mymodule_page($account) {
  user_save($account, array('status' => 1));
  drupal_goto('<front>');   
}

In this way, Drupal will automatically get the user ID, and pass to the page callback the user object for that user. drupal_goto() is necessary as the page callback is not showing any output; you can redirect the user to any pages you want. (I chose "<front>" because it's a path that is always defined, in Drupal). If you need to use a username, then you need to use a loader function that loads a user object knowing the username. As in Drupal there cannot be two users with the same username, it should avoid the user being acted upon is not the desired one.

function mymodule_menu() {
  $items['auth/%mymodule_username'] = array(
    'page callback' => 'mymodule_page',
    'page arguments' => array(1),
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
  );
  return $items;
}

function mymodule_page($account) {
  user_save($account, array('status' => 1));
  drupal_goto('<front>');   
}

function mymodule_username_load($name) {
  return user_load(array('name' => $name));
}

The code defines a new wildcard argument; if "%wildcard" is the name of the wildcard, then Drupal will look for the wildcard() function that needs to return FALSE in case of error; in that case, Drupal will return the "page not found" error (404).

Important I used the same value you used for "access callback," but it is not something that should be done, in this very specific case.
The reason is that the menu callback alters a user account; imagine what should happen if a user with a blocked account could do if he knows of this URL: He could enable his own account very easily. This is because the entry "access callback" you are using is saying "everybody can access this menu callback," which also means that Google, or any other search engine could enable a user just visiting the URL the search engine has found in some way.
In general, the rule is to restrict the access to a menu callback that alter some data, which includes also the case the menu callback deletes data.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.