You are here

makemeeting.module in Make Meeting Scheduler 7

Same filename and directory in other branches
  1. 6 makemeeting.module
  2. 7.2 makemeeting.module

Make Meeting module

File

makemeeting.module
View source
<?php

/**
 * @file
 *
 * Make Meeting module
 *
 */

/**
 * hook_theme implementation
 */
function makemeeting_theme() {
  return array(
    'makemeeting_calendarselector' => array(
      'render element' => 'element',
      'template' => 'makemeeting-calendarselector',
    ),
    'makemeeting_choices' => array(
      'render element' => 'element',
      'template' => 'makemeeting-choices',
    ),
    'makemeeting_pollpanel' => array(
      'variables' => array(
        'node' => NULL,
      ),
      'template' => 'makemeeting-pollpanel',
    ),
    'makemeeting_poll_admin' => array(
      'variables' => array(
        'node' => NULL,
        'admin_form' => NULL,
      ),
      'template' => 'makemeeting-poll-admin',
    ),
  );
}

/**
 * Preprocess for makemeeting choices
 *
 * @param $vars
 */
function makemeeting_preprocess_makemeeting_choices(&$vars) {
  global $user;

  // Get the element
  $element = $vars['element'];
  $vars['options'] = array();

  // Get the options data
  foreach ($element['#attributes']['days_and_options'] as $days => $options_array) {

    // Day of the option
    $option = array(
      'day' => check_plain(substr($days, strpos($days, "_") + 1)),
    );

    // Options of the day
    $options = array();
    foreach ($options_array as $o) {
      $start = strpos($o, "_");
      $options[substr($o, 0, $start)] = check_plain(substr($o, $start + 1));
    }
    $option['options'] = $options;
    $vars['options'][] = $option;
  }
  $votes = $votes_stats = array();
  foreach ($element['#attributes']['answers'] as $username => $vote) {
    $votes[$username] = array();
    foreach ($vars['options'] as $option) {
      foreach ($option['options'] as $id => $data) {

        // Initialize statistics
        if (!isset($votes_stats[$id])) {
          $votes_stats[$id] = array();
        }

        // Initialize vote
        if (!isset($vote[$id])) {
          $vote[$id] = 0;
        }

        // Analyse vote
        switch ($vote[$id]) {
          case 0:
            $votes[$username][$id] = 'no';
            break;
          case 1:
            $votes[$username][$id] = 'ok';
            break;
          case 2:
            $votes[$username][$id] = 'maybe';
        }

        // Update stats
        if (isset($votes_stats[$id][$vote[$id]])) {
          $votes_stats[$id][$vote[$id]]++;
        }
        else {
          $votes_stats[$id][$vote[$id]] = 1;
        }
      }
    }
  }
  $vars['total_count'] = count($votes) * count(reset($votes));
  $vars['votes'] = $votes;
  foreach ($votes_stats as &$stats) {
    $yes = isset($stats[1]) ? $stats[1] : 0;
    $no = isset($stats[0]) ? $stats[0] : 0;
    $maybe = isset($stats[2]) ? $stats[2] : 0;
    if ($element['#attributes']['maybe_option'] == 1) {
      $style = $no > $yes + $maybe ? "red" : ($yes > $no + $maybe ? "green" : "yellow");
    }
    else {
      $style = $yes > $no ? "green" : ($yes == $no ? "yellow" : "red");
    }
    $stats = array(
      'style' => $style,
      'yes' => $yes,
      'no' => $no,
      'maybe' => $maybe,
    );
  }
  $vars['votes_stats'] = $votes_stats;
  $vars['choices'] = array(
    'no' => t('No'),
    'ok' => t('Yes'),
    'maybe' => t('Maybe'),
  );
  $element = array(
    '#type' => 'textfield',
    '#name' => 'your_name',
    '#attributes' => array(),
    '#value' => isset($element['#value']['name']) ? $element['#value']['name'] : $user->name,
    '#size' => 20,
  );
  $vars['input'] = drupal_render($element);
  $vars['input_type'] = 'radio';
  if (isset($element['#attributes']['multiple_allowed']) && $element['#attributes']['multiple_allowed'] == 0) {
    $vars['input_type'] = 'checkbox';
  }
}

/**
 * hook_menu implementation
 */
function makemeeting_menu() {
  $items['admin/config/content/makemeeting'] = array(
    'title' => 'MakeMeeting',
    'description' => 'Main admin panel for Make Meeting module',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'makemeeting_admin_form',
    ),
    'access arguments' => array(
      'administer site configuration',
    ),
    'file' => 'makemeeting.admin.inc',
  );
  $items['makemeeting'] = array(
    'title' => 'Info page',
    'description' => 'The module information page',
    'page callback' => 'makemeeting_infopage',
    'access arguments' => array(
      'view makemeeting poll',
    ),
    'file' => 'makemeeting.pages.inc',
    'type' => MENU_CALLBACK,
  );
  $items['makemeeting/%'] = array(
    'title' => 'Question page',
    'description' => 'Make a vote on the question',
    'page callback' => 'makemeeting_show_pollpage',
    'page arguments' => array(
      1,
    ),
    'access arguments' => array(
      'view makemeeting poll',
    ),
    'file' => 'makemeeting.pages.inc',
    'type' => MENU_CALLBACK,
  );
  $items['makemeeting/%/log'] = array(
    'title' => 'Log page',
    'description' => 'Show logs',
    'page callback' => 'makemeeting_logpage',
    'page arguments' => array(
      1,
    ),
    'access arguments' => array(
      'view makemeeting poll',
    ),
    'file' => 'makemeeting.pages.inc',
    'type' => MENU_CALLBACK,
  );
  $items['makemeeting/%/sendfw'] = array(
    'title' => 'Send forward',
    'description' => 'Send the url to your friends',
    'page callback' => 'makemeeting_sendfw',
    'page arguments' => array(
      1,
    ),
    'access arguments' => array(
      'view makemeeting poll',
    ),
    'file' => 'makemeeting.pages.inc',
    'type' => MENU_CALLBACK,
  );
  $items['user/%user/makemeeting'] = array(
    'title' => 'My polls',
    'description' => 'List of my polls',
    'page callback' => 'makemeeting_mypage',
    'access callback' => '_makemeeting_access_userpolls',
    'access arguments' => array(
      1,
    ),
    'file' => 'makemeeting.pages.inc',
    'type' => MENU_SUGGESTED_ITEM,
  );
  return $items;
}

