| 1 |
<?php
|
| 2 |
// $Id: volunteer_timeslots.module,v 1.18 2007/02/17 02:13:50 pwolanin Exp $
|
| 3 |
|
| 4 |
/**
|
| 5 |
* @file
|
| 6 |
* Enables creation of an event where volunteers can sign up for particular time slots
|
| 7 |
*/
|
| 8 |
|
| 9 |
/**
|
| 10 |
* Implementation of hook_help().
|
| 11 |
*/
|
| 12 |
function volunteer_timeslots_help($section) {
|
| 13 |
switch ($section) {
|
| 14 |
case 'admin/settings/volunteer_timeslots':
|
| 15 |
return t('A node type representing an event with timeslots where users can sign up to volunteer');
|
| 16 |
}
|
| 17 |
}
|
| 18 |
|
| 19 |
/**
|
| 20 |
* Implementation of hook_node_info().
|
| 21 |
*/
|
| 22 |
function volunteer_timeslots_node_info() {
|
| 23 |
return array('volunteer_timeslots' => array(
|
| 24 |
'name' => t('Event with volunteer timeslots'),
|
| 25 |
'module' => 'volunteer_timeslots',
|
| 26 |
'description' => t("A content type for signing up volunteers for an event.")));
|
| 27 |
}
|
| 28 |
|
| 29 |
/**
|
| 30 |
* Implementation of hook_perm().
|
| 31 |
*/
|
| 32 |
function volunteer_timeslots_perm() {
|
| 33 |
return array('create volunteer events', 'edit own volunteer events', 'administer volunteer events');
|
| 34 |
}
|
| 35 |
|
| 36 |
/**
|
| 37 |
* menu callback to settings page.
|
| 38 |
*/
|
| 39 |
function volunteer_timeslots_settings() {
|
| 40 |
|
| 41 |
$form['volunteer_timeslots_organizer_updates'] = array(
|
| 42 |
'#type' => 'checkbox',
|
| 43 |
'#title' => t("Allow each event's organizer(s) to edit the event"),
|
| 44 |
'#default_value' => variable_get('volunteer_timeslots_organizer_updates', TRUE),
|
| 45 |
'#description' => t('If set, every user designated as an organizer of a volunteer event can edit that node.'),
|
| 46 |
);
|
| 47 |
|
| 48 |
$form['volunteer_timeslots_author_manages'] = array(
|
| 49 |
'#type' => 'checkbox',
|
| 50 |
'#title' => t("Allow each event's author to manage (add and remove) volunteers for the event"),
|
| 51 |
'#default_value' => variable_get('volunteer_timeslots_author_manages', TRUE),
|
| 52 |
'#description' => t("If set, the node author has the same ability as the event's organizer(s) to add or remove volunteers on the schedule."),
|
| 53 |
);
|
| 54 |
|
| 55 |
$hours = array(
|
| 56 |
-100 => t('never'),
|
| 57 |
6*60 => t('!s hours', array('!s' => '6')),
|
| 58 |
12*60 => t('!s hours', array('!s' => '12')),
|
| 59 |
18*60 => t('!s hours', array('!s' => '18')),
|
| 60 |
24*60 => t('!s hours', array('!s' => '24')),
|
| 61 |
36*60 => t('!s hours', array('!s' => '36')),
|
| 62 |
48*60 => t('!s hours', array('!s' => '48')),
|
| 63 |
72*60 => t('!s hours', array('!s' => '72')),
|
| 64 |
);
|
| 65 |
$form['volunteer_timeslots_remind_time'] = array(
|
| 66 |
'#type' => 'select',
|
| 67 |
'#title' => t('Number of hours in advance to send event reminder e-mails'),
|
| 68 |
'#default_value' => variable_get('volunteer_timeslots_remind_time', 36*60),
|
| 69 |
'#options' => $hours,
|
| 70 |
'#description' => t('This sets the maximum possible time before an event that the reminder e-mail will be sent. The actual time the e-mail is set depnds upon when and how often cron.php is executed on your system. Choose %s to disable automatic e-mail reminders', array('%s' => t('never'))),
|
| 71 |
);
|
| 72 |
if (module_exists('profile')) {
|
| 73 |
$result = db_query('SELECT * FROM {profile_fields} WHERE visibility != %d ORDER BY category, weight', PROFILE_HIDDEN);
|
| 74 |
while ($field = db_fetch_object($result)) {
|
| 75 |
$options[$field->name] = $field->title;
|
| 76 |
}
|
| 77 |
$form['volunteer_timeslots_profile_fields'] = array (
|
| 78 |
'#type' => 'checkboxes',
|
| 79 |
'#title' => t('User profile fields to include in the volunteer list for organizers'),
|
| 80 |
'#default_value' => variable_get('volunteer_timeslots_profile_fields', array()),
|
| 81 |
'#options' => $options,
|
| 82 |
);
|
| 83 |
$form['array_filter'] = array('#type' => 'value', '#value' => TRUE);
|
| 84 |
}
|
| 85 |
else {
|
| 86 |
$form['volunteer_timeslots_profile_note'] = array (
|
| 87 |
'#value' => '<p>'. t('Note: if you enable the profile module, you will be able to select profile fields to show in the volunteer roster.').'</p>',);
|
| 88 |
}
|
| 89 |
return system_settings_form($form);
|
| 90 |
}
|
| 91 |
|
| 92 |
|
| 93 |
|
| 94 |
/**
|
| 95 |
* Implementation of hook_access().
|
| 96 |
*/
|
| 97 |
function volunteer_timeslots_access($op, $node) {
|
| 98 |
global $user;
|
| 99 |
|
| 100 |
if ($op == 'create') {
|
| 101 |
return user_access('create volunteer events');
|
| 102 |
}
|
| 103 |
$delete_perm = (user_access('administer volunteer events') ||
|
| 104 |
(user_access('edit own volunteer events') && ($user->uid == $node->uid)));
|
| 105 |
if ($op == 'delete') {
|
| 106 |
if ($delete_perm) {
|
| 107 |
return TRUE;
|
| 108 |
}
|
| 109 |
}
|
| 110 |
if ($op == 'update') { //note- check against $node->validated work-around allows organizers to remove themselves from the list of organizers
|
| 111 |
if ($delete_perm ||
|
| 112 |
(variable_get('volunteer_timeslots_organizer_updates', TRUE) && (in_array($user->uid, $node->timeslots_organizers) || $node->validated))) {
|
| 113 |
return TRUE;
|
| 114 |
}
|
| 115 |
}
|
| 116 |
}
|
| 117 |
|
| 118 |
/**
|
| 119 |
* Implementation of hook_menu().
|
| 120 |
*/
|
| 121 |
function volunteer_timeslots_menu($may_cache) {
|
| 122 |
$items = array();
|
| 123 |
|
| 124 |
if ($may_cache) {
|
| 125 |
$items[] = array(
|
| 126 |
'path' => 'admin/settings/volunteer_timeslots',
|
| 127 |
'title' => t('Event with volunteer timeslots'),
|
| 128 |
'description' => t('Configure the volunteer timeslots.'),
|
| 129 |
'callback' => 'drupal_get_form',
|
| 130 |
'callback arguments' => 'volunteer_timeslots_settings',
|
| 131 |
'access' => user_access('administer site configuration'),
|
| 132 |
);
|
| 133 |
$items[] = array(
|
| 134 |
'path' => 'multiuser/autocomplete',
|
| 135 |
'title' => t('multiuser autocomplete'),
|
| 136 |
'callback' => 'multiuser_autocomplete',
|
| 137 |
'access' => user_access('access user profiles'),
|
| 138 |
'type' => MENU_CALLBACK,
|
| 139 |
);
|
| 140 |
}
|
| 141 |
else {
|
| 142 |
drupal_add_css(drupal_get_path('module', 'volunteer_timeslots') .'/volunteer_timeslots.css', 'module');
|
| 143 |
}
|
| 144 |
|
| 145 |
return $items;
|
| 146 |
}
|
| 147 |
|
| 148 |
function multiuser_autocomplete($string) {
|
| 149 |
// The user enters a comma-separated list of usernames. We only autocomplete the last one.
|
| 150 |
$array = explode(',',$string);
|
| 151 |
// Fetch last username
|
| 152 |
$last = trim(array_pop($array));
|
| 153 |
if ($last != '') {
|
| 154 |
$prefix = count($array) ? implode(',', $array) .', ' : '';
|
| 155 |
$matches = array();
|
| 156 |
$result = db_query_range("SELECT name FROM {users} WHERE status = 1 AND LOWER(name) LIKE LOWER('%s%%')", $last, 0, 10);
|
| 157 |
|
| 158 |
while ($user = db_fetch_object($result)) {
|
| 159 |
$matches[$prefix. $user->name] = check_plain($user->name);
|
| 160 |
}
|
| 161 |
print drupal_to_js($matches);
|
| 162 |
exit();
|
| 163 |
}
|
| 164 |
}
|
| 165 |
|
| 166 |
function timeslots_node_form_validate($form_id, $form_values, $form) {
|
| 167 |
$names = explode(',', $form_values['timeslots_organizers']);
|
| 168 |
foreach($names as $n) { // username validation
|
| 169 |
$n = trim($n);
|
| 170 |
if (!user_load(array('name' => $n, 'status' => 1))) {
|
| 171 |
form_set_error('timeslots_organizers', t('The username %name does not exist or is blocked.', array ('%name' => $n)));
|
| 172 |
}
|
| 173 |
}
|
| 174 |
}
|
| 175 |
|
| 176 |
/**
|
| 177 |
* Implementation of hook_form().
|
| 178 |
*/
|
| 179 |
function volunteer_timeslots_form(&$node) {
|
| 180 |
global $user;
|
| 181 |
$form['title'] = array(
|
| 182 |
'#type' => 'textfield',
|
| 183 |
'#title' => t('Title'),
|
| 184 |
'#required' => TRUE,
|
| 185 |
'#default_value' => $node->title,
|
| 186 |
'#weight' => -25,
|
| 187 |
'#description' => t('A brief title for your event for the calendar listing.'),
|
| 188 |
);
|
| 189 |
if (variable_get('event_nodeapi_volunteer_timeslots', 'never') == 'never') {
|
| 190 |
$form['message'] = array(
|
| 191 |
'#value' => t("You must have the event module enabled and make sure the type '%type' to selected to appear in the events calendar.", array( '%type' => t('Event with volunteer timeslots'))),
|
| 192 |
);
|
| 193 |
}
|
| 194 |
else {
|
| 195 |
$form['#validate']['timeslots_node_form_validate'] = array();
|
| 196 |
$form['timeslots'] = array(
|
| 197 |
'#type' => 'fieldset',
|
| 198 |
'#title' => t('Set up the timeslots for volunteers and the organizer for this event'),
|
| 199 |
'#collapsible' => TRUE,
|
| 200 |
'#collapsed' => FALSE,
|
| 201 |
'#weight' => -10,
|
| 202 |
);
|
| 203 |
if (!isset($node->timeslot_data)) {
|
| 204 |
$node->timeslot_data = array();
|
| 205 |
}
|
| 206 |
|
| 207 |
if (!empty($node->timeslots_organizers)) {
|
| 208 |
$names = array();
|
| 209 |
foreach ($node->timeslots_organizers as $uid) {
|
| 210 |
$account = user_load(array('uid' => $uid));
|
| 211 |
$names[] = $account->name;
|
| 212 |
}
|
| 213 |
$org_names = implode(', ',$names);
|
| 214 |
}
|
| 215 |
else {
|
| 216 |
$org_names = '';
|
| 217 |
}
|
| 218 |
|
| 219 |
$form['timeslots']['timeslots_organizers'] = array(
|
| 220 |
'#type' => 'textfield',
|
| 221 |
'#maxlength' => 255,
|
| 222 |
'#autocomplete_path' => 'multiuser/autocomplete',
|
| 223 |
'#title' => t('@s username of the event organizer', array('@s' => variable_get('site_name', 'local'))),
|
| 224 |
'#default_value' => $org_names,
|
| 225 |
'#description' => t("For example: %name. To specify multiple organizers, separate each username with a comma.", array('%name' => $user->name)),
|
| 226 |
'#required' => TRUE,
|
| 227 |
);
|
| 228 |
$period = drupal_map_assoc(array(60*15, 60*30, 60*45, 60*60, 60*90, 60*120, 60*150, 60*180, 60*180, 60*240, 60*300, 60*360, 60*420, 60*480), 'format_interval');
|
| 229 |
$form['timeslots']['timeslot_length'] = array(
|
| 230 |
'#type' => 'select',
|
| 231 |
'#title' => t('Length of each time slot'),
|
| 232 |
'#default_value' => isset($node->timeslot_length) ? $node->timeslot_length : 60*60,
|
| 233 |
'#options' => $period,
|
| 234 |
);
|
| 235 |
$numbers = drupal_map_assoc(array(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,20));
|
| 236 |
$form['timeslots']['num_volunteers'] = array(
|
| 237 |
'#type' => 'select',
|
| 238 |
'#title' => t('Number of volunteers in each time slot'),
|
| 239 |
'#default_value' => isset($node->num_volunteers) ? $node->num_volunteers : 1,
|
| 240 |
'#options' => $numbers,
|
| 241 |
'#description' => t('The volunteer form will have this number of volunteer spots in each time slot.'),
|
| 242 |
);
|
| 243 |
$form['timeslot_data'] = array(
|
| 244 |
'#type' => 'value',
|
| 245 |
'#value' => $node->timeslot_data,
|
| 246 |
);
|
| 247 |
if (user_access('administer volunteer events')) {
|
| 248 |
$form['administer'] = array(
|
| 249 |
'#type' => 'fieldset',
|
| 250 |
'#title' => t('Administer volunteers'),
|
| 251 |
'#collapsible' => TRUE,
|
| 252 |
'#collapsed' => TRUE,
|
| 253 |
'#weight' => -9,
|
| 254 |
);
|
| 255 |
$form['administer']['clear_volunteers'] = array(
|
| 256 |
'#type' => 'checkbox',
|
| 257 |
'#title' => t('Clear all volunteers'),
|
| 258 |
);
|
| 259 |
}
|
| 260 |
}
|
| 261 |
$form['body_filter']['body'] = array(
|
| 262 |
'#type' => 'textarea',
|
| 263 |
'#title' => t('volunteer event description'),
|
| 264 |
'#default_value' => $node->body,
|
| 265 |
'#rows' => 10,
|
| 266 |
'#required' => TRUE
|
| 267 |
);
|
| 268 |
$form['body_filter']['format'] = filter_form($node->format);
|
| 269 |
return $form;
|
| 270 |
}
|
| 271 |
|
| 272 |
/**
|
| 273 |
* Implementation of hook_load().
|
| 274 |
*/
|
| 275 |
function volunteer_timeslots_load($node) {
|
| 276 |
$values = db_fetch_array(db_query("SELECT * FROM {volunteer_timeslots} WHERE vid = %d", $node->vid));
|
| 277 |
$values['timeslot_data'] = unserialize($values['timeslot_data']);
|
| 278 |
$values['timeslots_organizers'] = explode(',', $values['timeslots_organizers']);
|
| 279 |
return $values;
|
| 280 |
}
|
| 281 |
|
| 282 |
|
| 283 |
/**
|
| 284 |
* Implementation of hook_view().
|
| 285 |
*
|
| 286 |
*/
|
| 287 |
function volunteer_timeslots_view(&$node, $teaser = FALSE, $page = FALSE) {
|
| 288 |
global $user;
|
| 289 |
|
| 290 |
$node = node_prepare($node, $teaser);
|
| 291 |
|
| 292 |
if (!$teaser) {
|
| 293 |
$admin = (user_access('administer volunteer events') ||
|
| 294 |
(($user->uid == $node->uid) && variable_get('volunteer_timeslots_author_manages', TRUE)) ||
|
| 295 |
in_array($user->uid, $node->timeslots_organizers)); //user is allowed to remove/add volunteers
|
| 296 |
$node->content['timeslots_signup_form'] = array(
|
| 297 |
'#value' => drupal_get_form('_timeslots_signup_form', $node, $admin),
|
| 298 |
'#weight' => 10,);
|
| 299 |
|
| 300 |
if ($admin) {
|
| 301 |
$node->content['timeslots_roster_form'] = array(
|
| 302 |
'#value' => drupal_get_form('_timeslots_roster_form', $node),
|
| 303 |
'#weight' => 20,);
|
| 304 |
}
|
| 305 |
|
| 306 |
}
|
| 307 |
|
| 308 |
return $node;
|
| 309 |
}
|
| 310 |
|
| 311 |
/**
|
| 312 |
* Generates each event's volunteer roster including textfields to record notes
|
| 313 |
*
|
| 314 |
*/
|
| 315 |
function _timeslots_roster_form($node) {
|
| 316 |
|
| 317 |
if (!count($node->timeslot_data[0]['all_volunteers'])) {
|
| 318 |
return array();
|
| 319 |
}
|
| 320 |
|
| 321 |
$form = array(
|
| 322 |
'#theme' => 'timeslots_roster_form',
|
| 323 |
'#tree' => TRUE,
|
| 324 |
);
|
| 325 |
|
| 326 |
$form['nid'] = array('#type' => 'value', '#value' => $node->nid);
|
| 327 |
|
| 328 |
$header = array("Username");
|
| 329 |
if ($profile = module_exists('profile')) {
|
| 330 |
$fields = variable_get('volunteer_timeslots_profile_fields', array());
|
| 331 |
}
|
| 332 |
foreach ($node->timeslot_data[0]['all_volunteers'] as $uid) {
|
| 333 |
if ($account = user_load(array('uid' => $uid))) {
|
| 334 |
$form['info'][$uid]['username'] = array('#value' => $account->name);
|
| 335 |
if ($profile) {
|
| 336 |
foreach ($fields as $profile_field) {
|
| 337 |
$form['info'][$uid][$profile_field] = array('#value' => $account->$profile_field);
|
| 338 |
}
|
| 339 |
}
|
| 340 |
$form['notes'][$uid] = array(
|
| 341 |
'#type' => 'textfield',
|
| 342 |
'#size' => 30,
|
| 343 |
'#default_value' => (isset($node->timeslot_data[0]['notes'][$uid])) ? $node->timeslot_data[0]['notes'][$uid] : '',
|
| 344 |
);
|
| 345 |
}
|
| 346 |
}
|
| 347 |
if ($profile) {
|
| 348 |
$result = db_query("SELECT * FROM {profile_fields} p WHERE p.name in ('". implode("','", $fields). "') ORDER BY p.category, p.weight");
|
| 349 |
|
| 350 |
while ($pf = db_fetch_object($result)) {
|
| 351 |
$header[] = $pf->title;
|
| 352 |
}
|
| 353 |
}
|
| 354 |
$header[] = t('Notes');
|
| 355 |
|
| 356 |
$form['header'] = array(
|
| 357 |
'#type' => 'value',
|
| 358 |
'#value' => $header,
|
| 359 |
);
|
| 360 |
$form['submit'] = array(
|
| 361 |
'#type' => 'submit',
|
| 362 |
'#value' => t('Update notes'),
|
| 363 |
'#attributes' => array('class' => 'volunteer-timeslots'),
|
| 364 |
);
|
| 365 |
return $form;
|
| 366 |
}
|
| 367 |
|
| 368 |
function theme_timeslots_roster_form($form) {
|
| 369 |
|
| 370 |
foreach (element_children($form['info']) as $uid) {
|
| 371 |
$items = array();
|
| 372 |
foreach (element_children($form['info'][$uid]) as $profile_field) {
|
| 373 |
$items[] = drupal_render($form['info'][$uid][$profile_field]);
|
| 374 |
}
|
| 375 |
$items[] = array('data'=> drupal_render($form['notes'][$uid]));
|
| 376 |
$rows[] = $items;
|
| 377 |
}
|
| 378 |
|
| 379 |
$output = theme('table', $form['header']['#value'], $rows, array('class' => 'volunteer-timeslots'), t('Volunteer roster'));
|
| 380 |
return $output. drupal_render($form);
|
| 381 |
}
|
| 382 |
|
| 383 |
|
| 384 |
function _timeslots_roster_form_submit($form_id, $form_values) {
|
| 385 |
$node = node_load($form_values['nid']);
|
| 386 |
if ($form_values['notes'] == $node->timeslot_data[0]['notes']) {
|
| 387 |
drupal_set_message(t('No changes were made.'));
|
| 388 |
return;
|
| 389 |
}
|
| 390 |
|
| 391 |
$node->timeslot_data[0]['notes'] = array(); //clear old notes
|
| 392 |
foreach ($form_values['notes'] as $uid => $note) {
|
| 393 |
$node->timeslot_data[0]['notes'][$uid] = $note;
|
| 394 |
}
|
| 395 |
$node->revision = TRUE;
|
| 396 |
node_save($node);
|
| 397 |
drupal_set_message(t('Your changes to the notes were made.'));
|
| 398 |
}
|
| 399 |
|
| 400 |
function _timeslots_signup_form($node, $admin) {
|
| 401 |
global $user;
|
| 402 |
$form = array(
|
| 403 |
'#theme' => 'timeslots_signup_form',
|
| 404 |
'#tree' => TRUE,
|
| 405 |
);
|
| 406 |
$none = theme('placeholder', t('volunteer needed'));
|
| 407 |
|
| 408 |
$form['nid'] = array('#type' => 'value', '#value' => $node->nid);
|
| 409 |
|
| 410 |
$access = user_access('access user profiles');
|
| 411 |
|
| 412 |
if (count($node->timeslot_data[0]['all_volunteers'])) {
|
| 413 |
$result = db_query("SELECT * FROM {users} WHERE uid in (". implode(',', $node->timeslot_data[0]['all_volunteers']). ")");
|
| 414 |
while ($account = db_fetch_object($result)) {
|
| 415 |
$users[$account->uid] = $account;
|
| 416 |
}
|
| 417 |
}
|
| 418 |
$box = FALSE; //flag to see if we have any checkbox elements in the form
|
| 419 |
$openings = array();
|
| 420 |
$form['num_slots'] = array( '#type' => 'value', '#value' => count($node->timeslot_data));
|
| 421 |
foreach ($node->timeslot_data as $slot => $data) {
|
| 422 |
$form['timeslot'][$slot]['start_time'] = array(
|
| 423 |
'#value' => format_date($data['start_time'], 'custom', 'g:i a', $node->start_offset),
|
| 424 |
);
|
| 425 |
$form['timeslot'][$slot]['end_time'] = array(
|
| 426 |
'#value' => format_date($data['end_time'], 'custom', 'g:i a', $node->start_offset),
|
| 427 |
);
|
| 428 |
if (count($data['volunteers']) < $node->num_volunteers) {
|
| 429 |
$openings[$slot] = $form['timeslot'][$slot]['start_time']['#value'];
|
| 430 |
}
|
| 431 |
if ($user->uid && ($node->event_end > time()) &&
|
| 432 |
(($checked = in_array($user->uid, $data['volunteers'])) || (isset($openings[$slot])))) {
|
| 433 |
$form['timeslot'][$slot]['box'] = array(
|
| 434 |
'#type' => 'checkbox',
|
| 435 |
'#default_value' => $checked,
|
| 436 |
);
|
| 437 |
$form['timeslot'][$slot]['was_checked'] = array(
|
| 438 |
'#type' => 'value',
|
| 439 |
'#value' => $checked,
|
| 440 |
);
|
| 441 |
$box = TRUE;
|
| 442 |
}
|
| 443 |
else {
|
| 444 |
$form['timeslot'][$slot]['box'] = array( '#value' => '', );
|
| 445 |
}
|
| 446 |
for ($i = 0; $i < $node->num_volunteers; $i++) {
|
| 447 |
$set = isset($data['volunteers'][$i]);
|
| 448 |
if (!$set) {
|
| 449 |
$name = $none;
|
| 450 |
}
|
| 451 |
elseif ($access) {
|
| 452 |
$name = l($users[$data['volunteers'][$i]]->name, 'user/'. $users[$data['volunteers'][$i]]->uid);;
|
| 453 |
}
|
| 454 |
else {
|
| 455 |
$name = $users[$data['volunteers'][$i]]->name;
|
| 456 |
}
|
| 457 |
$form['timeslot'][$slot]['name'][$i] = array(
|
| 458 |
'#value' => $name,
|
| 459 |
);
|
| 460 |
if ($set && $admin) {
|
| 461 |
$form['timeslot'][$slot]['remove'][$i] = array(
|
| 462 |
'#type' => 'checkbox',
|
| 463 |
'#return_value' => $users[$data['volunteers'][$i]]->uid,
|
| 464 |
);
|
| 465 |
}
|
| 466 |
else {
|
| 467 |
$form['timeslot'][$slot]['remove'][$i] = array('#type' => 'value', '#value' => 0, );
|
| 468 |
}
|
| 469 |
}
|
| 470 |
}
|
| 471 |
$form['event_end'] = array(
|
| 472 |
'#value' => t('The event ends %time.', array( '%time' => format_date($node->event_end, 'custom', 'D, g:i a', $node->end_offset))),
|
| 473 |
);
|
| 474 |
$form['box'] = array(
|
| 475 |
'#type' => 'value',
|
| 476 |
'#value' => $box,
|
| 477 |
);
|
| 478 |
$form['admin'] = array(
|
| 479 |
'#type' => 'value',
|
| 480 |
'#value' => $admin,
|
| 481 |
);
|
| 482 |
if ($admin) {
|
| 483 |
if (count($openings)) {
|
| 484 |
$form['add_volunteer'] = array(
|
| 485 |
'#type' => 'fieldset',
|
| 486 |
'#title' => t('Add a volunteer to the schedule'),
|
| 487 |
'#collapsible' => TRUE,
|
| 488 |
'#collapsed' => TRUE,
|
| 489 |
'#prefix' => '<div class="volunteer-timeslots">',
|
| 490 |
'#suffix' => '</div>',
|
| 491 |
);
|
| 492 |
$form['add_volunteer']['name'] = array(
|
| 493 |
'#type' => 'textfield',
|
| 494 |
'#maxlength' => 60,
|
| 495 |
'#autocomplete_path' => 'user/autocomplete',
|
| 496 |
|
| 497 |
'#description' => t("Enter a %s username. For example: %name.", array('%s' => variable_get('site_name', 'local'), '%name' => $user->name)),
|
| 498 |
);
|
| 499 |
$form['add_volunteer']['slot'] = array(
|
| 500 |
'#type' => 'select',
|
| 501 |
'#options' => $openings,
|
| 502 |
'#description' => t("The time slot to add the volunteer"),
|
| 503 |
);
|
| 504 |
}
|
| 505 |
else {
|
| 506 |
$form['no_openings'] = array(
|
| 507 |
'#value' => t('There are no open slots in the schedule.'),
|
| 508 |
);
|
| 509 |
}
|
| 510 |
}
|
| 511 |
if ($box || $admin) {
|
| 512 |
$form['send_me'] = array(
|
| 513 |
'#type' => 'checkbox',
|
| 514 |
'#title' => t("Send me a copy of this event's information"),
|
| 515 |
'#default_value' => !$admin, //checked by default except for admins/organizers
|
| 516 |
'#attributes' => array('class' => 'volunteer-timeslots'),
|
| 517 |
);
|
| 518 |
$form['submit'] = array(
|
| 519 |
'#type' => 'submit',
|
| 520 |
'#value' => t('Submit'),
|
| 521 |
'#attributes' => array('class' => 'volunteer-timeslots'),
|
| 522 |
);
|
| 523 |
$form['submit_info'] = array(
|
| 524 |
'#value' => '<p>'. t('After checking or unchecking boxes, click on the submit button to add your username, %name, to the schedule or to make the changes.', array('%name' => $user->name)). '</p>',
|
| 525 |
);
|
| 526 |
}
|
| 527 |
return $form;
|
| 528 |
}
|
| 529 |
|
| 530 |
function _timeslots_signup_form_validate($form_id, $form_values, $form) {
|
| 531 |
|
| 532 |
$node = node_load($form_values['nid']);
|
| 533 |
if (!empty($form_values['add_volunteer']['name'])) {
|
| 534 |
$name = trim($form_values['add_volunteer']['name']);
|
| 535 |
if (!empty($name)) {
|
| 536 |
if (!($account = user_load(array('name' => $name)))) {
|
| 537 |
form_set_error("add_volunteer][name", t('The username %name does not exist.', array ('%name' => theme('placeholder', $name))));
|
| 538 |
}
|
| 539 |
else {
|
| 540 |
global $user;
|
| 541 |
$slot = $form_values['add_volunteer']['slot'];
|
| 542 |
if ($form_values['timeslot'][$slot]['box'] && !$form_values['timeslot'][$slot]['was_checked']) {
|
| 543 |
if ((count($node->timeslot_data[$slot]['volunteers']) >= ($node->num_volunteers - 1)) &&
|
| 544 |
($account->uid != $user->uid)) {
|
| 545 |
form_set_error('add_volunteer', t('Error: you cannot add both yourself and another volunteer to that time slot'));
|
| 546 |
}
|
| 547 |
}
|
| 548 |
}
|
| 549 |
}
|
| 550 |
}
|
| 551 |
else { // does this work???
|
| 552 |
if ($form_values['timeslot'][$slot]['box'] && !$form_values['timeslot'][$slot]['was_checked']) {
|
| 553 |
if (count($node->timeslot_data[$slot]['volunteers']) >= $node->num_volunteers) {
|
| 554 |
form_set_error('', t('Sorry: That time slot has been filled.'));
|
| 555 |
}
|
| 556 |
}
|
| 557 |
}
|
| 558 |
}
|
| 559 |
|
| 560 |
function theme_timeslots_signup_form($form) {
|
| 561 |
|
| 562 |
$header = array(t('Time slot'));
|
| 563 |
if ($form['box']['#value']) {
|
| 564 |
$header[] = t('Sign up for this slot');
|
| 565 |
}
|
| 566 |
else {
|
| 567 |
$header[] = '';
|
| 568 |
}
|
| 569 |
$header[] = t('Volunteers');
|
| 570 |
if ($form['admin']['#value']) {
|
| 571 |
$header[] = t('Remove');
|
| 572 |
}
|
| 573 |
else {
|
| 574 |
$header[] = '';
|
| 575 |
}
|
| 576 |
$rows = array();
|
| 577 |
for ($slot = 0; $slot < $form['num_slots']['#value']; $slot++) {
|
| 578 |
foreach (element_children($form['timeslot'][$slot]['name']) as $i) {
|
| 579 |
if ($i == 0) {
|
| 580 |
$arow = array(drupal_render($form['timeslot'][$slot]['start_time']).' - '. drupal_render($form['timeslot'][$slot]['end_time']));
|
| 581 |
if ($form['box']['#value']) {
|
| 582 |
$arow[] = drupal_render($form['timeslot'][$slot]['box']);
|
| 583 |
}
|
| 584 |
else {
|
| 585 |
$arow[] = '';
|
| 586 |
}
|
| 587 |
$arow[] = drupal_render($form['timeslot'][$slot]['name'][0]);
|
| 588 |
$arow[] = drupal_render($form['timeslot'][$slot]['remove'][0]);
|
| 589 |
$rows[] = array(data => $arow, 'class' => 'ugly');
|
| 590 |
}
|
| 591 |
else {
|
| 592 |
$rows[] = array('', '', drupal_render($form['timeslot'][$slot]['name'][$i]), drupal_render($form['timeslot'][$slot]['remove'][$i]));
|
| 593 |
}
|
| 594 |
}
|
| 595 |
$rows[] = array(array('data' => '<hr />', 'colspan' => '4'));
|
| 596 |
}
|
| 597 |
$rows[] = array(array('data' => drupal_render($form['event_end']), 'colspan' => '4'));
|
| 598 |
$output = theme('table', $header, $rows, array('class' => 'volunteer-timeslots'), t('Event volunteer schedule'));
|
| 599 |
|
| 600 |
return $output . drupal_render($form);
|
| 601 |
}
|
| 602 |
|
| 603 |
function _timeslots_signup_form_submit($form_id, $form_values) {
|
| 604 |
global $user;
|
| 605 |
$node = node_load($form_values['nid']);
|
| 606 |
|
| 607 |
$changed = array();
|
| 608 |
$remove = array();
|
| 609 |
foreach($form_values['timeslot'] as $slot => $data) {
|
| 610 |
if (isset($data['box']) && ($data['box'] != $data['was_checked'])) {
|
| 611 |
$changed[$slot] = TRUE;
|
| 612 |
}
|
| 613 |
if ($form_values['admin']) {
|
| 614 |
foreach ($data['remove'] as $uid) {
|
| 615 |
if ($uid > 0) {
|
| 616 |
$remove[$slot] = TRUE;
|
| 617 |
}
|
| 618 |
}
|
| 619 |
}
|
| 620 |
}
|
| 621 |
if (!count($changed) && !count($remove) && empty($form_values['add_volunteer']['name'])) {
|
| 622 |
drupal_set_message(t('No changes were made.'));
|
| 623 |
return;
|
| 624 |
}
|
| 625 |
$all_volunteers = array();
|
| 626 |
|
| 627 |
foreach($form_values['timeslot'] as $slot => $data) {
|
| 628 |
$vol = $node->timeslot_data[$slot]['volunteers'];
|
| 629 |
if (isset($changed[$slot])) {
|
| 630 |
if ($data['box']) {
|
| 631 |
$vol[] = $user->uid;
|
| 632 |
$node->timeslot_data[0]['all_volunteers'][] = $user->uid;
|
| 633 |
}
|
| 634 |
elseif ($data['was_checked']) {
|
| 635 |
if (($i = array_search($user->uid, $vol)) !== FALSE) {
|
| 636 |
$vol[$i] = $vol[count($vol) - 1];
|
| 637 |
array_pop($vol);
|
| 638 |
}
|
| 639 |
}
|
| 640 |
}
|
| 641 |
if (isset($remove[$slot])) { //admins and organizers can remove individual volunteers
|
| 642 |
foreach ($data['remove'] as $uid) {
|
| 643 |
if ($uid > 0) {
|
| 644 |
if (($i = array_search($uid, $vol)) !== FALSE) {
|
| 645 |
$vol[$i] = $vol[count($vol) - 1];
|
| 646 |
array_pop($vol);
|
| 647 |
}
|
| 648 |
}
|
| 649 |
}
|
| 650 |
}
|
| 651 |
if (isset($form_values['add_volunteer']['name']) && $form_values['add_volunteer']['slot'] == $slot) {
|
| 652 |
$name = trim($form_values['add_volunteer']['name']);
|
| 653 |
if (!empty($name)) {
|
| 654 |
$account = user_load(array('name' => $name));
|
| 655 |
$vol[] = $account->uid;
|
| 656 |
}
|
| 657 |
}
|
| 658 |
$node->timeslot_data[$slot]['volunteers'] = array_unique($vol);
|
| 659 |
$all_volunteers = array_merge($all_volunteers, $node->timeslot_data[$slot]['volunteers']);
|
| 660 |
}
|
| 661 |
$node->timeslot_data[0]['all_volunteers'] = array_unique($all_volunteers);
|
| 662 |
$node->revision = TRUE;
|
| 663 |
node_save($node);
|
| 664 |
drupal_set_message(t('Your changes to the schedule were made.'));
|
| 665 |
if ($form_values['send_me']) {
|
| 666 |
volunteer_timeslots_reminder_mail($node, $user->uid, "Information about the event:");
|
| 667 |
drupal_set_message(t('Information about the event was sent to your e-mail address.'));
|
| 668 |
}
|
| 669 |
}
|
| 670 |
|
| 671 |
/**
|
| 672 |
* Implementation of hook_nodeapi().
|
| 673 |
*
|
| 674 |
* hook_nodeapi is implemented instead of hook_submit so that event module has
|
| 675 |
* a chance to act first and properly process the event's start and end times.
|
| 676 |
*/
|
| 677 |
function volunteer_timeslots_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
|
| 678 |
|
| 679 |
if($node->type == 'volunteer_timeslots') {
|
| 680 |
if ($op == 'submit') {
|
| 681 |
//insure a rational end time- at least one time slot after the event start.
|
| 682 |
if ($node->event_end <= $node->event_start) {
|
| 683 |
$node->event_end = $node->event_start + $node->timeslot_length;
|
| 684 |
}
|
| 685 |
$start = $node->event_start;
|
| 686 |
$end = $node->event_end;
|
| 687 |
$num_slots = ceil(($end - $start)/$node->timeslot_length);
|
| 688 |
|
| 689 |
if ($node->clear_volunteers) {
|
| 690 |
unset($node->timeslot_data);
|
| 691 |
}
|
| 692 |
|
| 693 |
$data[0]['all_volunteers'] = array();
|
| 694 |
for ($i=0; $i<$num_slots; $i++) {
|
| 695 |
$data[$i]['start_time'] = $start + $i* $node->timeslot_length;
|
| 696 |
if ($i+1 == $num_slots) {
|
| 697 |
$data[$i]['end_time'] = $end;
|
| 698 |
}
|
| 699 |
else {
|
| 700 |
$data[$i]['end_time'] = $start + ($i+1)* $node->timeslot_length;
|
| 701 |
}
|
| 702 |
if (count($node->timeslot_data[$i]['volunteers'])) {
|
| 703 |
$data[$i]['volunteers'] = $node->timeslot_data[$i]['volunteers'];
|
| 704 |
$data[0]['all_volunteers'] = array_merge($data[0]['all_volunteers'], $node->timeslot_data[$i]['volunteers']);
|
| 705 |
}
|
| 706 |
else {
|
| 707 |
$data[$i]['volunteers'] = array();
|
| 708 |
}
|
| 709 |
}
|
| 710 |
$data[0]['all_volunteers'] = array_unique($data[0]['all_volunteers']);
|
| 711 |
foreach ($data[0]['all_volunteers'] as $uid) {
|
| 712 |
$data[0]['notes'][$uid] = $node->timeslot_data[0]['notes'][$uid];
|
| 713 |
}
|
| 714 |
$node->timeslot_data = $data;
|
| 715 |
//$node->revision = TRUE;
|
| 716 |
$names = explode(',', $node->timeslots_organizers);
|
| 717 |
$organizers = array();
|
| 718 |
foreach($names as $n) {
|
| 719 |
// validation has already been done in _validate, convert to uid values
|
| 720 |
if ($account = user_load(array('name' => trim($n)))) {
|
| 721 |
$organizers[] = $account->uid;
|
| 722 |
}
|
| 723 |
}
|
| 724 |
$node->timeslots_organizers = $organizers;
|
| 725 |
}
|
| 726 |
}
|
| 727 |
}
|
| 728 |
|
| 729 |
/**
|
| 730 |
* Implementation of hook_insert().
|
| 731 |
*/
|
| 732 |
function volunteer_timeslots_insert(&$node) {
|
| 733 |
db_query("INSERT INTO {volunteer_timeslots} (nid, vid, timeslot_length, num_volunteers, timeslots_organizers, timeslot_data) VALUES (%d, %d, %d, %d, '%s', '%s')",
|
| 734 |
$node->nid, $node->vid, $node->timeslot_length, $node->num_volunteers, implode(',', $node->timeslots_organizers), serialize($node->timeslot_data));
|
| 735 |
}
|
| 736 |
|
| 737 |
function _volunteer_timeslots_data_insert(&$node) {
|
| 738 |
}
|
| 739 |
|
| 740 |
/**
|
| 741 |
* Implementation of hook_update().
|
| 742 |
*/
|
| 743 |
function volunteer_timeslots_update(&$node) {
|
| 744 |
if ($node->revision) {
|
| 745 |
volunteer_timeslots_insert($node);
|
| 746 |
}
|
| 747 |
else {
|
| 748 |
db_query("UPDATE {volunteer_timeslots} SET timeslot_length = %d, num_volunteers = %d, timeslots_organizers = '%s', timeslot_data = '%s' WHERE vid = %d",
|
| 749 |
$node->timeslot_length, $node->num_volunteers, implode(',', $node->timeslots_organizers), serialize($node->timeslot_data), $node->vid);
|
| 750 |
}
|
| 751 |
}
|
| 752 |
|
| 753 |
/**
|
| 754 |
* Implementation of hook_delete().
|
| 755 |
*/
|
| 756 |
function volunteer_timeslots_delete(&$node) {
|
| 757 |
db_query('DELETE FROM {volunteer_timeslots} WHERE nid = %d', $node->nid);
|
| 758 |
}
|
| 759 |
|
| 760 |
|
| 761 |
function volunteer_timeslots_link($type, $node = NULL, $teaser = FALSE) {
|
| 762 |
$links = array();
|
| 763 |
global $user;
|
| 764 |
|
| 765 |
if ($type == 'node' && $node->type == 'volunteer_timeslots' && !$user->uid) {
|
| 766 |
$destination = "destination=". drupal_urlencode("node/". $node->nid);
|
| 767 |
if (variable_get('user_register', 1)) {
|
| 768 |
$links['volunteer_timeslots_login'] = array(
|
| 769 |
'title' => t('<a href="!login">Login</a> or <a href="!register">register</a> to volunteer', array('!login' => url('user/login', $destination), '!register' => check_url(url('user/register', $destination)))),
|
| 770 |
'html' => TRUE,
|
| 771 |
);
|
| 772 |
}
|
| 773 |
else {
|
| 774 |
$links['volunteer_timeslots_login_register'] = array(
|
| 775 |
'title' => t('<a href="!login">Login</a> to volunteer', array('!login' => check_url(url('user/login', $destination)))),
|
| 776 |
'html' => TRUE,
|
| 777 |
);
|
| 778 |
}
|
| 779 |
}
|
| 780 |
|
| 781 |
return $links;
|
| 782 |
}
|
| 783 |
|
| 784 |
/**
|
| 785 |
* Implementation of hook_cron().
|
| 786 |
*/
|
| 787 |
function volunteer_timeslots_cron() {
|
| 788 |
|
| 789 |
if (($remind_time = variable_get('volunteer_timeslots_remind_time', 36*60)) < 0) {
|
| 790 |
return;
|
| 791 |
}
|
| 792 |
|
| 793 |
$check_time = time() - (30 * 60 * 60);
|
| 794 |
$result = db_query('SELECT vt.* FROM {volunteer_timeslots} vt INNER JOIN {node} n ON n.vid = vt.vid INNER JOIN {event} e ON n.nid = e.nid WHERE n.status = 1 AND n.moderate = 0 AND e.event_start >= %d ORDER BY event_start', $check_time);
|
| 795 |
|
| 796 |
while ($event = db_fetch_object($result)) {
|
| 797 |
$node = node_load($event->nid);
|
| 798 |
$minutesleft = (int)(($node->event_start - time()) / 60);
|
| 799 |
if (($minutesleft < $remind_time) && ($minutesleft > 0) && !variable_get($node->nid. '_timeslots_reminder_sent', FALSE)) {
|
| 800 |
foreach ($node->timeslot_data[0]['all_volunteers'] as $uid) {
|
| 801 |
volunteer_timeslots_reminder_mail($node, $uid);
|
| 802 |
}
|
| 803 |
$account = user_load(array('uid' => $node->timeslots_organizers[0], 'status' => 1));
|
| 804 |
watchdog('mail', t('Volunteer timeslots: reminder e-mails about %url were sent on behalf of %name-from.', array('%name-from' => l($account->name,'user/'. $account->uid), '%url' => l('node/'.$node->nid,'node/'.$node->nid))));
|
| 805 |
variable_set($node->nid. '_timeslots_reminder_sent', TRUE);
|
| 806 |
}
|
| 807 |
elseif ($minutesleft < 0) {
|
| 808 |
variable_del($node->nid. '_timeslots_reminder_sent');
|
| 809 |
}
|
| 810 |
}
|
| 811 |
}
|
| 812 |
|
| 813 |
/**
|
| 814 |
* Send an e-mail with information or a reminder
|
| 815 |
*/
|
| 816 |
function volunteer_timeslots_reminder_mail($node, $uid, $opening = "Reminder- you have volunteered for a time slot at:") {
|
| 817 |
static $organizer = array();
|
| 818 |
static $text = array();
|
| 819 |
|
| 820 |
if (empty($organizer[$node->nid])) {
|
| 821 |
$organizer[$node->nid] = user_load(array('uid' => $node->timeslots_organizers[0], 'status' => 1));
|
| 822 |
if (empty($organizer[$node->nid])) {
|
| 823 |
watchdog('user', t("Volunteer timeslots: the user ID '%s' for node/%n could not be loaded.", array('%s' => $node->timeslots_organizers[0], '%n' => $node->nid)), WATCHDOG_ERROR);
|
| 824 |
$organizer[$node->nid]->mail = variable_get('site_mail', ini_get('sendmail_from'));
|
| 825 |
}
|
| 826 |
}
|
| 827 |
|
| 828 |
$account = user_load(array('uid' => $uid, 'status' => 1));
|
| 829 |
if (empty($account)) {
|
| 830 |
watchdog('user', t("Volunteer timeslots: the user ID '%s' for node/%n could not be loaded.", array('%s' => $uid, '%n' => $node->nid)), WATCHDOG_ERROR);
|
| 831 |
return;
|
| 832 |
}
|
| 833 |
|
| 834 |
// Compose the body:
|
| 835 |
if (empty($text[$node->nid])) {
|
| 836 |
switch (variable_get('event_timezone_display', 'event')) {
|
| 837 |
case 'event' :
|
| 838 |
include_once(EVENT_PATH .'/event_timezones.inc');
|
| 839 |
$start_offset = event_get_offset($node->timezone, $node->event_start);
|
| 840 |
break;
|
| 841 |
case 'user' :
|
| 842 |
$start_offset = $account->timezone;
|
| 843 |
break;
|
| 844 |
case 'site' :
|
| 845 |
$start_offset = variable_get('date_default_timezone', 0);
|
| 846 |
break;
|
| 847 |
}
|
| 848 |
$start_format = format_date($node->event_start, 'small', '', $start_offset);
|
| 849 |
$message[] = t($opening. ' @title', array('@title' => $node->title));
|
| 850 |
$message[] = t('This is scheduled for @event_start. To see which time slot you volunteered for, go to !url', array('@event_start' => $start_format, '!url' => url("node/".$node->nid, NULL, NULL, TRUE)));
|
| 851 |
$message[] = vt_mail_output(check_markup($node->body, $node->format, FALSE));
|
| 852 |
// Tidy up the body:
|
| 853 |
foreach ($message as $key => $value) {
|
| 854 |
$message[$key] = wordwrap($value);
|
| 855 |
}
|
| 856 |
$text[$node->nid] = implode("\n\n", $message);
|
| 857 |
}
|
| 858 |
|
| 859 |
// Prepare all fields:
|
| 860 |
$to = $account->mail;
|
| 861 |
$from = $organizer[$node->nid]->mail;
|
| 862 |
|
| 863 |
// Format the subject:
|
| 864 |
$subject = '['. variable_get('site_name', 'drupal') .'] '. t('Event volunteer information');
|
| 865 |
|
| 866 |
// Prepare the body:
|
| 867 |
$body = $account->name.",\n\n". $text[$node->nid];
|
| 868 |
|
| 869 |
// Send the e-mail:
|
| 870 |
drupal_mail('volunteer_timeslots_reminder', $to, $subject, $body, $from);
|
| 871 |
}
|
| 872 |
|
| 873 |
// takes filtered HTML as input and transforms for email
|
| 874 |
// modified from og.module
|
| 875 |
function vt_mail_output($body, $html = TRUE) {
|
| 876 |
|
| 877 |
if ($html) {
|
| 878 |
$pattern = '@(<a href="(.+?)">(.+?)</a>)@i';
|
| 879 |
$body = preg_replace($pattern, '$3 ($2)', $body);
|
| 880 |
$body = preg_replace('!</?blockquote>!i', '"', $body);
|
| 881 |
$body = preg_replace('!</?(em|i)>!i', '/', $body);
|
| 882 |
$body = preg_replace('!</?(b|strong)>!i', '*', $body);
|
| 883 |
$body = preg_replace("@<br />(?!\n)@i", "\n", $body);
|
| 884 |
$body = preg_replace("@</p>(?!\n\n)@i", "\n\n", $body);
|
| 885 |
$body = preg_replace("@<li>@i", "\n* ", $body);
|
| 886 |
$body = strip_tags($body);
|
| 887 |
$body = decode_entities($body);
|
| 888 |
}
|
| 889 |
else {
|
| 890 |
$body = decode_entities($body);
|
| 891 |
}
|
| 892 |
return $body;
|
| 893 |
}
|