1<?php 2 3/* 4 * Task coordinator is taken from tasktypes 5 */ 6//require_once 'entity.php'; 7// 8//class BEZ_mdl_Dummy_Task extends BEZ_mdl_Entity { 9// protected $coordinator; 10// 11// function __construct($model, $defaults=array()) { 12// parent::__construct($model); 13// 14// if (isset($defaults['issue'])) { 15// $issue = $this->model->issues->get_one($defaults['issue']); 16// $this->coordinator = $issue->coordinator; 17// } else { 18// $this->coordinator = ''; 19// } 20// } 21// 22// public function __get($property) { 23// if ($property === 'coordinator') { 24// return $this->coordinator; 25// } 26// parent::__get($property); 27// } 28//} 29 30namespace dokuwiki\plugin\bez\mdl; 31 32use dokuwiki\plugin\bez\meta\Mailer; 33use dokuwiki\plugin\bez\meta\PermissionDeniedException; 34use dokuwiki\plugin\bez\meta\ValidationException; 35 36class Task extends Entity { 37 38 protected $id; 39 40 protected $original_poster, $assignee, $closed_by; 41 42 protected $private, $lock; 43 44 protected $state, $type; 45 46 protected $create_date, $last_activity_date, $last_modification_date, $close_date; 47 48 protected $cost, $plan_date, $all_day_event, $start_time, $finish_time; 49 50 protected $content, $content_html; 51 52 protected $thread_id, $thread_comment_id, $task_program_id; 53 54 /** @var \dokuwiki\plugin\bez\mdl\Thread */ 55 protected $thread; 56 57 /** @var Thread_comment */ 58 protected $thread_comment; 59 60 //virtual 61 protected $task_program_name; 62 63 public static function get_columns() { 64 return array('id', 65 'original_poster', 'assignee', 'closed_by', 66 'private', 'lock', 67 'state', 'type', 68 'create_date', 'last_activity_date', 'last_modification_date', 'close_date', 69 'cost', 'plan_date', 'all_day_event', 'start_time', 'finish_time', 70 'content', 'content_html', 71 'thread_id', 'thread_comment_id', 'task_program_id'); 72 } 73 74 public static function get_types() { 75 return array('correction', 'corrective', 'preventive', 'program'); 76 } 77 78 public static function get_states() { 79 return array('opened', 'done'); 80 } 81 82 public function __get($property) { 83 if ($property == 'thread' || $property == 'thread_comment' || $property == 'task_program_name') { 84 return $this->$property; 85 } 86 return parent::__get($property); 87 } 88 89 90// private function state_string() { 91// switch($this->state) { 92// case '0': return 'task_opened'; 93// case '-outdated': return 'task_outdated'; 94// case '1': return 'task_done'; 95// case '2': return 'task_rejected'; 96// } 97// } 98// 99// private function action_string() { 100// switch($this->action) { 101// case '0': return 'correction'; 102// case '1': return 'corrective_action'; 103// case '2': return 'preventive_action'; 104// case '3': return 'programme'; 105// } 106// } 107// 108// public function cost_localized() { 109// if ($this->cost === '') { 110// return ''; 111// } 112// 113// return sprintf('%.2f', (float)$this->cost); 114// } 115// 116// private function update_virtual_columns() { 117// $this->state_string = $this->model->action->getLang($this->state_string()); 118// $this->action_string = $this->model->action->getLang($this->action_string()); 119// $this->tasktype_string = $this->model->tasktypes->get_one($this->tasktype)->type; 120// } 121// 122// public function user_is_executor() { 123// if ($this->executor === $this->model->user_nick || 124// $this->model->acl->get_level() >= BEZ_AUTH_ADMIN) { 125// return true; 126// } 127// } 128 129 //by defaults you can set: cause, tasktype and issue 130 //tasktype is required 131 public function __construct($model, $defaults=array()) { 132 parent::__construct($model, $defaults); 133 134 135 //array(filter, NULL) 136 $this->validator->set_rules(array( 137// 'reporter' => array(array('dw_user'), 'NOT NULL'), 138// 'date' => array(array('unix_timestamp'), 'NOT NULL'), 139// 'close_date' => array(array('unix_timestamp'), 'NULL'), 140// 'cause' => array(array('numeric'), 'NULL'), 141 142// 'executor' => array(array('dw_user'), 'NOT NULL'), 143 144// 'issue' => array(array('numeric'), 'NULL'), 145 146 'assignee' => array(array('dw_user'), 'NOT NULL'), 147 'cost' => array(array('numeric'), 'NULL'), 148 'plan_date' => array(array('iso_date'), 'NOT NULL'), 149 'all_day_event' => array(array('select', array('0', '1')), 'NOT NULL'), 150 'start_time' => array(array('time'), 'NULL'), 151 'finish_time' => array(array('time'), 'NULL'), 152 'content' => array(array('length', 10000), 'NOT NULL'), 153 'thread_comment_id' => array(array('numeric'), 'NULL'), 154 'task_program_id' => array(array('numeric'), 'NULL') 155 156// 'state' => array(array('select', array('0', '1', '2')), 'NULL'), 157// 'reason' => array(array('length', 10000), 'NULL'), 158 159// 'coordinator' => array(array('dw_user', array('-none')), 'NOT NULL'), 160 )); 161 162 //we've created empty object 163 if ($this->id === NULL) { 164 $this->original_poster = $this->model->user_nick; 165 $this->create_date = date('c'); 166 $this->last_activity_date = $this->create_date; 167 $this->last_modification_date = $this->create_date; 168 169 $this->state = 'opened'; 170 171 if (isset($defaults['thread'])) { 172 $this->thread = $defaults['thread']; 173 $this->thread_id = $this->thread->id; 174 $this->type = 'correction'; 175 176 if (isset($defaults['thread_comment'])) { 177 $this->thread_comment = $defaults['thread_comment']; 178 $this->thread_comment_id = $this->thread_comment->id; 179 180 if ($this->thread_comment->type == 'cause_real') { 181 $this->type = 'corrective'; 182 } else { 183 $this->type = 'preventive'; 184 } 185 } 186 } 187 188// //meta 189// $this->reporter = $this->model->user_nick; 190// $this->date = time(); 191// 192// $this->state = '0'; 193// $this->all_day_event = '1'; 194// 195// //throws ValidationException 196// $this->issue = $this->validator->validate_field('issue', $defaults['issue']); 197// 198// if ($this->issue !== '') { 199// $issue = $this->model->issues->get_one($defaults['issue']); 200// $this->coordinator = $issue->coordinator; 201// } else { 202// $this->coordinator = ''; 203// } 204// 205// //throws ValidationException 206// $this->validator->validate_field('cause', $defaults['cause']); 207// $this->cause = $defaults['cause']; 208// 209// //by default reporter is a executor 210// $this->executor = $this->reporter; 211 212 213 //we get object form db 214 } else { 215 if ($this->thread_id != '') { 216 if (isset($defaults['thread']) && $this->thread_id == $defaults['thread']->id) { 217 $this->thread = $defaults['thread']; 218 } elseif ($this->thread_id != null) { 219 $this->thread = $this->model->threadFactory->get_one($this->thread_id); 220 } 221 222 if (isset($defaults['thread_comment']) && $this->thread_comment_id == $defaults['thread_comment']->id) { 223 $this->thread_comment = $defaults['thread_comment']; 224 } elseif ($this->thread_comment_id != null) { 225 $this->thread_comment = $this->model->thread_commentFactory->get_one($this->thread_comment_id); 226 } 227 228 } 229 } 230 231 if ($this->thread_id == '') { 232 $this->validator->set_rules(array( 233 'task_program_id' => array(array('numeric'), 'NOT NULL'), 234 )); 235 //this field is unused in program tasks 236 $this->validator->delete_rule('thread_comment_id'); 237 } 238 239 240// //close_date required 241// if ($this->state !== '0') { 242// $this->validator->set_rules(array( 243// 'close_date' => array(array('unix_timestamp'), 'NOT NULL') 244// )); 245// } 246 247 //explode subscribents 248// if ($this->subscribents !== NULL) { 249// $exp_part = explode(',', $this->subscribents); 250// foreach ($exp_part as $subscribent) { 251// $this->subscribents_array[$subscribent] = $subscribent; 252// } 253// } 254// 255// //we've created empty object 256// if ($this->id === NULL) { 257// //throws ValidationException 258// $this->validator->validate_field('tasktype', $defaults['tasktype']); 259// $this->tasktype = $defaults['tasktype']; 260// } 261 } 262 263 264 public function set_data($post, $filter=NULL) { 265 parent::set_data($post); 266 267 $this->content_html = p_render('xhtml',p_get_instructions($this->content), $ignore); 268 269 //update dates 270 $this->last_modification_date = date('c'); 271 $this->last_activity_date = $this->last_modification_date; 272 273 //specjalne reguły 274// if ($this->issue === '') { 275// $this->cause = ''; 276// } 277 278 //set parsed 279// $this->task_cache = $this->helper->wiki_parse($this->task); 280// $this->reason_cache = $this->helper->wiki_parse($this->reason); 281 282 //update virtuals 283 //$this->update_virtual_columns(); 284 285 return true; 286 } 287 288 public function set_state($state) { 289 if ($this->acl_of('state') < BEZ_PERMISSION_CHANGE) { 290 throw new PermissionDeniedException(); 291 } 292 293 if (!in_array($state, array('opened', 'done'))) { 294 throw new ValidationException('task', array('sholud be opened or done')); 295 } 296 297 //nothing to do 298 if ($state == $this->state) { 299 return; 300 } 301 302 if ($state == 'done') { 303 $this->model->sqlite->query("UPDATE {$this->get_table_name()} SET state=?, closed_by=?, close_date=? WHERE id=?", 304 $state, 305 $this->model->user_nick, 306 date('c'), 307 $this->id); 308 //reopen the task 309 } else { 310 $this->model->sqlite->query("UPDATE {$this->get_table_name()} SET state=? WHERE id=?", $state, $this->id); 311 } 312 313 $this->state = $state; 314 } 315 316 public function update_last_activity() { 317 $this->last_activity_date = date('c'); 318 $this->model->sqlite->query('UPDATE task SET last_activity_date=? WHERE id=?', 319 $this->last_activity_date, $this->id); 320 } 321 322// public function update_cache() { 323// if ($this->model->acl->get_level() < BEZ_AUTH_ADMIN) { 324// return false; 325// } 326// $this->task_cache = $this->helper->wiki_parse($this->task); 327// $this->reason_cache = $this->helper->wiki_parse($this->reason); 328// } 329// 330// public function set_state($data) { 331// //reason is required while changing state 332// if ($data['state'] === '2') { 333// $this->validator->set_rules(array( 334// 'reason' => array(array('length', 10000), 'NOT NULL') 335// )); 336// } 337// 338// $val_data = $this->validator->validate($data, array('state', 'reason')); 339// if ($val_data === false) { 340// throw new ValidationException('tasks', $this->validator->get_errors()); 341// } 342// 343// //if state is changed 344// if ($this->state != $data['state']) { 345// $this->close_date = time(); 346// } 347// 348// $this->set_property_array($val_data); 349// $this->reason_cache = $this->helper->wiki_parse($this->reason); 350// 351// //update virtuals 352// $this->update_virtual_columns(); 353// 354// return true; 355// } 356// 357// public function get_meta_fields() { 358// return array('reporter', 'date', 'close_date'); 359// } 360// 361// public function set_meta($post) { 362// 363// if (isset($post['date'])) { 364// $unix = strtotime($post['date']); 365// //if $unix === false validator will catch it 366// if ($unix !== false) { 367// $post['date'] = (string)$unix; 368// } 369// } 370// 371// if (isset($post['close_date'])) { 372// $unix = strtotime($post['close_date']); 373// //if $unix === false validator will catch it 374// if ($unix !== false) { 375// $post['close_date'] = (string)$unix; 376// } 377// } 378// 379// parent::set_data($post, $this->get_meta_fields()); 380// } 381// 382// public function is_subscribent($user=NULL) { 383// if ($user === NULL) { 384// $user = $this->model->user_nick; 385// } 386// if (in_array($user, $this->subscribents_array)) { 387// return true; 388// } 389// return false; 390// } 391// 392// public function get_subscribents() { 393// return $this->subscribents_array; 394// } 395// 396// public function get_participants() { 397// $subscribents = array_merge(array($this->reporter, $this->executor), 398// $this->subscribents_array); 399// $full_names = array(); 400// foreach ($subscribents as $par) { 401// $name = $this->model->users->get_user_full_name($par); 402// if ($name == '') { 403// $full_names[$par] = $par; 404// } else { 405// $full_names[$par] = $name; 406// } 407// } 408// ksort($full_names); 409// return $full_names; 410// } 411// 412// public function remove_subscribent($subscribent) { 413// if ($subscribent !== $this->model->user_nick && 414// $this->acl_of('subscribents') < BEZ_PERMISSION_CHANGE) { 415// throw new PermissionDeniedException(); 416// } 417// 418// if ($this->issue != '') { 419// throw new ConsistencyViolationException('cannot modify subscribents from issue related tasks'); 420// } 421// 422// if (!isset($this->subscribents_array[$subscribent])) { 423// throw new ConsistencyViolationException('user '.$subscribent.' wasn\'t subscriber so cannot be removed'); 424// } 425// 426// unset($this->subscribents_array[$subscribent]); 427// $this->subscribents = implode(',', $this->subscribents_array); 428// } 429// 430// public function add_subscribent($subscribent) { 431// if ($subscribent !== $this->model->user_nick && 432// $this->acl_of('subscribents') < BEZ_PERMISSION_CHANGE) { 433// throw new PermissionDeniedException(); 434// } 435// 436// if ($this->issue != '') { 437// throw new ConsistencyViolationException('cannot add subscribents to issue related tasks'); 438// } 439// 440// if ($this->model->users->exists($subscribent) && 441// !in_array($subscribent, $this->subscribents_array)) { 442// $this->subscribents_array[$subscribent] = $subscribent; 443// $this->subscribents = implode(',', $this->subscribents_array); 444// 445// return true; 446// } 447// 448// return false; 449// } 450 451 public function get_participants($filter='') { 452 if ($this->acl_of('participants') < BEZ_PERMISSION_VIEW) { 453 throw new PermissionDeniedException(); 454 } 455 if ($this->id === NULL) { 456 return array(); 457 } 458 459 $sql = 'SELECT * FROM task_participant WHERE'; 460 $possible_flags = array('original_poster', 'assignee', 'commentator', 'subscribent'); 461 if ($filter != '') { 462 if (!in_array($filter, $possible_flags)) { 463 throw new \Exception("unknown flag $filter"); 464 } 465 $sql .= " $filter=1 AND"; 466 } 467 $sql .= ' task_id=? ORDER BY user_id'; 468 469 $r = $this->model->sqlite->query($sql, $this->id); 470 $pars = $this->model->sqlite->res2arr($r); 471 $participants = array(); 472 foreach ($pars as $par) { 473 $participants[$par['user_id']] = $par; 474 } 475 476 return $participants; 477 } 478 479 public function get_participant($user_id) { 480 if ($this->acl_of('participants') < BEZ_PERMISSION_VIEW) { 481 throw new PermissionDeniedException(); 482 } 483 if ($this->id === NULL) { 484 return array(); 485 } 486 487 $r = $this->model->sqlite->query('SELECT * FROM task_participant WHERE task_id=? AND user_id=?', $this->id, $user_id); 488 $par = $this->model->sqlite->res2row($r); 489 if (!is_array($par)) { 490 return false; 491 } 492 493 return $par; 494 } 495 496 public function is_subscribent($user_id=null) { 497 if ($user_id == null) { 498 $user_id = $this->model->user_nick; 499 } 500 $par = $this->get_participant($user_id); 501 if ($par['subscribent'] == 1) { 502 return true; 503 } 504 return false; 505 } 506 507 public function remove_participant_flags($user_id, $flags) { 508 if ($this->acl_of('participants') < BEZ_PERMISSION_CHANGE) { 509 throw new PermissionDeniedException(); 510 } 511 512 //thread not saved yet 513 if ($this->id === NULL) { 514 throw new \Exception('cannot remove flags from not saved thread'); 515 } 516 517 $possible_flags = array('original_poster', 'assignee', 'commentator', 'subscribent'); 518 if (array_intersect($flags, $possible_flags) != $flags) { 519 throw new \Exception('unknown flags'); 520 } 521 522 $set = implode(',', array_map(function ($v) { return "$v=0"; }, $flags)); 523 524 $sql = "UPDATE task_participant SET $set WHERE task_id=? AND user_id=?"; 525 $this->model->sqlite->query($sql, $this->id, $user_id); 526 527 } 528 529 public function set_participant_flags($user_id, $flags=array()) { 530 if ($this->acl_of('participants') < BEZ_PERMISSION_CHANGE) { 531 throw new PermissionDeniedException(); 532 } 533 534 //thread not saved yet 535 if ($this->id === NULL) { 536 throw new \Exception('cannot add flags to not saved thread'); 537 } 538 539 //validate user 540 if (!$this->model->userFactory->exists($user_id)) { 541 throw new \Exception("$user_id isn't dokuwiki user"); 542 } 543 544 $possible_flags = array('original_poster', 'assignee', 'commentator', 'subscribent'); 545 if (array_intersect($flags, $possible_flags) != $flags) { 546 throw new \Exception('unknown flags'); 547 } 548 549 $participant = $this->get_participant($user_id); 550 if ($participant == false) { 551 $participant = array_fill_keys($possible_flags, 0); 552 553 $participant['task_id'] = $this->id; 554 $participant['user_id'] = $user_id; 555 $participant['added_by'] = $this->model->user_nick; 556 $participant['added_date'] = date('c'); 557 } 558 $values = array_merge($participant, array_fill_keys($flags, 1)); 559 560 $keys = join(',', array_keys($values)); 561 $vals = join(',', array_fill(0,count($values),'?')); 562 563 $sql = "REPLACE INTO task_participant ($keys) VALUES ($vals)"; 564 $this->model->sqlite->query($sql, array_values($values)); 565 566 567 568// if (! ( $this->user_is_coordinator() || 569// $participant === $this->model->user_nick || 570// $participant === $this->coordinator) //dodajemy nowego koordynatora 571// ) { 572// throw new PermissionDeniedException(); 573// } 574// if ($this->model->users->exists($participant)) { 575// $this->participants_array[$participant] = $participant; 576// $this->participants = implode(',', $this->participants_array); 577// } 578 } 579 580 public function invite($client) { 581 $this->set_participant_flags($client, array('subscribent')); 582 $this->mail_notify_invite($client); 583 } 584 585 private function mail_notify($replacements=array(), $users=false) { 586 $plain = io_readFile($this->model->action->localFN('task-notification')); 587 $html = io_readFile($this->model->action->localFN('task-notification', 'html')); 588 589 $task_link = $this->model->action->url('task', 'tid', $this->id); 590 591 $reps = array( 592 'task_id' => $this->id, 593 'task_link' => $task_link, 594 'who' => $this->original_poster 595 ); 596 597 //$replacements can override $reps 598 $rep = array_merge($reps, $replacements); 599 600 if (!isset($rep['who_full_name'])) { 601 $rep['who_full_name'] = 602 $this->model->userFactory->get_user_full_name($rep['who']); 603 } 604 605 //auto title 606 if (!isset($rep['subject'])) { 607// if (isset($rep['content'])) { 608// $rep['subject'] = array_shift(explode('.', $rep['content'], 2)); 609// } 610 $rep['subject'] = '#z'.$this->id. ' ' . $this->task_program_name; 611 } 612 613 //we must do it manually becouse Mailer uses htmlspecialchars() 614 $html = str_replace('@TASK_TABLE@', $rep['task_table'], $html); 615 616 $mailer = new Mailer(); 617 $mailer->setBody($plain, $rep, $rep, $html, false); 618 619 if ($users === FALSE) { 620 $users = $this->get_participants('subscribent'); 621 622 //don't notify current user 623 unset($users[$this->model->user_nick]); 624 } 625 626 $emails = array_map(function($user) { 627 return $this->model->userFactory->get_user_email($user); 628 }, $users); 629 630 $mailer->to($emails); 631 $mailer->subject($rep['subject']); 632 633 $send = $mailer->send(); 634 if ($send === false) { 635 //this may mean empty $emails 636 //throw new Exception("can't send email"); 637 } 638 } 639 640 protected function bez_html_array_to_style_list($arr) { 641 $output = ''; 642 foreach ($arr as $k => $v) { 643 $output .= $k.': '. $v . ';'; 644 } 645 return $output; 646 } 647 648 protected function bez_html_irrtable($style) { 649 $argv = func_get_args(); 650 $argc = func_num_args(); 651 if (isset($style['table'])) { 652 $output = '<table style="'.self::bez_html_array_to_style_list($style['table']).'">'; 653 } else { 654 $output = '<table>'; 655 } 656 657 $tr_style = ''; 658 if (isset($style['tr'])) { 659 $tr_style = 'style="'.self::bez_html_array_to_style_list($style['tr']).'"'; 660 } 661 662 $td_style = ''; 663 if (isset($style['td'])) { 664 $td_style = 'style="'.self::bez_html_array_to_style_list($style['td']).'"'; 665 } 666 667 $row_max = 0; 668 669 for ($i = 1; $i < $argc; $i++) { 670 $row = $argv[$i]; 671 $c = count($row); 672 if ($c > $row_max) { 673 $row_max = $c; 674 } 675 } 676 677 for ($j = 1; $j < $argc; $j++) { 678 $row = $argv[$j]; 679 $output .= '<tr '.$tr_style.'>' . NL; 680 $c = count($row); 681 for ($i = 0; $i < $c; $i++) { 682 //last element 683 if ($i === $c - 1 && $c < $row_max) { 684 $output .= '<td '.$td_style.' colspan="' . ( $row_max - $c + 1 ) . '">' . NL; 685 } else { 686 $output .= '<td '.$td_style.'>' . NL; 687 } 688 $output .= $row[$i] . NL; 689 $output .= '</td>' . NL; 690 } 691 $output .= '</tr>' . NL; 692 } 693 $output .= '</table>' . NL; 694 return $output; 695 } 696 697 public function mail_notify_task_box($users=false, $replacements=array()) { 698// if ($issue_obj !== NULL && $issue_obj->id !== $this->issue) { 699// throw new Exception('issue object id and task->issue does not match'); 700// } 701 702 $top_row = array( 703 '<strong>'.$this->model->action->getLang('executor').': </strong>' . 704 $this->model->userFactory->get_user_full_name($this->assignee), 705 706 '<strong>'.$this->model->action->getLang('reporter').': </strong>' . 707 $this->model->userFactory->get_user_full_name($this->original_poster) 708 ); 709 710 if ($this->task_program_name != '') { 711 $top_row[] = 712 '<strong>'.$this->model->action->getLang('task_type').': </strong>' . 713 $this->task_program_name; 714 } 715 716 if ($this->cost != '') { 717 $top_row[] = 718 '<strong>'.$this->model->action->getLang('cost').': </strong>' . 719 $this->cost; 720 } 721 722 //BOTTOM ROW 723 $bottom_row = array( 724 '<strong>'.$this->model->action->getLang('plan_date').': </strong>' . 725 $this->plan_date 726 ); 727 728 if ($this->all_day_event == '0') { 729 $bottom_row[] = 730 '<strong>'.$this->model->action->getLang('start_time').': </strong>' . 731 $this->start_time; 732 $bottom_row[] = 733 '<strong>'.$this->model->action->getLang('finish_time').': </strong>' . 734 $this->finish_time; 735 } 736 737 $rep = array( 738 'content' => $this->content, 739 'content_html' => 740 '<h2 style="font-size: 1.2em;">'. 741 '<a href="'.$this->model->action->url('task', 'tid', $this->id).'">' . 742 '#z'.$this->id . 743 '</a> ' . 744 lcfirst($this->model->action->getLang('task_type_' . $this->type)) . ' ' . 745 '(' . 746 lcfirst($this->model->action->getLang('task_' . $this->state)) . 747 ')' . 748 '</h2>' . 749 self::bez_html_irrtable(array( 750 'table' => array( 751 'border-collapse' => 'collapse', 752 'font-size' => '0.8em', 753 'width' => '100%' 754 ), 755 'td' => array( 756 'border-top' => '1px solid #8bbcbc', 757 'border-bottom' => '1px solid #8bbcbc', 758 'padding' => '.3em .5em' 759 ) 760 ), $top_row, $bottom_row) . $this->content_html, 761 'who' => $this->model->user_nick, 762 'when' => $this->create_date, 763 'custom_content' => true 764 ); 765 766 $rep['action_color'] = '#e4f4f4'; 767 $rep['action_border_color'] = '#8bbcbc'; 768 769 //$replacements can override $reps 770 $rep = array_merge($rep, $replacements); 771 772// if ($this->thread == NULL) { 773// $this->mail_notify($rep, $users); 774// } else { 775// $this->thread->mail_notify($rep); 776// } 777 $this->mail_notify($rep, $users); 778 } 779 780 public function mail_notify_subscribents($replacements=array()) { 781 $this->mail_notify_task_box(false, $replacements); 782 } 783 784 public function mail_notify_add($users=false, $replacements=array()) { 785 $replacements['action'] = $this->model->action->getLang('mail_task_added'); 786 $this->mail_notify_task_box($users, $replacements); 787 } 788 789 public function mail_notify_remind($users=false) { 790 $replacements = array(); 791 792 $replacements['action'] = $this->model->action->getLang('mail_task_remind'); 793 //we don't want any who 794 $replacements['who_full_name'] = ''; 795 796 //$users = array($this->executor); 797 $this->mail_notify_task_box($users, $replacements); 798 } 799 800 public function mail_notify_invite($client) { 801 $replacements = array(); 802 803 $replacements['action'] = $this->model->action->getLang('mail_task_invite'); 804 805 $users = array($client); 806 $this->mail_notify_task_box($users, $replacements); 807 } 808} 809