Parent Directory
|
Revision Log
|
Revision Graph
Fixed a problem with the way the string was formatted on insert in the previous patch.
| 1 | <?php |
| 2 | // $Id: promotion.module,v 1.14 2008/02/19 22:24:30 hanenkamp Exp $ |
| 3 | |
| 4 | // Size of the pager on the Promotional Codes screen |
| 5 | define('PROMO_CODES_PER_PAGE', 20); |
| 6 | define('PROMO_STAT_USERS_PER_PAGE', 50); |
| 7 | |
| 8 | // Match types |
| 9 | define('PROMO_TYPE_EXACT', 1); |
| 10 | define('PROMO_TYPE_SIMPLE', 2); |
| 11 | define('PROMO_TYPE_ADVANCED', 3); |
| 12 | |
| 13 | // Activation action |
| 14 | define('PROMO_ACT_IMMEDIATE', 1); |
| 15 | define('PROMO_ACT_ROLES_WAIT', 2); |
| 16 | define('PROMO_ACT_ALL_WAIT', 3); |
| 17 | |
| 18 | // Expiraiton actions |
| 19 | define('PROMO_EXP_ACTION_DEMOTE', 1); |
| 20 | define('PROMO_EXP_ACTION_DEMOTE_AND_BLOCK', 2); |
| 21 | define('PROMO_EXP_ACTION_BLOCK', 3); |
| 22 | define('PROMO_EXP_ACTION_DELETE', 4); |
| 23 | |
| 24 | /** |
| 25 | * Implements hook_help(). |
| 26 | */ |
| 27 | function promotion_help($section) { |
| 28 | switch ($section) { |
| 29 | case 'admin/settings/promotion': |
| 30 | $output = t('Use this settings screen to set the general settings affecting all promotions on your web site.'); |
| 31 | break; |
| 32 | } |
| 33 | |
| 34 | return $output; |
| 35 | } |
| 36 | |
| 37 | /** |
| 38 | * Implements hook_perm(). |
| 39 | */ |
| 40 | function promotion_perm() { |
| 41 | return array('administer promotion', 'manage promotional codes', 'access promotion statistics'); |
| 42 | } |
| 43 | |
| 44 | /** |
| 45 | * Provides the main settings page. |
| 46 | */ |
| 47 | function promotion_settings() { |
| 48 | $form = array(); |
| 49 | |
| 50 | $user_register = variable_get('user_register', 1); |
| 51 | |
| 52 | // Disabled unless user_register == 1 or 2. I do this to avoid allowing |
| 53 | // modules like Invite causing problems (Invite sets user_register = 3 to mean |
| 54 | // by invitation only, which isn't compatible with this anyway) |
| 55 | if ($user_register != 1 && $user_register != 2) { |
| 56 | $form['disabled_message'] = array( |
| 57 | '#value' => '<div class="error">'.t('Disabled. Cannot customize registration unless public registrations are allowed by visitors on the <a href="!user_settings">User settings</a> screen.', array( '!user_settings' => url('admin/user/settings') )).'</div>', |
| 58 | ); |
| 59 | } |
| 60 | |
| 61 | // Enabled. |
| 62 | else { |
| 63 | |
| 64 | // Is promotion required? Default is no. |
| 65 | $form['promotion_required'] = array( |
| 66 | '#type' => 'checkbox', |
| 67 | '#title' => t('Require a valid promotional code to register for an account.'), |
| 68 | '#default_value' => variable_get('promotion_required', 0), |
| 69 | ); |
| 70 | } |
| 71 | |
| 72 | return system_settings_form($form); |
| 73 | } |
| 74 | |
| 75 | /** |
| 76 | * Implements hook_menu(). |
| 77 | */ |
| 78 | function promotion_menu($may_cache) { |
| 79 | $items = array(); |
| 80 | |
| 81 | if ($may_cache) { |
| 82 | // General settings page |
| 83 | $items[] = array( |
| 84 | 'path' => 'admin/settings/promotion', |
| 85 | 'title' => t('Promotion settings'), |
| 86 | 'description' => t('Configure the general settings for the promotional code system.'), |
| 87 | 'callback' => 'drupal_get_form', |
| 88 | 'callback arguments' => 'promotion_settings', |
| 89 | 'access' => user_access('administer promotion'), |
| 90 | 'type' => MENU_NORMAL_ITEM, |
| 91 | ); |
| 92 | |
| 93 | // Configure available promotions |
| 94 | $items[] = array( |
| 95 | 'path' => 'admin/user/promotion', |
| 96 | 'title' => t('Promotional codes'), |
| 97 | 'description' => t('Configure the promotional codes available for web site registration.'), |
| 98 | 'callback' => 'promotion_list', |
| 99 | 'access' => user_access('manage promotional codes'), |
| 100 | 'type' => MENU_NORMAL_ITEM, |
| 101 | ); |
| 102 | |
| 103 | // The default task of listing the promotions |
| 104 | $items[] = array( |
| 105 | 'path' => 'admin/user/promotion/list', |
| 106 | 'title' => t('List'), |
| 107 | 'type' => MENU_DEFAULT_LOCAL_TASK, |
| 108 | ); |
| 109 | |
| 110 | $items[] = array( |
| 111 | 'path' => 'admin/user/promotion/add', |
| 112 | 'title' => t('New code'), |
| 113 | 'callback' => 'promotion_add', |
| 114 | 'access' => user_access('manage promotional codes'), |
| 115 | 'type' => MENU_LOCAL_TASK, |
| 116 | ); |
| 117 | |
| 118 | $items[] = array( |
| 119 | 'path' => 'admin/logs/promotion', |
| 120 | 'title' => t('Promotion Statistics'), |
| 121 | 'description' => t('View how popular your sign-up promotions have been.'), |
| 122 | 'callback' => 'promotion_statistics', |
| 123 | 'access' => user_access('access promotion statistics'), |
| 124 | 'type' => MENU_NORMAL_ITEM, |
| 125 | ); |
| 126 | } |
| 127 | |
| 128 | else { |
| 129 | if (arg(0) == 'admin' && arg(1) == 'user' && arg(2) == 'promotion' && is_numeric(arg(3))) { |
| 130 | $pid = arg(3); |
| 131 | $items[] = array( |
| 132 | 'path' => 'admin/user/promotion/' . $pid, |
| 133 | 'title' => t('Edit'), |
| 134 | 'callback' => 'promotion_edit', |
| 135 | 'callback arguments' => array($pid), |
| 136 | 'access' => user_access('manage promotional codes'), |
| 137 | 'type' => MENU_CALLBACK, |
| 138 | ); |
| 139 | $items[] = array( |
| 140 | 'path' => 'admin/user/promotion/' . $pid . '/delete', |
| 141 | 'title' => t('Delete'), |
| 142 | 'callback' => 'drupal_get_form', |
| 143 | 'callback arguments' => array('promotion_delete_confirm', $pid), |
| 144 | 'access' => user_access('manage promotional codes'), |
| 145 | 'type' => MENU_CALLBACK, |
| 146 | ); |
| 147 | } |
| 148 | |
| 149 | if (arg(0) == 'admin' && arg(1) == 'logs' && arg(2) == 'promotion' && is_numeric(arg(3))) { |
| 150 | $pid = arg(3); |
| 151 | $detail = arg(4); |
| 152 | |
| 153 | $items[] = array( |
| 154 | 'path' => 'admin/logs/promotion/' . $pid, |
| 155 | 'title' => t('Promotion Statistics'), |
| 156 | 'callback' => 'promotion_statistics', |
| 157 | 'callback arguments' => array($pid, $detail), |
| 158 | 'access' => user_access('access promotion statistics'), |
| 159 | 'type' => MENU_CALLBACK, |
| 160 | ); |
| 161 | } |
| 162 | } |
| 163 | |
| 164 | return $items; |
| 165 | } |
| 166 | |
| 167 | function promotion_list() { |
| 168 | $header = array( |
| 169 | array('data' => t('Name'), 'field' => 'name'), |
| 170 | array('data' => t('Active'), 'field' => 'active_promotion'), |
| 171 | array('data' => t('Code'), 'field' => 'simple_code'), |
| 172 | array('data' => t('Start Date'), 'field' => 'start_date'), |
| 173 | array('data' => t('End Date'), 'field' => 'end_date'), |
| 174 | array('data' => t('Expiration'), 'field' => 'expiration_date'), |
| 175 | ); |
| 176 | |
| 177 | $sql = 'SELECT pid, name, active_promotion, simple_code, start_date, end_date, expiration_date FROM {promotion_codes}'; |
| 178 | $sql .= tablesort_sql($header); |
| 179 | $result = pager_query($sql, PROMO_CODES_PER_PAGE); |
| 180 | |
| 181 | while ($promo_code = db_fetch_object($result)) { |
| 182 | $rows[] = array( |
| 183 | l($promo_code->name, 'admin/user/promotion/'.$promo_code->pid), |
| 184 | $promo_code->active_promotion ? 'yes' : 'no', |
| 185 | $promo_code->simple_code, |
| 186 | $promo_code->start_date ? format_date($promo_code->start_date) : 'none', |
| 187 | $promo_code->end_date ? format_date($promo_code->end_date) : 'none', |
| 188 | $promo_code->expiration_date ? format_date($promo_code->expiration_date) : 'none', |
| 189 | ); |
| 190 | } |
| 191 | |
| 192 | if (count($rows)) { |
| 193 | $output = theme('table', $header, $rows); |
| 194 | |
| 195 | $pager = theme('pager', NULL, PROMO_CODES_PER_PAGE, 0); |
| 196 | if (!empty($pager)) { |
| 197 | $output .= $pager; |
| 198 | } |
| 199 | } |
| 200 | |
| 201 | else { |
| 202 | $output .= '<p>'.t('No promotional codes have been created.').'</p>'; |
| 203 | } |
| 204 | |
| 205 | return $output; |
| 206 | } |
| 207 | |
| 208 | function promotion_form($promotion, $form_values = NULL) { |
| 209 | if ($promotion->pid) { |
| 210 | $form['pid'] = array( |
| 211 | '#type' => 'value', |
| 212 | '#value' => $promotion->pid, |
| 213 | ); |
| 214 | } |
| 215 | |
| 216 | $form['name'] = array( |
| 217 | '#type' => 'textfield', |
| 218 | '#title' => t('Name'), |
| 219 | '#default_value' => $promotion->name, |
| 220 | '#size' => 60, |
| 221 | '#maxlength' => 128, |
| 222 | '#required' => TRUE, |
| 223 | ); |
| 224 | |
| 225 | $form['description'] = array( |
| 226 | '#type' => 'textarea', |
| 227 | '#title' => t('Description'), |
| 228 | '#default_value' => $promotion->description, |
| 229 | ); |
| 230 | |
| 231 | // Get the roles, but exclude anonymous and authenticated |
| 232 | $roles = user_roles(1); |
| 233 | $keys = array_keys($roles, 'authenticated user'); |
| 234 | unset($roles[$keys[0]]); |
| 235 | |
| 236 | $form['code'] = array( |
| 237 | '#type' => 'fieldset', |
| 238 | '#title' => t('Promotion Codes'), |
| 239 | '#description' => t('These settings describe the code that is actually accepted by this promotion.'), |
| 240 | '#collapsible' => TRUE, |
| 241 | '#collapsed' => FALSE, |
| 242 | ); |
| 243 | |
| 244 | $form['code']['code_type'] = array( |
| 245 | '#type' => 'radios', |
| 246 | '#title' => t('Select a format for the promotion code'), |
| 247 | '#default_value' => $promotion->code_type, |
| 248 | '#options' => array( |
| 249 | 1 => t('<strong>Exact code.</strong> Use when you want all registrants to use the exact same code.'), |
| 250 | 2 => t('<strong>Simple format.</strong> Use when you have a range of codes with numbers or letters. For example, if you want to accept codes %promo_000 through %promo_999, you could use the format %promo_123.', array('%promo_000' => 'PROMO-000', '%promo_999' => 'PROMO-999', '%promo_123' => 'PROMO-[123]')), |
| 251 | # 3 => t('<strong>Advanced.</strong> Use custom PHP code to validate the code. Only do this if you have a complex code you want to use and know how to write PHP code.'), |
| 252 | ), |
| 253 | '#required' => TRUE, |
| 254 | ); |
| 255 | |
| 256 | $form['code']['simple_code'] = array( |
| 257 | '#type' => 'textfield', |
| 258 | '#title' => t('Exact or Simple code'), |
| 259 | '#description' => t('If you selected <strong>Exact code</strong> above, enter that code here. If you chose <strong>Simple format</strong>, you may use [] containing letters or numbers to indicate that you accept any letter or number at that position in the code. All other letters, numbers, and symbols will be matched exactly. For example, "PROMO-[000]" would accept "PROMO-123" and "promo-123," but not "PRO-123" and not "PROMO-ABC." Promotional codes are not case sensitive.'), |
| 260 | '#default_value' => $promotion->simple_code, |
| 261 | '#size' => 30, |
| 262 | '#maxlength' => 30, |
| 263 | '#required' => TRUE, |
| 264 | ); |
| 265 | |
| 266 | # $form['code']['advanced_validator'] = array( |
| 267 | # '#type' => 'textarea', |
| 268 | # '#title' => t('Advanced Validation Code'), |
| 269 | # '#description' => t('If you selected <strong>Advanced</strong> above, enter the PHP code to validate the promotional code here. The variable $code will be set to the text of the code and $user will contain the user information submitted with the user registration form.'), |
| 270 | # '#default_value' => $promotion->advanced_validator, |
| 271 | # ); |
| 272 | |
| 273 | $form['code']['max_use_count'] = array( |
| 274 | '#type' => 'select', |
| 275 | '#title' => t('Select the number of times a single code may be used'), |
| 276 | '#description' => t('This is the number of times a code may be used to register for an account. If you use an exact code, this allows you to have a limited number of individuals sign up under that code. If you use a range of codes using the simple code format or a custom validator, you can choose to allow each code to be used only once or more than once.'), |
| 277 | '#options' => array( |
| 278 | 1 => 1, |
| 279 | 2 => 2, |
| 280 | 3 => 3, |
| 281 | 4 => 4, |
| 282 | 5 => 5, |
| 283 | 10 => 10, |
| 284 | 50 => 50, |
| 285 | 100 => 100, |
| 286 | 500 => 500, |
| 287 | 1000 => 1000, |
| 288 | 0 => t('unlimited'), |
| 289 | ), |
| 290 | '#default_value' => $promotion->max_use_count, |
| 291 | '#required' => TRUE, |
| 292 | ); |
| 293 | |
| 294 | $form['availability'] = array( |
| 295 | '#type' => 'fieldset', |
| 296 | '#title' => t('Availability'), |
| 297 | '#collapsible' => TRUE, |
| 298 | '#collapsed' => TRUE, |
| 299 | ); |
| 300 | |
| 301 | $form['availability']['active_promotion'] = array( |
| 302 | '#type' => 'checkbox', |
| 303 | '#title' => t('Is this promotion currently available?'), |
| 304 | '#description' => t('By unchecking the box, the promotion is completely deactivated. The promotion will not be available regardless of any other setting. If checked, the promotion is available as long as the current date is between the start date and the end date. <strong>WARNING:</strong> If delayed activation or account expiration are checked, any accounts that are pending activation or would expire will not while this is checked. If you want to make sure accounts expire properly, do not uncheck this box until all accounts have expired.'), |
| 305 | '#default_value' => $promotion->active_promotion, |
| 306 | ); |
| 307 | |
| 308 | $form['availability']['start_date'] = array( |
| 309 | '#type' => 'textfield', |
| 310 | '#title' => t('Start date'), |
| 311 | '#default_value' => $promotion->start_date ? format_date($promotion->start_date, 'custom', 'Y-m-d H:i:s') : '', |
| 312 | '#description' => t('If set, specifies the first day this promotion will be accepted. If not set, the promotion is immediately available. Must be in YYYY-MM-DD format.'), |
| 313 | '#attributes' => array('class' => 'jscalendar'), |
| 314 | ); |
| 315 | |
| 316 | $form['availability']['end_date'] = array( |
| 317 | '#type' => 'textfield', |
| 318 | '#title' => t('End date'), |
| 319 | '#default_value' => $promotion->end_date ? format_date($promotion->end_date, 'custom', 'Y-m-d H:i:s') : '', |
| 320 | '#description' => t('If set, specifies the first day this promotion is no longer accepted (i.e., it will be available until the day before). If not set, the promotion is available indefinitely. Must be in YYYY-MM-DD format.'), |
| 321 | '#attributes' => array('class' => 'jscalendar'), |
| 322 | ); |
| 323 | |
| 324 | $form['activation'] = array( |
| 325 | '#type' => 'fieldset', |
| 326 | '#title' => t('Activation'), |
| 327 | '#collapsible' => TRUE, |
| 328 | '#collapsed' => TRUE, |
| 329 | ); |
| 330 | |
| 331 | $activate_when_choices = array( |
| 332 | 1 => t('<strong>Immediately.</strong> Other than waiting for email validation and administrator approval, the acount should be immediately activated.'), |
| 333 | 2 => t('<strong>Immediately, but postpone promotion.</strong> The account is activated immediately, but the roles granted by this promotion will not be granted until the activation date.'), |
| 334 | 3 => t('<strong>Delayed account activation.</strong> The account will not be created until after the activation date.'), |
| 335 | ); |
| 336 | |
| 337 | if (count($roles) == 0) { |
| 338 | unset($activate_when_choices[2]); |
| 339 | } |
| 340 | |
| 341 | $form['activation']['activate_when'] = array( |
| 342 | '#type' => 'radios', |
| 343 | '#title' => t('Accounts registered with this promotion are activated when'), |
| 344 | '#options' => $activate_when_choices, |
| 345 | '#default_value' => $promotion->activate_when, |
| 346 | ); |
| 347 | |
| 348 | $form['activation']['activation_date'] = array( |
| 349 | '#type' => 'textfield', |
| 350 | '#title' => t('Activation date'), |
| 351 | '#default_value' => $promotion->activation_date ? format_date($promotion->activation_date, 'custom', 'Y-m-d H:i:s') : '', |
| 352 | '#attributes' => array('class' => 'jscalendar'), |
| 353 | ); |
| 354 | |
| 355 | if (count($roles) > 0) { |
| 356 | $form['activation']['promotion_roles'] = array( |
| 357 | '#type' => 'checkboxes', |
| 358 | '#title' => t('Select the roles registrants under this promotion receive'), |
| 359 | '#description' => t('These are the roles that should be assigned to any user registering under this promotion.'), |
| 360 | '#default_value' => $promotion->promotion_roles, |
| 361 | '#options' => $roles, |
| 362 | ); |
| 363 | } |
| 364 | |
| 365 | $form['expiration'] = array( |
| 366 | '#type' => 'fieldset', |
| 367 | '#title' => t('Expiration'), |
| 368 | '#description' => t('These settings determine if accounts registered under a promotion expire and what happens to an account after the promotion expires.'), |
| 369 | '#collapsible' => TRUE, |
| 370 | '#collapsed' => TRUE, |
| 371 | ); |
| 372 | |
| 373 | $form['expiration']['accounts_expire'] = array( |
| 374 | '#type' => 'checkbox', |
| 375 | '#title' => t('Accounts registered with this promotion will expire.'), |
| 376 | '#description' => t('If checked, accounts will be demoted, blocked, or deleted after the date given.'), |
| 377 | '#default_value' => $promotion->accounts_expire, |
| 378 | ); |
| 379 | |
| 380 | $form['expiration']['expiration_date'] = array( |
| 381 | '#type' => 'textfield', |
| 382 | '#title' => t('Expiration date'), |
| 383 | '#default_value' => $promotion->expiration_date ? format_date($promotion->expiration_date, 'custom', 'Y-m-d H:i:s') : '', |
| 384 | '#attributes' => array('class' => 'jscalendar'), |
| 385 | ); |
| 386 | |
| 387 | $expiration_actions = array(); |
| 388 | if (count($roles) > 0) { |
| 389 | $expiration_actions[1] = t('Demote the accounts'); |
| 390 | $expiration_actions[2] = t('Demote and block the accounts'); |
| 391 | } |
| 392 | $expiration_actions[3] = t('Block the accounts'); |
| 393 | $expiration_actions[4] = t('Delete the accounts'); |
| 394 | |
| 395 | $form['expiration']['expiration_action'] = array( |
| 396 | '#type' => 'radios', |
| 397 | '#title' => t('After expiration, take which action'), |
| 398 | '#options' => $expiration_actions, |
| 399 | '#default_value' => $promotion->expiration_action, |
| 400 | ); |
| 401 | |
| 402 | // Only show if there are custom roles available to use |
| 403 | if (count($roles) > 0) { |
| 404 | $form['expiration']['demotion_roles'] = array( |
| 405 | '#type' => 'checkboxes', |
| 406 | '#title' => t('Demotion Roles'), |
| 407 | '#description' => t('These are the roles users registered with this promotion will lose if you have chosen to perform demotion on expiration.'), |
| 408 | '#default_value' => $promotion->demotion_roles, |
| 409 | '#options' => $roles, |
| 410 | ); |
| 411 | } |
| 412 | # |
| 413 | # $form['advanced'] = array( |
| 414 | # '#type' => 'fieldset', |
| 415 | # '#title' => t('Advanced Options'), |
| 416 | # '#collapsible' => TRUE, |
| 417 | # '#collapsed' => TRUE, |
| 418 | # ); |
| 419 | # |
| 420 | # $form['advanced']['bypass_verification'] = array( |
| 421 | # '#type' => 'checkbox', |
| 422 | # '#title' => t('Registrants using this promotional code bypass email verification.'), |
| 423 | # '#description' => t('If checked, an extra email field will be added to the registration form for confirmation and the user will receive a welcome message rather than a confirmation message to their inbox.'), |
| 424 | # '#default_value' => $promotion->bypass_verification, |
| 425 | # ); |
| 426 | # |
| 427 | # $form['advanced']['bypass_administration'] = array( |
| 428 | # '#type' => 'checkbox', |
| 429 | # '#title' => t('Registrants using this promotional code bypass administrator approval.'), |
| 430 | # '#description' => t('If registration normally requires administrator approval, checking this box will cause registrants using this code to skip that step.'), |
| 431 | # '#default_value' => $promotion->bypass_administrator, |
| 432 | # ); |
| 433 | # |
| 434 | # $form['advanced']['linked_code'] = array( |
| 435 | # '#type' => 'checkbox', |
| 436 | # '#title' => t('Allow this promotional code to be given as a link.'), |
| 437 | # '#default_value' => $promotion->linked_code, |
| 438 | # ); |
| 439 | # |
| 440 | # $form['advanced']['code_link'] = array( |
| 441 | # '#type' => 'textfield', |
| 442 | # '#title' => t('Promotional code link'), |
| 443 | # '#description' => t('A final slash and then the code must be added to the URL when sending out the links.'), |
| 444 | # '#default_value' => $promotion->code_link, |
| 445 | # '#field_prefix' => url(NULL, NULL, NULL, TRUE) . (variable_get('clean_url', 0) ? '' : '?q='), |
| 446 | # ); |
| 447 | |
| 448 | $form['submit'] = array( |
| 449 | '#type' => 'submit', |
| 450 | '#value' => $promotion->pid ? t('Update') : t('Create'), |
| 451 | ); |
| 452 | |
| 453 | if ($promotion->pid) { |
| 454 | $form['delete'] = array( |
| 455 | '#type' => 'submit', |
| 456 | '#value' => t('Delete'), |
| 457 | ); |
| 458 | } |
| 459 | |
| 460 | return $form; |
| 461 | } |
| 462 | |
| 463 | function promotion_form_validate($form_id, $form_values) { |
| 464 | $op = 'create'; |
| 465 | $pid_clause = ''; |
| 466 | if (isset($form_values['pid'])) { |
| 467 | $pid_clause = 'AND pid <> %d'; |
| 468 | $op = 'update'; |
| 469 | } |
| 470 | |
| 471 | // Make sure that the name is not already taken |
| 472 | $result = db_query("SELECT pid FROM {promotion_codes} WHERE name = '%s' $pid_clause", $form_values['name'], $form_values['pid']); |
| 473 | if (db_num_rows($result) > 0) { |
| 474 | form_set_error('name', t('A promotion with that name already exists.')); |
| 475 | } |
| 476 | |
| 477 | // Make sure the code is valid |
| 478 | if ($form_values['code_type'] == PROMO_TYPE_SIMPLE) { |
| 479 | if (!preg_match('/^(?:[^\[\]]+|\[[0-9a-zA-Z]*\])+$/', $form_values['simple_code'])) { |
| 480 | form_set_error('simple_code', t('The simple code format given is not valid. Make sure you do not have an umatched "[" or "]" and that any brackets contain only letters and numbers.')); |
| 481 | } |
| 482 | } |
| 483 | |
| 484 | // Tests for delayed activation |
| 485 | if ($form_values['activate_when'] == PROMO_ACT_ROLES_WAIT |
| 486 | || $form_values['activate_when'] == PROMO_ACT_ALL_WAIT) { |
| 487 | |
| 488 | // If delayed activation is used, there must be a date |
| 489 | if (!$form_values['activation_date']) { |
| 490 | form_set_error('activation_date', t('Activation date is required if you have chosen to delay promotion or activation.')); |
| 491 | } |
| 492 | } |
| 493 | |
| 494 | // Tests for when roles are assigned late |
| 495 | if ($form_values['activate_when'] == PROMO_ACT_ROLES_WAIT) { |
| 496 | |
| 497 | // If roles are going to be assigned late, there must be some roles checked |
| 498 | if (array_reduce($form_values['promotion_roles'], create_function('$a,$b', 'return $a + $b;')) == 0) { |
| 499 | form_set_error('promotion_roles', t('You have asked that the roles assigned be delayed. However, you have not selected any roles. Please do so before continuing.')); |
| 500 | } |
| 501 | } |
| 502 | |
| 503 | // Tests for when accounts expire |
| 504 | if ($form_values['accounts_expire']) { |
| 505 | |
| 506 | // If accounts may expire, the expiration must be set |
| 507 | if (!$form_values['expiration_date']) { |
| 508 | form_set_error('expiration_date', t('Expiration date is required if accounts may expire.')); |
| 509 | } |
| 510 | |
| 511 | // If accounts expire, we need to know what action to take |
| 512 | if (!$form_values['expiration_action']) { |
| 513 | form_set_error('expiration_action', t('The expiration action must be selected if accounts may expire.')); |
| 514 | } |
| 515 | |
| 516 | // Tests for when expiration involves stripping roles from accounts |
| 517 | if ($form_values['expiration_action'] == PROMO_EXP_ACTION_DEMOTE |
| 518 | || $form_values['expiration_action'] == PROMO_EXP_ACTION_DEMOTE_AND_BLOCK) { |
| 519 | |
| 520 | // If roles are stripped, we must set some roles to strip |
| 521 | if (array_reduce($form_values['demotion_roles'], create_function('$a,$b', 'return $a + $b;')) == 0) { |
| 522 | form_set_error('demotion_roles', t('You have asked that members registered during a promotion be demoted, but have not selected the roles they lose. Please check one or more roles before continuing.')); |
| 523 | } |
| 524 | } |
| 525 | } |
| 526 | |
| 527 | // Make sure these are dates, if they are set |
| 528 | $field_names = array( |
| 529 | 'start_date' => t('Start date'), |
| 530 | 'end_date' => t('End date'), |
| 531 | 'activation_date' => t('Activation date'), |
| 532 | 'expiration_date' => t('Expiration date'), |
| 533 | ); |
| 534 | |
| 535 | $now = time(); |
| 536 | foreach ($field_names as $date => $title) { |
| 537 | |
| 538 | // Don't bother to validate the date if it isn't even set |
| 539 | if ($form_values[$date]) { |
| 540 | $parsed_date = strtotime($form_values[$date]); |
| 541 | |
| 542 | // It's not a valid date, complain |
| 543 | if (!$parsed_date) { |
| 544 | form_set_error($date, t('The %field given is not recognized.', array( '%field' => $title ))); |
| 545 | } |
| 546 | |
| 547 | // The end_date and expiration_date should be in the future |
| 548 | elseif ($parsed_date < $now && ($date == 'end_date' || $date == 'expiration_date')) { |
| 549 | |
| 550 | // Don't let them create this thing! |
| 551 | if ($op == 'create') { |
| 552 | form_set_error($date, t('The %field given is in the past and it must be in the future.', array('%field' => $title))); |
| 553 | } |
| 554 | |
| 555 | // This is just a warning! |
| 556 | else { |
| 557 | drupal_set_message(t('The %field given is in the past and it should be in the future. You may want to go back and !edit.', array('%field' => $title, '!edit' => l(t('edit the promotion'), 'admin/user/promotion/'.$form_values['pid']))), 'error'); |
| 558 | } |
| 559 | } |
| 560 | } |
| 561 | } |
| 562 | |
| 563 | // Make sure that that the expiration date is after the activation date |
| 564 | if ($form_values['activate_when'] == PROMO_ACT_ROLES_WAIT |
| 565 | || $form_values['activate_when'] == PROMO_ACT_ALL_WAIT) { |
| 566 | |
| 567 | $activation_date = strtotime($form_values['activation_date']); |
| 568 | $expiration_date = strtotime($form_values['expiration_date']); |
| 569 | |
| 570 | if ($form_values['accounts_expire'] && $activation_date && $expiration_date) { |
| 571 | if ($activation_date >= $expiration_date) { |
| 572 | form_set_error('activation_date', t('The activation date must be sooner than the expiration date.')); |
| 573 | } |
| 574 | } |
| 575 | } |
| 576 | |
| 577 | // Make sure that the end date is after the start date |
| 578 | if ($form_values['start_date'] && $form_values['end_date']) { |
| 579 | $start_date = strtotime($form_values['start_date']); |
| 580 | $end_date = strtotime($form_values['end_date']); |
| 581 | |
| 582 | if ($start_date && $end_date && $start_date >= $end_date) { |
| 583 | form_set_error('start_date', t('The start date must be sooner than the end date.')); |
| 584 | } |
| 585 | } |
| 586 | |
| 587 | // Make sure that the activation date comes on or after the start date |
| 588 | if ($form_values['start_date'] && ($form_values['activate_when'] == PROMO_ACT_ROLES_WAIT || $form_values['activate_when'] == PROMO_ACT_ALL_WAIT) && $form_values['activation_date']) { |
| 589 | $start_date = strtotime($form_values['start_date']); |
| 590 | $activation_date = strtotime($form_values['activation_date']); |
| 591 | |
| 592 | if ($start_date && $activation_date && $start_date > $activation_date) { |
| 593 | form_set_error('start_date', t('The start date must not be after the activation date.')); |
| 594 | } |
| 595 | } |
| 596 | |
| 597 | // Make sure that the expiration date comes on or after the end date |
| 598 | if ($form_values['end_date'] && $form_values['accounts_expire'] && $form_values['expiration_date']) { |
| 599 | $end_date = strtotime($form_values['end_date']); |
| 600 | $expiration_date = strtotime($form_values['expiration_date']); |
| 601 | |
| 602 | if ($end_date && $expiration_date && $end_date > $expiration_date) { |
| 603 | form_set_error('end_date', t('The end date must not be after the expiration date.')); |
| 604 | } |
| 605 | } |
| 606 | } |
| 607 | |
| 608 | /** |
| 609 | * Internal function for setting up the {promotion_codes_roles} table. |
| 610 | */ |
| 611 | function _promotion_update_roles($pid, $roles, $promotion) { |
| 612 | db_query("DELETE FROM {promotion_codes_roles} WHERE pid = %d AND promotion = %d", $pid, $promotion); |
| 613 | |
| 614 | if (isset($roles)) { |
| 615 | foreach ($roles as $role) { |
| 616 | if ($role) { |
| 617 | db_query("INSERT INTO {promotion_codes_roles} (pid, rid, promotion) VALUES (%d, %d, %d)", $pid, $role, $promotion); |
| 618 | } |
| 619 | } |
| 620 | } |
| 621 | } |
| 622 | |
| 623 | function promotion_form_submit($form_id, $form_values) { |
| 624 | // Convert dates from the submitted values into seconds since the epoch |
| 625 | foreach (array('start_date', 'end_date', 'expiration_date', 'activation_date') as $date) { |
| 626 | if ($form_values[$date]) { |
| 627 | $form_values[$date] = strtotime($form_values[$date]); |
| 628 | } |
| 629 | else { |
| 630 | $form_values[$date] = 0; |
| 631 | } |
| 632 | } |
| 633 | |
| 634 | // update |
| 635 | if ($form_values['pid']) { |
| 636 | db_query(" |
| 637 | UPDATE {promotion_codes} |
| 638 | SET name = '%s', description = '%s', active_promotion = %d, |
| 639 | start_date = %d, end_date = %d, code_type = %d, simple_code = '%s', |
| 640 | max_use_count = %d, accounts_expire = %d, expiration_date = %d, |
| 641 | expiration_action = %d, activate_when = %d, activation_date = %d |
| 642 | WHERE pid = %d", |
| 643 | $form_values['name'], |
| 644 | $form_values['description'], |
| 645 | $form_values['active_promotion'], |
| 646 | $form_values['start_date'], |
| 647 | $form_values['end_date'], |
| 648 | $form_values['code_type'], |
| 649 | $form_values['simple_code'], |
| 650 | $form_values['max_use_count'], |
| 651 | $form_values['accounts_expire'], |
| 652 | $form_values['expiration_date'], |
| 653 | $form_values['expiration_action'], |
| 654 | $form_values['activate_when'], |
| 655 | $form_values['activation_date'], |
| 656 | $form_values['pid'] |
| 657 | ); |
| 658 | |
| 659 | _promotion_update_roles($form_values['pid'], $form_values['promotion_roles'], 1); |
| 660 | _promotion_update_roles($form_values['pid'], $form_values['demotion_roles'], 0); |
| 661 | |
| 662 | drupal_set_message(t('Updated a promotion.')); |
| 663 | } |
| 664 | |
| 665 | // insert |
| 666 | else { |
| 667 | $pid = db_next_id('{promotion_codes}_pid'); |
| 668 | |
| 669 | db_query(" |
| 670 | INSERT INTO {promotion_codes} (pid, name, description, active_promotion, |
| 671 | start_date, end_date, code_type, simple_code, max_use_count, |
| 672 | accounts_expire, expiration_date, expiration_action, activate_when, |
| 673 | activation_date) |
| 674 | VALUES (%d, '%s', '%s', %d, %d, %d, %d, '%s', %d, %d, %d, %d, %d, %d)", |
| 675 | $pid, |
| 676 | $form_values['name'], |
| 677 | $form_values['description'], |
| 678 | $form_values['active_promotion'], |
| 679 | $form_values['start_date'], |
| 680 | $form_values['end_date'], |
| 681 | $form_values['code_type'], |
| 682 | $form_values['simple_code'], |
| 683 | $form_values['max_use_count'], |
| 684 | $form_values['accounts_expire'], |
| 685 | $form_values['expiration_date'], |
| 686 | $form_values['expiration_action'], |
| 687 | $form_values['activate_when'], |
| 688 | $form_values['activation_date'] |
| 689 | ); |
| 690 | |
| 691 | _promotion_update_roles($pid, $form_values['promotion_roles'], 1); |
| 692 | _promotion_update_roles($pid, $form_values['demotion_roles'], 0); |
| 693 | |
| 694 | drupal_set_message(t('Created a new promotion.')); |
| 695 | } |
| 696 | |
| 697 | return 'admin/user/promotion'; |
| 698 | } |
| 699 | |
| 700 | function promotion_add() { |
| 701 | // Setup the defaults |
| 702 | $promotion['active_promotion'] = 1; |
| 703 | $promotion['activate_when'] = 1; |
| 704 | |
| 705 | $output = drupal_get_form('promotion_form', (object) $promotion); |
| 706 | return $output; |
| 707 | } |
| 708 | |
| 709 | function promotion_edit($pid) { |
| 710 | // Check for delete |
| 711 | if ($_POST['op'] == t('Delete')) { |
| 712 | drupal_goto('admin/user/promotion/'.$pid.'/delete'); |
| 713 | } |
| 714 | |
| 715 | // Load the promotion |
| 716 | if ($promotion = promotion_get_promotion($pid)) { |
| 717 | return drupal_get_form('promotion_form', $promotion); |
| 718 | } |
| 719 | |
| 720 | else { |
| 721 | return drupal_not_found(); |
| 722 | } |
| 723 | } |
| 724 | |
| 725 | function promotion_delete_confirm($pid) { |
| 726 | $promotion = promotion_get_promotion($pid); |
| 727 | |
| 728 | $form['pid'] = array('#type' => 'value', '#value' => $pid); |
| 729 | return confirm_form($form, |
| 730 | t('Are you sure you want to delete %name?', array('%name' => $promotion->name)), |
| 731 | 'admin/user/promotion/' . $pid, |
| 732 | t('<p>This action cannot be undone. You will no longer be able to see statistics related to this promotion.</p><p><strong>CAUTION:</strong> You may wish to mark this promotion as inactive instead.</p>'), |
| 733 | t('Delete'), t('Cancel')); |
| 734 | } |
| 735 | |
| 736 | function promotion_delete_confirm_submit($form_id, $form_values) { |
| 737 | if ($form_values['confirm']) { |
| 738 | db_query('DELETE FROM {promotion_codes} WHERE pid = %d', $form_values['pid']); |
| 739 | } |
| 740 | |
| 741 | return 'admin/user/promotion'; |
| 742 | } |
| 743 | |
| 744 | function promotion_get_promotion($pid) { |
| 745 | if ($result = db_query("SELECT * FROM {promotion_codes} WHERE pid = %d", $pid)) { |
| 746 | $promotion = db_fetch_object($result); |
| 747 | |
| 748 | $result = db_query("SELECT * FROM {promotion_codes_roles} WHERE pid = %d", $pid); |
| 749 | while ($code_role = db_fetch_array($result)) { |
| 750 | if ($code_role['promotion']) { |
| 751 | $promotion->promotion_roles[$code_role['rid']] = $code_role['rid']; |
| 752 | } |
| 753 | else { |
| 754 | $promotion->demotion_roles[$code_role['rid']] = $code_role['rid']; |
| 755 | } |
| 756 | } |
| 757 | |
| 758 | return $promotion; |
| 759 | } |
| 760 | |
| 761 | return NULL; |
| 762 | } |
| 763 | |
| 764 | /** |
| 765 | * Implementation of hook_user(). |
| 766 | */ |
| 767 | function promotion_user($op, &$edit, &$account, $category = NULL) { |
| 768 | if ($op == 'register') { |
| 769 | if (arg(0) == 'user' && arg(1) == 'register') { |
| 770 | $url_code = arg(2); // /user/register/CODE |
| 771 | } |
| 772 | $required = variable_get('promotion_required', 0); |
| 773 | |
| 774 | $form['promotion'] = array( |
| 775 | '#type' => 'fieldset', |
| 776 | '#title' => t('Promotional code'), |
| 777 | ); |
| 778 | $form['promotion']['promotional_code'] = array( |
| 779 | '#type' => $url_code ? 'item' : 'textfield', |
| 780 | '#title' => t('Promotional code'), |
| 781 | '#description' => |
| 782 | ($url_code ? t('You have been given a direct link to this promotion. If you do not want to use this promotion or would like to use another, !click_here.', array('!click_here' => l('click here', 'user/register'))) : |
| 783 | ($required ? t('You must enter a promotional code to register for an account.') |
| 784 | : t('Please enter a promotional code, if you have one.'))), |
| 785 | '#required' => $required, |
| 786 | '#size' => 30, |
| 787 | '#maxlength' => 30, |
| 788 | ); |
| 789 | if ($url_code) { |
| 790 | $form['promotional_code']['#value'] = $url_code; |
| 791 | $form['promotional_code'] = array( |
| 792 | '#type' => 'value', |
| 793 | '#value' => $url_code, |
| 794 | ); |
| 795 | } |
| 796 | |
| 797 | return $form; |
| 798 | } |
| 799 | |
| 800 | elseif ($op == 'validate' && $category == 'account') { |
| 801 | // We perform this validation if the promotional code is present, otherwise |
| 802 | // we assume that this is just editing the existing user, which we don't |
| 803 | // care about. |
| 804 | if (isset($edit['promotional_code']) && $edit['promotional_code']) { |
| 805 | $promotion = promotion_find_match($edit['promotional_code']); |
| 806 | |
| 807 | if (!$promotion->valid_match) { |
| 808 | form_set_error('promotional_code', $promotion->validation_error); |
| 809 | } |
| 810 | } |
| 811 | } |
| 812 | |
| 813 | elseif ($op == 'insert') { |
| 814 | if (isset($edit['promotional_code']) && $edit['promotional_code']) { |
| 815 | $promotion = promotion_find_match($edit['promotional_code']); |
| 816 | |
| 817 | $now = time(); |
| 818 | $status = 1; |
| 819 | |
| 820 | // Delay role activation if the promotion requests it and the activation |
| 821 | // date is yet future |
| 822 | if ($promotion->activate_when == PROMO_ACT_ROLES_WAIT && $promotion->activation_date > $now) { |
| 823 | $user_register = variable_get('user_register', 1); |
| 824 | if ($user_register == 1) { |
| 825 | drupal_set_message(t('Your account will be activated after verifying your email address. However, some features of this site may not available until after %date, which is the promotion you signed up with officially starts.', array('%date' => format_date($promotion->activation_date, 'large')))); |
| 826 | } |
| 827 | else { |
| 828 | drupal_set_message(t('Once your account has been approved and your email address verified, you account will be activated. However, some features of this site may not be available until after %date, which is when the promotion you signed up with officially starts.', array('%date' => format_date($promotion->activation_date, 'large')))); |
| 829 | } |
| 830 | |
| 831 | watchdog('promotion', |
| 832 | t('Delaying role activation of account %user because the promotion date of %promo is in the future.', array('%promo' => $promotion->title, '%user' => $edit['name'])), |
| 833 | WATCHDOG_NOTICE, l('edit', '/user/'.$edit['uid'])); |
| 834 | |
| 835 | $status = 0; |
| 836 | } |
| 837 | |
| 838 | // Delay account activation if the promotion requests it and the |
| 839 | // activation date is yet future |
| 840 | elseif ($promotion->activate_when == PROMO_ACT_ALL_WAIT && $promotion->activation_date > $now) { |
| 841 | drupal_set_message(t('Your account will not be available after verifying your email address. The promotion you have signed up with has not yet started. Your account will become active after %date.', array('%date' => format_date($promotion->activation_date, 'large')))); |
| 842 | |
| 843 | // Make sure the account is blocked |
| 844 | db_query(" |
| 845 | UPDATE {users} SET status = %d WHERE uid = %d", |
| 846 | 0, $edit['uid']); |
| 847 | |
| 848 | watchdog('promotion', |
| 849 | t('Delaying account activation of account %user because the promotion date of %promo is in the future.', array('%promo' => $promotion->title, '%user' => $edit['name'])), |
| 850 | WATCHDOG_NOTICE, l('edit', '/user/'.$edit['uid'])); |
| 851 | |
| 852 | $status = 0; |
| 853 | } |
| 854 | |
| 855 | db_query(" |
| 856 | INSERT INTO {promotion_codes_users} (pid, uid, code_used, status) |
| 857 | VALUES (%d, %d, '%s', %d)", |
| 858 | $promotion->pid, $account->uid, $edit['promotional_code'], $status); |
| 859 | |
| 860 | $edit['promotional_code'] = NULL; |
| 861 | |
| 862 | if ($status) { |
| 863 | // Add initial role promotion |
| 864 | $edit['roles'] = $promotion->promotion_roles; |
| 865 | |
| 866 | watchdog('promotion', |
| 867 | t('Activating roles of account %user using %promo.', array('%promo' => $promotion->title, '%user' => $edit['name'])), |
| 868 | WATCHDOG_NOTICE, l('edit', '/user/'.$edit['uid'])); |
| 869 | } |
| 870 | } |
| 871 | } |
| 872 | |
| 873 | // $op == 'delete' is not implemented on purpose. Registered codes remain |
| 874 | // used even if the user that used that code no longer exists. |
| 875 | } |
| 876 | |
| 877 | /** |
| 878 | * This method searches through the available and active promotions to find a |
| 879 | * matching promotion record. It then loads and returns that record. In |
| 880 | * addition, it sets the valid_match value to TRUE. |
| 881 | * |
| 882 | * On failure, it returns an object that has the valid_match value set to FALSE |
| 883 | * and the validation_error set to a localized message to return to the user. No |
| 884 | * other values will be set on the returned object. |
| 885 | */ |
| 886 | function promotion_find_match($code) { |
| 887 | // Search for active promotions |
| 888 | $now = time(); |
| 889 | $result = db_query(" |
| 890 | SELECT pid |
| 891 | FROM {promotion_codes} |
| 892 | WHERE active_promotion = 1 |
| 893 | AND (start_date IS NULL OR start_date = 0 OR start_date <= %d) |
| 894 | AND (end_date IS NULL OR end_date = 0 OR end_date >= %d)", |
| 895 | $now, $now); |
| 896 | |
| 897 | // Iterate through the active promotions found |
| 898 | while ($promo = db_fetch_array($result)) { |
| 899 | |
| 900 | // Load the promotion object |
| 901 | $promotion = promotion_get_promotion($promo['pid']); |
| 902 | |
| 903 | // Check to see if the given promotion matches the code |
| 904 | if (promotion_match($promotion, $code)) { |
| 905 | // Appears to match, but make sure it has not been already used too |
| 906 | // many times... |
| 907 | if ($promotion->max_use_count > 0) { |
| 908 | $result = db_query(" |
| 909 | SELECT count(*) AS user_count |
| 910 | FROM {promotion_codes_users} |
| 911 | WHERE pid = %d AND lower(code_used) = lower('%s')", |
| 912 | $promotion->pid, $code); |
| 913 | |
| 914 | // fetch the count |
| 915 | if ($counter = db_fetch_array($result)) { |
| 916 | if ($counter['user_count'] >= $promotion->max_use_count) { |
| 917 | // Too bad, already used up |
| 918 | $used_up_promotion = $promotion; |
| 919 | continue; |
| 920 | // Keep searching, just in case it matches another promotion |
| 921 | } |
| 922 | } |
| 923 | } |
| 924 | |
| 925 | // Success! Found a matching promotion that it can consume |
| 926 | $promotion->valid_match = TRUE; |
| 927 | return $promotion; |
| 928 | } |
| 929 | } |
| 930 | |
| 931 | // We looked, but all we found was a used promotion |
| 932 | if ($used_up_promotion) { |
| 933 | $used_up_promotion->valid_match = FALSE; |
| 934 | $used_up_promotion->validation_error = t('Sorry, the promotional code you have given has already been used.'); |
| 935 | return $used_up_promotion; |
| 936 | } |
| 937 | |
| 938 | // They have an invalid code, but let's try to be specific with the error |
| 939 | // message in case it's an old imperial--er promotional code. |
| 940 | $result = db_query(" |
| 941 | SELECT pid |
| 942 | FROM {promotion_codes} |
| 943 | WHERE active_promotion = 0 OR start_date > %d OR end_date < %d", |
| 944 | $now, $now); |
| 945 | |
| 946 | // iterate through all codes to find any possible match |
| 947 | while ($promo = db_fetch_array($result)) { |
| 948 | $promotion = promotion_get_promotion($promo['pid']); |
| 949 | |
| 950 | // Attempt to match this code against this inactive promotion |
| 951 | if (promotion_match($promotion, $code)) { |
| 952 | |
| 953 | // The promotion hasn't yet started |
| 954 | if ($promotion->start_date && $promotion->start_date > $now) { |
| 955 | $promotion->valid_match = FALSE; |
| 956 | $promotion->validation_error = t('The promotional code you have given is not yet available.'); |
| 957 | return $promotion; |
| 958 | } |
| 959 | |
| 960 | // The promotion has ended |
| 961 | if ($promotion->end_date && $promotion->end_date < $now) { |
| 962 | $promotion->valid_match = FALSE; |
| 963 | $promotion->validation_error = t('The promotional code you have entered has expired and is no longer available.'); |
| 964 | return $promotion; |
| 965 | } |
| 966 | |
| 967 | // The promotion just isn't active |
| 968 | if (!$promotion->active_promotion) { |
| 969 | $promotion->valid_match = FALSE; |
| 970 | $promotion->validation_error = t('The promotional code you have entered is not currently active.'); |
| 971 | return $promotion; |
| 972 | } |
| 973 | } |
| 974 | } |
| 975 | |
| 976 | // Complete non-match, return a generic error |
| 977 | $promotion = array( |
| 978 | 'valid_match' => FALSE, |
| 979 | 'validation_error' => t('Sorry, but the code you have given does not match any current promotion. Please check that it is correct and try again.'), |
| 980 | ); |
| 981 | return (object) $promotion; |
| 982 | } |
| 983 | |
| 984 | /** |
| 985 | * Matches a specific code against a promotion. This matches the code against |
| 986 | * the promotion. |
| 987 | * |
| 988 | * Returns TRUE if the code matches or FALSE if it does not. |
| 989 | */ |
| 990 | function promotion_match($promotion, $code) { |
| 991 | // Perform an exact match (ignoring case) |
| 992 | if ($promotion->code_type == PROMO_TYPE_EXACT) { |
| 993 | return strcasecmp($promotion->simple_code, $code) == 0; |
| 994 | } |
| 995 | |
| 996 | // Convert the promotion code into a regulary expression and match |
| 997 | elseif ($promotion->code_type == PROMO_TYPE_SIMPLE) { |
| 998 | |
| 999 | // Process the code matcher into a regular expression |
| 1000 | $state = 'exact'; |
| 1001 | $simple_match = ''; |
| 1002 | foreach (str_split($promotion->simple_code) as $char) { |
| 1003 | if ($state == 'exact') { |
| 1004 | if ($char == '[') { |
| 1005 | $state = 'match'; |
| 1006 | } |
| 1007 | else { |
| 1008 | $simple_match .= preg_quote($char); |
| 1009 | } |
| 1010 | } |
| 1011 | else { |
| 1012 | if ($char == ']') { |
| 1013 | $state = 'exact'; |
| 1014 | } |
| 1015 | elseif (ctype_alpha($char)) { |
| 1016 | $simple_match .= '\p{L}'; // match any unicode letter |
| 1017 | } |
| 1018 | elseif (ctype_digit($char)) { |
| 1019 | $simple_match .= '\p{N}'; // match any unicode number |
| 1020 | } |
| 1021 | else { |
| 1022 | $simple_match .= preg_quote($char); // uh? what? |
| 1023 | } |
| 1024 | } |
| 1025 | } |
| 1026 | |
| 1027 | // Perform the comparison |
| 1028 | return preg_match("/^$simple_match\$/i", $code); |
| 1029 | } |
| 1030 | |
| 1031 | // Shouldn't happen |
| 1032 | else { |
| 1033 | watchdog('promotion', |
| 1034 | t('Unknown promotional code type %code_type', array('%code_type' => $promotion->code_type)), |
| 1035 | WATCHDOG_ERROR, l('edit', 'admin/user/promotion/'.$promotion->pid)); |
| 1036 | return FALSE; |
| 1037 | } |
| 1038 | } |
| 1039 | |
| 1040 | /** |
| 1041 | * Implements hook_cron(). |
| 1042 | * |
| 1043 | * This performs the work of expiring an unexpired promotion account. |
| 1044 | */ |
| 1045 | function promotion_cron() { |
| 1046 | $now = time(); |
| 1047 | _promotion_process_activation($now); |
| 1048 | _promotion_process_expiration($now); |
| 1049 | } |
| 1050 | |
| 1051 | /** |
| 1052 | * Performs the work during cron of activating accounts when a promotion has |
| 1053 | * become active. |
| 1054 | */ |
| 1055 | function _promotion_process_activation($now) { |
| 1056 | $result = db_query(" |
| 1057 | SELECT p.pid AS pid, c.uid AS uid, c.code_used AS code_used |
| 1058 | FROM {promotion_codes_users} c INNER JOIN {promotion_codes} p |
| 1059 | ON c.pid = p.pid |
| 1060 | WHERE p.active_promotion = 1 |
| 1061 | AND (p.activate_when = 2 OR p.activate_when = 3) |
| 1062 | AND p.activation_date < %d AND c.status = 0 |
| 1063 | AND (p.accounts_expire = 0 OR p.expiration_date > %d)", |
| 1064 | $now, $now); |
| 1065 | |
| 1066 | while ($pid_uid = db_fetch_array($result)) { |
| 1067 | $promotion = promotion_get_promotion($pid_uid['pid']); |
| 1068 | $account = user_load(array(uid => $pid_uid['uid'])); |
| 1069 | |
| 1070 | if ($promotion && $account) { |
| 1071 | $edit['roles'] = $account->roles; |
| 1072 | foreach ($promotion->promotion_roles as $rid) { |
| 1073 | $edit['roles'][$rid] = $rid; |
| 1074 | } |
| 1075 | |
| 1076 | if ($promotion->activate_when == PROMO_ACT_ALL_WAIT) { |
| 1077 | $edit['status'] = 1; |
| 1078 | } |
| 1079 | |
| 1080 | watchdog('promotion', |
| 1081 | t('Activating %name with email address %email with promotion %promotion (%code).', array('%name' => $account->name, '%email' => $account->mail, '%promotion' => $promotion->name, '%code' => $pid_uid['code_used'])), |
| 1082 | WATCHDOG_NOTICE); |
| 1083 | |
| 1084 | user_save($account, $edit); |
| 1085 | } |
| 1086 | |
| 1087 | db_query(" |
| 1088 | UPDATE {promotion_codes_users} |
| 1089 | SET status = 1 |
| 1090 | WHERE pid = %d AND uid = %d |
| 1091 | ", $pid_uid['pid'], $pid_uid['uid']); |
| 1092 | } |
| 1093 | } |
| 1094 | |
| 1095 | /** |
| 1096 | * Performs the work during cron of actually deactivating accounts when a |
| 1097 | * promotion has expired. |
| 1098 | */ |
| 1099 | function _promotion_process_expiration($now) { |
| 1100 | $result = db_query(" |
| 1101 | SELECT p.pid AS pid, c.uid AS uid, c.code_used AS code_used |
| 1102 | FROM {promotion_codes_users} c INNER JOIN {promotion_codes} p |
| 1103 | ON c.pid = p.pid |
| 1104 | WHERE p.active_promotion = 1 AND p.accounts_expire = 1 |
| 1105 | AND p.expiration_date < %d AND c.status = 1 |
| 1106 | ", $now); |
| 1107 | |
| 1108 | while ($pid_uid = db_fetch_array($result)) { |
| 1109 | $promotion = promotion_get_promotion($pid_uid['pid']); |
| 1110 | $account = user_load(array(uid => $pid_uid['uid'])); |
| 1111 | |
| 1112 | if ($promotion && $account) { |
| 1113 | if ($promotion->expiration_action == PROMO_EXP_ACTION_DELETE) { |
| 1114 | user_delete(NULL, $account->uid); |
| 1115 | |
| 1116 | watchdog('promotion', |
| 1117 | t('Deleted %name with email address %email because promotion %promotion (%code) expired.', array('%name' => $account->name, '%email' => $account->mail, '%promotion' => $promotion->name, '%code' => $pid_uid['code_used'])), |
| 1118 | WATCHDOG_NOTICE); |
| 1119 | } |
| 1120 | |
| 1121 | else { |
| 1122 | $edit = array(); |
| 1123 | |
| 1124 | if ($promotion->expiration_action == PROMO_EXP_ACTION_BLOCK |
| 1125 | || $promotion->expiration_action == PROMO_EXP_ACTION_DEMOTE_AND_BLOCK) { |
| 1126 | |
| 1127 | $edit['status'] = 0; |
| 1128 | |
| 1129 | watchdog('promotion', |
| 1130 | t('Blocking %name with email address %email because promotion %promotion (%code) expired.', array('%name' => $account->name, '%email' => $account->mail, '%promotion' => $promotion->name, '%code' => $pid_uid['code_used'])), |
| 1131 | WATCHDOG_NOTICE); |
| 1132 | } |
| 1133 | |
| 1134 | if ($promotion->expiration_action == PROMO_EXP_ACTION_DEMOTE |
| 1135 | || $promotion->expiration_action == PROMO_EXP_ACTION_DEMOTE_AND_BLOCK) { |
| 1136 | |
| 1137 | $edit['roles'] = $account->roles; |
| 1138 | foreach ($promotion->demotion_roles as $rid) { |
| 1139 | unset($edit['roles'][$rid]); |
| 1140 | } |
| 1141 | |
| 1142 | watchdog('promotion', |
| 1143 | t('Demoting %name with email address %email because promotion %promotion (%code) expired.', array('%name' => $account->name, '%email' => $account->mail, '%promotion' => $promotion->name, '%code' => $pid_uid['code_used'])), |
| 1144 | WATCHDOG_NOTICE); |
| 1145 | } |
| 1146 | |
| 1147 | user_save($account, $edit); |
| 1148 | } |
| 1149 | } |
| 1150 | |
| 1151 | db_query(" |
| 1152 | UPDATE {promotion_codes_users} |
| 1153 | SET status = 0 |
| 1154 | WHERE pid = %d AND uid = %d |
| 1155 | ", $pid_uid['pid'], $pid_uid['uid']); |
| 1156 | } |
| 1157 | } |
| 1158 | |
| 1159 | function promotion_statistics($pid = NULL, $detail = NULL) { |
| 1160 | if (!isset($pid)) { |
| 1161 | return _promotion_statistics_general(); |
| 1162 | } |
| 1163 |