/**
 * hook_perm implementation
 */
function makemeeting_permission() {
  return array(
    'access all polls' => array(
      'title' => t("Access all makemeeting polls"),
      'restrict access' => TRUE,
    ),
    'access own polls' => array(
      'title' => t("Access own makemeeting polls"),
    ),
    'view makemeeting poll' => array(
      'title' => t("Access makemeeting polls"),
    ),
  );
}
function _makemeeting_access_userpolls($account) {
  global $user;
  return user_access('access all polls') || $user->uid == $account->uid && user_access('access own polls');
}

/**
 * hook_elements implementation
 *
 * Custom form elements: calendarselector and pollpanel
 */
function makemeeting_element_info() {
  $types['makemeeting_choices'] = array(
    '#input' => TRUE,
    '#process' => array(
      '_makemeeting_choices_process',
    ),
    '#attributes' => array(
      'dates_and_options' => array(),
      'answers' => NULL,
      'multiple_allowed' => NULL,
      'maybe_option' => NULL,
      'secure' => NULL,
    ),
    '#theme' => 'makemeeting_choices',
    '#value_callback' => 'form_type_makemeeting_choices_value',
  );
  $types['makemeeting_calendarselector'] = array(
    '#input' => TRUE,
    '#process' => array(
      '_makemeeting_calendarselector_process',
    ),
    '#attributes' => array(
      'selected_dates_and_options' => array(),
    ),
    '#theme' => 'makemeeting_calendarselector',
    '#value_callback' => 'form_type_makemeeting_calendarselector_value',
  );
  return $types;
}

/**
 * Process the makemeeting_calendarselector element before rendering
 *
 * @param $element
 */
function _makemeeting_calendarselector_process($element) {

  // Adding javascript locales and settings
  $days = array(
    t('Su'),
    t('Mon'),
    t('Tue'),
    t('Wed'),
    t('Th'),
    t('Fr'),
    t('Sat'),
  );
  $months = array(
    t('January'),
    t('Febuary'),
    t('March'),
    t('April'),
    t('May'),
    t('June'),
    t('July'),
    t('August'),
    t('September'),
    t('October'),
    t('November'),
    t('December'),
  );
  $element['#attributes']['months'] = $months;
  $nav_links = array(
    'p' => '&laquo;',
    'n' => '&raquo;',
    't' => t('Today'),
    'b' => t('Add date to list'),
  );
  drupal_add_js(array(
    'makemeeting' => array(
      'days' => $days,
      'months' => $months,
      'navLinks' => $nav_links,
    ),
  ), 'setting');
  drupal_add_js(drupal_get_path('module', 'makemeeting') . '/jcalendar-source.js');
  drupal_add_css(drupal_get_path('module', 'makemeeting') . '/jcalendar.css');
  return $element;
}

/**
 * Fetch the values from the makemeeting_calendarselector form element
 *
 * @param $element
 * @param bool $input
 * @param null $form_state
 */
function form_type_makemeeting_calendarselector_value(&$element, $input = FALSE, $form_state = NULL) {
  if (!empty($form_state['input'])) {

    // collecting the selected date and options from the posted form
    // and put it into the calendar element's 'value' field
    $day_options = array();
    $days = array();

    // using preg_match to indentifing and collecting dynamicly created input fields
    foreach ($form_state['input'] as $k => $v) {
      preg_match("/(day_)(\\d+)/i", $k, $matches_day);
      if (!empty($matches_day)) {
        $days[] = $v;
        $day_options[$v] = array();
      }
    }
    foreach ($form_state['input'] as $k => $v) {
      preg_match("/(day_option_)(\\d+)(_)(\\d+)/i", $k, $matches_options);
      if (!empty($matches_options)) {
        $field_name = $form_state['input']['day_' . $matches_options[2]];
        $day_options[$field_name][] = $v;
      }
    }
    return $day_options;
  }
}

/**
 * Process the makemeeting_choices element before rendering
 *
 * @param $element
 */
function _makemeeting_choices_process($element) {

  // Adding custom css
  drupal_add_css(drupal_get_path('module', 'makemeeting') . '/pollpanel.css');
  return $element;
}

/**
 * Fetch the values from the makemeeting_choices form element
 *
 * @param $element
 * @param bool $input
 * @param null $form_state
 */
