6

I am making a diary website, where users can make a daily diary entry. A node acts as a diary page, so naturally I need to limit the user to make 1 node per a day. How can I do this?


Steps I have tried

Using Node Limit

This contains an option for 1 node per a day. But in fact, it is 1 node per 24 hours. So if my user makes a diary entry at 3:00pm, they have to wait until 3:00pm the next day until making the next one. Because it is diary, it would be better if the limit reset at Midnight every day, but there doesn't seem to be a way of doing this.

Using Rules

The problem with Rules is that you have to fire off the rule on Node Creation. This creates a usability issue, as my user will finish their (unallowed second) diary entry before being told that it is not allowed.

1

3 Answers 3

2

Check the answer here: Denying access to node form edit. Deny access to user by checking whether he has created a node the specific day.

function MYMODULE_node_access($node, $op, $account) {
  $type = is_string($node) ? $node : $node->type;

  if ($type == 'my_type' && ($op == 'create' || $op == 'update')) {
    my_module_check_if_user_has_published_content_today($account);
    if ($account->something == 'something') { // allow access
      return NODE_ACCESS_ALLOW;
    }
    else {
      return NODE_ACCESS_DENY;
    }
  }
// Return the default ignore value if your module doesn't need to get involved in this decision
  return NODE_ACCESS_IGNORE;
}

You should implement the select query that loads all nodes for the specific user on the specific day. You need to join node and user tables. Every node has a UTC value of the creation date. You can check if there is a node that was created after 00:00:01 and 23:59:59 in the specific day.

1
  • @Poteny Switters I don't quite understand how to use that code to check the time of the last node created by a user.
    – big_smile
    Commented Mar 9, 2015 at 11:02
2

You could implement this using the Rules module, together with the Flag module, as further detailed below ...

Step 1 - Content type

Create a dedicated content type to be used for these diary entries (nodes), let's call this type Diary (with machine name diary). So to add a diary entry, one will use a path like node/add/diary.

Step 2 - Flag

Create a flag, using the Flag module. Let's call (label) it DailyDiaryCompleted.

Step 3 - Rule to disallow multiple nodes on the same day

Create a rule, which is triggered when a user wants to start adding a new diary entry, so using a node/add/diary path. Refer to my answer to "How to limit adding content of a specific content type to paid memberships only?" for a rule that you could use as an example. Read on for more details about this rule.

Rules Event

Use Rules Event "Drupal is initializing".

Rules Conditions

  1. a condition related to "site:current-page:url", to check if it matches node/add/diary.

  2. a condition to check if "this user" has already been flagged yet with the DailyDiaryCompleted flag

Rules Actions

Set a drupal error message, to indicate they already create such diary node "today" (to stop them from starting the creation of such new node).

Step 4 - Rule to mark daily diary completed

Create a rule, which is triggered after saving a new node of type Diary. The Rules Action is to flag this user with the DailyDiaryCompleted flag.

Step 5 - Rule for daily housekeeping

Create a rule, to list all users that have been flagged with the DailyDiaryCompleted, and for each of them, perform an unflag of that flag.

Step 6 - Daily housekeeping

Use the "Rules Once per Day" module. Here is how it works (as per the comment in issue 2495775, from the module owner):

  • You specify a trigger hour on the administration settings page for this module.
  • The Rule trigger will then run when cron tasks are first run after the start of that hour. The actual run time will depend on your cron task timings.

The way I understand/Read this (haven't experimented with it yet though) is like so:

  • The "Event" will only be triggered when a cron job is run.
  • And that event will only be triggered 1 time / day, i.e. "next time cron runs after the trigger hour has passed".

So by scheduling the rule (from the previous step, i.e. "Rule for daily housekeeping") shortly after your midnight, all the flagged users from the previous day will be able to create a new diary node again "the next day".

1

You can disable the node form and provide a helpful message if a diary entry was already submitted today. You can also use a presave hook to perform the same check in case the node can be submitted without a form (for example, using a web service).

<?php

/**
 * Implements hook_form_alter().
 *
 * Perform alterations before a form is rendered.
 */
function MYMODULE_form_alter(&$form, &$form_state, $form_id) {
  switch ($form_id) {
    case 'MYNODE_node_form':
      // Disable the node form if the user submitted an entry today.
      if (MYMODULE_user_submitted_today()) {
        $form['#disabled'] = TRUE;
        drupal_set_message(t('You already submitted a diary entry for today.'), 'status');        
      }
      break;
  }
}

/**
 * Implements hook_node_presave().
 */
function MYMODULE_node_presave($node) {
  if (MYMODULE_user_submitted_today($node->uid)) {
    drupal_set_message(t('You already submitted a diary entry for today.'), 'status');
    throw new Exception('Node save aborted. Entry for today already submitted.');
  }
}

/**
 * Checks if a user submitted a diary entry today.
 */
function MYMODULE_user_submitted_today($uid = NULL) {
  if (!$uid) {
    global $user;
    $account = $user;
    $uid = $account->uid;
  }

  // Get the timestamp for the user's latest diary entry.
  $sql = 'SELECT n.created
    FROM {node} n
    WHERE n.type = :type
    AND n.uid = :uid
    ORDER BY n.created DESC
    LIMIT 1';
  $last_created = db_query($sql, array(
    ':type' => 'diary',
    ':uid' => $uid,
  ));

  if (date('z-Y', $last_created) == date('z-Y')) {
    return TRUE;
  }
  return FALSE;
}
2
  • Thanks, I get this error message: Warning: date() expects parameter 2 to be long, object given in journal_user_submitted_today() (line 53 of /journal/sites/all/modules/journal/journal.module). (Line 53 is if (date('z-Y', $last_created) == date('z-Y')) ). Also, the user is able to post multiple nodes and does not see the error message. I have tried to convert the date object to an integer, but have been unable to get it to work.
    – big_smile
    Commented Mar 12, 2015 at 16:57
  • 1
    The error is from D7 result sets, to fetch that one record you would have to loop over the result of the query object (even though it's only one record, see link below) and then store last created field or use fetch(), more info on getting result sets can be found here: drupal.org/node/1251174 (if I have time in a bit I will edit answer with the correct call unless someone has time before then) Commented Mar 12, 2015 at 20:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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