1<?php 2 3//if(!defined('DOKU_INC')) die(); 4 5//require_once 'entity.php'; 6 7namespace dokuwiki\plugin\bez\mdl; 8 9use dokuwiki\plugin\bez\meta\Mailer; 10use dokuwiki\plugin\bez\meta\PermissionDeniedException; 11use dokuwiki\plugin\bez\meta\ValidationException; 12 13class Thread extends Entity { 14 15 protected $id; 16 17 protected $original_poster, $coordinator; 18 19 protected $private, $lock; 20 21 protected $type, $state; 22 23 protected $create_date, $last_activity_date, $last_modification_date, $close_date; 24 25 protected $title, $content, $content_html; 26 27 protected $priority; 28 29 protected $task_count, $task_count_open, $task_sum_cost; 30 31 /*new labels to add when object saved*/ 32 //protected $new_label_ids; 33 protected $labels; 34 35 public static function get_columns() { 36 return array('id', 37 'original_poster', 'coordinator', 38 'private', 'lock', 39 'type', 'state', 40 'create_date', 'last_activity_date', 'last_modification_date', 'close_date', 41 'title', 'content', 'content_html', 42 'priority', 43 'task_count', 'task_count_open', 'task_sum_cost'); 44 } 45 46 public static function get_select_columns() { 47 $cols = parent::get_select_columns(); 48 array_push($cols, 'label_id', 'label_name'); 49 return $cols; 50 } 51 52 public static function get_states() { 53 return array('proposal', 'opened', 'done', 'closed', 'rejected'); 54 } 55 56 57// private function state_string() { 58// if ($this->state === '2') { 59// return 'state_rejected'; 60// } else if ($this->coordinator === '-proposal') { 61// return 'state_proposal'; 62// } else if ( $this->state === '0' && 63// (int)$this->assigned_tasks_count > 0 && 64// (int)$this->opened_tasks_count === 0) { 65// return 'state_done'; 66// } else if ($this->state === '0') { 67// return 'state_opened'; 68// } else if ($this->state === '1') { 69// return 'state_closed'; 70// } 71// } 72// 73// private function type_string() { 74// if ($this->type === '') { 75// return ''; 76// } 77// $issuetype = $this->model->issuetypes->get_one($this->type)->get_assoc(); 78// return $issuetype[$this->model->conf['lang']]; 79// } 80// 81// private function priority() { 82// if ($this->state === '2') { 83// return '3'; 84// } 85// $min_pr = $this->model->tasks->min_priority(array('issue' => $this->id)); 86// if ($min_pr === NULL) { 87// return 'None'; 88// } 89// return $min_pr; 90// } 91 92 public function user_is_coordinator() { 93 if ($this->coordinator === $this->model->user_nick || 94 $this->model->acl->get_level() >= BEZ_AUTH_ADMIN) { 95 return true; 96 } 97 } 98 99 public function __construct($model, $defaults=array()) { 100 parent::__construct($model); 101 102 $this->validator->set_rules(array( 103 'coordinator' => array(array('dw_user'), 'NULL'), 104 'title' => array(array('length', 200), 'NOT NULL'), 105 'content' => array(array('length', 10000), 'NOT NULL') 106 )); 107 108// $this->validator->set_rules(array( 109// 'title' => array(array('length', 200), 'NOT NULL'), 110// 'description' => array(array('length', 10000), 'NOT NULL'), 111// 'state' => array(array('select', array('0', '1', '2')), 'NULL'), 112// 'opinion' => array(array('length', 10000), 'NOT NULL'), 113// 'type' => array(array('numeric'), 'NULL'), 114// 'coordinator' => array(array('dw_user'), 'NOT NULL'), 115// 'reporter' => array(array('dw_user'), 'NOT NULL'), 116// 'date' => array(array('unix_timestamp'), 'NOT NULL'), 117// 'last_mod' => array(array('unix_timestamp'), 'NULL'), 118// 'last_activity' => array(array('sqlite_datetime'), 'NOT NULL') 119// )); 120 121// $this->validator->set_rules(array( 122 //'coordinator' => array(array('dw_user'), 'NULL'), 123// 'original_poster' => array(array('dw_user'), 'NOT NULL'), 124// 'title' => array(array('length', 200), 'NOT NULL'), 125// 'content' => array(array('length', 10000), 'NOT NULL'), 126// 'state' => array(array('select', array('0', '1', '2')), 'NULL'), 127// 'opinion' => array(array('length', 10000), 'NOT NULL'), 128// 'type' => array(array('select'), 'NULL'), 129 130// 'create_date' => array(array('sqlite_datetime'), 'NOT NULL'), 131// 'last_mod' => array(array('sqlite_datetime'), 'NULL'), 132// 'last_activity' => array(array('sqlite_datetime'), 'NOT NULL') 133// )); 134 135 //we've created empty object (new record) 136 if ($this->id === NULL) { 137 $this->original_poster = $this->model->user_nick; 138 $this->create_date = date('c'); 139 $this->last_activity_date = $this->create_date; 140 $this->last_modification_date = $this->create_date; 141 142 $this->state = 'proposal'; 143 144// $this->close_date = ''; 145 146// $this->lock = '0'; 147// $this->private = '0'; 148// $this->type = '1';//type 1 - issue 149// $this->state = '0';//state 0 - proposal 150 151 //$this->update_last_activity(); 152 153 //$this->state = '0'; 154 155 if ($this->model->acl->get_level() >= BEZ_AUTH_LEADER) { 156// $this->validator->add_rule('cooridnator', array(array('dw_user'), 'NOT NULL')); 157 //throws ValidationException 158// $this->coordinator = $this->validator->validate_field('coordinator', $defaults['coordinator']); 159 if (!$this->model->userFactory->exists($defaults['coordinator'])) { 160 throw new ValidationException('thread', array('coordinator' => 'is_null')); 161 } 162 $this->coordinator = $defaults['coordinator']; 163 $this->state = 'opened'; 164 } 165// } else { 166// $this->coordinator = '-proposal'; 167// } 168 169 170// $this->add_participant($this->reporter); 171// $this->add_subscribent($this->reporter); 172// if ($this->coordinator !== '-proposal') { 173// $this->add_participant($this->coordinator); 174// $this->add_subscribent($this->coordinator); 175// } 176 177 } 178 //close_date required 179// if ($this->state !== 'state_proposal' && $this->state !== 'state_opened') { 180// $this->validator->set_rules(array( 181// 'close_date' => array(array('unix_timestamp'), 'NOT NULL') 182// )); 183// } 184 185 186// if ($this->participants !== NULL) { 187// $exp_part = explode(',', $this->participants); 188// foreach ($exp_part as $participant) { 189// $this->participants_array[$participant] = $participant; 190// } 191// } 192// 193// if ($this->subscribents !== NULL) { 194// $exp_part = explode(',', $this->subscribents); 195// foreach ($exp_part as $subscribent) { 196// $this->subscribents_array[$subscribent] = $subscribent; 197// } 198// } 199 } 200 201 public function set_data($data, $filter=NULL) { 202 $input = array('title', 'content', 'coordinator'); 203 $val_data = $this->validator->validate($data, $input); 204 205 if ($val_data === false) { 206 throw new ValidationException('thread', $this->validator->get_errors()); 207 } 208 209 210 //change coordinator at the end(!) 211 if (isset($val_data['coordinator'])) { 212 $val_coordinator = $val_data['coordinator']; 213 unset($val_data['coordinator']); 214 } 215 216 $this->set_property_array($val_data); 217 218 if (isset($val_coordinator)) { 219 $this->set_property('coordinator', $val_coordinator); 220 } 221 222 $this->content_html = p_render('xhtml',p_get_instructions($this->content), $ignore); 223 224 //update dates 225 $this->last_modification_date = date('c'); 226 $this->last_activity_date = $this->last_modification_date; 227 } 228 229 public function update_last_activity() { 230 $this->last_activity_date = date('c'); 231 $this->model->sqlite->query('UPDATE thread SET last_activity_date=? WHERE id=?', 232 $this->last_activity_date, $this->id); 233 } 234 235// public function set_labels($labels_ids = array()) { 236// 237// } 238 239// public function get_meta_fields() { 240// return array('reporter', 'date', 'last_mod', 'last_activity'); 241// } 242// 243// public function set_meta($post) { 244// 245// if (isset($post['date'])) { 246// $unix = strtotime($post['date']); 247// //if $unix === false validator will catch it 248// if ($unix !== false) { 249// $post['date'] = (string)$unix; 250// } 251// } 252// 253// if (isset($post['last_mod'])) { 254// $unix = strtotime($post['last_mod']); 255// //if $unix === false validator will catch it 256// if ($unix !== false) { 257// $post['last_mod'] = (string)$unix; 258// } 259// } 260// 261// parent::set_data($post, $this->get_meta_fields()); 262// } 263 264// public function update_cache() { 265// if ($this->model->acl->get_level() < BEZ_AUTH_ADMIN) { 266// return false; 267// } 268// $this->description_cache = $this->helper->wiki_parse($this->description); 269// $this->opinion_cache = $this->helper->wiki_parse($this->opinion); 270// } 271// 272// public function set_state($data) { 273// 274// $input = array('state', 'opinion'); 275// $val_data = $this->validator->validate($data, $input); 276// 277// if ($val_data === false) { 278// throw new ValidationException('issues', $this->validator->get_errors()); 279// } 280// 281// $this->set_property_array($val_data); 282// 283// if (count($this->validator->get_errors()) > 0) { 284// throw new ValidationException('issues', $this->validator->get_errors()); 285// } 286// 287// //update activity on state update 288// $this->last_mod = time(); 289// $this->update_last_activity(); 290// $this->opinion_cache = $this->helper->wiki_parse($this->opinion); 291// 292// //update virtuals 293// //$this->update_virtual_columns(); 294// } 295 296// public function update_last_activity() { 297// $this->last_activity = $this->sqlite_date(); 298// } 299 300 //private $participants; 301 public function get_participants($filter='') { 302 if ($this->acl_of('participants') < BEZ_PERMISSION_VIEW) { 303 throw new PermissionDeniedException(); 304 } 305 if ($this->id === NULL) { 306 return array(); 307 } 308 309 $sql = 'SELECT * FROM thread_participant WHERE'; 310 $possible_flags = array('original_poster', 'coordinator', 'commentator', 'task_assignee', 'subscribent'); 311 if ($filter != '') { 312 if (!in_array($filter, $possible_flags)) { 313 throw new \Exception("unknown flag $filter"); 314 } 315 $sql .= " $filter=1 AND"; 316 } 317 $sql .= ' thread_id=? ORDER BY user_id'; 318 319 $r = $this->model->sqlite->query($sql, $this->id); 320 $pars = $this->model->sqlite->res2arr($r); 321 $participants = array(); 322 foreach ($pars as $par) { 323 $participants[$par['user_id']] = $par; 324 } 325 326 return $participants; 327 } 328 329 public function get_participant($user_id) { 330 if ($this->acl_of('participants') < BEZ_PERMISSION_VIEW) { 331 throw new PermissionDeniedException(); 332 } 333 if ($this->id === NULL) { 334 return array(); 335 } 336 337 $r = $this->model->sqlite->query('SELECT * FROM thread_participant WHERE thread_id=? AND user_id=?', $this->id, $user_id); 338 $par = $this->model->sqlite->res2row($r); 339 if (!is_array($par)) { 340 return false; 341 } 342 343 return $par; 344 } 345 346 public function is_subscribent($user_id=null) { 347 if ($user_id == null) { 348 $user_id = $this->model->user_nick; 349 } 350 $par = $this->get_participant($user_id); 351 if ($par['subscribent'] == 1) { 352 return true; 353 } 354 return false; 355 } 356 357 public function remove_participant_flags($user_id, $flags) { 358 if ($this->acl_of('participants') < BEZ_PERMISSION_CHANGE) { 359 throw new PermissionDeniedException(); 360 } 361 362 //thread not saved yet 363 if ($this->id === NULL) { 364 throw new \Exception('cannot remove flags from not saved thread'); 365 } 366 367 $possible_flags = array('original_poster', 'coordinator', 'commentator', 'task_assignee', 'subscribent'); 368 if (array_intersect($flags, $possible_flags) != $flags) { 369 throw new \Exception('unknown flags'); 370 } 371 372 $set = implode(',', array_map(function ($v) { return "$v=0"; }, $flags)); 373 374 $sql = "UPDATE thread_participant SET $set WHERE thread_id=? AND user_id=?"; 375 $this->model->sqlite->query($sql, $this->id, $user_id); 376 377 } 378 379 public function set_participant_flags($user_id, $flags=array()) { 380 if ($this->acl_of('participants') < BEZ_PERMISSION_CHANGE) { 381 throw new PermissionDeniedException(); 382 } 383 384 //thread not saved yet 385 if ($this->id === NULL) { 386 throw new \Exception('cannot add flags to not saved thread'); 387 } 388 389 //validate user 390 if (!$this->model->userFactory->exists($user_id)) { 391 throw new \Exception("$user_id isn't dokuwiki user"); 392 } 393 394 $possible_flags = array('original_poster', 'coordinator', 'commentator', 'task_assignee', 'subscribent'); 395 if (array_intersect($flags, $possible_flags) != $flags) { 396 throw new \Exception('unknown flags'); 397 } 398 399 $participant = $this->get_participant($user_id); 400 if ($participant == false) { 401 $participant = array_fill_keys($possible_flags, 0); 402 403 $participant['thread_id'] = $this->id; 404 $participant['user_id'] = $user_id; 405 $participant['added_by'] = $this->model->user_nick; 406 $participant['added_date'] = date('c'); 407 } 408 $values = array_merge($participant, array_fill_keys($flags, 1)); 409 410 $keys = join(',', array_keys($values)); 411 $vals = join(',', array_fill(0,count($values),'?')); 412 413 $sql = "REPLACE INTO thread_participant ($keys) VALUES ($vals)"; 414 $this->model->sqlite->query($sql, array_values($values)); 415 416 417 418// if (! ( $this->user_is_coordinator() || 419// $participant === $this->model->user_nick || 420// $participant === $this->coordinator) //dodajemy nowego koordynatora 421// ) { 422// throw new PermissionDeniedException(); 423// } 424// if ($this->model->users->exists($participant)) { 425// $this->participants_array[$participant] = $participant; 426// $this->participants = implode(',', $this->participants_array); 427// } 428 } 429 430 public function get_labels() { 431 if ($this->acl_of('labels') < BEZ_PERMISSION_VIEW) { 432 throw new PermissionDeniedException(); 433 } 434 435 //record not saved 436 if ($this->id === NULL) { 437 return array(); 438 } 439 440 $labels = array(); 441 $r = $this->model->sqlite->query('SELECT * FROM label JOIN thread_label ON label.id = thread_label.label_id 442 WHERE thread_label.thread_id=?', $this->id); 443 $arr = $this->model->sqlite->res2arr($r); 444 foreach ($arr as $label) { 445 $labels[$label['id']] = $label; 446 } 447 448 return $labels; 449 } 450 451// public function get_label_id($name) { 452// $labels = $this->get_labels(); 453// 454// foreach ($labels as $label) { 455// if ($label['name'] == $name) { 456// return $label['label_id']; 457// } 458// } 459// return false; 460// } 461 462 public function add_label($label_id) { 463 if ($this->acl_of('labels') < BEZ_PERMISSION_CHANGE) { 464 throw new PermissionDeniedException(); 465 } 466 467 468 //issue not saved yet 469 if ($this->id === NULL) { 470 throw new \Exception('cannot add labels to not saved thread. use initial_save() instead'); 471 } 472 473 //label already assigned, nothing to do 474// if ($this->get_label_id($name)) return; 475 476 $r = $this->model->sqlite->query('SELECT id FROM label WHERE id=?', $label_id); 477 $label_id = $this->model->sqlite->res2single($r); 478 if (!$label_id) { 479 throw new \Exception("label($label_id) doesn't exist"); 480 } 481 482 483 $this->model->sqlite->storeEntry('thread_label', 484 array('thread_id' => $this->id, 485 'label_id' => $label_id)); 486 487 } 488 489 public function remove_label($label_id) { 490 if ($this->acl_of('labels') < BEZ_PERMISSION_CHANGE) { 491 throw new PermissionDeniedException(); 492 } 493 494 //issue not saved yet 495 if ($this->id === NULL) { 496 throw new \Exception('cannot remove labels from not saved thread. use initial_save() instead'); 497 } 498 499 /** @var \PDOStatement $r */ 500 $r = $this->model->sqlite->query('DELETE FROM thread_label WHERE thread_id=? AND label_id=?',$this->id, $label_id); 501 if ($r->rowCount() != 1) { 502 throw new \Exception('label was not assigned to this thread'); 503 } 504 505 } 506 507 public function causes_without_tasks_count() { 508 return 0; 509 } 510 511 public function get_causes() { 512 $r = $this->model->sqlite->query('SELECT id FROM thread_comment WHERE thread_id=?', $this->id); 513 $arr = $this->model->sqlite->res2arr($r); 514 $causes = array(); 515 foreach ($arr as $cause) { 516 $causes[] = $cause['id']; 517 } 518 519 return $causes; 520 } 521 522// public function remove_label($name) { 523// if ($this->acl_of('labels') < BEZ_PERMISSION_CHANGE) { 524// throw new PermissionDeniedException(); 525// } 526// //label not assigned 527// $label_id = $this->get_label($name); 528// 529// if ($label_id === false) { 530// throw new \Exception('label don not exists'); 531// } 532// 533// $this->model->sqlite->query('DELETE FROM thread_label WHERE thread_id=?, label_id=?', $this->id, $label_id); 534// } 535 536// public function add_subscribent($subscribent) { 537// if (! ( $this->user_is_coordinator() || 538// $subscribent === $this->model->user_nick || 539// $subscribent === $this->coordinator) //dodajemy nowego koordynatora) 540// ) { 541// throw new PermissionDeniedException(); 542// } 543// 544// if ($this->model->users->exists($subscribent) && 545// !in_array($subscribent, $this->subscribents_array)) { 546// $this->subscribents_array[$subscribent] = $subscribent; 547// $this->subscribents = implode(',', $this->subscribents_array); 548// return true; 549// } 550// return false; 551// } 552// 553// public function remove_subscribent($subscribent) { 554// if (! ( $this->user_is_coordinator() || 555// $subscribent === $this->model->user_nick) 556// ) { 557// throw new PermissionDeniedException(); 558// } 559// unset($this->subscribents_array[$subscribent]); 560// $this->subscribents = implode(',', $this->subscribents_array); 561// } 562// 563// public function get_subscribents() { 564// return $this->subscribents_array; 565// } 566 567// public function get_participants() { 568// $full_names = []; 569// 570// $involved = array_merge($this->subscribents_array, $this->participants_array); 571// foreach ($involved as $par) { 572// $name = $this->model->users->get_user_full_name($par); 573// if ($name == '') { 574// $full_names[$par] = $par; 575// } else { 576// $full_names[$par] = $name; 577// } 578// } 579// //coordinator on top 580// uksort($full_names, function ($a, $b) use($full_names) { 581// if ($a === $this->coordinator) { 582// return -1; 583// } else if ($b === $this->coordinator) { 584// return 1; 585// } 586// return $full_names[$a] > $full_names[$b]; 587// }); 588// 589// return $full_names; 590// } 591 592// public function is_subscribent($user=NULL) { 593// if ($user === NULL) { 594// $user = $this->model->user_nick; 595// } 596// if (in_array($user, $this->subscribents_array)) { 597// return true; 598// } 599// return false; 600// } 601// 602// public function is_task_executor($user=NULL) { 603// if ($user === NULL) { 604// $user = $this->model->user_nick; 605// } 606// $sth = $this->model->db->prepare('SELECT COUNT(*) FROM tasks 607// WHERE issue=:issue AND executor=:executor'); 608// $sth->execute(array(':issue' => $this->id, ':executor' => $user)); 609// $fetch = $sth->fetch(); 610// if ($fetch[0] === '0') { 611// return false; 612// } else { 613// return true; 614// } 615// } 616// 617// public function is_commentator($user=NULL) { 618// if ($user === NULL) { 619// $user = $this->model->user_nick; 620// } 621// $sth = $this->model->db->prepare('SELECT COUNT(*) FROM commcauses 622// WHERE issue=:issue AND reporter=:reporter'); 623// $sth->execute(array(':issue' => $this->id, ':reporter' => $user)); 624// $fetch = $sth->fetch(); 625// if ($fetch[0] === '0') { 626// return false; 627// } else { 628// return true; 629// } 630// } 631// 632// private $causes_without_tasks = -1; 633// public function causes_without_tasks_count() { 634// if ($this->causes_without_tasks === -1) { 635// $sth = $this->model->db->prepare('SELECT COUNT(*) FROM 636// (SELECT tasks.id 637// FROM commcauses LEFT JOIN tasks ON commcauses.id = tasks.cause 638// WHERE commcauses.type > 0 AND commcauses.issue = ? 639// GROUP BY commcauses.id) 640// WHERE id IS NULL'); 641// $sth->execute(array($this->id)); 642// $count = $sth->fetchColumn(); 643// 644// $this->causes_without_tasks = (int)$count; 645// } 646// return $this->causes_without_tasks; 647// } 648 649 //http://data.agaric.com/capture-all-sent-mail-locally-postfix 650 //https://askubuntu.com/questions/192572/how-do-i-read-local-email-in-thunderbird 651 public function mail_notify($replacements=array(), $users=false) { 652 $plain = io_readFile($this->model->action->localFN('thread-notification')); 653 $html = io_readFile($this->model->action->localFN('thread-notification', 'html')); 654 655 $thread_reps = array( 656 'thread_id' => $this->id, 657 'thread_link' => $this->model->action->url('thread', 'id', $this->id), 658 'thread_unsubscribe' => 659 $this->model->action->url('thread', 'id', $this->id, 'action', 'unsubscribe'), 660 'custom_content' => false, 661 'action_border_color' => 'transparent', 662 'action_color' => 'transparent', 663 ); 664 665 //$replacements can override $issue_reps 666 $rep = array_merge($thread_reps, $replacements); 667 //auto title 668 if (!isset($rep['subject'])) { 669 $rep['subject'] = '#'.$this->id. ' ' .$this->title; 670 } 671 if (!isset($rep['content_html'])) { 672 $rep['content_html'] = $rep['content']; 673 } 674 if (!isset($rep['who_full_name'])) { 675 $rep['who_full_name'] = 676 $this->model->userFactory->get_user_full_name($rep['who']); 677 } 678 679 //format when 680 $rep['when'] = dformat(strtotime($rep['when']), '%Y-%m-%d %H:%M'); 681 682 if ($rep['custom_content'] === false) { 683 $html = str_replace('@CONTENT_HTML@', ' 684 <div style="margin: 5px 0;"> 685 <strong>@WHO_FULL_NAME@</strong> <br> 686 <span style="color: #888">@WHEN@</span> 687 </div> 688 @CONTENT_HTML@ 689 ', $html); 690 } 691 692 //we must do it manually becouse Mailer uses htmlspecialchars() 693 $html = str_replace('@CONTENT_HTML@', $rep['content_html'], $html); 694 695 $mailer = new Mailer(); 696 $mailer->setBody($plain, $rep, $rep, $html, false); 697 698 if ($users == FALSE) { 699 $users = array_map(function($par) { 700 return $par['user_id']; 701 }, $this->get_participants('subscribent')); 702 703 //don't notify myself 704 unset($users[$this->model->user_nick]); 705 } 706 707 $emails = array_map(function($user_id) { 708 return $this->model->userFactory->get_user_email($user_id); 709 }, $users); 710 711 712 $mailer->to($emails); 713 $mailer->subject($rep['subject']); 714 715 $send = $mailer->send(); 716 if ($send === false) { 717 //this may mean empty $emails 718 //throw new Exception("can't send email"); 719 } 720 } 721 722 protected function mail_issue_box_reps($replacements=array()) { 723 $replacements['custom_content'] = true; 724 725 $html = '<h2 style="font-size: 1.2em;">'; 726 $html .= '<a style="font-size:115%" href="@THREAD_LINK@">#@THREAD_ID@</a> '; 727 728 if ( ! empty($this->type_string)) { 729 $html .= $this->type_string; 730 } else { 731 $html .= '<i style="color: #777"> '. 732 $this->model->action->getLang('issue_type_no_specified'). 733 '</i>'; 734 } 735 736 $html .= ' ('. $this->model->action->getLang('state_' . $this->state ) .') '; 737 738 $html .= '<span style="color: #777; font-weight: normal; font-size: 90%;">'; 739 $html .= $this->model->action->getLang('coordinator') . ': '; 740 $html .= '<span style="font-weight: bold;">'; 741 742 if ($this->state == 'proposal') { 743 $html .= '<i style="font-weight: normal;">' . 744 $this->model->action->getLang('proposal') . 745 '</i>'; 746 } else { 747 $html .= $this->model->userFactory->get_user_full_name($this->coordinator); 748 } 749 $html .= '</span></span></h2>'; 750 751 $html .= '<h2 style="font-size: 1.2em;border-bottom: 1px solid @ACTION_BORDER_COLOR@">' . $this->title . '</h2>'; 752 753 $html .= $this->content_html; 754 755// if ($this->state !== '0') { 756// $html .= '<h3 style="font-size:100%; border-bottom: 1px dotted #bbb">'; 757// if ($this->state === '1') { 758// $html .= $this->model->action->getLang('opinion'); 759// } else { 760// $html .= $this->model->action->getLang('reason'); 761// } 762// $html .= '</h3>'; 763// $html .= $this->opinion_cache; 764// } 765 766 $replacements['content_html'] = $html; 767 768 769 switch ($this->priority) { 770 case '0': 771 $replacements['action_color'] = '#F8E8E8'; 772 $replacements['action_border_color'] = '#F0AFAD'; 773 break; 774 case '1': 775 $replacements['action_color'] = '#ffd'; 776 $replacements['action_border_color'] = '#dd9'; 777 break; 778 case '2': 779 $replacements['action_color'] = '#EEF6F0'; 780 $replacements['action_border_color'] = '#B0D2B6'; 781 break; 782 case 'None': 783 $replacements['action_color'] = '#e7f1ff'; 784 $replacements['action_border_color'] = '#a3c8ff'; 785 break; 786 default: 787 $replacements['action_color'] = '#fff'; 788 $replacements['action_border_color'] = '#bbb'; 789 break; 790 } 791 792 return $replacements; 793 } 794 795 public function mail_notify_change_state() { 796 $this->mail_notify($this->mail_issue_box_reps(array( 797 'who' => $this->model->user_nick, 798 'action' => $this->model->action->getLang('mail_mail_notify_change_state_action'), 799 //'subject' => $this->model->action->getLang('mail_mail_notify_change_state_subject') . ' #'.$this->id 800 ))); 801 } 802 803 public function mail_notify_invite($client) { 804 $this->mail_notify($this->mail_issue_box_reps(array( 805 'who' => $this->model->user_nick, 806 'action' => $this->model->action->getLang('mail_mail_notify_invite_action'), 807 //'subject' => $this->model->action->getLang('mail_mail_notify_invite_subject') . ' #'.$this->id 808 )), array($client)); 809 } 810 811 public function mail_inform_coordinator() { 812 $this->mail_notify($this->mail_issue_box_reps(array( 813 'who' => $this->model->user_nick, 814 'action' => $this->model->action->getLang('mail_mail_inform_coordinator_action'), 815 //'subject' => $this->model->action->getLang('mail_mail_inform_coordinator_subject') . ' #'.$this->id 816 )), array($this->coordinator)); 817 } 818 819 public function mail_notify_issue_inactive($users=false) { 820 $this->mail_notify($this->mail_issue_box_reps(array( 821 'who' => '', 822 'action' => $this->model->action->getLang('mail_mail_notify_issue_inactive'), 823 )), $users); 824 } 825} 826