function form_type_makemeeting_choices_value(&$element, $input = FALSE, $form_state = NULL) {
  if (!empty($form_state['input'])) {

    // processing posted datas
    if ($element['#attributes']['maybe_option'] == 1 || $element['#attributes']['multiple_allowed'] == 1) {
      $alter_ids = array();

      // collects the alter_ids and the vote values
      foreach ($form_state['input'] as $k => $v) {
        if (preg_match("/option_(\\d+)/", $k, $matches)) {
          $alter_ids[$matches[1]] = $v;
        }
      }
    }
    else {
      $alter_ids = array();

      // collect only the alter_ids
      foreach ($form_state['input'] as $k => $v) {
        if (preg_match("/option_/i", $k)) {
          $alter_ids[] = $v;
        }
      }
    }
    return array(
      'alter_ids' => $alter_ids,
      'name' => $form_state['input']['your_name'],
    );
  }
  return $element;
}

/**
 * Implementation of hook_form_alter()
 */
function makemeeting_form_alter(&$form, $form_state, $form_id) {

  // Remove preview button from makemeeting node form
  if ($form_id == 'makemeeting_node_form') {
    unset($form['actions']['preview']);
  }
}

/**
 * Implementation of hook_node_info()
 */
function makemeeting_node_info() {
  return array(
    'makemeeting' => array(
      'name' => t('Event'),
      'base' => 'node_makemeeting',
      'description' => t("Create a poll for a business lunch, a meeting or a movie night."),
      'has_title' => TRUE,
      'title_label' => t('Your question'),
      'has_body' => TRUE,
      'body_label' => t('Add some description'),
    ),
  );
}

/**
 * Implementation of hook_node_access()
 */
function makemeeting_node_access($node, $op, $account) {
  if (is_object($node) && $node->type == 'makemeeting') {
    switch ($op) {

      // disabling the edit page: we don't give access to any user
      // reason: we're using custom urls to update the nodes, and only
      // the owner of the poll has the custom admin url
      case 'update':
        return FALSE;
      case 'delete':
        return user_access('delete poll', $account) && $account->uid == $node->uid;
    }
  }
  return FALSE;
}

/**
 * Implementation of hook_node_form()
 */
function node_makemeeting_form(&$node) {
  global $user;
  $type = node_type_get_type($node);
  if ($type->has_title) {
    $form['title'] = array(
      '#type' => 'textfield',
      '#title' => check_plain($type->title_label),
      '#required' => TRUE,
      '#default_value' => $node->title,
      '#weight' => -5,
    );
  }
  if ($type->has_body) {
    $form['body'] = array(
      '#type' => 'textarea',
      '#title' => check_plain($type->body_label),
      '#default_value' => isset($node->body) ? $node->body : '',
      '#rows' => 5,
    );
  }
  if (isset($node->nid) && $node->uid == 0 || $user->uid == 0) {
    $form['anonym'] = array(
      '#type' => 'fieldset',
      '#title' => t('Add your name and email'),
      '#tree' => TRUE,
    );
    $form['anonym']['user_name'] = array(
      '#type' => 'textfield',
      '#title' => t('Your name'),
      '#maxlength' => 100,
      '#description' => t('This is optional.'),
    );
    $form['anonym']['user_email'] = array(
      '#type' => 'textfield',
      '#title' => t('Your e-mail'),
      '#description' => t('This is optional, too. But if you add, we can send e-mail notification after every valid vote.'),
      '#maxlength' => 100,
    );
  }

  // transform the days_and_options array to the structure required by the theme funcion
  if (isset($node->days_and_options) && is_array($node->days_and_options)) {
    $attributes = array();
    $i = 1;
    foreach ($node->days_and_options as $days => $options_array) {
      $start_day = strpos($days, "_");
      $day_str = substr($days, $start_day + 1);
      $attributes['date_' . $i] = $day_str;
      foreach ($options_array as $k => $option) {
        $start_option = strpos($option, "_");
        $option_str = substr($option, $start_option + 1);
        $attributes['option_' . $i][] = $option_str;
      }
      $i++;
    }
  }
  else {

    // initializing data for dates and options (options are empty)
    $attributes = array(
      'date_1' => date("Y-m-d"),
      'option_1' => array(
        "",
        "",
      ),
    );
  }
  $form['calendar'] = array(
    '#type' => 'makemeeting_calendarselector',
    '#title' => t('Calendar test'),
    '#description' => t('Use the calendar above to select the days, then add the options for the days. For example select the day of tomorrow and add "AM", "PM" as options. You can use only upcoming days.'),
    '#attributes' => array(
      'selected_dates_and_options' => $attributes,
    ),
  );
  $form['poll_options'] = array(
    '#type' => 'fieldset',
    '#title' => t('Scheduler options'),
    '#tree' => TRUE,
  );
  $form['poll_options']['secure'] = array(
    '#type' => 'radios',
    '#title' => t('Show previous votes'),
    '#description' => t("Deny new voters to see the previous votes."),
    '#options' => array(
      '0' => t('Yes'),
      '1' => t('No'),
    ),
    '#default_value' => isset($node->secure) ? $node->secure : 0,
  );
  $form['poll_options']['maybe_option'] = array(
    '#type' => 'radios',
    '#title' => t('Maybe option'),
    '#description' => t("Voters can select maybe as answer too."),
    '#options' => array(
      '0' => t('Disabled'),
      '1' => t('Enabled'),
    ),
    '#default_value' => isset($node->maybe_option) ? $node->maybe_option : 0,
  );
  $form['poll_options']['multiple_allowed'] = array(
    '#type' => 'radios',
    '#title' => t('Multiple option is selectable per answers.'),
    '#options' => array(
      '0' => t('Disabled'),
      '1' => t('Enabled'),
    ),
    '#default_value' => isset($node->multiple_allowed) ? $node->multiple_allowed : 0,
  );
  $form['email'] = array(
    '#type' => 'fieldset',
    '#title' => t('E-mail notification'),
  );
  $form['email']['email_notification'] = array(
    '#type' => 'radios',
    '#title' => t('Send me an e-mail after every valid vote'),
    '#options' => array(
      '1' => t('Yes'),
      '0' => t('No'),
    ),
    '#default_value' => isset($node->email_notification) ? $node->email_notification : 1,
  );
  return $form;
}

