Quick question - should this module work for anonymous users? I can get it to work for a user but not for an anonymous user, even when both are permissioned for 'manage own favorites'.

Thanks

Comments

anea02’s picture

Category: support » feature

OK, I think I have answered my own question and the answer is 'no'. I had a quick look at the module code and everything is linked backed to the user ID. Would it be a huge amount of work to support anonymous users as well? This module is the only module I can find that can stand a chance of helping me (aside from the lack of anonymous support it is a perfect match for my needs) because it can store any page within the site as a favourite (views, panels etc.)

Thanks

jusyjim’s picture

I would be willing to contribute $ to the developer for adding support for anonymous usage as well as ajax refresh of favorites.

mpavel’s picture

Component: Miscellaneous » Code

Hi there,

I've made some changes to the code to allow unregistered visitors to add pages to their favorites.

The changes to the code are quite simple. Here's how it works:

1. Unregistered visitor clicks 'Add to favorites'
2. If a cookie 'favsuid' already exists, use it as the user id and run the DELETE/INSERT queries
3. Else create the cookie with the value of 'time()' and run the queries
4. Unregistered visitor clicks 'Remove from favorites'
5. Basically do step 2, 3 again but just DELETE favorite where userid = 'favsuid' cookie

The updated code tries not to interfeere with the original and basically just has checks if the userid is set or not ...
Also, if the visitor registers and logs in on the website he won't see his Favorites links anymore - but he can add more as a logged in user. When he logs out he'll see the original Favorites again.

Hope all this makes sense.

Here is the content of 'favorites.module.php'

<?php
// $Id: favorites.module,v 1.3.2.5 2010/02/28 18:36:53 ezrag Exp $

/**
 * @file
 *
 * The favorites module allows users to bookmark any path within a site.
 */


/*
 * Implementation of hook_perm().
 */
function favorites_perm() {
  return array('manage own favorites', 'manage all favorites');
}

/*
 * Implementation of hook_menu().
 */
function favorites_menu() {
  $items['favorites/remove/%favorite'] = array(
    'page callback' => 'favorites_remove_favorite',
    'page arguments' => array(2),
    'access arguments' => array('manage own favorites'),
    'title' => 'Remove Favorite',
    'type' => MENU_CALLBACK,
  );
  return $items;
}

/**
 * Helper function to load a favorite.
 *
 * @param int $fid
 * @return object of the data in the favorites table.
 */
function favorite_load($fid) {
  return db_fetch_object(db_query("SELECT * FROM {favorites} WHERE fid = %d", $fid));
}

function favorites_theme() {
  return array(
    'favorites' => array(
      'arguments' => array(
        'favorites' => array(),
      ),
    ),
  );
}

/*
 * Deletes a favorite.
 */
function favorites_remove_favorite($favorite) {
  global $user;


  if (empty($user->uid)) {
    db_query("DELETE FROM {favorites} WHERE fid = %d", $favorite->fid);
  } else {
    $access = (user_access('manage own favorites') && $user->uid == $favorite->uid) || user_access('manage all favorites');
    if (!$access) {
      drupal_set_message(t("You do not have permission to remove this favorite."));
      drupal_goto();
    }
    
    if (!drupal_valid_token($_GET['token'], $favorite->timestamp . $favorite->uid . $favorite->path)) {
      drupal_set_message(t("Invalid token."));
      drupal_goto();
    }
    db_query("DELETE FROM {favorites} WHERE fid = %d", $favorite->fid);
  }

  //The query string contains the redirection page.
  drupal_goto();
}

/*
 * Implementation of hook_block().
 *
 */
function favorites_block($op = 'list', $delta = 0, $edit = array()) {
  if ($op == 'list') {
    $blocks[0]['info'] = t('User Favorites block');
    $blocks[0]['cache'] = BLOCK_NO_CACHE;
    return $blocks;
  }
  if ($op == 'view') {
    switch ($delta) {
      case 0:
        if (user_access('manage own favorites')) {
          return favorites_user_block();
        }

    }
  }
}

/*
 * Generates the "My Favorites" block.
 */
function favorites_user_block() {
  global $user;
  $output = '';
  if (empty($user->uid)) {
    $favorites = favorites_load_favorites($_COOKIE['favsuid']);
  } else {
    $favorites = favorites_load_favorites($user->uid);
  }
  $output .= theme('favorites', $favorites);
  $output .= drupal_get_form('favorites_add_favorite_form');
  $block['subject'] = t('Your Favourites');
  $block['content'] = $output;
  return $block;
}


/*
 * Returned a themed item list of favorites with title, link and link to delete.
 */
function theme_favorites($favorites = array()) {
  $items = array();
  $destination = drupal_get_destination();
  $destination = str_replace('destination=', '', $destination);
  $i = 0;
  
  foreach ($favorites as $favorite) {
    $query = array();
    $items[]= l(htmlspecialchars_decode($favorite->title), $favorite->path, array('query' => $favorite->query)) . ' ' . l('x', 'favorites/remove/' . $favorite->fid, array('class' => 'favorites-remove', 'query' => array('token' => $favorite->token, 'destination' => $destination)));
    $i += 1;
  }
  
  if ($i == 0) {
    return theme('item_list', array('No favourites added.'));
  }
  return theme('item_list', $items);
}

/*
 * Add a favorite.
 */