/**
 * Implementation of hook_node_insert()
 */
function node_makemeeting_insert($node) {
  global $user;

  // Poll_head
  // generate the poll urls and save them
  $poll_url = _makemeeting_generate_url('url', 10);
  $admin_url = _makemeeting_generate_url('admin_url', 25);

  // save the poll options
  $values = array(
    'nid' => $node->nid,
    'vid' => $node->vid,
    'uid' => $user->uid,
    'email_notification' => $node->email_notification,
    'poll_type' => 1,
    'url' => $poll_url,
    'admin_url' => $admin_url,
    'multiple_allowed' => $node->poll_options['multiple_allowed'],
    'secure' => $node->poll_options['secure'],
    'maybe_option' => $node->poll_options['maybe_option'],
  );
  $query = db_insert('makemeeting_poll_heads')
    ->fields($values);
  if (isset($node->anonym)) {
    $query
      ->fields(array(
      'anonym_name' => $node->anonym['user_name'],
      'anonym_email' => $node->anonym['user_email'],
    ));
  }
  $query
    ->execute();

  // we get the selected dates and options in $node->calendar
  // collecting the form datas in makemeeting_calendarselector_process()
  if (isset($node->calendar)) {
    foreach ($node->calendar as $day => $options_array) {
      $values = array(
        'nid' => $node->nid,
        'answer_text' => $day,
        'type' => 1,
      );
      $answer_id = db_insert('makemeeting_poll_rows')
        ->fields($values)
        ->execute();
      foreach ($options_array as $option) {
        $values = array(
          'answer_id' => $answer_id,
          'alter_text' => $option,
        );
        db_insert('makemeeting_poll_alters')
          ->fields($values)
          ->execute();
      }
    }
  }

  // setting the output texts: the url of the poll page and the admin page
  drupal_set_message(l(t("Poll page URL: !url", array(
    "!url" => url('makemeeting/' . $poll_url, array(
      "absolute" => TRUE,
    )),
  )), "makemeeting/" . $poll_url));
  drupal_set_message(l(t("Admin page URL: !url", array(
    "!url" => url('makemeeting/' . $admin_url, array(
      "absolute" => TRUE,
    )),
  )), "makemeeting/" . $admin_url));

  // send an email message
  if ($node->email_notification) {
    $mail = $name = "";
    if ($user->uid > 0) {
      $mail = $user->mail;
    }
    elseif (valid_email_address($node->anonym['user_email'])) {
      $mail = $node->anonym['user_email'];
    }
    if ($mail != "") {
      if ($user->uid > 0) {
        $name = $user->name;
      }
      elseif (isset($node->anonym['user_name'])) {
        $name = $node->anonym['user_name'];
      }
      $params = array(
        "name" => $name,
        "poll_url" => $poll_url,
        "admin_url" => $admin_url,
      );
      drupal_mail('makemeeting', 'create_new_poll', $mail, language_default(), $params);
    }
  }
  drupal_goto('makemeeting/' . $poll_url);
}

/**
 * Implementation of hook_node_delete()
 */
function node_makemeeting_delete($node) {
  $res = db_query("SELECT answer_id FROM {makemeeting_poll_rows} WHERE nid = :nid", array(
    ':nid' => $node->nid,
  ));
  foreach ($res as $answer_id_row) {
    db_query("DELETE FROM {makemeeting_poll_alters} WHERE answer_id = :answer_id", array(
      ':answer_id' => $answer_id_row->answer_id,
    ));
  }
  db_query("DELETE FROM {makemeeting_poll_rows} WHERE nid = :nid", array(
    ':nid' => $node->nid,
  ));
  db_query("DELETE FROM {makemeeting_poll_heads} WHERE nid = :nid", array(
    ':nid' => $node->nid,
  ));
  db_query("DELETE FROM {makemeeting_poll_votes} WHERE poll_id = :poll_id", array(
    ':poll_id' => $node->nid,
  ));
}

/**
 * Implementation of hook_node_load()
 */
function node_makemeeting_load(&$nodes) {
  foreach ($nodes as &$node) {

    // load the poll days and options
    $days_and_options = array();
    $poll_head = db_query("SELECT * FROM {makemeeting_poll_heads} WHERE nid = :nid", array(
      ':nid' => $node->nid,
    ))
      ->fetchAssoc();
    $answer_result = db_query("SELECT * FROM {makemeeting_poll_rows} WHERE nid = :nid ORDER BY answer_id", array(
      ':nid' => $node->nid,
    ));
    foreach ($answer_result as $answer_row) {
      $options_result = db_query("SELECT * FROM {makemeeting_poll_alters} WHERE answer_id = :answer_id ORDER BY alter_id", array(
        ':answer_id' => $answer_row->answer_id,
      ));
      foreach ($options_result as $options_row) {
        $days_and_options[$answer_row->answer_id . "_" . $answer_row->answer_text][] = $options_row->alter_id . "_" . $options_row->alter_text;
      }
    }

    // load answers
    $answers = array();
    $votes_result = db_query("SELECT * FROM {makemeeting_poll_votes} WHERE poll_id = :poll_id ORDER BY dt", array(
      ':poll_id' => $node->nid,
    ));
    foreach ($votes_result as $votes_row) {
      $answers[$votes_row->user_name][$votes_row->answer_id] = $votes_row->answer_value;
    }
    $node->days_and_options = $days_and_options;
    $node->answers = $answers;
    $node->poll_type = $poll_head['poll_type'];
    $node->poll_url = $poll_head['url'];
    $node->poll_admin_url = $poll_head['admin_url'];
    $node->anonym_name = $poll_head['anonym_name'];
    $node->anonym_email = $poll_head['anonym_email'];
    $node->email_notification = $poll_head['email_notification'];
    $node->secure = $poll_head['secure'];
    $node->multiple_allowed = $poll_head['multiple_allowed'];
    $node->maybe_option = $poll_head['maybe_option'];
  }
}

/**
 * Implementation of hook_node_view()
 */
function node_makemeeting_view($node, $view_mode) {

  // We hide the poll body from the list site/node if it is not direct access
  // @TODO take this to another level, maybe hook_node_access
  if (!preg_match("/" . $node->poll_url . "/i", request_uri())) {
    $node->content = array();
  }
  else {
    $node->content['poll_form'] = drupal_get_form('makemeeting_pollpanel_form', $node);
    $node->content['poll_panel'] = array(
      "#markup" => theme('makemeeting_pollpanel', array(
        'node' => $node,
      )),
    );
  }
  return $node;
}

/**
 * The poll panel form
 */
function makemeeting_pollpanel_form($form, &$form_state, $node) {
  $form['add_your_vote'] = array(
    '#type' => 'fieldset',
    '#title' => t('Add your vote'),
    '#tree' => TRUE,
  );
  $attributes = array(
    'days_and_options' => isset($node->days_and_options) ? $node->days_and_options : NULL,
    'answers' => isset($node->answers) ? $node->answers : NULL,
    'multiple_allowed' => isset($node->multiple_allowed) ? $node->multiple_allowed : NULL,
    'maybe_option' => isset($node->maybe_option) ? $node->maybe_option : NULL,
    'secure' => isset($node->secure) ? $node->secure : NULL,
  );
  $form['add_your_vote']['pollpanel'] = array(
    '#type' => 'makemeeting_choices',
    '#title' => t('Add your vote'),
    '#attributes' => $attributes,
    '#default_value' => $attributes,
    '#description' => t('Choose your name and select the answers.'),
  );
  $form['node_id'] = array(
    '#type' => 'value',
    '#value' => $node->nid,
  );
  $form['poll_url'] = array(
    '#type' => 'value',
    '#value' => $node->poll_url,
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Submit'),
  );
  return $form;
}

/**
 * pollpanel_form validate function
 */
function makemeeting_pollpanel_form_validate($form, &$form_state) {
  $node = node_load($form_state['values']['node_id']);
  if ($form_state['values']['poll_url'] != $node->poll_url) {
    form_set_error('add_your_vote', t('Hacking attempt.'));
  }
  if ($form_state['input']['your_name'] == "") {
    form_set_error('pollpanel', t('You must enter your name.'));
  }
}

/**
 * pollpanel_form submit function
 */
function makemeeting_pollpanel_form_submit($form, &$form_state) {
  $node = node_load($form_state['values']['node_id']);
  $values = array(
    'user_name' => $form_state['values']['add_your_vote']['pollpanel']['name'],
    'poll_id' => $node->nid,
    'dt' => REQUEST_TIME,
  );
  if ($node->maybe_option == 1 || $node->multiple_allowed == 1) {

    // We are using $vote_value here
    foreach ($form_state['values']['add_your_vote']['pollpanel']['alter_ids'] as $alter_id => $vote_value) {
      $values['answer_id'] = $alter_id;
      $values['answer_value'] = $vote_value;
      db_insert('makemeeting_poll_votes')
        ->fields($values)
        ->execute();
    }
  }
  else {

    // $vote_value is 1 here -> checked is yes
    $values['answer_value'] = 1;
    foreach ($form_state['values']['add_your_vote']['pollpanel']['alter_ids'] as $alter_id) {
      $values['answer_id'] = $alter_id;
      db_insert('makemeeting_poll_votes')
        ->fields($values)
        ->execute();
    }
  }

  // Log
  makemeeting_insert_log($node->nid, $form_state['values']['add_your_vote']['pollpanel']['name']);

  // send notification email
  if ($node->email_notification == 1) {

    // if anonym and has valid email address
    if ($node->uid == 0) {
      if (valid_email_address($node->user_email)) {
        $params = array(
          'name' => $node->user_name == "" ? t("user") : $node->user_name,
          'poll_url' => $node->poll_url,
        );
        drupal_mail('makemeeting', 'new_vote', $node->user_mail, language_default(), $params);
      }
    }
    else {

      // if registered and has valid email address
      $account = user_load($node->uid);
      if (valid_email_address($account->mail)) {
        $params = array(
          'name' => $account->name,
          'poll_url' => $node->poll_url,
        );
        drupal_mail('makemeeting', 'new_vote', $account->mail, user_preferred_language($account), $params);
      }
    }
  }
  drupal_set_message(t("Succesfull."));
  return;
}

/**
 * hook_mail implementation
 */