function favorites_add_favorite($values) {
  global $user;
  
  $now = time();

  if (empty($user->uid)) {
    if (isset($_COOKIE['favsuid'])) {
      $uid = $_COOKIE['favsuid'];
    } else {
      $uid = $now;
      setcookie("favsuid", $uid, $now+60*60*24*300, "/");
    }
    db_query("DELETE FROM {favorites} WHERE uid = %d AND path = '%s' AND query = '%s'", $uid, $values['path'], $values['query']);
    db_query("INSERT INTO {favorites} (uid, path, query, title, timestamp) VALUES (%d, '%s', '%s', '%s', %d)", $uid, $values['path'], $values['query'], $values['title'], $now);
    return;
  }
    
  db_query("DELETE FROM {favorites} WHERE uid = %d AND path = '%s' AND query = '%s'", $user->uid, $values['path'], $values['query']);
  db_query("INSERT INTO {favorites} (uid, path, query, title, timestamp) VALUES (%d, '%s', '%s', '%s', %d)", $user->uid, $values['path'], $values['query'], $values['title'], $now);
}

function favorites_add_favorite_form() {
  global $user;
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t("Add this page"),
    '#submit' => array('favorites_add_favorite_form_submit'),
  );
  $form['path'] = array(
    '#type' => 'value',
    '#value' => strip_tags($_GET['q']),
  );

  $form['query'] = array(
    '#type' => 'value',
    '#value' => drupal_query_string_encode($_GET, array('q')),
  );

  $title = drupal_get_title();
  if (empty($title)) {
    $title = check_plain(variable_get('site_name', 'Home'));
  }

  $title = strip_tags($title);
  $form['title'] = array(
    '#type' => 'value',
    '#value' => $title,
  );

  //Preserve the current path with query string.
  $destination = drupal_get_destination();
  $form['#redirect'] = array($_GET['q'], drupal_query_string_encode($_GET, array('q')));

  return $form;
}


function favorites_add_favorite_form_submit($form, &$form_state) {
  favorites_add_favorite($form_state['values']);
}

/*
 * Load the favorites for a particular user.
 */
function favorites_load_favorites($uid = 0) {
  $favorites = array();

  $query = db_query("SELECT * FROM {favorites} WHERE uid = %d ORDER BY timestamp DESC", $uid);
  while ($result = db_fetch_object($query)) {
    $favorite = $result;
    $favorite->query = $favorite->query;
    $favorite->token = favorite_token($favorite);
    $favorites[] = $favorite;
  }
  return $favorites;
}

/*
 * Generate a token for a particular favorite.
 */
function favorite_token($favorite = NULL) {
  return drupal_get_token($favorite->timestamp . $favorite->uid . $favorite->path);
}

doitDave’s picture

Status: Active » Closed (won't fix)

There would be several ways to implement this for anonymous users. Be it cookie or session based or even with an individual password to identify...hey, wait a second: The latter already exists (see user/register)... and the first two also do: Check "menu > bookmarks" in your browser...

Haha, okay, caught me. That was nasty kidding. Apologies. But without kidding, it all ends up in re-inventing the wheel. Session or cookie based implementations, in the end, all necessarily mean to store something client-sided, i.e. in the browser. But why would you while literally every browser, even good old Lynx, already provides bookmarks. So let's see what this module is intended for: Provide platform and browser independent bookmarks. Those who do not want to register with your site, will use del.icio.us, digg etc. Those who don't bother, well, are no longer anonymous.

TL; DR: I think this is really no feature that would make any sense at all. Correct me, if I missed something (and feel free to re-open in such a case).

savel’s picture

Version: 6.x-1.2 » 7.x-1.0

Here is the simple scenario:

I need to build a simple basket for some content type. I.e. to let he/she mark some of 200 offers as "interesting" and then mail list to administrator via simple form.

So it's important to have favorites for guest users.

doitDave’s picture

Status: Closed (won't fix) » Active

Ok, you have a point. So let's reopen it. But I can't promise anything right now. For one thing I'm deeply caught in other projects. And for the other, if at all, this would have to work is the $_SESSION variable or cookies. I will think about it ocasionally.

If, of course, anyone else is willing to take it, feel free to provide solid patch (against the current dev branch, please).

doitDave’s picture

Version: 7.x-1.0 » 7.x-1.x-dev
Assigned: Unassigned » doitDave
Status: Active » Fixed

I have now implemented an abstraction layer for the CRUD internals. It distinguishes between registered users and guests and operates with cookies instead of DB entries for the latter ones.

I have tested it working so far, with and without JS. Before it goes into a new release, please test it.

It will be in the next dev snapshot of July 1st, 2013. Enjoy!

Status: Fixed » Closed (fixed)

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

System Lord’s picture

7.x-2.x dev
Anonymous user: "You do not have permission to remove this favorite."

Anonymous user can save pages/links now but they cannot delete them.

System Lord’s picture

This module is ideal for my site. Actually it's exactly what I need. I will pay $$ to have it fixed.

System Lord’s picture

#9 - same problem with 7.x-2.0-beta1.

kemsnake’s picture

Issue summary: View changes
StatusFileSize
new1.18 KB

patch for #9. added some checks. patch for 7.x-2.0-beta1

kemsnake’s picture

StatusFileSize
new1.11 KB

clean code from #12