function makemeeting_mail($key, &$message, $params) {
  $options = array(
    'langcode' => $message['language']->language,
  );
  switch ($key) {

    // send to friends the poll link
    case 'refer':
      $variables = array(
        '!site' => variable_get('site_name', 'Drupal'),
        '!nickname' => $params['name'],
        '!poll_owner' => $params['owner_name'],
        '!poll_link' => url('makemeeting/' . $params['poll_url'], array(
          "absolute" => TRUE,
        )),
      );
      $message['subject'] = t('Please vote at !site', $variables, $options);
      $message['body'][] = t('Dear !nickname,

please follow the link below to answer the question of !poll_owner.

!poll_link

Greetings,
!site', $variables, $options);
      break;

    // send notify to poll owner
    case 'new_vote':
      $variables = array(
        '!name' => $params['name'],
        '!site' => variable_get('site_name', 'Drupal'),
        '!poll_link' => url('makemeeting/' . $params['poll_url'], array(
          "absolute" => TRUE,
        )),
      );
      $message['subject'] = t('New vote on !site', $variables, $options);
      $message['body'][] = t('Dear !name,

somebody voted on your poll!
Check it at the following link:

!poll_link', $variables, $options);
      break;
    case 'create_new_poll':
      $variables = array(
        '!name' => $params['name'],
        '!site' => variable_get('site_name', 'Drupal'),
        '!poll_link' => url('makemeeting/' . $params['poll_url'], array(
          "absolute" => TRUE,
        )),
        '!admin_link' => url('makemeeting/' . $params['admin_url'], array(
          "absolute" => TRUE,
        )),
      );
      $message['subject'] = t('Created new poll');
      $message['body'][] = t("Dear !name,\n\nyour poll created successfull!\nYour poll's link are the following:\n\nPoll link: !poll_link\nAdmin link: !admin_link", $variables, $options);
      break;
  }
}

/**
 * makemeeting_insert_log()
 *
 * @return void
 */
function makemeeting_insert_log($nid, $username) {
  db_insert('makemeeting_poll_logs')
    ->fields(array(
    'nid',
    'username',
    'dt',
  ))
    ->values(array(
    $nid,
    $username,
    REQUEST_TIME,
  ))
    ->execute();
}

/**
 * makemeeting_update_poll()
 *
 * @return
 */
function makemeeting_update_poll($form, &$form_state, $node) {
  $type = node_type_get_type($node);
  if ($type->has_title) {
    $form['title'] = array(
      '#type' => 'textfield',
      '#title' => check_plain($type->title_label),
      '#required' => TRUE,
      '#default_value' => $node->title,
      '#weight' => -5,
    );
  }
  if ($type->has_body) {
    $form['body'] = array(
      '#type' => 'textarea',
      '#title' => check_plain($type->body_label),
      '#default_value' => isset($node->body) ? $node->body : '',
      '#rows' => 5,
    );
  }
  if (isset($node->nid) && $node->uid == 0) {
    $form['anonym'] = array(
      '#type' => 'fieldset',
      '#title' => t('Add your name and email'),
      '#tree' => TRUE,
    );
    $form['anonym']['user_name'] = array(
      '#type' => 'textfield',
      '#title' => t('Your name'),
      '#maxlength' => 100,
      '#default_value' => check_plain($node->anonym_name),
      '#description' => t('This is optional.'),
    );
    $form['anonym']['user_email'] = array(
      '#type' => 'textfield',
      '#title' => t('Your e-mail'),
      '#description' => t('This is optional, too. But if you add, we can send e-mail notification after every valid vote.'),
      '#default_value' => check_plain($node->anonym_email),
      '#maxlength' => 100,
    );
  }

  // translate the collected db datas into node data
  if (is_array($node->days_and_options)) {
    $attributes = array();
    $i = 1;
    foreach ($node->days_and_options as $days => $options_array) {
      $start_day = strpos($days, "_");
      $day_str = substr($days, $start_day + 1);
      $attributes['date_' . $i] = $day_str;
      foreach ($options_array as $k => $option) {
        $start_option = strpos($option, "_");
        $option_str = substr($option, $start_option + 1);
        $attributes['option_' . $i][] = $option_str;
      }
      $i++;
    }
  }
  else {
    $attributes = array(
      'date_1' => date("Y-m-d"),
      'option_1' => array(
        "",
        "",
      ),
    );
  }
  $form['calendar'] = array(
    '#type' => 'makemeeting_calendarselector',
    '#title' => t('Calendar test'),
    '#description' => t('Use the calendar above to select the days, then add the options for the days. For example select the day of tomorrow and add "AM", "PM" as options. You can use only upcoming days.'),
    '#attributes' => array(
      'selected_dates_and_options' => $attributes,
    ),
  );
  $form['poll_options'] = array(
    '#type' => 'fieldset',
    '#title' => t('Scheduler options'),
    '#tree' => TRUE,
  );
  $form['poll_options']['secure'] = array(
    '#type' => 'radios',
    '#title' => t('Show previous votes'),
    '#description' => t("Deny new voters to see the previous votes."),
    '#options' => array(
      '0' => t('Yes'),
      '1' => t('No'),
    ),
    '#default_value' => isset($node->secure) ? $node->secure : 0,
  );
  $form['poll_options']['maybe_option'] = array(
    '#type' => 'radios',
    '#title' => t('Maybe option'),
    '#description' => t("Voters can select maybe as answer too."),
    '#options' => array(
      '0' => t('Disabled'),
      '1' => t('Enabled'),
    ),
    '#default_value' => isset($node->maybe_option) ? $node->maybe_option : 0,
  );
  $form['poll_options']['multiple_allowed'] = array(
    '#type' => 'radios',
    '#title' => t('Multiple option is selectable per answers.'),
    '#options' => array(
      '0' => t('Disabled'),
      '1' => t('Enabled'),
    ),
    '#default_value' => isset($node->multiple_allowed) ? $node->multiple_allowed : 0,
  );
  $form['email'] = array(
    '#type' => 'fieldset',
    '#title' => t('E-mail notification'),
  );
  $form['email']['email_notification'] = array(
    '#type' => 'radios',
    '#title' => t('Send me an e-mail after every valid vote'),
    '#options' => array(
      '1' => t('Yes'),
      '0' => t('No'),
    ),
    '#default_value' => isset($node->email_notification) ? $node->email_notification : 0,
  );
  $form['poll_admin_url'] = array(
    '#type' => 'value',
    '#value' => $node->poll_admin_url,
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Submit'),
  );
  return $form;
}

/**
 * makemeeting_update_poll_submit()
 *
 * @return void
 */
function makemeeting_update_poll_submit($form, &$form_state) {

  // poll head
  $node_id = db_query("SELECT nid FROM {makemeeting_poll_heads} WHERE admin_url = :admin_url", array(
    ':admin_url' => $form_state['values']['poll_admin_url'],
  ))
    ->fetchField();
  $node = node_load($node_id);

  // save node options
  $node->title = $form_state['values']['title'];
  $node->body = $form_state['values']['body'];
  node_save($node);

  // save poll options
  db_update('makemeeting_poll_heads')
    ->fields(array(
    'anonym_name' => $form_state['values']['anonym']['user_name'],
    'anonym_email' => $form_state['values']['anonym']['user_email'],
    'email_notification' => $form_state['values']['email_notification'],
    'multiple_allowed' => $form_state['values']['poll_options']['multiple_allowed'],
    'secure' => $form_state['values']['poll_options']['secure'],
    'maybe_option' => $form_state['values']['poll_options']['maybe_option'],
  ))
    ->condition('nid', $node_id)
    ->execute();

  // days and options
  // collect the ids of the days which are already in the db
  $days_ids_result = db_query("SELECT answer_id FROM {makemeeting_poll_rows} WHERE nid = :nid", array(
    ':nid' => $node->nid,
  ));
  $days_ids = array();
  foreach ($days_ids_result as $row) {
    $days_ids[] = $row->answer_id;
  }

  // insert and update days and options datas
  $i = 0;
  foreach ($form_state['values']['calendar'] as $day => $options_array) {

    // get the first id in the db
    $current_answer_id = $days_ids[$i++];

    // if we have an option in this position, we updating it
    if ($current_answer_id > 0) {
      db_update('makemeeting_poll_rows')
        ->fields(array(
        'answer_text' => $day,
      ))
        ->condition('answer_id', $current_answer_id)
        ->execute();
      $answer_id = $current_answer_id;
    }
    else {

      // else we insert a new row with the new day
      $answer_id = db_insert('makemeeting_poll_rows')
        ->fields(array(
        'nid',
        'answer_text',
        'type',
      ), array(
        $node->nid,
        $day,
        1,
      ))
        ->execute();
    }

    // at here we have in $answer_id the acutal day, so we updating the day's option
    // the method is the same
    // collecting the options ids for the day
    $options_ids_result = db_query("SELECT alter_id FROM {makemeeting_poll_alters} WHERE answer_id = :answer_id", array(
      ':answer_id' => $answer_id,
    ));
    $options_ids = array();
    foreach ($options_ids_result as $row) {
      $options_ids[] = $row->alter_id;
    }

    // drive through the options array, and update the old or insert the new one
    $j = 0;
    foreach ($options_array as $option) {
      $current_alter_id = $options_ids[$j++];
      if ($current_alter_id > 0) {
        db_query("UPDATE {makemeeting_poll_alters} SET alter_text = '%s' WHERE alter_id = %d", $option, $current_alter_id);
      }
      else {
        db_query("INSERT INTO {makemeeting_poll_alters} (answer_id, alter_text) VALUES (%d, '%s')", $answer_id, $option);
      }
    }

    // if there is some unused id in $options_ids, that's mean we deleted them
    while ($j < sizeof($options_ids)) {
      db_query("DELETE FROM {makemeeting_poll_alters} WHERE alter_id = :alter_id", array(
        ':alter_id' => $options_ids[$j],
      ));
      $j++;
    }
  }

  // if there is some unused id in $days_ids, that's mean we deleted them
  while ($i < sizeof($days_ids)) {
    db_query("DELETE FROM {makemeeting_poll_rows} WHERE answer_id = :answer_id", array(
      ':answer_id' => $days_ids[$i],
    ));
    $i++;
  }
  drupal_set_message(t("Saved."));
  drupal_goto('makemeeting/' . $form_state['values']['poll_admin_url']);
}

/**
 * makemeeting_sendfw_form()
 *
 * @return
 */
function makemeeting_sendfw_form($form, &$form_state, $node) {
  $form['sendfw'] = array(
    '#type' => 'fieldset',
    '#title' => t('Add your friends e-mail addresses'),
    '#tree' => TRUE,
  );
  for ($i = 0; $i < 5; $i++) {
    $form['sendfw']['address_' . $i] = array(
      '#type' => 'textfield',
      '#title' => t('E-mail address #@num', array(
        "@num" => $i + 1,
      )),
      '#maxlength' => 100,
    );
  }
  $form['sendfw']['poll_url'] = array(
    '#type' => 'value',
    '#value' => $node->poll_url,
  );
  $form['sendfw']['submit_bt'] = array(
    '#type' => 'submit',
    '#value' => t('Send'),
  );
  return $form;
}

/**
 * makemeeting_sendfw_form_submit()
 *
 * @return void
 */
function makemeeting_sendfw_form_submit($form, &$form_state) {

  // load node
  $node_id = db_query("SELECT nid FROM {makemeeting_poll_heads} WHERE url = :url", array(
    ':url' => $form['#post']['sendfw']['poll_url'],
  ))
    ->fetchField();
  $node = node_load($node_id);

  // owner name
  if ($node->uid == 0) {
    $owner_name = $node->user_name == "" ? t("user") : $node->user_name;
  }
  else {
    $account = user_load($node->uid);
    $owner_name = $account->name;
  }

  // mail params
  $mail_params = array(
    "name" => t("user"),
    "owner_name" => $owner_name,
    "poll_url" => $node->poll_url,
  );

  // send emails
  for ($i = 0; $i < 5; $i++) {
    if (!empty($form['#post']['sendfw']['address_' . $i])) {
      $email = $form['#post']['sendfw']['address_' . $i];
      drupal_mail('makemeeting', 'refer', $email, language_default(), $mail_params);
    }
  }
  drupal_set_message(t("Mail sent."));
}

/**
 * makemeeting_sendfw_form_validate()
 *
 * @return void
 */
function makemeeting_sendfw_form_validate($form_id, $form_values) {
  for ($i = 0; $i < 5; $i++) {
    if (!empty($form_values['values']['sendfw']['address_' . $i])) {
      if (!valid_email_address($form_values['values']['sendfw']['address_' . $i])) {
        form_set_error('sendfw[address_' . $i . ']', t('E-mail #@count is not valid', array(
          "@count" => $i + 1,
        )));
      }
    }
  }
}

/**
 * Helper function to generate a unique keychain
 *
 * @param $field
 *    The field to be unique
 * @param $length
 *    Lengh of the keychain
 * @return string
 */
function _makemeeting_generate_url($field, $length) {
  $url = _makemeeting_keygen($length);
  $query = db_select('makemeeting_poll_heads', 'm')
    ->fields('m');
  while ($query
    ->condition($field, $url)
    ->execute()
    ->rowCount() > 0) {
    $url = _makemeeting_keygen($length);
  }
  return $url;
}

/**
 * Helper function to generate a keychain
 *
 * @param $length
 *    Lengh of the keychain
 * @return string
 */
function _makemeeting_keygen($length) {
  $pattern = "1234567890abcdefghijklmnopqrstuvwxyz";
  $key = $pattern[rand(0, 35)];
  for ($i = 1; $i < $length; $i++) {
    $key .= $pattern[rand(0, 35)];
  }
  return $key;
}

/**
 * Implements hook_menu_alter()
 */
function makemeeting_menu_alter(&$items) {
  $items['node/%node']['page callback'] = 'makemeeting_page_view';
}

/**
 * Wrapper around node_page_view().
 */
function makemeeting_page_view($node) {
  if ($node->type == 'makemeeting') {
    global $user;
    if ($user->uid == $node->uid || $user->uid == 1) {
      return node_page_view($node);
    }
    else {

      // Avoid display of node/NID pages to prevent data leakage
      return drupal_access_denied();
    }
  }
  else {
    return node_page_view($node);
  }
}

Functions

Namesort descending Description
form_type_makemeeting_calendarselector_value Fetch the values from the makemeeting_calendarselector form element
form_type_makemeeting_choices_value Fetch the values from the makemeeting_choices form element
makemeeting_element_info hook_elements implementation
makemeeting_form_alter Implementation of hook_form_alter()
makemeeting_insert_log makemeeting_insert_log()
makemeeting_mail hook_mail implementation
makemeeting_menu hook_menu implementation
makemeeting_menu_alter Implements hook_menu_alter()
makemeeting_node_access Implementation of hook_node_access()
makemeeting_node_info Implementation of hook_node_info()
makemeeting_page_view Wrapper around node_page_view().
makemeeting_permission hook_perm implementation
makemeeting_pollpanel_form The poll panel form
makemeeting_pollpanel_form_submit pollpanel_form submit function
makemeeting_pollpanel_form_validate pollpanel_form validate function
makemeeting_preprocess_makemeeting_choices Preprocess for makemeeting choices
makemeeting_sendfw_form makemeeting_sendfw_form()
makemeeting_sendfw_form_submit makemeeting_sendfw_form_submit()
makemeeting_sendfw_form_validate makemeeting_sendfw_form_validate()
makemeeting_theme hook_theme implementation
makemeeting_update_poll makemeeting_update_poll()
makemeeting_update_poll_submit makemeeting_update_poll_submit()
node_makemeeting_delete Implementation of hook_node_delete()
node_makemeeting_form Implementation of hook_node_form()
node_makemeeting_insert Implementation of hook_node_insert()
node_makemeeting_load Implementation of hook_node_load()
node_makemeeting_view Implementation of hook_node_view()
_makemeeting_access_userpolls
_makemeeting_calendarselector_process Process the makemeeting_calendarselector element before rendering
_makemeeting_choices_process Process the makemeeting_choices element before rendering
_makemeeting_generate_url Helper function to generate a unique keychain
_makemeeting_keygen Helper function to generate a keychain