PageRenderTime 44ms CodeModel.GetById 35ms RepoModel.GetById 2ms app.codeStats 0ms

/api/Model.class.php

https://github.com/Hildy/cerb5
PHP | 4404 lines | 3227 code | 715 blank | 462 comment | 503 complexity | ace8680c2cbe2b4f2bb02556c858870a MD5 | raw file
  1. <?php
  2. /***********************************************************************
  3. | Cerberus Helpdesk(tm) developed by WebGroup Media, LLC.
  4. |-----------------------------------------------------------------------
  5. | All source code & content (c) Copyright 2007, WebGroup Media LLC
  6. | unless specifically noted otherwise.
  7. |
  8. | This source code is released under the Cerberus Public License.
  9. | The latest version of this license can be found here:
  10. | http://www.cerberusweb.com/license.php
  11. |
  12. | By using this software, you acknowledge having read this license
  13. | and agree to be bound thereby.
  14. | ______________________________________________________________________
  15. | http://www.cerberusweb.com http://www.webgroupmedia.com/
  16. ***********************************************************************/
  17. /*
  18. * IMPORTANT LICENSING NOTE from your friends on the Cerberus Helpdesk Team
  19. *
  20. * Sure, it would be so easy to just cheat and edit this file to use the
  21. * software without paying for it. But we trust you anyway. In fact, we're
  22. * writing this software for you!
  23. *
  24. * Quality software backed by a dedicated team takes money to develop. We
  25. * don't want to be out of the office bagging groceries when you call up
  26. * needing a helping hand. We'd rather spend our free time coding your
  27. * feature requests than mowing the neighbors' lawns for rent money.
  28. *
  29. * We've never believed in encoding our source code out of paranoia over not
  30. * getting paid. We want you to have the full source code and be able to
  31. * make the tweaks your organization requires to get more done -- despite
  32. * having less of everything than you might need (time, people, money,
  33. * energy). We shouldn't be your bottleneck.
  34. *
  35. * We've been building our expertise with this project since January 2002. We
  36. * promise spending a couple bucks [Euro, Yuan, Rupees, Galactic Credits] to
  37. * let us take over your shared e-mail headache is a worthwhile investment.
  38. * It will give you a sense of control over your in-box that you probably
  39. * haven't had since spammers found you in a game of "E-mail Address
  40. * Battleship". Miss. Miss. You sunk my in-box!
  41. *
  42. * A legitimate license entitles you to support, access to the developer
  43. * mailing list, the ability to participate in betas and the warm fuzzy
  44. * feeling of feeding a couple obsessed developers who want to help you get
  45. * more done than 'the other guy'.
  46. *
  47. * - Jeff Standen, Mike Fogg, Brenan Cavish, Darren Sugita, Dan Hildebrandt
  48. * and Joe Geck.
  49. * WEBGROUP MEDIA LLC. - Developers of Cerberus Helpdesk
  50. */
  51. class Model_PreParseRule {
  52. public $id;
  53. public $created;
  54. public $name;
  55. public $criteria;
  56. public $actions;
  57. public $pos;
  58. public $is_sticky = 0;
  59. public $sticky_order = 0;
  60. /**
  61. * Returns a Model_PreParserRule on a match, or NULL
  62. *
  63. * @param boolean $is_new
  64. * @param string $from
  65. * @param string $to
  66. * @param CerberusParserMessage $message
  67. * @return Model_PreParserRule[]
  68. */
  69. static function getMatches(CerberusParserMessage $message) {
  70. $filters = DAO_PreParseRule::getAll();
  71. $headers = $message->headers;
  72. // New or reply?
  73. $is_new = (isset($message->headers['in-reply-to']) || isset($message->headers['references'])) ? false : true;
  74. // From address
  75. $fromInst = CerberusParser::getAddressFromHeaders($headers);
  76. // Stackable
  77. $matches = array();
  78. // Custom fields
  79. $custom_fields = DAO_CustomField::getAll();
  80. // Criteria extensions
  81. $filter_criteria_exts = DevblocksPlatform::getExtensions('cerberusweb.mail_filter.criteria', false);
  82. // Lazy load when needed on criteria basis
  83. $address_field_values = null;
  84. $org_field_values = null;
  85. // check filters
  86. if(is_array($filters))
  87. foreach($filters as $filter) {
  88. $passed = 0;
  89. // check criteria
  90. foreach($filter->criteria as $rule_key => $rule) {
  91. @$value = $rule['value'];
  92. switch($rule_key) {
  93. case 'dayofweek':
  94. $current_day = strftime('%w');
  95. // $current_day = 1;
  96. // Forced to English abbrevs as indexes
  97. $days = array('sun','mon','tue','wed','thu','fri','sat');
  98. // Is the current day enabled?
  99. if(isset($rule[$days[$current_day]])) {
  100. $passed++;
  101. }
  102. break;
  103. case 'timeofday':
  104. $current_hour = strftime('%H');
  105. $current_min = strftime('%M');
  106. // $current_hour = 17;
  107. // $current_min = 5;
  108. if(null != ($from_time = @$rule['from']))
  109. list($from_hour, $from_min) = explode(':', $from_time);
  110. if(null != ($to_time = @$rule['to']))
  111. if(list($to_hour, $to_min) = explode(':', $to_time));
  112. // Do we need to wrap around to the next day's hours?
  113. if($from_hour > $to_hour) { // yes
  114. $to_hour += 24; // add 24 hrs to the destination (1am = 25th hour)
  115. }
  116. // Are we in the right 24 hourly range?
  117. if((integer)$current_hour >= $from_hour && (integer)$current_hour <= $to_hour) {
  118. // If we're in the first hour, are we minutes early?
  119. if($current_hour==$from_hour && (integer)$current_min < $from_min)
  120. break;
  121. // If we're in the last hour, are we minutes late?
  122. if($current_hour==$to_hour && (integer)$current_min > $to_min)
  123. break;
  124. $passed++;
  125. }
  126. break;
  127. case 'type':
  128. if(($is_new && 0 == strcasecmp($value,'new'))
  129. || (!$is_new && 0 == strcasecmp($value,'reply')))
  130. $passed++;
  131. break;
  132. case 'from':
  133. $regexp_from = DevblocksPlatform::strToRegExp($value);
  134. if(preg_match($regexp_from, $fromInst->email)) {
  135. $passed++;
  136. }
  137. break;
  138. case 'tocc':
  139. $tocc = array();
  140. $destinations = DevblocksPlatform::parseCsvString($value);
  141. // Build a list of To/Cc addresses on this message
  142. @$to_list = imap_rfc822_parse_adrlist($headers['to'],'localhost');
  143. @$cc_list = imap_rfc822_parse_adrlist($headers['cc'],'localhost');
  144. if(is_array($to_list))
  145. foreach($to_list as $addy) {
  146. $tocc[] = $addy->mailbox . '@' . $addy->host;
  147. }
  148. if(is_array($cc_list))
  149. foreach($cc_list as $addy) {
  150. $tocc[] = $addy->mailbox . '@' . $addy->host;
  151. }
  152. $dest_flag = false; // bail out when true
  153. if(is_array($destinations) && is_array($tocc))
  154. foreach($destinations as $dest) {
  155. if($dest_flag) break;
  156. $regexp_dest = DevblocksPlatform::strToRegExp($dest);
  157. foreach($tocc as $addy) {
  158. if(@preg_match($regexp_dest, $addy)) {
  159. $passed++;
  160. $dest_flag = false;
  161. break;
  162. }
  163. }
  164. }
  165. break;
  166. case 'header1':
  167. case 'header2':
  168. case 'header3':
  169. case 'header4':
  170. case 'header5':
  171. $header = strtolower($rule['header']);
  172. if(empty($value)) { // we're checking for null/blanks
  173. if(!isset($headers[$header]) || empty($headers[$header])) {
  174. $passed++;
  175. }
  176. } elseif(isset($headers[$header]) && !empty($headers[$header])) {
  177. $regexp_header = DevblocksPlatform::strToRegExp($value);
  178. // handle arrays like Received: and (broken)Content-Type headers (farking spammers)
  179. if(is_array($headers[$header])) {
  180. foreach($headers[$header] as $array_header) {
  181. if(preg_match($regexp_header, str_replace(array("\r","\n"),' ',$array_header))) {
  182. $passed++;
  183. break;
  184. }
  185. }
  186. } else {
  187. // Flatten CRLF
  188. if(preg_match($regexp_header, str_replace(array("\r","\n"),' ',$headers[$header]))) {
  189. $passed++;
  190. }
  191. }
  192. }
  193. break;
  194. case 'body':
  195. // Line-by-line body scanning (sed-like)
  196. $lines = preg_split("/[\r\n]/", $message->body);
  197. if(is_array($lines))
  198. foreach($lines as $line) {
  199. if(@preg_match($value, $line)) {
  200. $passed++;
  201. break;
  202. }
  203. }
  204. break;
  205. case 'body_encoding':
  206. $regexp_bodyenc = DevblocksPlatform::strToRegExp($value);
  207. if(preg_match($regexp_bodyenc, $message->body_encoding))
  208. $passed++;
  209. break;
  210. case 'attachment':
  211. $regexp_file = DevblocksPlatform::strToRegExp($value);
  212. // check the files in the raw message
  213. foreach($message->files as $file_name => $file) { /* @var $file ParserFile */
  214. if(preg_match($regexp_file, $file_name)) {
  215. $passed++;
  216. break;
  217. }
  218. }
  219. break;
  220. default: // ignore invalids
  221. // Custom Fields
  222. if(0==strcasecmp('cf_',substr($rule_key,0,3))) {
  223. $field_id = substr($rule_key,3);
  224. // Make sure it exists
  225. if(null == (@$field = $custom_fields[$field_id]))
  226. continue;
  227. // Lazy values loader
  228. $field_values = array();
  229. switch($field->source_extension) {
  230. case ChCustomFieldSource_Address::ID:
  231. if(null == $address_field_values)
  232. $address_field_values = array_shift(DAO_CustomFieldValue::getValuesBySourceIds(ChCustomFieldSource_Address::ID, $fromInst->id));
  233. $field_values =& $address_field_values;
  234. break;
  235. case ChCustomFieldSource_Org::ID:
  236. if(null == $org_field_values)
  237. $org_field_values = array_shift(DAO_CustomFieldValue::getValuesBySourceIds(ChCustomFieldSource_Org::ID, $fromInst->contact_org_id));
  238. $field_values =& $org_field_values;
  239. break;
  240. }
  241. // Type sensitive value comparisons
  242. // [TODO] Operators
  243. // [TODO] Highly redundant
  244. switch($field->type) {
  245. case 'S': // string
  246. case 'T': // clob
  247. case 'U': // URL
  248. $field_val = isset($field_values[$field_id]) ? $field_values[$field_id] : '';
  249. $oper = isset($rule['oper']) ? $rule['oper'] : "=";
  250. if($oper == "=" && @preg_match(DevblocksPlatform::strToRegExp($value, true), $field_val))
  251. $passed++;
  252. elseif($oper == "!=" && @!preg_match(DevblocksPlatform::strToRegExp($value, true), $field_val))
  253. $passed++;
  254. break;
  255. case 'N': // number
  256. if(!isset($field_values[$field_id]))
  257. break;
  258. $field_val = isset($field_values[$field_id]) ? $field_values[$field_id] : 0;
  259. $oper = isset($rule['oper']) ? $rule['oper'] : "=";
  260. if($oper=="=" && intval($field_val)==intval($value))
  261. $passed++;
  262. elseif($oper=="!=" && intval($field_val)!=intval($value))
  263. $passed++;
  264. elseif($oper==">" && intval($field_val) > intval($value))
  265. $passed++;
  266. elseif($oper=="<" && intval($field_val) < intval($value))
  267. $passed++;
  268. break;
  269. case 'E': // date
  270. $field_val = isset($field_values[$field_id]) ? intval($field_values[$field_id]) : 0;
  271. $from = isset($rule['from']) ? $rule['from'] : "0";
  272. $to = isset($rule['to']) ? $rule['to'] : "now";
  273. if(intval(@strtotime($from)) <= $field_val && intval(@strtotime($to)) >= $field_val) {
  274. $passed++;
  275. }
  276. break;
  277. case 'C': // checkbox
  278. $field_val = isset($field_values[$field_id]) ? $field_values[$field_id] : 0;
  279. if(intval($value)==intval($field_val))
  280. $passed++;
  281. break;
  282. case 'D': // dropdown
  283. case 'M': // multi-picklist
  284. case 'X': // multi-checkbox
  285. case 'W': // worker
  286. $field_val = isset($field_values[$field_id]) ? $field_values[$field_id] : array();
  287. if(!is_array($value)) $value = array($value);
  288. if(is_array($field_val)) { // if multiple things set
  289. foreach($field_val as $v) { // loop through possible
  290. if(isset($value[$v])) { // is any possible set?
  291. $passed++;
  292. break;
  293. }
  294. }
  295. } else { // single
  296. if(isset($value[$field_val])) { // is our set field in possibles?
  297. $passed++;
  298. break;
  299. }
  300. }
  301. break;
  302. }
  303. } elseif(isset($filter_criteria_exts[$rule_key])) { // criteria extensions
  304. try {
  305. $crit_ext = $filter_criteria_exts[$rule_key]->createInstance();
  306. if($crit_ext->matches($filter, $message)) {
  307. $passed++;
  308. break;
  309. }
  310. } catch(Exception $e) {
  311. // Oops!
  312. //print_r($e);
  313. }
  314. }
  315. break;
  316. }
  317. }
  318. // If our rule matched every criteria, stop and return the filter
  319. if($passed == count($filter->criteria)) {
  320. DAO_PreParseRule::increment($filter->id); // ++ the times we've matched
  321. $matches[] = $filter;
  322. // Check our actions and see if we should bail out early
  323. if(isset($filter->actions) && !empty($filter->actions))
  324. foreach($filter->actions as $action_key => $action) {
  325. switch($action_key) {
  326. case 'nothing':
  327. case 'blackhole':
  328. case 'redirect':
  329. case 'bounce':
  330. return $matches;
  331. break;
  332. }
  333. }
  334. }
  335. }
  336. return $matches;
  337. }
  338. }
  339. class Model_GroupInboxFilter {
  340. public $id = 0;
  341. public $name = '';
  342. public $group_id = 0;
  343. public $criteria = array();
  344. public $actions = array();
  345. public $pos = 0;
  346. public $is_sticky = 0;
  347. public $sticky_order = 0;
  348. public $is_stackable = 0;
  349. /**
  350. * @return Model_GroupInboxFilter|false
  351. */
  352. static function getMatches($group_id, $ticket_id, $only_rule_id=0) {
  353. $matches = array();
  354. if(empty($group_id))
  355. return false;
  356. if(!empty($only_rule_id)) {
  357. $filters = array(
  358. DAO_GroupInboxFilter::get($only_rule_id)
  359. );
  360. } else {
  361. $filters = DAO_GroupInboxFilter::getByGroupId($group_id);
  362. }
  363. // Check the ticket
  364. if(null === ($ticket = DAO_Ticket::getTicket($ticket_id)))
  365. return false;
  366. // Build our objects
  367. $ticket_from = DAO_Address::get($ticket->last_wrote_address_id);
  368. $ticket_group_id = $ticket->team_id;
  369. // [TODO] These expensive checks should only populate when needed
  370. $messages = DAO_Ticket::getMessagesByTicket($ticket_id);
  371. $message_headers = array();
  372. if(empty($messages))
  373. return false;
  374. if(null != (@$message_last = array_pop($messages))) { /* @var $message_last CerberusMessage */
  375. $message_headers = $message_last->getHeaders();
  376. }
  377. // Clear the rest of the message manifests
  378. unset($messages);
  379. $custom_fields = DAO_CustomField::getAll();
  380. // Lazy load when needed on criteria basis
  381. $ticket_field_values = null;
  382. $address_field_values = null;
  383. $org_field_values = null;
  384. // Check filters
  385. if(is_array($filters))
  386. foreach($filters as $filter) { /* @var $filter Model_GroupInboxFilter */
  387. $passed = 0;
  388. // Skip filters with no criteria
  389. if(!is_array($filter->criteria) || empty($filter->criteria))
  390. continue;
  391. // check criteria
  392. foreach($filter->criteria as $rule_key => $rule) {
  393. @$value = $rule['value'];
  394. switch($rule_key) {
  395. case 'dayofweek':
  396. $current_day = strftime('%w');
  397. // $current_day = 1;
  398. // Forced to English abbrevs as indexes
  399. $days = array('sun','mon','tue','wed','thu','fri','sat');
  400. // Is the current day enabled?
  401. if(isset($rule[$days[$current_day]])) {
  402. $passed++;
  403. }
  404. break;
  405. case 'timeofday':
  406. $current_hour = strftime('%H');
  407. $current_min = strftime('%M');
  408. // $current_hour = 17;
  409. // $current_min = 5;
  410. if(null != ($from_time = @$rule['from']))
  411. list($from_hour, $from_min) = explode(':', $from_time);
  412. if(null != ($to_time = @$rule['to']))
  413. if(list($to_hour, $to_min) = explode(':', $to_time));
  414. // Do we need to wrap around to the next day's hours?
  415. if($from_hour > $to_hour) { // yes
  416. $to_hour += 24; // add 24 hrs to the destination (1am = 25th hour)
  417. }
  418. // Are we in the right 24 hourly range?
  419. if((integer)$current_hour >= $from_hour && (integer)$current_hour <= $to_hour) {
  420. // If we're in the first hour, are we minutes early?
  421. if($current_hour==$from_hour && (integer)$current_min < $from_min)
  422. break;
  423. // If we're in the last hour, are we minutes late?
  424. if($current_hour==$to_hour && (integer)$current_min > $to_min)
  425. break;
  426. $passed++;
  427. }
  428. break;
  429. case 'tocc':
  430. $tocc = array();
  431. $destinations = DevblocksPlatform::parseCsvString($value);
  432. // Build a list of To/Cc addresses on this message
  433. @$to_list = imap_rfc822_parse_adrlist($message_headers['to'],'localhost');
  434. @$cc_list = imap_rfc822_parse_adrlist($message_headers['cc'],'localhost');
  435. if(is_array($to_list))
  436. foreach($to_list as $addy) {
  437. $tocc[] = $addy->mailbox . '@' . $addy->host;
  438. }
  439. if(is_array($cc_list))
  440. foreach($cc_list as $addy) {
  441. $tocc[] = $addy->mailbox . '@' . $addy->host;
  442. }
  443. $dest_flag = false; // bail out when true
  444. if(is_array($destinations) && is_array($tocc))
  445. foreach($destinations as $dest) {
  446. if($dest_flag) break;
  447. $regexp_dest = DevblocksPlatform::strToRegExp($dest);
  448. foreach($tocc as $addy) {
  449. if(@preg_match($regexp_dest, $addy)) {
  450. $passed++;
  451. $dest_flag = false;
  452. break;
  453. }
  454. }
  455. }
  456. break;
  457. case 'from':
  458. $regexp_from = DevblocksPlatform::strToRegExp($value);
  459. if(@preg_match($regexp_from, $ticket_from->email)) {
  460. $passed++;
  461. }
  462. break;
  463. case 'subject':
  464. $regexp_subject = DevblocksPlatform::strToRegExp($value);
  465. if(@preg_match($regexp_subject, $ticket->subject)) {
  466. $passed++;
  467. }
  468. break;
  469. case 'body':
  470. if(null == ($message_body = $message_last->getContent()))
  471. break;
  472. // Line-by-line body scanning (sed-like)
  473. $lines = preg_split("/[\r\n]/", $message_body);
  474. if(is_array($lines))
  475. foreach($lines as $line) {
  476. if(@preg_match($value, $line)) {
  477. $passed++;
  478. break;
  479. }
  480. }
  481. break;
  482. case 'header1':
  483. case 'header2':
  484. case 'header3':
  485. case 'header4':
  486. case 'header5':
  487. @$header = strtolower($rule['header']);
  488. if(empty($header)) {
  489. $passed++;
  490. break;
  491. }
  492. if(empty($value)) { // we're checking for null/blanks
  493. if(!isset($message_headers[$header]) || empty($message_headers[$header])) {
  494. $passed++;
  495. }
  496. } elseif(isset($message_headers[$header]) && !empty($message_headers[$header])) {
  497. $regexp_header = DevblocksPlatform::strToRegExp($value);
  498. // Flatten CRLF
  499. if(@preg_match($regexp_header, str_replace(array("\r","\n"),' ',$message_headers[$header]))) {
  500. $passed++;
  501. }
  502. }
  503. break;
  504. default: // ignore invalids
  505. // Custom Fields
  506. if(0==strcasecmp('cf_',substr($rule_key,0,3))) {
  507. $field_id = substr($rule_key,3);
  508. // Make sure it exists
  509. if(null == (@$field = $custom_fields[$field_id]))
  510. continue;
  511. // Lazy values loader
  512. $field_values = array();
  513. switch($field->source_extension) {
  514. case ChCustomFieldSource_Address::ID:
  515. if(null == $address_field_values)
  516. $address_field_values = array_shift(DAO_CustomFieldValue::getValuesBySourceIds(ChCustomFieldSource_Address::ID, $ticket_from->id));
  517. $field_values =& $address_field_values;
  518. break;
  519. case ChCustomFieldSource_Org::ID:
  520. if(null == $org_field_values)
  521. $org_field_values = array_shift(DAO_CustomFieldValue::getValuesBySourceIds(ChCustomFieldSource_Org::ID, $ticket_from->contact_org_id));
  522. $field_values =& $org_field_values;
  523. break;
  524. case ChCustomFieldSource_Ticket::ID:
  525. if(null == $ticket_field_values)
  526. $ticket_field_values = array_shift(DAO_CustomFieldValue::getValuesBySourceIds(ChCustomFieldSource_Ticket::ID, $ticket->id));
  527. $field_values =& $ticket_field_values;
  528. break;
  529. }
  530. // No values, default.
  531. // if(!isset($field_values[$field_id]))
  532. // continue;
  533. // Type sensitive value comparisons
  534. // [TODO] Operators
  535. switch($field->type) {
  536. case 'S': // string
  537. case 'T': // clob
  538. case 'U': // URL
  539. $field_val = isset($field_values[$field_id]) ? $field_values[$field_id] : '';
  540. $oper = isset($rule['oper']) ? $rule['oper'] : "=";
  541. if($oper == "=" && @preg_match(DevblocksPlatform::strToRegExp($value, true), $field_val))
  542. $passed++;
  543. elseif($oper == "!=" && @!preg_match(DevblocksPlatform::strToRegExp($value, true), $field_val))
  544. $passed++;
  545. break;
  546. case 'N': // number
  547. if(!isset($field_values[$field_id]))
  548. break;
  549. $field_val = intval($field_values[$field_id]);
  550. $oper = isset($rule['oper']) ? $rule['oper'] : "=";
  551. if($oper=="=" && $field_val == intval($value))
  552. $passed++;
  553. elseif($oper=="!=" && $field_val != intval($value))
  554. $passed++;
  555. elseif($oper==">" && $field_val > intval($value))
  556. $passed++;
  557. elseif($oper=="<" && $field_val < intval($value))
  558. $passed++;
  559. break;
  560. case 'E': // date
  561. $field_val = isset($field_values[$field_id]) ? intval($field_values[$field_id]) : 0;
  562. $from = isset($rule['from']) ? $rule['from'] : "0";
  563. $to = isset($rule['to']) ? $rule['to'] : "now";
  564. if(intval(@strtotime($from)) <= $field_val && intval(@strtotime($to)) >= $field_val) {
  565. $passed++;
  566. }
  567. break;
  568. case 'C': // checkbox
  569. $field_val = isset($field_values[$field_id]) ? $field_values[$field_id] : 0;
  570. if(intval($value)==intval($field_val))
  571. $passed++;
  572. break;
  573. case 'D': // dropdown
  574. case 'X': // multi-checkbox
  575. case 'M': // multi-picklist
  576. case 'W': // worker
  577. $field_val = isset($field_values[$field_id]) ? $field_values[$field_id] : array();
  578. if(!is_array($value)) $value = array($value);
  579. if(is_array($field_val)) { // if multiple things set
  580. foreach($field_val as $v) { // loop through possible
  581. if(isset($value[$v])) { // is any possible set?
  582. $passed++;
  583. break;
  584. }
  585. }
  586. } else { // single
  587. if(isset($value[$field_val])) { // is our set field in possibles?
  588. $passed++;
  589. break;
  590. }
  591. }
  592. break;
  593. }
  594. }
  595. break;
  596. }
  597. }
  598. // If our rule matched every criteria, stop and return the filter
  599. if($passed == count($filter->criteria)) {
  600. DAO_GroupInboxFilter::increment($filter->id); // ++ the times we've matched
  601. $matches[$filter->id] = $filter;
  602. // If we're not stackable anymore, bail out.
  603. if(!$filter->is_stackable)
  604. return $matches;
  605. }
  606. }
  607. // If last rule was still stackable...
  608. if(!empty($matches))
  609. return $matches;
  610. // No matches
  611. return false;
  612. }
  613. /**
  614. * @param integer[] $ticket_ids
  615. */
  616. function run($ticket_ids) {
  617. $fields = array();
  618. $field_values = array();
  619. $groups = DAO_Group::getAll();
  620. $buckets = DAO_Bucket::getAll();
  621. $workers = DAO_Worker::getAll();
  622. $custom_fields = DAO_CustomField::getAll();
  623. // actions
  624. if(is_array($this->actions))
  625. foreach($this->actions as $action => $params) {
  626. switch($action) {
  627. case 'status':
  628. if(isset($params['is_waiting']))
  629. $fields[DAO_Ticket::IS_WAITING] = intval($params['is_waiting']);
  630. if(isset($params['is_closed']))
  631. $fields[DAO_Ticket::IS_CLOSED] = intval($params['is_closed']);
  632. if(isset($params['is_deleted']))
  633. $fields[DAO_Ticket::IS_DELETED] = intval($params['is_deleted']);
  634. break;
  635. case 'assign':
  636. if(isset($params['worker_id'])) {
  637. $w_id = intval($params['worker_id']);
  638. if(0 == $w_id || isset($workers[$w_id]))
  639. $fields[DAO_Ticket::NEXT_WORKER_ID] = $w_id;
  640. }
  641. break;
  642. case 'move':
  643. if(isset($params['group_id']) && isset($params['bucket_id'])) {
  644. $g_id = intval($params['group_id']);
  645. $b_id = intval($params['bucket_id']);
  646. if(isset($groups[$g_id]) && (0==$b_id || isset($buckets[$b_id]))) {
  647. $fields[DAO_Ticket::TEAM_ID] = $g_id;
  648. $fields[DAO_Ticket::CATEGORY_ID] = $b_id;
  649. }
  650. }
  651. break;
  652. case 'spam':
  653. if(isset($params['is_spam'])) {
  654. if(intval($params['is_spam'])) {
  655. foreach($ticket_ids as $ticket_id)
  656. CerberusBayes::markTicketAsSpam($ticket_id);
  657. } else {
  658. foreach($ticket_ids as $ticket_id)
  659. CerberusBayes::markTicketAsNotSpam($ticket_id);
  660. }
  661. }
  662. break;
  663. default:
  664. // Custom fields
  665. if(substr($action,0,3)=="cf_") {
  666. $field_id = intval(substr($action,3));
  667. if(!isset($custom_fields[$field_id]) || !isset($params['value']))
  668. break;
  669. $field_values[$field_id] = $params;
  670. }
  671. break;
  672. }
  673. }
  674. if(!empty($ticket_ids)) {
  675. if(!empty($fields))
  676. DAO_Ticket::updateTicket($ticket_ids, $fields);
  677. // Custom Fields
  678. C4_AbstractView::_doBulkSetCustomFields(ChCustomFieldSource_Ticket::ID, $field_values, $ticket_ids);
  679. }
  680. }
  681. };
  682. /**
  683. * Enter description here...
  684. *
  685. */
  686. abstract class C4_AbstractView {
  687. public $id = 0;
  688. public $name = "";
  689. public $view_columns = array();
  690. public $params = array();
  691. public $renderPage = 0;
  692. public $renderLimit = 10;
  693. public $renderSortBy = '';
  694. public $renderSortAsc = 1;
  695. function getData() {
  696. }
  697. function render() {
  698. echo ' '; // Expect Override
  699. }
  700. function renderCriteria($field) {
  701. echo ' '; // Expect Override
  702. }
  703. protected function _renderCriteriaCustomField($tpl, $field_id) {
  704. $field = DAO_CustomField::get($field_id);
  705. $tpl_path = APP_PATH . '/features/cerberusweb.core/templates/';
  706. switch($field->type) {
  707. case Model_CustomField::TYPE_DROPDOWN:
  708. case Model_CustomField::TYPE_MULTI_PICKLIST:
  709. case Model_CustomField::TYPE_MULTI_CHECKBOX:
  710. $tpl->assign('field', $field);
  711. $tpl->display('file:' . $tpl_path . 'internal/views/criteria/__cfield_picklist.tpl');
  712. break;
  713. case Model_CustomField::TYPE_CHECKBOX:
  714. $tpl->display('file:' . $tpl_path . 'internal/views/criteria/__cfield_checkbox.tpl');
  715. break;
  716. case Model_CustomField::TYPE_DATE:
  717. $tpl->display('file:' . $tpl_path . 'internal/views/criteria/__date.tpl');
  718. break;
  719. case Model_CustomField::TYPE_NUMBER:
  720. $tpl->display('file:' . $tpl_path . 'internal/views/criteria/__number.tpl');
  721. break;
  722. case Model_CustomField::TYPE_WORKER:
  723. $tpl->assign('workers', DAO_Worker::getAllActive());
  724. $tpl->display('file:' . $tpl_path . 'internal/views/criteria/__worker.tpl');
  725. break;
  726. default:
  727. $tpl->display('file:' . $tpl_path . 'internal/views/criteria/__string.tpl');
  728. break;
  729. }
  730. }
  731. /**
  732. * Enter description here...
  733. *
  734. * @param string $field
  735. * @param string $oper
  736. * @param string $value
  737. * @abstract
  738. */
  739. function doSetCriteria($field, $oper, $value) {
  740. // Expect Override
  741. }
  742. protected function _doSetCriteriaCustomField($token, $field_id) {
  743. $field = DAO_CustomField::get($field_id);
  744. @$oper = DevblocksPlatform::importGPC($_POST['oper'],'string','');
  745. @$value = DevblocksPlatform::importGPC($_POST['value'],'string','');
  746. $criteria = null;
  747. switch($field->type) {
  748. case Model_CustomField::TYPE_DROPDOWN:
  749. case Model_CustomField::TYPE_MULTI_PICKLIST:
  750. case Model_CustomField::TYPE_MULTI_CHECKBOX:
  751. @$options = DevblocksPlatform::importGPC($_POST['options'],'array',array());
  752. if(!empty($options)) {
  753. $criteria = new DevblocksSearchCriteria($token,$oper,$options);
  754. } else {
  755. $criteria = new DevblocksSearchCriteria($token,DevblocksSearchCriteria::OPER_IS_NULL);
  756. }
  757. break;
  758. case Model_CustomField::TYPE_CHECKBOX:
  759. $criteria = new DevblocksSearchCriteria($token,$oper,!empty($value) ? 1 : 0);
  760. break;
  761. case Model_CustomField::TYPE_NUMBER:
  762. $criteria = new DevblocksSearchCriteria($token,$oper,intval($value));
  763. break;
  764. case Model_CustomField::TYPE_DATE:
  765. @$from = DevblocksPlatform::importGPC($_REQUEST['from'],'string','');
  766. @$to = DevblocksPlatform::importGPC($_REQUEST['to'],'string','');
  767. if(empty($from)) $from = 0;
  768. if(empty($to)) $to = 'today';
  769. $criteria = new DevblocksSearchCriteria($token,$oper,array($from,$to));
  770. break;
  771. case Model_CustomField::TYPE_WORKER:
  772. @$oper = DevblocksPlatform::importGPC($_REQUEST['oper'],'string','eq');
  773. @$worker_ids = DevblocksPlatform::importGPC($_POST['worker_id'],'array',array());
  774. $criteria = new DevblocksSearchCriteria($token,$oper,$worker_ids);
  775. break;
  776. default: // TYPE_SINGLE_LINE || TYPE_MULTI_LINE
  777. if(($oper == DevblocksSearchCriteria::OPER_LIKE || $oper == DevblocksSearchCriteria::OPER_NOT_LIKE)
  778. && false === (strpos($value,'*'))) {
  779. $value = '*'.$value.'*';
  780. }
  781. $criteria = new DevblocksSearchCriteria($token,$oper,$value);
  782. break;
  783. }
  784. return $criteria;
  785. }
  786. /**
  787. * This method automatically fixes any cached strange options, like
  788. * deleted custom fields.
  789. *
  790. */
  791. protected function _sanitize() {
  792. $fields = $this->getColumns();
  793. $custom_fields = DAO_CustomField::getAll();
  794. $needs_save = false;
  795. // Parameter sanity check
  796. if(is_array($this->params))
  797. foreach($this->params as $pidx => $null) {
  798. if(substr($pidx,0,3)!="cf_")
  799. continue;
  800. if(0 != ($cf_id = intval(substr($pidx,3)))) {
  801. // Make sure our custom fields still exist
  802. if(!isset($custom_fields[$cf_id])) {
  803. unset($this->params[$pidx]);
  804. $needs_save = true;
  805. }
  806. }
  807. }
  808. // View column sanity check
  809. if(is_array($this->view_columns))
  810. foreach($this->view_columns as $cidx => $c) {
  811. // Custom fields
  812. if(substr($c,0,3) == "cf_") {
  813. if(0 != ($cf_id = intval(substr($c,3)))) {
  814. // Make sure our custom fields still exist
  815. if(!isset($custom_fields[$cf_id])) {
  816. unset($this->view_columns[$cidx]);
  817. $needs_save = true;
  818. }
  819. }
  820. } else {
  821. // If the column no longer exists (rare but worth checking)
  822. if(!isset($fields[$c])) {
  823. unset($this->view_columns[$cidx]);
  824. $needs_save = true;
  825. }
  826. }
  827. }
  828. // Sort by sanity check
  829. if(substr($this->renderSortBy,0,3)=="cf_") {
  830. if(0 != ($cf_id = intval(substr($this->renderSortBy,3)))) {
  831. if(!isset($custom_fields[$cf_id])) {
  832. $this->renderSortBy = null;
  833. $needs_save = true;
  834. }
  835. }
  836. }
  837. if($needs_save) {
  838. C4_AbstractViewLoader::setView($this->id, $this);
  839. }
  840. }
  841. function renderCriteriaParam($param) {
  842. $field = $param->field;
  843. $vals = $param->value;
  844. if(!is_array($vals))
  845. $vals = array($vals);
  846. // Do we need to do anything special on custom fields?
  847. if('cf_'==substr($field,0,3)) {
  848. $field_id = intval(substr($field,3));
  849. $custom_fields = DAO_CustomField::getAll();
  850. switch($custom_fields[$field_id]->type) {
  851. case Model_CustomField::TYPE_WORKER:
  852. $workers = DAO_worker::getAll();
  853. foreach($vals as $idx => $worker_id) {
  854. if(isset($workers[$worker_id]))
  855. $vals[$idx] = $workers[$worker_id]->getName();
  856. }
  857. break;
  858. }
  859. }
  860. echo implode(', ', $vals);
  861. }
  862. /**
  863. * All the view's available fields
  864. *
  865. * @return array
  866. */
  867. static function getFields() {
  868. // Expect Override
  869. return array();
  870. }
  871. /**
  872. * All searchable fields
  873. *
  874. * @return array
  875. */
  876. static function getSearchFields() {
  877. // Expect Override
  878. return array();
  879. }
  880. /**
  881. * All fields that can be displayed as columns in the view
  882. *
  883. * @return array
  884. */
  885. static function getColumns() {
  886. // Expect Override
  887. return array();
  888. }
  889. function doCustomize($columns, $num_rows=10) {
  890. $this->renderLimit = $num_rows;
  891. $viewColumns = array();
  892. foreach($columns as $col) {
  893. if(empty($col))
  894. continue;
  895. $viewColumns[] = $col;
  896. }
  897. $this->view_columns = $viewColumns;
  898. }
  899. function doSortBy($sortBy) {
  900. $iSortAsc = intval($this->renderSortAsc);
  901. // [JAS]: If clicking the same header, toggle asc/desc.
  902. if(0 == strcasecmp($sortBy,$this->renderSortBy)) {
  903. $iSortAsc = (0 == $iSortAsc) ? 1 : 0;
  904. } else { // [JAS]: If a new header, start with asc.
  905. $iSortAsc = 1;
  906. }
  907. $this->renderSortBy = $sortBy;
  908. $this->renderSortAsc = $iSortAsc;
  909. }
  910. function doPage($page) {
  911. $this->renderPage = $page;
  912. }
  913. function doRemoveCriteria($field) {
  914. unset($this->params[$field]);
  915. $this->renderPage = 0;
  916. }
  917. function doResetCriteria() {
  918. $this->params = array();
  919. $this->renderPage = 0;
  920. }
  921. public static function _doBulkSetCustomFields($source_extension,$custom_fields, $ids) {
  922. $fields = DAO_CustomField::getAll();
  923. if(!empty($custom_fields))
  924. foreach($custom_fields as $cf_id => $params) {
  925. if(!is_array($params) || !isset($params['value']))
  926. continue;
  927. $cf_val = $params['value'];
  928. // Data massaging
  929. switch($fields[$cf_id]->type) {
  930. case Model_CustomField::TYPE_DATE:
  931. $cf_val = intval(@strtotime($cf_val));
  932. break;
  933. case Model_CustomField::TYPE_CHECKBOX:
  934. case Model_CustomField::TYPE_NUMBER:
  935. $cf_val = (0==strlen($cf_val)) ? '' : intval($cf_val);
  936. break;
  937. }
  938. // If multi-selection types, handle delta changes
  939. if(Model_CustomField::TYPE_MULTI_PICKLIST==$fields[$cf_id]->type
  940. || Model_CustomField::TYPE_MULTI_CHECKBOX==$fields[$cf_id]->type) {
  941. if(is_array($cf_val))
  942. foreach($cf_val as $val) {
  943. $op = substr($val,0,1);
  944. $val = substr($val,1);
  945. if(is_array($ids))
  946. foreach($ids as $id) {
  947. if($op=='+')
  948. DAO_CustomFieldValue::setFieldValue($source_extension,$id,$cf_id,$val,true);
  949. elseif($op=='-')
  950. DAO_CustomFieldValue::unsetFieldValue($source_extension,$id,$cf_id,$val);
  951. }
  952. }
  953. // Otherwise, set/unset as a single field
  954. } else {
  955. if(is_array($ids))
  956. foreach($ids as $id) {
  957. if(0 != strlen($cf_val))
  958. DAO_CustomFieldValue::setFieldValue($source_extension,$id,$cf_id,$cf_val);
  959. else
  960. DAO_CustomFieldValue::unsetFieldValue($source_extension,$id,$cf_id);
  961. }
  962. }
  963. }
  964. }
  965. };
  966. /**
  967. * Used to persist a C4_AbstractView instance and not be encumbered by
  968. * classloading issues (out of the session) from plugins that might have
  969. * concrete AbstractView implementations.
  970. */
  971. class C4_AbstractViewModel {
  972. public $class_name = '';
  973. public $id = 0;
  974. public $name = "";
  975. public $view_columns = array();
  976. public $params = array();
  977. public $renderPage = 0;
  978. public $renderLimit = 10;
  979. public $renderSortBy = '';
  980. public $renderSortAsc = 1;
  981. };
  982. /**
  983. * This is essentially an AbstractView Factory
  984. */
  985. class C4_AbstractViewLoader {
  986. static $views = null;
  987. const VISIT_ABSTRACTVIEWS = 'abstractviews_list';
  988. static private function _init() {
  989. $visit = CerberusApplication::getVisit();
  990. self::$views = $visit->get(self::VISIT_ABSTRACTVIEWS,array());
  991. }
  992. /**
  993. * @param string $view_label Abstract view identifier
  994. * @return boolean
  995. */
  996. static function exists($view_label) {
  997. if(is_null(self::$views)) self::_init();
  998. return isset(self::$views[$view_label]);
  999. }
  1000. /**
  1001. * Enter description here...
  1002. *
  1003. * @param string $class C4_AbstractView
  1004. * @param string $view_label ID
  1005. * @return C4_AbstractView instance
  1006. */
  1007. static function getView($view_label, C4_AbstractViewModel $defaults=null) {
  1008. $active_worker = CerberusApplication::getActiveWorker();
  1009. if(is_null(self::$views)) self::_init();
  1010. if(self::exists($view_label)) {
  1011. $model = self::$views[$view_label];
  1012. return self::unserializeAbstractView($model);
  1013. } else {
  1014. // See if the worker has their own saved prefs
  1015. @$prefs = unserialize(DAO_WorkerPref::get($active_worker->id, 'view'.$view_label));
  1016. // If no worker prefsd, check if we're passed defaults
  1017. if((empty($prefs) || !$prefs instanceof C4_AbstractViewModel) && !empty($defaults))
  1018. $prefs = $defaults;
  1019. // Create a default view if it doesn't exist
  1020. if(!empty($prefs) && $prefs instanceof C4_AbstractViewModel) {
  1021. if(!empty($prefs->class_name) || class_exists($prefs->class_name)) {
  1022. $view = new $prefs->class_name;
  1023. $view->id = $view_label;
  1024. if(!empty($prefs->view_columns))
  1025. $view->view_columns = $prefs->view_columns;
  1026. if(!empty($prefs->renderLimit))
  1027. $view->renderLimit = $prefs->renderLimit;
  1028. if(null !== $prefs->renderSortBy)
  1029. $view->renderSortBy = $prefs->renderSortBy;
  1030. if(null !== $prefs->renderSortAsc)
  1031. $view->renderSortAsc = $prefs->renderSortAsc;
  1032. self::setView($view_label, $view);
  1033. return $view;
  1034. }
  1035. }
  1036. }
  1037. return null;
  1038. }
  1039. /**
  1040. * Enter description here...
  1041. *
  1042. * @param string $class C4_AbstractView
  1043. * @param string $view_label ID
  1044. * @param C4_AbstractView $view
  1045. */
  1046. static function setView($view_label, $view) {
  1047. if(is_null(self::$views)) self::_init();
  1048. self::$views[$view_label] = self::serializeAbstractView($view);
  1049. self::_save();
  1050. }
  1051. static function deleteView($view_label) {
  1052. unset(self::$views[$view_label]);
  1053. self::_save();
  1054. }
  1055. static private function _save() {
  1056. // persist
  1057. $visit = CerberusApplication::getVisit();
  1058. $visit->set(self::VISIT_ABSTRACTVIEWS, self::$views);
  1059. }
  1060. static function serializeAbstractView($view) {
  1061. if(!$view instanceof C4_AbstractView) {
  1062. return null;
  1063. }
  1064. $model = new C4_AbstractViewModel();
  1065. $model->class_name = get_class($view);
  1066. $model->id = $view->id;
  1067. $model->name = $view->name;
  1068. $model->view_columns = $view->view_columns;
  1069. $model->params = $view->params;
  1070. $model->renderPage = $view->renderPage;
  1071. $model->renderLimit = $view->renderLimit;
  1072. $model->renderSortBy = $view->renderSortBy;
  1073. $model->renderSortAsc = $view->renderSortAsc;
  1074. return $model;
  1075. }
  1076. static function unserializeAbstractView(C4_AbstractViewModel $model) {
  1077. if(!class_exists($model->class_name, true))
  1078. return null;
  1079. if(null == ($inst = new $model->class_name))
  1080. return null;
  1081. /* @var $inst C4_AbstractView */
  1082. $inst->id = $model->id;
  1083. $inst->name = $model->name;
  1084. $inst->view_columns = $model->view_columns;
  1085. $inst->params = $model->params;
  1086. $inst->renderPage = $model->renderPage;
  1087. $inst->renderLimit = $model->renderLimit;
  1088. $inst->renderSortBy = $model->renderSortBy;
  1089. $inst->renderSortAsc = $model->renderSortAsc;
  1090. return $inst;
  1091. }
  1092. };
  1093. class Model_Address {
  1094. public $id;
  1095. public $email = '';
  1096. public $first_name = '';
  1097. public $last_name = '';
  1098. public $contact_org_id = 0;
  1099. public $num_spam = 0;
  1100. public $num_nonspam = 0;
  1101. public $is_banned = 0;
  1102. public $is_registered = 0;
  1103. public $pass = '';
  1104. public $last_autoreply;
  1105. function Model_Address() {}
  1106. function getName() {
  1107. return sprintf("%s%s%s",
  1108. $this->first_name,
  1109. (!empty($this->first_name) && !empty($this->last_name)) ? " " : "",
  1110. $this->last_name
  1111. );
  1112. }
  1113. };
  1114. class Model_AddressToWorker {
  1115. public $address;
  1116. public $worker_id;
  1117. public $is_confirmed;
  1118. public $code;
  1119. public $code_expire;
  1120. }
  1121. class View_DevblocksTemplate extends C4_AbstractView {
  1122. const DEFAULT_ID = 'templates';
  1123. function __construct() {
  1124. $this->id = self::DEFAULT_ID;
  1125. $this->name = 'Templates';
  1126. $this->renderLimit = 25;
  1127. $this->renderSortBy = SearchFields_DevblocksTemplate::PATH;
  1128. $this->renderSortAsc = true;
  1129. $this->view_columns = array(
  1130. SearchFields_DevblocksTemplate::PLUGIN_ID,
  1131. // SearchFields_DevblocksTemplate::TAG,
  1132. SearchFields_DevblocksTemplate::LAST_UPDATED,
  1133. );
  1134. $this->doResetCriteria();
  1135. }
  1136. function getData() {
  1137. return DAO_DevblocksTemplate::search(
  1138. $this->view_columns,
  1139. $this->params,
  1140. $this->renderLimit,
  1141. $this->renderPage,
  1142. $this->renderSortBy,
  1143. $this->renderSortAsc
  1144. );
  1145. }
  1146. function render() {
  1147. $this->_sanitize();
  1148. $tpl = DevblocksPlatform::getTemplateService();
  1149. $tpl->assign('id', $this->id);
  1150. $tpl->assign('view', $this);
  1151. // $custom_fields = DAO_CustomField::getBySource(ChCustomFieldSource_Worker::ID);
  1152. // $tpl->assign('custom_fields', $custom_fields);
  1153. $tpl->assign('view_fields', $this->getColumns());
  1154. $tpl->display('file:' . APP_PATH . '/features/usermeet.core/templates/community/display/tabs/templates/view.tpl');
  1155. }
  1156. function renderCriteria($field) {
  1157. $tpl = DevblocksPlatform::getTemplateService();
  1158. $tpl->assign('id', $this->id);
  1159. switch($field) {
  1160. case SearchFields_DevblocksTemplate::CONTENT:
  1161. case SearchFields_DevblocksTemplate::PATH:
  1162. case SearchFields_DevblocksTemplate::PLUGIN_ID:
  1163. case SearchFields_DevblocksTemplate::TAG:
  1164. $tpl->display('file:' . APP_PATH . '/features/cerberusweb.core/templates/internal/views/criteria/__string.tpl');
  1165. break;
  1166. case SearchFields_DevblocksTemplate::LAST_UPDATED:
  1167. $tpl->display('file:' . APP_PATH . '/features/cerberusweb.core/templates/internal/views/criteria/__date.tpl');
  1168. break;
  1169. default:
  1170. // Custom Fields
  1171. // if('cf_' == substr($field,0,3)) {
  1172. // $this->_renderCriteriaCustomField($tpl, substr($field,3));
  1173. // } else {
  1174. // echo ' ';
  1175. // }
  1176. break;
  1177. }
  1178. }
  1179. function renderCriteriaParam($param) {
  1180. $field = $param->field;
  1181. $values = !is_array($param->value) ? array($param->value) : $param->value;
  1182. switch($field) {
  1183. // case SearchFields_WorkerEvent::WORKER_ID:
  1184. // $workers = DAO_Worker::getAll();
  1185. // $strings = array();
  1186. //
  1187. // foreach($values as $val) {
  1188. // if(empty($val))
  1189. // $strings[] = "Nobody";
  1190. // elseif(!isset($workers[$val]))
  1191. // continue;
  1192. // else
  1193. // $strings[] = $workers[$val]->getName();
  1194. // }
  1195. // echo implode(", ", $strings);
  1196. // break;
  1197. default:
  1198. parent::renderCriteriaParam($param);
  1199. break;
  1200. }
  1201. }
  1202. static function getFields() {
  1203. return SearchFields_DevblocksTemplate::getFields();
  1204. }
  1205. static function getSearchFields() {
  1206. $fields = self::getFields();
  1207. return $fields;
  1208. }
  1209. static function getColumns() {
  1210. $fields = self::getFields();
  1211. return $fields;
  1212. }
  1213. function doResetCriteria() {
  1214. parent::doResetCriteria();
  1215. // $this->params = array(
  1216. // SearchFields_WorkerEvent::NUM_NONSPAM => new DevblocksSearchCriteria(SearchFields_WorkerEvent::NUM_NONSPAM,'>',0),
  1217. // );
  1218. }
  1219. function doSetCriteria($field, $oper, $value) {
  1220. $criteria = null;
  1221. switch($field) {
  1222. case SearchFields_DevblocksTemplate::CONTENT:
  1223. case SearchFields_DevblocksTemplate::PATH:
  1224. case SearchFields_DevblocksTemplate::PLUGIN_ID:
  1225. case SearchFields_DevblocksTemplate::TAG:
  1226. // force wildcards if none used on a LIKE
  1227. if(($oper == DevblocksSearchCriteria::OPER_LIKE || $oper == DevblocksSearchCriteria::OPER_NOT_LIKE)
  1228. && false === (strpos($value,'*'))) {
  1229. $value = '*'.$value.'*';
  1230. }
  1231. $criteria = new DevblocksSearchCriteria($field, $oper, $value);
  1232. break;
  1233. case SearchFields_DevblocksTemplate::LAST_UPDATED:
  1234. @$from = DevblocksPlatform::importGPC($_REQUEST['from'],'string','');
  1235. @$to = DevblocksPlatform::importGPC($_REQUEST['to'],'string','');
  1236. if(empty($from)) $from = 0;
  1237. if(empty($to)) $to = 'today';
  1238. $criteria = new DevblocksSearchCriteria($field,$oper,array($from,$to));
  1239. break;
  1240. default:
  1241. // Custom Fields
  1242. // if(substr($field,0,3)=='cf_') {
  1243. // $criteria = $this->_doSetCriteriaCustomField($field, substr($field,3));
  1244. // }
  1245. break;
  1246. }
  1247. if(!empty($criteria)) {
  1248. $this->params[$field] = $criteria;
  1249. $this->renderPage = 0;
  1250. }
  1251. }
  1252. function doBulkUpdate($filter, $do, $ids=array()) {
  1253. @set_time_limit(600); // [TODO] Temp!
  1254. $change_fields = array();
  1255. $deleted = false;
  1256. $custom_fields = array();
  1257. if(empty($do))
  1258. return;
  1259. // Make sure we have checked items if we want a checked list
  1260. if(0 == strcasecmp($filter,"checks") && empty($ids))
  1261. return;
  1262. if(is_array($do))
  1263. foreach($do as $k => $v) {
  1264. switch($k) {
  1265. case 'deleted':
  1266. $deleted = true;
  1267. break;
  1268. default:
  1269. // Custom fields
  1270. if(substr($k,0,3)=="cf_") {
  1271. $custom_fields[substr($k,3)] = $v;
  1272. }
  1273. break;
  1274. }
  1275. }
  1276. $pg = 0;
  1277. if(empty($ids))
  1278. do {
  1279. list($objects,$null) = DAO_DevblocksTemplate::search(
  1280. array(),
  1281. $this->params,
  1282. 100,
  1283. $pg++,
  1284. DAO_DevblocksTemplate::ID,
  1285. true,
  1286. false
  1287. );
  1288. $ids = array_merge($ids, array_keys($objects));
  1289. } while(!empty($objects));
  1290. $batch_total = count($ids);
  1291. for($x=0;$x<=$batch_total;$x+=100) {
  1292. $batch_ids = array_slice($ids,$x,100);
  1293. if(!$deleted)
  1294. DAO_DevblocksTemplate::update($batch_ids, $change_fields);
  1295. else
  1296. DAO_DevblocksTemplate::delete($batch_ids);
  1297. // Custom Fields
  1298. // self::_doBulkSetCustomFields(ChCustomFieldSource_Worker::ID, $custom_fields, $batch_ids);
  1299. unset($batch_ids);
  1300. }
  1301. if($deleted) {
  1302. // Clear template cache
  1303. $tpl = DevblocksPlatform::getTemplateService();
  1304. $tpl->clear_compiled_tpl();
  1305. }
  1306. unset($ids);
  1307. }
  1308. };
  1309. class C4_TicketView extends C4_AbstractView {
  1310. const DEFAULT_ID = 'tickets_workspace';
  1311. function __construct() {
  1312. $this->id = self::DEFAULT_ID;
  1313. $this->name = 'Tickets';
  1314. $this->renderLimit = 10;
  1315. $this->renderSortBy = SearchFields_Ticket::TICKET_UPDATED_DATE;
  1316. $this->renderSortAsc = false;
  1317. $this->view_columns = array(
  1318. SearchFields_Ticket::TICKET_LAST_ACTION_CODE,
  1319. SearchFields_Ticket::TICKET_UPDATED_DATE,
  1320. SearchFields_Ticket::TICKET_TEAM_ID,
  1321. SearchFields_Ticket::TICKET_CATEGORY_ID,
  1322. SearchFields_Ticket::TICKET_SPAM_SCORE,
  1323. );
  1324. }
  1325. function getData() {
  1326. $objects = DAO_Ticket::search(
  1327. $this->view_columns,
  1328. $this->params,
  1329. $this->renderLimit,
  1330. $this->renderPage,
  1331. $this->renderSortBy,
  1332. $this->renderSortAsc
  1333. );
  1334. return $objects;
  1335. }
  1336. function render() {
  1337. $this->_sanitize();
  1338. $tpl = DevblocksPlatform::getTemplateService();
  1339. $tpl->assign('id', $this->id);
  1340. $view_path = APP_PATH . '/features/cerberusweb.core/templates/tickets/';
  1341. $tpl->assign('view_path',$view_path);
  1342. $tpl->assign('view', $this);
  1343. $visit = CerberusApplication::getVisit();
  1344. $results = self::getData();
  1345. $tpl->assign('results', $results);
  1346. @$ids = array_keys($results[0]);
  1347. $workers = DAO_Worker::getAll();
  1348. $tpl->assign('workers', $workers);
  1349. $teams = DAO_Group::getAll();
  1350. $tpl->assign('teams', $teams);
  1351. $buckets = DAO_Bucket::getAll();
  1352. $tpl->assign('buckets', $buckets);
  1353. $team_categories = DAO_Bucket::getTeams();
  1354. $tpl->assign('team_categories', $team_categories);
  1355. $custom_fields = DAO_CustomField::getBySource(ChCustomFieldSource_Ticket::ID);
  1356. $tpl->assign('custom_fields', $custom_fields);
  1357. // Undo?
  1358. $last_action = C4_TicketView::getLastAction($this->id);
  1359. $tpl->assign('last_action', $last_action);
  1360. if(!empty($last_action) && !is_null($last_action->ticket_ids)) {
  1361. $tpl->assign('last_action_count', count($last_action->ticket_ids));
  1362. }
  1363. $tpl->assign('timestamp_now', time());
  1364. $tpl->assign('view_fields', $this->getColumns());
  1365. $tpl->display('file:' . $view_path . 'ticket_view.tpl');
  1366. }
  1367. function doResetCriteria() {
  1368. $active_worker = CerberusApplication::getActiveWorker(); /* @var $active_worker CerberusWorker */
  1369. $active_worker_memberships = $active_worker->getMemberships();
  1370. $this->params = array(
  1371. SearchFields_Ticket::TICKET_CLOSED => new DevblocksSearchCriteria(SearchFields_Ticket::TICKET_CLOSED,'=',0),
  1372. SearchFields_Ticket::TICKET_TEAM_ID => new DevblocksSearchCriteria(SearchFields_Ticket::TICKET_TEAM_ID,'in',array_keys($active_worker_memberships)), // censor
  1373. );
  1374. $this->renderPage = 0;
  1375. }
  1376. function renderCriteria($field) {
  1377. $tpl = DevblocksPlatform::getTemplateService();
  1378. $tpl->assign('id', $this->id);
  1379. $tpl_path = APP_PATH . '/features/cerberusweb.core/templates/';
  1380. switch($field) {
  1381. case SearchFields_Ticket::TICKET_ID:
  1382. case SearchFields_Ticket::TICKET_MASK:
  1383. case SearchFields_Ticket::TICKET_SUBJECT:
  1384. case SearchFields_Ticket::TICKET_FIRST_WROTE:
  1385. case SearchFields_Ticket::TICKET_LAST_WROTE:
  1386. case SearchFields_Ticket::REQUESTER_ADDRESS:
  1387. case SearchFields_Ticket::TICKET_INTERESTING_WORDS:
  1388. case SearchFields_Ticket::ORG_NAME:
  1389. $tpl->display('file:' . $tpl_path . 'internal/views/criteria/__string.tpl');
  1390. break;
  1391. case SearchFields_Ticket::TICKET_MESSAGE_CONTENT:
  1392. $tpl->display('file:' . $tpl_path . 'internal/views/criteria/__fulltext.tpl');
  1393. break;
  1394. case SearchFields_Ticket::TICKET_FIRST_WROTE_SPAM:
  1395. case SearchFields_Ticket::TICKET_FIRST_WROTE_NONSPAM:
  1396. $tpl->display('file:' . $tpl_path . 'internal/views/criteria/__number.tpl');
  1397. break;
  1398. case SearchFields_Ticket::TICKET_WAITING:
  1399. case SearchFields_Ticket::TICKET_DELETED:
  1400. case SearchFields_Ticket::TICKET_CLOSED:
  1401. $tpl->display('file:' . $tpl_path . 'internal/views/criteria/__bool.tpl');
  1402. break;
  1403. case SearchFields_Ticket::TICKET_CREATED_DATE:
  1404. case SearchFields_Ticket::TICKET_UPDATED_DATE:
  1405. case SearchFields_Ticket::TICKET_DUE_DATE:
  1406. $tpl->display('file:' . $tpl_path . 'internal/views/criteria/__date.tpl');
  1407. break;
  1408. case SearchFields_Ticket::TICKET_SPAM_TRAINING:
  1409. $tpl->display('file:' . $tpl_path . 'tickets/search/criteria/ticket_spam_training.tpl');
  1410. break;
  1411. case SearchFields_Ticket::TICKET_SPAM_SCORE:
  1412. $tpl->display('file:' . $tpl_path . 'tickets/search/criteria/ticket_spam_score.tpl');
  1413. break;
  1414. case SearchFields_Ticket::TICKET_LAST_ACTION_CODE:
  1415. $tpl->display('file:' . $tpl_path . 'tickets/search/criteria/ticket_last_action.tpl');
  1416. break;
  1417. case SearchFields_Ticket::TICKET_NEXT_WORKER_ID:
  1418. case SearchFields_Ticket::TICKET_LAST_WORKER_ID:
  1419. $workers = DAO_Worker::getAll();
  1420. $tpl->assign('workers', $workers);
  1421. $tpl->display('file:' . $tpl_path . 'internal/views/criteria/__worker.tpl');
  1422. break;
  1423. case SearchFields_Ticket::TICKET_TEAM_ID:
  1424. $teams = DAO_Group::getAll();
  1425. $tpl->assign('teams', $teams);
  1426. $team_categories = DAO_Bucket::getTeams();
  1427. $tpl->assign('team_categories', $team_categories);
  1428. $tpl->display('file:' . $tpl_path . 'tickets/search/criteria/ticket_team.tpl');
  1429. break;
  1430. default:
  1431. // Custom Fields
  1432. if('cf_' == substr($field,0,3)) {
  1433. $this->_renderCriteriaCustomField($tpl, substr($field,3));
  1434. } else {
  1435. echo ' ';
  1436. }
  1437. break;
  1438. }
  1439. }
  1440. function renderCriteriaParam($param) {
  1441. $field = $param->field;
  1442. $values = !is_array($param->value) ? array($param->value) : $param->value;
  1443. switch($field) {
  1444. case SearchFields_Ticket::TICKET_LAST_WORKER_ID:
  1445. case SearchFields_Ticket::TICKET_NEXT_WORKER_ID:
  1446. $workers = DAO_Worker::getAll();
  1447. $strings = array();
  1448. foreach($values as $val) {
  1449. if(empty($val))
  1450. $strings[] = "Nobody";
  1451. elseif(!isset($workers[$val]))
  1452. continue;
  1453. else
  1454. $strings[] = $workers[$val]->getName();
  1455. }
  1456. echo implode(", ", $strings);
  1457. break;
  1458. case SearchFields_Ticket::TICKET_TEAM_ID:
  1459. $teams = DAO_Group::getAll();
  1460. $strings = array();
  1461. foreach($values as $val) {
  1462. if(!isset($teams[$val]))
  1463. continue;
  1464. $strings[] = $teams[$val]->name;
  1465. }
  1466. echo implode(", ", $strings);
  1467. break;
  1468. case SearchFields_Ticket::TICKET_CATEGORY_ID:
  1469. $buckets = DAO_Bucket::getAll();
  1470. $strings = array();
  1471. foreach($values as $val) {
  1472. if(0==$val) {
  1473. $strings[] = "Inbox";
  1474. } elseif(!isset($buckets[$val])) {
  1475. continue;
  1476. } else {
  1477. $strings[] = $buckets[$val]->name;
  1478. }
  1479. }
  1480. echo implode(", ", $strings);
  1481. break;
  1482. case SearchFields_Ticket::TICKET_LAST_ACTION_CODE:
  1483. $strings = array();
  1484. foreach($values as $val) {
  1485. switch($val) {
  1486. case 'O':
  1487. $strings[] = "New Ticket";
  1488. break;
  1489. case 'R':
  1490. $strings[] = "Customer Reply";
  1491. break;
  1492. case 'W':
  1493. $strings[] = "Worker Reply";
  1494. break;
  1495. }
  1496. }
  1497. echo implode(", ", $strings);
  1498. break;
  1499. case SearchFields_Ticket::TICKET_SPAM_TRAINING:
  1500. $strings = array();
  1501. foreach($values as $val) {
  1502. switch($val) {
  1503. case 'S':
  1504. $strings[] = "Spam";
  1505. break;
  1506. case 'N':
  1507. $strings[] = "Not Spam";
  1508. break;
  1509. default:
  1510. $strings[] = "Not Trained";
  1511. break;
  1512. }
  1513. }
  1514. echo implode(", ", $strings);
  1515. break;
  1516. default:
  1517. parent::renderCriteriaParam($param);
  1518. break;
  1519. }
  1520. }
  1521. static function getFields() {
  1522. return SearchFields_Ticket::getFields();
  1523. }
  1524. static function getSearchFields() {
  1525. $fields = self::getFields();
  1526. unset($fields[SearchFields_Ticket::TICKET_CATEGORY_ID]);
  1527. unset($fields[SearchFields_Ticket::TICKET_UNLOCK_DATE]);
  1528. return $fields;
  1529. }
  1530. static function getColumns() {
  1531. $fields = self::getFields();
  1532. unset($fields[SearchFields_Ticket::TICKET_MESSAGE_CONTENT]);
  1533. unset($fields[SearchFields_Ticket::REQUESTER_ID]);
  1534. unset($fields[SearchFields_Ticket::REQUESTER_ADDRESS]);
  1535. unset($fields[SearchFields_Ticket::TICKET_UNLOCK_DATE]);
  1536. unset($fields[SearchFields_Ticket::TICKET_INTERESTING_WORDS]);
  1537. return $fields;
  1538. }
  1539. function doSetCriteria($field, $oper, $value) {
  1540. $criteria = null;
  1541. switch($field) {
  1542. case SearchFields_Ticket::TICKET_ID:
  1543. case SearchFields_Ticket::TICKET_MASK:
  1544. case SearchFields_Ticket::TICKET_SUBJECT:
  1545. case SearchFields_Ticket::TICKET_FIRST_WROTE:
  1546. case SearchFields_Ticket::TICKET_LAST_WROTE:
  1547. case SearchFields_Ticket::REQUESTER_ADDRESS:
  1548. case SearchFields_Ticket::TICKET_INTERESTING_WORDS:
  1549. case SearchFields_Ticket::ORG_NAME:
  1550. // force wildcards if none used on a LIKE
  1551. if(($oper == DevblocksSearchCriteria::OPER_LIKE || $oper == DevblocksSearchCriteria::OPER_NOT_LIKE)
  1552. && false === (strpos($value,'*'))) {
  1553. $value = '*'.$value.'*';
  1554. }
  1555. $criteria = new DevblocksSearchCriteria($field, $oper, $value);
  1556. break;
  1557. case SearchFields_Ticket::TICKET_MESSAGE_CONTENT:
  1558. $criteria = new DevblocksSearchCriteria($field, $oper, $value);
  1559. break;
  1560. case SearchFields_Ticket::TICKET_WAITING:
  1561. case SearchFields_Ticket::TICKET_DELETED:
  1562. case SearchFields_Ticket::TICKET_CLOSED:
  1563. @$bool = DevblocksPlatform::importGPC($_REQUEST['bool'],'integer',1);
  1564. $criteria = new DevblocksSearchCriteria($field,$oper,$bool);
  1565. break;
  1566. case SearchFields_Ticket::TICKET_FIRST_WROTE_SPAM:
  1567. case SearchFields_Ticket::TICKET_FIRST_WROTE_NONSPAM:
  1568. $criteria = new DevblocksSearchCriteria($field,$oper,$value);
  1569. break;
  1570. case SearchFields_Ticket::TICKET_CREATED_DATE:
  1571. case SearchFields_Ticket::TICKET_UPDATED_DATE:
  1572. case SearchFields_Ticket::TICKET_DUE_DATE:
  1573. @$from = DevblocksPlatform::importGPC($_REQUEST['from'],'string','');
  1574. @$to = DevblocksPlatform::importGPC($_REQUEST['to'],'string','');
  1575. if(empty($from) || (!is_numeric($from) && @false === strtotime(str_replace('.','-',$from))))
  1576. $from = 0;
  1577. if(empty($to) || (!is_numeric($to) && @false === strtotime(str_replace('.','-',$to))))
  1578. $to = 'now';
  1579. $criteria = new DevblocksSearchCriteria($field,$oper,array($from,$to));
  1580. break;
  1581. case SearchFields_Ticket::TICKET_SPAM_SCORE:
  1582. @$score = DevblocksPlatform::importGPC($_REQUEST['score'],'integer',null);
  1583. if(!is_null($score) && is_numeric($score)) {
  1584. $criteria = new DevblocksSearchCriteria($field,$oper,intval($score)/100);
  1585. }
  1586. break;
  1587. case SearchFields_Ticket::TICKET_SPAM_TRAINING:
  1588. $criteria = new DevblocksSearchCriteria($field,$oper,$value);
  1589. break;
  1590. case SearchFields_Ticket::TICKET_LAST_ACTION_CODE:
  1591. @$last_action_code = DevblocksPlatform::importGPC($_REQUEST['last_action'],'array',array());
  1592. $criteria = new DevblocksSearchCriteria($field,$oper,$last_action_code);
  1593. break;
  1594. case SearchFields_Ticket::TICKET_LAST_WORKER_ID:
  1595. case SearchFields_Ticket::TICKET_NEXT_WORKER_ID:
  1596. @$worker_id = DevblocksPlatform::importGPC($_REQUEST['worker_id'],'array',array());
  1597. $criteria = new DevblocksSearchCriteria($field,$oper,$worker_id);
  1598. break;
  1599. case SearchFields_Ticket::TICKET_TEAM_ID:
  1600. @$team_ids = DevblocksPlatform::importGPC($_REQUEST['team_id'],'array');
  1601. @$bucket_ids = DevblocksPlatform::importGPC($_REQUEST['bucket_id'],'array');
  1602. if(!empty($team_ids))
  1603. $this->params[SearchFields_Ticket::TICKET_TEAM_ID] = new DevblocksSearchCriteria(SearchFields_Ticket::TICKET_TEAM_ID,$oper,$team_ids);
  1604. if(!empty($bucket_ids))
  1605. $this->params[SearchFields_Ticket::TICKET_CATEGORY_ID] = new DevblocksSearchCriteria(SearchFields_Ticket::TICKET_CATEGORY_ID,$oper,$bucket_ids);
  1606. break;
  1607. default:
  1608. // Custom Fields
  1609. if(substr($field,0,3)=='cf_') {
  1610. $criteria = $this->_doSetCriteriaCustomField($field, substr($field,3));
  1611. }
  1612. break;
  1613. }
  1614. if(!empty($criteria)) {
  1615. $this->params[$field] = $criteria;
  1616. $this->renderPage = 0;
  1617. }
  1618. }
  1619. /**
  1620. * @param array
  1621. * @param array
  1622. * @return boolean
  1623. * [TODO] Find a better home for this?
  1624. */
  1625. function doBulkUpdate($filter, $filter_param, $data, $do, $ticket_ids=array()) {
  1626. @set_time_limit(600);
  1627. // Make sure we have checked items if we want a checked list
  1628. if(0 == strcasecmp($filter,"checks") && empty($ticket_ids))
  1629. return;
  1630. $rule = new Model_GroupInboxFilter();
  1631. $rule->actions = $do;
  1632. $params = $this->params;
  1633. if(empty($filter)) {
  1634. $data[] = '*'; // All, just to permit a loop in foreach($data ...)
  1635. }
  1636. switch($filter) {
  1637. default:
  1638. case 'subject':
  1639. case 'sender':
  1640. case 'header':
  1641. if(is_array($data))
  1642. foreach($data as $v) {
  1643. $new_params = array();
  1644. $do_header = null;
  1645. switch($filter) {
  1646. case 'subject':
  1647. $new_params = array(
  1648. new DevblocksSearchCriteria(SearchFields_Ticket::TICKET_SUBJECT,DevblocksSearchCriteria::OPER_LIKE,$v)
  1649. );
  1650. $do_header = 'subject';
  1651. $ticket_ids = array();
  1652. break;
  1653. case 'sender':
  1654. $new_params = array(
  1655. new DevblocksSearchCriteria(SearchFields_Ticket::SENDER_ADDRESS,DevblocksSearchCriteria::OPER_LIKE,$v)
  1656. );
  1657. $do_header = 'from';
  1658. $ticket_ids = array();
  1659. break;
  1660. case 'header':
  1661. $new_params = array(
  1662. // [TODO] It will eventually come up that we need multiple header matches (which need to be pair grouped as OR)
  1663. new DevblocksSearchCriteria(SearchFields_Ticket::TICKET_MESSAGE_HEADER,DevblocksSearchCriteria::OPER_EQ,$filter_param),
  1664. new DevblocksSearchCriteria(SearchFields_Ticket::TICKET_MESSAGE_HEADER_VALUE,DevblocksSearchCriteria::OPER_EQ,$v)
  1665. );
  1666. $ticket_ids = array();
  1667. break;
  1668. }
  1669. $new_params = array_merge($new_params, $params);
  1670. $pg = 0;
  1671. if(empty($ticket_ids)) {
  1672. do {
  1673. list($tickets,$null) = DAO_Ticket::search(
  1674. array(),
  1675. $new_params,
  1676. 100,
  1677. $pg++,
  1678. SearchFields_Ticket::TICKET_ID,
  1679. true,
  1680. false
  1681. );
  1682. $ticket_ids = array_merge($ticket_ids, array_keys($tickets));
  1683. } while(!empty($tickets));
  1684. }
  1685. $batch_total = count($ticket_ids);
  1686. for($x=0;$x<=$batch_total;$x+=200) {
  1687. $batch_ids = array_slice($ticket_ids,$x,200);
  1688. $rule->run($batch_ids);
  1689. unset($batch_ids);
  1690. }
  1691. }
  1692. break;
  1693. }
  1694. unset($ticket_ids);
  1695. }
  1696. static function createSearchView() {
  1697. $active_worker = CerberusApplication::getActiveWorker();
  1698. $memberships = $active_worker->getMemberships();
  1699. $translate = DevblocksPlatform::getTranslationService();
  1700. $view = new C4_TicketView();
  1701. $view->id = CerberusApplication::VIEW_SEARCH;
  1702. $view->name = $translate->_('common.search_results');
  1703. $view->view_columns = array(
  1704. SearchFields_Ticket::TICKET_LAST_ACTION_CODE,
  1705. SearchFields_Ticket::TICKET_UPDATED_DATE,
  1706. SearchFields_Ticket::TICKET_TEAM_ID,
  1707. SearchFields_Ticket::TICKET_CATEGORY_ID,
  1708. SearchFields_Ticket::TICKET_SPAM_SCORE,
  1709. );
  1710. $view->params = array(
  1711. SearchFields_Ticket::TICKET_CLOSED => new DevblocksSearchCriteria(SearchFields_Ticket::TICKET_CLOSED,DevblocksSearchCriteria::OPER_EQ,0),
  1712. SearchFields_Ticket::TICKET_TEAM_ID => new DevblocksSearchCriteria(SearchFields_Ticket::TICKET_TEAM_ID,'in',array_keys($memberships)), // censor
  1713. );
  1714. $view->renderLimit = 100;
  1715. $view->renderPage = 0;
  1716. $view->renderSortBy = null; // SearchFields_Ticket::TICKET_UPDATED_DATE
  1717. $view->renderSortAsc = 0;
  1718. return $view;
  1719. }
  1720. static public function setLastAction($view_id, Model_TicketViewLastAction $last_action=null) {
  1721. $visit = CerberusApplication::getVisit(); /* @var $visit CerberusVisit */
  1722. $view_last_actions = $visit->get(CerberusVisit::KEY_VIEW_LAST_ACTION,array());
  1723. if(!is_null($last_action) && !empty($last_action->ticket_ids)) {
  1724. $view_last_actions[$view_id] = $last_action;
  1725. } else {
  1726. if(isset($view_last_actions[$view_id])) {
  1727. unset($view_last_actions[$view_id]);
  1728. }
  1729. }
  1730. $visit->set(CerberusVisit::KEY_VIEW_LAST_ACTION,$view_last_actions);
  1731. }
  1732. /**
  1733. * @param string $view_id
  1734. * @return Model_TicketViewLastAction
  1735. */
  1736. static public function getLastAction($view_id) {
  1737. $visit = CerberusApplication::getVisit(); /* @var $visit CerberusVisit */
  1738. $view_last_actions = $visit->get(CerberusVisit::KEY_VIEW_LAST_ACTION,array());
  1739. return (isset($view_last_actions[$view_id]) ? $view_last_actions[$view_id] : null);
  1740. }
  1741. static public function clearLastActions() {
  1742. $visit = CerberusApplication::getVisit(); /* @var $visit CerberusVisit */
  1743. $visit->set(CerberusVisit::KEY_VIEW_LAST_ACTION,array());
  1744. }
  1745. };
  1746. class C4_AddressView extends C4_AbstractView {
  1747. const DEFAULT_ID = 'addresses';
  1748. function __construct() {
  1749. $translate = DevblocksPlatform::getTranslationService();
  1750. $this->id = self::DEFAULT_ID;
  1751. $this->name = $translate->_('addy_book.tab.addresses');
  1752. $this->renderLimit = 10;
  1753. $this->renderSortBy = 'a_email';
  1754. $this->renderSortAsc = true;
  1755. $this->view_columns = array(
  1756. SearchFields_Address::FIRST_NAME,
  1757. SearchFields_Address::LAST_NAME,
  1758. SearchFields_Address::ORG_NAME,
  1759. SearchFields_Address::IS_REGISTERED,
  1760. SearchFields_Address::NUM_NONSPAM,
  1761. SearchFields_Address::NUM_SPAM,
  1762. );
  1763. $this->params = array(
  1764. SearchFields_Address::IS_REGISTERED => new DevblocksSearchCriteria(SearchFields_Address::IS_REGISTERED,'=',1),
  1765. );
  1766. }
  1767. function getData() {
  1768. $objects = DAO_Address::search(
  1769. $this->view_columns,
  1770. $this->params,
  1771. $this->renderLimit,
  1772. $this->renderPage,
  1773. $this->renderSortBy,
  1774. $this->renderSortAsc
  1775. );
  1776. return $objects;
  1777. }
  1778. function render() {
  1779. $this->_sanitize();
  1780. $tpl = DevblocksPlatform::getTemplateService();
  1781. $tpl->assign('id', $this->id);
  1782. $tpl->assign('view', $this);
  1783. $address_fields = DAO_CustomField::getBySource(ChCustomFieldSource_Address::ID);
  1784. $tpl->assign('custom_fields', $address_fields);
  1785. $tpl->assign('view_fields', $this->getColumns());
  1786. $tpl->display('file:' . APP_PATH . '/features/cerberusweb.core/templates/contacts/addresses/address_view.tpl');
  1787. }
  1788. function renderCriteria($field) {
  1789. $tpl = DevblocksPlatform::getTemplateService();
  1790. $tpl->assign('id', $this->id);
  1791. $tpl_path = APP_PATH . '/features/cerberusweb.core/templates/';
  1792. switch($field) {
  1793. case SearchFields_Address::EMAIL:
  1794. case SearchFields_Address::FIRST_NAME:
  1795. case SearchFields_Address::LAST_NAME:
  1796. case SearchFields_Address::ORG_NAME:
  1797. $tpl->display('file:' . APP_PATH . '/features/cerberusweb.core/templates/internal/views/criteria/__string.tpl');
  1798. break;
  1799. case SearchFields_Address::NUM_SPAM:
  1800. case SearchFields_Address::NUM_NONSPAM:
  1801. $tpl->display('file:' . APP_PATH . '/features/cerberusweb.core/templates/internal/views/criteria/__number.tpl');
  1802. break;
  1803. case SearchFields_Address::IS_BANNED:
  1804. case SearchFields_Address::IS_REGISTERED:
  1805. $tpl->display('file:' . APP_PATH . '/features/cerberusweb.core/templates/internal/views/criteria/__bool.tpl');
  1806. break;
  1807. default:
  1808. // Custom Fields
  1809. if('cf_' == substr($field,0,3)) {
  1810. $this->_renderCriteriaCustomField($tpl, substr($field,3));
  1811. } else {
  1812. echo ' ';
  1813. }
  1814. break;
  1815. }
  1816. }
  1817. function renderCriteriaParam($param) {
  1818. $field = $param->field;
  1819. $values = !is_array($param->value) ? array($param->value) : $param->value;
  1820. switch($field) {
  1821. default:
  1822. parent::renderCriteriaParam($param);
  1823. break;
  1824. }
  1825. }
  1826. static function getFields() {
  1827. return SearchFields_Address::getFields();
  1828. }
  1829. static function getSearchFields() {
  1830. $fields = self::getFields();
  1831. unset($fields[SearchFields_Address::ID]);
  1832. unset($fields[SearchFields_Address::CONTACT_ORG_ID]);
  1833. unset($fields[SearchFields_Address::PASS]);
  1834. return $fields;
  1835. }
  1836. static function getColumns() {
  1837. $fields = self::getFields();
  1838. unset($fields[SearchFields_Address::PASS]);
  1839. return $fields;
  1840. }
  1841. function doResetCriteria() {
  1842. parent::doResetCriteria();
  1843. $this->params = array(
  1844. SearchFields_Address::IS_REGISTERED => new DevblocksSearchCriteria(SearchFields_Address::IS_REGISTERED,'=',1),
  1845. );
  1846. }
  1847. function doSetCriteria($field, $oper, $value) {
  1848. $criteria = null;
  1849. switch($field) {
  1850. case SearchFields_Address::EMAIL:
  1851. case SearchFields_Address::FIRST_NAME:
  1852. case SearchFields_Address::LAST_NAME:
  1853. case SearchFields_Address::ORG_NAME:
  1854. // force wildcards if none used on a LIKE
  1855. if(($oper == DevblocksSearchCriteria::OPER_LIKE || $oper == DevblocksSearchCriteria::OPER_NOT_LIKE)
  1856. && false === (strpos($value,'*'))) {
  1857. $value = '*'.$value.'*';
  1858. }
  1859. $criteria = new DevblocksSearchCriteria($field, $oper, $value);
  1860. break;
  1861. case SearchFields_Address::NUM_SPAM:
  1862. case SearchFields_Address::NUM_NONSPAM:
  1863. $criteria = new DevblocksSearchCriteria($field,$oper,$value);
  1864. break;
  1865. case SearchFields_Address::IS_BANNED:
  1866. @$bool = DevblocksPlatform::importGPC($_REQUEST['bool'],'integer',1);
  1867. $criteria = new DevblocksSearchCriteria($field,$oper,$bool);
  1868. break;
  1869. case SearchFields_Address::IS_REGISTERED:
  1870. @$bool = DevblocksPlatform::importGPC($_REQUEST['bool'],'integer',1);
  1871. $criteria = new DevblocksSearchCriteria($field,$oper,$bool);
  1872. break;
  1873. default:
  1874. // Custom Fields
  1875. if(substr($field,0,3)=='cf_') {
  1876. $criteria = $this->_doSetCriteriaCustomField($field, substr($field,3));
  1877. }
  1878. break;
  1879. }
  1880. if(!empty($criteria)) {
  1881. $this->params[$field] = $criteria;
  1882. $this->renderPage = 0;
  1883. }
  1884. }
  1885. function doBulkUpdate($filter, $do, $ids=array()) {
  1886. @set_time_limit(600); // [TODO] Temp!
  1887. $change_fields = array();
  1888. $custom_fields = array();
  1889. // Make sure we have actions
  1890. if(empty($do))
  1891. return;
  1892. // Make sure we have checked items if we want a checked list
  1893. if(0 == strcasecmp($filter,"checks") && empty($ids))
  1894. return;
  1895. if(is_array($do))
  1896. foreach($do as $k => $v) {
  1897. switch($k) {
  1898. case 'org_id':
  1899. $change_fields[DAO_Address::CONTACT_ORG_ID] = intval($v);
  1900. break;
  1901. case 'banned':
  1902. $change_fields[DAO_Address::IS_BANNED] = intval($v);
  1903. break;
  1904. default:
  1905. // Custom fields
  1906. if(substr($k,0,3)=="cf_") {
  1907. $custom_fields[substr($k,3)] = $v;
  1908. }
  1909. }
  1910. }
  1911. $pg = 0;
  1912. if(empty($ids))
  1913. do {
  1914. list($objects,$null) = DAO_Address::search(
  1915. array(),
  1916. $this->params,
  1917. 100,
  1918. $pg++,
  1919. SearchFields_Address::ID,
  1920. true,
  1921. false
  1922. );
  1923. $ids = array_merge($ids, array_keys($objects));
  1924. } while(!empty($objects));
  1925. $batch_total = count($ids);
  1926. for($x=0;$x<=$batch_total;$x+=100) {
  1927. $batch_ids = array_slice($ids,$x,100);
  1928. DAO_Address::update($batch_ids, $change_fields);
  1929. // Custom Fields
  1930. self::_doBulkSetCustomFields(ChCustomFieldSource_Address::ID, $custom_fields, $batch_ids);
  1931. unset($batch_ids);
  1932. }
  1933. unset($ids);
  1934. }
  1935. };
  1936. class C4_AttachmentView extends C4_AbstractView {
  1937. const DEFAULT_ID = 'attachments';
  1938. function __construct() {
  1939. $this->id = self::DEFAULT_ID;
  1940. $this->name = 'Attachments';
  1941. $this->renderLimit = 100;
  1942. $this->renderSortBy = SearchFields_Attachment::FILE_SIZE;
  1943. $this->renderSortAsc = false;
  1944. $this->view_columns = array(
  1945. SearchFields_Attachment::MIME_TYPE,
  1946. SearchFields_Attachment::FILE_SIZE,
  1947. SearchFields_Attachment::MESSAGE_CREATED_DATE,
  1948. SearchFields_Attachment::ADDRESS_EMAIL,
  1949. SearchFields_Attachment::TICKET_MASK,
  1950. );
  1951. // $this->params = array(
  1952. // SearchFields_Address::NUM_NONSPAM => new DevblocksSearchCriteria(SearchFields_Address::NUM_NONSPAM,'>',0),
  1953. // );
  1954. }
  1955. function getData() {
  1956. $objects = DAO_Attachment::search(
  1957. $this->params,
  1958. $this->renderLimit,
  1959. $this->renderPage,
  1960. $this->renderSortBy,
  1961. $this->renderSortAsc
  1962. );
  1963. return $objects;
  1964. }
  1965. function render() {
  1966. $this->_sanitize();
  1967. $tpl = DevblocksPlatform::getTemplateService();
  1968. $tpl->assign('id', $this->id);
  1969. $tpl->assign('view', $this);
  1970. $tpl->assign('view_fields', $this->getColumns());
  1971. $tpl->display('file:' . APP_PATH . '/features/cerberusweb.core/templates/configuration/tabs/attachments/view.tpl');
  1972. }
  1973. function renderCriteria($field) {
  1974. $tpl = DevblocksPlatform::getTemplateService();
  1975. $tpl->assign('id', $this->id);
  1976. switch($field) {
  1977. case SearchFields_Attachment::DISPLAY_NAME:
  1978. case SearchFields_Attachment::FILEPATH:
  1979. case SearchFields_Attachment::MIME_TYPE:
  1980. case SearchFields_Attachment::TICKET_MASK:
  1981. case SearchFields_Attachment::TICKET_SUBJECT:
  1982. case SearchFields_Attachment::ADDRESS_EMAIL:
  1983. $tpl->display('file:' . APP_PATH . '/features/cerberusweb.core/templates/internal/views/criteria/__string.tpl');
  1984. break;
  1985. // case SearchFields_Attachment::ID:
  1986. // case SearchFields_Attachment::MESSAGE_ID:
  1987. case SearchFields_Attachment::TICKET_ID:
  1988. case SearchFields_Attachment::FILE_SIZE:
  1989. $tpl->display('file:' . APP_PATH . '/features/cerberusweb.core/templates/internal/views/criteria/__number.tpl');
  1990. break;
  1991. case SearchFields_Attachment::MESSAGE_IS_OUTGOING:
  1992. $tpl->display('file:' . APP_PATH . '/features/cerberusweb.core/templates/internal/views/criteria/__bool.tpl');
  1993. break;
  1994. case SearchFields_Attachment::MESSAGE_CREATED_DATE:
  1995. $tpl->display('file:' . APP_PATH . '/features/cerberusweb.core/templates/internal/views/criteria/__date.tpl');
  1996. break;
  1997. default:
  1998. echo '';
  1999. break;
  2000. }
  2001. }
  2002. function renderCriteriaParam($param) {
  2003. $field = $param->field;
  2004. $values = !is_array($param->value) ? array($param->value) : $param->value;
  2005. switch($field) {
  2006. default:
  2007. parent::renderCriteriaParam($param);
  2008. break;
  2009. }
  2010. }
  2011. static function getFields() {
  2012. return SearchFields_Attachment::getFields();
  2013. }
  2014. static function getSearchFields() {
  2015. $fields = self::getFields();
  2016. unset($fields[SearchFields_Attachment::ID]);
  2017. unset($fields[SearchFields_Attachment::MESSAGE_ID]);
  2018. return $fields;
  2019. }
  2020. static function getColumns() {
  2021. $fields = self::getFields();
  2022. return $fields;
  2023. }
  2024. function doResetCriteria() {
  2025. parent::doResetCriteria();
  2026. // $this->params = array(
  2027. // SearchFields_Address::NUM_NONSPAM => new DevblocksSearchCriteria(SearchFields_Address::NUM_NONSPAM,'>',0),
  2028. // );
  2029. }
  2030. function doSetCriteria($field, $oper, $value) {
  2031. $criteria = null;
  2032. switch($field) {
  2033. case SearchFields_Attachment::DISPLAY_NAME:
  2034. case SearchFields_Attachment::MIME_TYPE:
  2035. case SearchFields_Attachment::FILEPATH:
  2036. case SearchFields_Attachment::TICKET_MASK:
  2037. case SearchFields_Attachment::TICKET_SUBJECT:
  2038. case SearchFields_Attachment::ADDRESS_EMAIL:
  2039. // force wildcards if none used on a LIKE
  2040. if(($oper == DevblocksSearchCriteria::OPER_LIKE || $oper == DevblocksSearchCriteria::OPER_NOT_LIKE)
  2041. && false === (strpos($value,'*'))) {
  2042. $value = '*'.$value.'*';
  2043. }
  2044. $criteria = new DevblocksSearchCriteria($field, $oper, $value);
  2045. break;
  2046. case SearchFields_Attachment::ID:
  2047. case SearchFields_Attachment::MESSAGE_ID:
  2048. case SearchFields_Attachment::TICKET_ID:
  2049. case SearchFields_Attachment::FILE_SIZE:
  2050. $criteria = new DevblocksSearchCriteria($field,$oper,$value);
  2051. break;
  2052. case SearchFields_Attachment::MESSAGE_CREATED_DATE:
  2053. @$from = DevblocksPlatform::importGPC($_REQUEST['from'],'string','');
  2054. @$to = DevblocksPlatform::importGPC($_REQUEST['to'],'string','');
  2055. if(empty($from)) $from = 0;
  2056. if(empty($to)) $to = 'today';
  2057. $criteria = new DevblocksSearchCriteria($field,$oper,array($from,$to));
  2058. break;
  2059. case SearchFields_Attachment::MESSAGE_IS_OUTGOING:
  2060. @$bool = DevblocksPlatform::importGPC($_REQUEST['bool'],'integer',1);
  2061. $criteria = new DevblocksSearchCriteria($field,$oper,$bool);
  2062. break;
  2063. }
  2064. if(!empty($criteria)) {
  2065. $this->params[$field] = $criteria;
  2066. $this->renderPage = 0;
  2067. }
  2068. }
  2069. function doBulkUpdate($filter, $do, $ids=array()) {
  2070. @set_time_limit(0);
  2071. $change_fields = array();
  2072. $deleted = false;
  2073. // Make sure we have actions
  2074. if(empty($do))
  2075. return;
  2076. // Make sure we have checked items if we want a checked list
  2077. if(0 == strcasecmp($filter,"checks") && empty($ids))
  2078. return;
  2079. if(is_array($do))
  2080. foreach($do as $k => $v) {
  2081. switch($k) {
  2082. case 'deleted':
  2083. $deleted = true;
  2084. break;
  2085. default:
  2086. break;
  2087. }
  2088. }
  2089. $pg = 0;
  2090. if(empty($ids))
  2091. do {
  2092. list($objects,$null) = DAO_Attachment::search(
  2093. $this->params,
  2094. 100,
  2095. $pg++,
  2096. SearchFields_Attachment::ID,
  2097. true,
  2098. false
  2099. );
  2100. $ids = array_merge($ids, array_keys($objects));
  2101. } while(!empty($objects));
  2102. $batch_total = count($ids);
  2103. for($x=0;$x<=$batch_total;$x+=100) {
  2104. $batch_ids = array_slice($ids,$x,100);
  2105. if(!$deleted) {
  2106. DAO_Attachment::update($batch_ids, $change_fields);
  2107. } else {
  2108. DAO_Attachment::delete($batch_ids);
  2109. }
  2110. unset($batch_ids);
  2111. }
  2112. unset($ids);
  2113. }
  2114. };
  2115. class C4_ContactOrgView extends C4_AbstractView {
  2116. const DEFAULT_ID = 'contact_orgs';
  2117. function __construct() {
  2118. $translate = DevblocksPlatform::getTranslationService();
  2119. $this->id = self::DEFAULT_ID;
  2120. $this->name = $translate->_('addy_book.tab.organizations');
  2121. $this->renderSortBy = 'c_name';
  2122. $this->renderSortAsc = true;
  2123. $this->view_columns = array(
  2124. SearchFields_ContactOrg::COUNTRY,
  2125. SearchFields_ContactOrg::CREATED,
  2126. SearchFields_ContactOrg::PHONE,
  2127. SearchFields_ContactOrg::WEBSITE,
  2128. );
  2129. }
  2130. function getData() {
  2131. $objects = DAO_ContactOrg::search(
  2132. $this->view_columns,
  2133. $this->params,
  2134. $this->renderLimit,
  2135. $this->renderPage,
  2136. $this->renderSortBy,
  2137. $this->renderSortAsc
  2138. );
  2139. return $objects;
  2140. }
  2141. function render() {
  2142. $this->_sanitize();
  2143. $tpl = DevblocksPlatform::getTemplateService();
  2144. $tpl->assign('core_tpl', APP_PATH . '/features/cerberusweb.core/templates/');
  2145. $tpl->assign('id', $this->id);
  2146. $tpl->assign('view', $this);
  2147. $org_fields = DAO_CustomField::getBySource(ChCustomFieldSource_Org::ID);
  2148. $tpl->assign('custom_fields', $org_fields);
  2149. $tpl->assign('view_fields', $this->getColumns());
  2150. $tpl->display('file:' . APP_PATH . '/features/cerberusweb.core/templates/contacts/orgs/contact_view.tpl');
  2151. }
  2152. function renderCriteria($field) {
  2153. $tpl = DevblocksPlatform::getTemplateService();
  2154. $tpl->assign('id', $this->id);
  2155. switch($field) {
  2156. case SearchFields_ContactOrg::NAME:
  2157. case SearchFields_ContactOrg::STREET:
  2158. case SearchFields_ContactOrg::CITY:
  2159. case SearchFields_ContactOrg::PROVINCE:
  2160. case SearchFields_ContactOrg::POSTAL:
  2161. case SearchFields_ContactOrg::COUNTRY:
  2162. case SearchFields_ContactOrg::PHONE:
  2163. case SearchFields_ContactOrg::WEBSITE:
  2164. $tpl->display('file:' . APP_PATH . '/features/cerberusweb.core/templates/internal/views/criteria/__string.tpl');
  2165. break;
  2166. case SearchFields_ContactOrg::CREATED:
  2167. $tpl->display('file:' . APP_PATH . '/features/cerberusweb.core/templates/internal/views/criteria/__date.tpl');
  2168. break;
  2169. default:
  2170. // Custom Fields
  2171. if('cf_' == substr($field,0,3)) {
  2172. $this->_renderCriteriaCustomField($tpl, substr($field,3));
  2173. } else {
  2174. echo ' ';
  2175. }
  2176. break;
  2177. }
  2178. }
  2179. function renderCriteriaParam($param) {
  2180. $field = $param->field;
  2181. $values = !is_array($param->value) ? array($param->value) : $param->value;
  2182. switch($field) {
  2183. default:
  2184. parent::renderCriteriaParam($param);
  2185. break;
  2186. }
  2187. }
  2188. static function getFields() {
  2189. return SearchFields_ContactOrg::getFields();
  2190. }
  2191. static function getSearchFields() {
  2192. $fields = self::getFields();
  2193. unset($fields[SearchFields_ContactOrg::ID]);
  2194. return $fields;
  2195. }
  2196. static function getColumns() {
  2197. return self::getFields();
  2198. }
  2199. function doSetCriteria($field, $oper, $value) {
  2200. $criteria = null;
  2201. switch($field) {
  2202. case SearchFields_ContactOrg::NAME:
  2203. case SearchFields_ContactOrg::STREET:
  2204. case SearchFields_ContactOrg::CITY:
  2205. case SearchFields_ContactOrg::PROVINCE:
  2206. case SearchFields_ContactOrg::POSTAL:
  2207. case SearchFields_ContactOrg::COUNTRY:
  2208. case SearchFields_ContactOrg::PHONE:
  2209. case SearchFields_ContactOrg::WEBSITE:
  2210. // force wildcards if none used on a LIKE
  2211. if(($oper == DevblocksSearchCriteria::OPER_LIKE || $oper == DevblocksSearchCriteria::OPER_NOT_LIKE)
  2212. && false === (strpos($value,'*'))) {
  2213. $value = '*'.$value.'*';
  2214. }
  2215. $criteria = new DevblocksSearchCriteria($field, $oper, $value);
  2216. break;
  2217. case SearchFields_ContactOrg::CREATED:
  2218. @$from = DevblocksPlatform::importGPC($_REQUEST['from'],'string','');
  2219. @$to = DevblocksPlatform::importGPC($_REQUEST['to'],'string','');
  2220. if(empty($from)) $from = 0;
  2221. if(empty($to)) $to = 'today';
  2222. $criteria = new DevblocksSearchCriteria($field,$oper,array($from,$to));
  2223. break;
  2224. default:
  2225. // Custom Fields
  2226. if(substr($field,0,3)=='cf_') {
  2227. $criteria = $this->_doSetCriteriaCustomField($field, substr($field,3));
  2228. }
  2229. break;
  2230. }
  2231. if(!empty($criteria)) {
  2232. $this->params[$field] = $criteria;
  2233. $this->renderPage = 0;
  2234. }
  2235. }
  2236. function doBulkUpdate($filter, $do, $ids=array()) {
  2237. @set_time_limit(0);
  2238. $change_fields = array();
  2239. $custom_fields = array();
  2240. // Make sure we have actions
  2241. if(empty($do))
  2242. return;
  2243. // Make sure we have checked items if we want a checked list
  2244. if(0 == strcasecmp($filter,"checks") && empty($ids))
  2245. return;
  2246. if(is_array($do))
  2247. foreach($do as $k => $v) {
  2248. switch($k) {
  2249. case 'country':
  2250. $change_fields[DAO_ContactOrg::COUNTRY] = $v;
  2251. break;
  2252. default:
  2253. // Custom fields
  2254. if(substr($k,0,3)=="cf_") {
  2255. $custom_fields[substr($k,3)] = $v;
  2256. }
  2257. break;
  2258. }
  2259. }
  2260. $pg = 0;
  2261. if(empty($ids))
  2262. do {
  2263. list($objects,$null) = DAO_ContactOrg::search(
  2264. array(),
  2265. $this->params,
  2266. 100,
  2267. $pg++,
  2268. SearchFields_ContactOrg::ID,
  2269. true,
  2270. false
  2271. );
  2272. $ids = array_merge($ids, array_keys($objects));
  2273. } while(!empty($objects));
  2274. $batch_total = count($ids);
  2275. for($x=0;$x<=$batch_total;$x+=100) {
  2276. $batch_ids = array_slice($ids,$x,100);
  2277. DAO_ContactOrg::update($batch_ids, $change_fields);
  2278. // Custom Fields
  2279. self::_doBulkSetCustomFields(ChCustomFieldSource_Org::ID, $custom_fields, $batch_ids);
  2280. unset($batch_ids);
  2281. }
  2282. unset($ids);
  2283. }
  2284. };
  2285. class C4_TaskView extends C4_AbstractView {
  2286. const DEFAULT_ID = 'tasks';
  2287. const DEFAULT_TITLE = 'All Open Tasks';
  2288. function __construct() {
  2289. $this->id = self::DEFAULT_ID;
  2290. $this->name = self::DEFAULT_TITLE;
  2291. $this->renderLimit = 25;
  2292. $this->renderSortBy = SearchFields_Task::DUE_DATE;
  2293. $this->renderSortAsc = true;
  2294. $this->view_columns = array(
  2295. SearchFields_Task::SOURCE_EXTENSION,
  2296. SearchFields_Task::UPDATED_DATE,
  2297. SearchFields_Task::DUE_DATE,
  2298. SearchFields_Task::WORKER_ID,
  2299. );
  2300. $this->params = array(
  2301. SearchFields_Task::IS_COMPLETED => new DevblocksSearchCriteria(SearchFields_Task::IS_COMPLETED,'=',0),
  2302. );
  2303. }
  2304. function getData() {
  2305. $objects = DAO_Task::search(
  2306. $this->view_columns,
  2307. $this->params,
  2308. $this->renderLimit,
  2309. $this->renderPage,
  2310. $this->renderSortBy,
  2311. $this->renderSortAsc
  2312. );
  2313. return $objects;
  2314. }
  2315. function render() {
  2316. $this->_sanitize();
  2317. $tpl = DevblocksPlatform::getTemplateService();
  2318. $tpl->assign('id', $this->id);
  2319. $tpl->assign('view', $this);
  2320. $workers = DAO_Worker::getAll();
  2321. $tpl->assign('workers', $workers);
  2322. $tpl->assign('timestamp_now', time());
  2323. // Pull the results so we can do some row introspection
  2324. $results = $this->getData();
  2325. $tpl->assign('results', $results);
  2326. // $source_renderers = DevblocksPlatform::getExtensions('cerberusweb.task.source', true);
  2327. // Make a list of unique source_extension and load their renderers
  2328. $source_extensions = array();
  2329. if(is_array($results) && isset($results[0]))
  2330. foreach($results[0] as $rows) {
  2331. $source_extension = $rows[SearchFields_Task::SOURCE_EXTENSION];
  2332. if(!isset($source_extensions[$source_extension])
  2333. && !empty($source_extension)
  2334. && null != ($mft = DevblocksPlatform::getExtension($source_extension))) {
  2335. $source_extensions[$source_extension] = $mft->createInstance();
  2336. }
  2337. }
  2338. $tpl->assign('source_renderers', $source_extensions);
  2339. // Custom fields
  2340. $custom_fields = DAO_CustomField::getBySource(ChCustomFieldSource_Task::ID);
  2341. $tpl->assign('custom_fields', $custom_fields);
  2342. $tpl->assign('view_fields', $this->getColumns());
  2343. $tpl->display('file:' . APP_PATH . '/features/cerberusweb.core/templates/tasks/view.tpl');
  2344. }
  2345. function renderCriteria($field) {
  2346. $tpl = DevblocksPlatform::getTemplateService();
  2347. $tpl_path = APP_PATH . '/features/cerberusweb.core/templates/';
  2348. $tpl->assign('id', $this->id);
  2349. switch($field) {
  2350. case SearchFields_Task::TITLE:
  2351. $tpl->display('file:' . APP_PATH . '/features/cerberusweb.core/templates/internal/views/criteria/__string.tpl');
  2352. break;
  2353. case SearchFields_Task::SOURCE_EXTENSION:
  2354. $source_renderers = DevblocksPlatform::getExtensions('cerberusweb.task.source', true);
  2355. $tpl->assign('sources', $source_renderers);
  2356. $tpl->display('file:' . $tpl_path . 'tasks/criteria/source.tpl');
  2357. break;
  2358. case SearchFields_Task::IS_COMPLETED:
  2359. $tpl->display('file:' . APP_PATH . '/features/cerberusweb.core/templates/internal/views/criteria/__bool.tpl');
  2360. break;
  2361. case SearchFields_Task::UPDATED_DATE:
  2362. case SearchFields_Task::DUE_DATE:
  2363. case SearchFields_Task::COMPLETED_DATE:
  2364. $tpl->display('file:' . APP_PATH . '/features/cerberusweb.core/templates/internal/views/criteria/__date.tpl');
  2365. break;
  2366. case SearchFields_Task::WORKER_ID:
  2367. $workers = DAO_Worker::getAll();
  2368. $tpl->assign('workers', $workers);
  2369. $tpl->display('file:' . APP_PATH . '/features/cerberusweb.core/templates/internal/views/criteria/__worker.tpl');
  2370. break;
  2371. default:
  2372. // Custom Fields
  2373. if('cf_' == substr($field,0,3)) {
  2374. $this->_renderCriteriaCustomField($tpl, substr($field,3));
  2375. } else {
  2376. echo ' ';
  2377. }
  2378. break;
  2379. }
  2380. }
  2381. function renderCriteriaParam($param) {
  2382. $field = $param->field;
  2383. $translate = DevblocksPlatform::getTranslationService();
  2384. $values = !is_array($param->value) ? array($param->value) : $param->value;
  2385. switch($field) {
  2386. case SearchFields_Task::WORKER_ID:
  2387. $workers = DAO_Worker::getAll();
  2388. $strings = array();
  2389. foreach($values as $val) {
  2390. if(empty($val))
  2391. $strings[] = "Nobody";
  2392. elseif(!isset($workers[$val]))
  2393. continue;
  2394. else
  2395. $strings[] = $workers[$val]->getName();
  2396. }
  2397. echo implode(", ", $strings);
  2398. break;
  2399. case SearchFields_Task::SOURCE_EXTENSION:
  2400. $sources = $ext = DevblocksPlatform::getExtensions('cerberusweb.task.source', true);
  2401. $strings = array();
  2402. foreach($values as $val) {
  2403. if(!isset($sources[$val]))
  2404. continue;
  2405. else
  2406. $strings[] = $sources[$val]->getSourceName();
  2407. }
  2408. echo implode(", ", $strings);
  2409. break;
  2410. default:
  2411. parent::renderCriteriaParam($param);
  2412. break;
  2413. }
  2414. }
  2415. static function getFields() {
  2416. return SearchFields_Task::getFields();
  2417. }
  2418. static function getSearchFields() {
  2419. $fields = self::getFields();
  2420. unset($fields[SearchFields_Task::ID]);
  2421. unset($fields[SearchFields_Task::SOURCE_ID]);
  2422. return $fields;
  2423. }
  2424. static function getColumns() {
  2425. $fields = self::getFields();
  2426. unset($fields[SearchFields_Task::ID]);
  2427. unset($fields[SearchFields_Task::SOURCE_ID]);
  2428. return $fields;
  2429. }
  2430. function doResetCriteria() {
  2431. parent::doResetCriteria();
  2432. $this->params = array(
  2433. SearchFields_Task::IS_COMPLETED => new DevblocksSearchCriteria(SearchFields_Task::IS_COMPLETED,'=',0)
  2434. );
  2435. }
  2436. function doSetCriteria($field, $oper, $value) {
  2437. $criteria = null;
  2438. switch($field) {
  2439. case SearchFields_Task::TITLE:
  2440. // force wildcards if none used on a LIKE
  2441. if(($oper == DevblocksSearchCriteria::OPER_LIKE || $oper == DevblocksSearchCriteria::OPER_NOT_LIKE)
  2442. && false === (strpos($value,'*'))) {
  2443. $value = '*'.$value.'*';
  2444. }
  2445. $criteria = new DevblocksSearchCriteria($field, $oper, $value);
  2446. break;
  2447. case SearchFields_Task::SOURCE_EXTENSION:
  2448. @$sources = DevblocksPlatform::importGPC($_REQUEST['sources'],'array',array());
  2449. $criteria = new DevblocksSearchCriteria($field,$oper,$sources);
  2450. break;
  2451. case SearchFields_Task::UPDATED_DATE:
  2452. case SearchFields_Task::COMPLETED_DATE:
  2453. case SearchFields_Task::DUE_DATE:
  2454. @$from = DevblocksPlatform::importGPC($_REQUEST['from'],'string','');
  2455. @$to = DevblocksPlatform::importGPC($_REQUEST['to'],'string','');
  2456. if(empty($from)) $from = 0;
  2457. if(empty($to)) $to = 'today';
  2458. $criteria = new DevblocksSearchCriteria($field,$oper,array($from,$to));
  2459. break;
  2460. case SearchFields_Task::IS_COMPLETED:
  2461. @$bool = DevblocksPlatform::importGPC($_REQUEST['bool'],'integer',1);
  2462. $criteria = new DevblocksSearchCriteria($field,$oper,$bool);
  2463. break;
  2464. case SearchFields_Task::WORKER_ID:
  2465. @$worker_id = DevblocksPlatform::importGPC($_REQUEST['worker_id'],'array',array());
  2466. $criteria = new DevblocksSearchCriteria($field,$oper,$worker_id);
  2467. break;
  2468. default:
  2469. // Custom Fields
  2470. if(substr($field,0,3)=='cf_') {
  2471. $criteria = $this->_doSetCriteriaCustomField($field, substr($field,3));
  2472. }
  2473. break;
  2474. }
  2475. if(!empty($criteria)) {
  2476. $this->params[$field] = $criteria;
  2477. $this->renderPage = 0;
  2478. }
  2479. }
  2480. function doBulkUpdate($filter, $do, $ids=array()) {
  2481. @set_time_limit(600); // [TODO] Temp!
  2482. $change_fields = array();
  2483. $custom_fields = array();
  2484. // Make sure we have actions
  2485. if(empty($do))
  2486. return;
  2487. // Make sure we have checked items if we want a checked list
  2488. if(0 == strcasecmp($filter,"checks") && empty($ids))
  2489. return;
  2490. if(is_array($do))
  2491. foreach($do as $k => $v) {
  2492. switch($k) {
  2493. case 'due':
  2494. @$date = strtotime($v);
  2495. $change_fields[DAO_Task::DUE_DATE] = intval($date);
  2496. break;
  2497. case 'status':
  2498. if(1==intval($v)) { // completed
  2499. $change_fields[DAO_Task::IS_COMPLETED] = 1;
  2500. $change_fields[DAO_Task::COMPLETED_DATE] = time();
  2501. } else { // active
  2502. $change_fields[DAO_Task::IS_COMPLETED] = 0;
  2503. $change_fields[DAO_Task::COMPLETED_DATE] = 0;
  2504. }
  2505. break;
  2506. case 'worker_id':
  2507. $change_fields[DAO_Task::WORKER_ID] = intval($v);
  2508. break;
  2509. default:
  2510. // Custom fields
  2511. if(substr($k,0,3)=="cf_") {
  2512. $custom_fields[substr($k,3)] = $v;
  2513. }
  2514. }
  2515. }
  2516. $pg = 0;
  2517. if(empty($ids))
  2518. do {
  2519. list($objects,$null) = DAO_Task::search(
  2520. array(),
  2521. $this->params,
  2522. 100,
  2523. $pg++,
  2524. SearchFields_Task::ID,
  2525. true,
  2526. false
  2527. );
  2528. $ids = array_merge($ids, array_keys($objects));
  2529. } while(!empty($objects));
  2530. $batch_total = count($ids);
  2531. for($x=0;$x<=$batch_total;$x+=100) {
  2532. $batch_ids = array_slice($ids,$x,100);
  2533. DAO_Task::update($batch_ids, $change_fields);
  2534. // Custom Fields
  2535. self::_doBulkSetCustomFields(ChCustomFieldSource_Task::ID, $custom_fields, $batch_ids);
  2536. unset($batch_ids);
  2537. }
  2538. unset($ids);
  2539. }
  2540. };
  2541. class C4_WorkerView extends C4_AbstractView {
  2542. const DEFAULT_ID = 'workers';
  2543. function __construct() {
  2544. $this->id = self::DEFAULT_ID;
  2545. $this->name = 'Workers';
  2546. $this->renderLimit = 25;
  2547. $this->renderSortBy = SearchFields_Worker::FIRST_NAME;
  2548. $this->renderSortAsc = true;
  2549. $this->view_columns = array(
  2550. SearchFields_Worker::FIRST_NAME,
  2551. SearchFields_Worker::LAST_NAME,
  2552. SearchFields_Worker::TITLE,
  2553. SearchFields_Worker::EMAIL,
  2554. SearchFields_Worker::LAST_ACTIVITY_DATE,
  2555. SearchFields_Worker::IS_SUPERUSER,
  2556. );
  2557. $this->doResetCriteria();
  2558. }
  2559. function getData() {
  2560. return DAO_Worker::search(
  2561. $this->view_columns,
  2562. $this->params,
  2563. $this->renderLimit,
  2564. $this->renderPage,
  2565. $this->renderSortBy,
  2566. $this->renderSortAsc
  2567. );
  2568. }
  2569. function render() {
  2570. $this->_sanitize();
  2571. $tpl = DevblocksPlatform::getTemplateService();
  2572. $tpl->assign('id', $this->id);
  2573. $tpl->assign('view', $this);
  2574. $custom_fields = DAO_CustomField::getBySource(ChCustomFieldSource_Worker::ID);
  2575. $tpl->assign('custom_fields', $custom_fields);
  2576. $tpl->assign('view_fields', $this->getColumns());
  2577. $tpl->display('file:' . APP_PATH . '/features/cerberusweb.core/templates/configuration/tabs/workers/view.tpl');
  2578. }
  2579. function renderCriteria($field) {
  2580. $tpl = DevblocksPlatform::getTemplateService();
  2581. $tpl->assign('id', $this->id);
  2582. switch($field) {
  2583. case SearchFields_Worker::EMAIL:
  2584. case SearchFields_Worker::FIRST_NAME:
  2585. case SearchFields_Worker::LAST_NAME:
  2586. case SearchFields_Worker::TITLE:
  2587. $tpl->display('file:' . APP_PATH . '/features/cerberusweb.core/templates/internal/views/criteria/__string.tpl');
  2588. break;
  2589. case SearchFields_Worker::IS_DISABLED:
  2590. case SearchFields_Worker::IS_SUPERUSER:
  2591. $tpl->display('file:' . APP_PATH . '/features/cerberusweb.core/templates/internal/views/criteria/__bool.tpl');
  2592. break;
  2593. case SearchFields_Worker::LAST_ACTIVITY_DATE:
  2594. $tpl->display('file:' . APP_PATH . '/features/cerberusweb.core/templates/internal/views/criteria/__date.tpl');
  2595. break;
  2596. default:
  2597. // Custom Fields
  2598. if('cf_' == substr($field,0,3)) {
  2599. $this->_renderCriteriaCustomField($tpl, substr($field,3));
  2600. } else {
  2601. echo ' ';
  2602. }
  2603. break;
  2604. }
  2605. }
  2606. function renderCriteriaParam($param) {
  2607. $field = $param->field;
  2608. $values = !is_array($param->value) ? array($param->value) : $param->value;
  2609. switch($field) {
  2610. // case SearchFields_WorkerEvent::WORKER_ID:
  2611. // $workers = DAO_Worker::getAll();
  2612. // $strings = array();
  2613. //
  2614. // foreach($values as $val) {
  2615. // if(empty($val))
  2616. // $strings[] = "Nobody";
  2617. // elseif(!isset($workers[$val]))
  2618. // continue;
  2619. // else
  2620. // $strings[] = $workers[$val]->getName();
  2621. // }
  2622. // echo implode(", ", $strings);
  2623. // break;
  2624. default:
  2625. parent::renderCriteriaParam($param);
  2626. break;
  2627. }
  2628. }
  2629. static function getFields() {
  2630. return SearchFields_Worker::getFields();
  2631. }
  2632. static function getSearchFields() {
  2633. $fields = self::getFields();
  2634. unset($fields[SearchFields_Worker::ID]);
  2635. unset($fields[SearchFields_Worker::LAST_ACTIVITY]);
  2636. return $fields;
  2637. }
  2638. static function getColumns() {
  2639. $fields = self::getFields();
  2640. unset($fields[SearchFields_Worker::LAST_ACTIVITY]);
  2641. return $fields;
  2642. }
  2643. function doResetCriteria() {
  2644. parent::doResetCriteria();
  2645. // $this->params = array(
  2646. // SearchFields_WorkerEvent::NUM_NONSPAM => new DevblocksSearchCriteria(SearchFields_WorkerEvent::NUM_NONSPAM,'>',0),
  2647. // );
  2648. }
  2649. function doSetCriteria($field, $oper, $value) {
  2650. $criteria = null;
  2651. switch($field) {
  2652. case SearchFields_Worker::EMAIL:
  2653. case SearchFields_Worker::FIRST_NAME:
  2654. case SearchFields_Worker::LAST_NAME:
  2655. case SearchFields_Worker::TITLE:
  2656. // force wildcards if none used on a LIKE
  2657. if(($oper == DevblocksSearchCriteria::OPER_LIKE || $oper == DevblocksSearchCriteria::OPER_NOT_LIKE)
  2658. && false === (strpos($value,'*'))) {
  2659. $value = '*'.$value.'*';
  2660. }
  2661. $criteria = new DevblocksSearchCriteria($field, $oper, $value);
  2662. break;
  2663. case SearchFields_Worker::LAST_ACTIVITY_DATE:
  2664. @$from = DevblocksPlatform::importGPC($_REQUEST['from'],'string','');
  2665. @$to = DevblocksPlatform::importGPC($_REQUEST['to'],'string','');
  2666. if(empty($from)) $from = 0;
  2667. if(empty($to)) $to = 'today';
  2668. $criteria = new DevblocksSearchCriteria($field,$oper,array($from,$to));
  2669. break;
  2670. case SearchFields_Worker::IS_DISABLED:
  2671. case SearchFields_Worker::IS_SUPERUSER:
  2672. @$bool = DevblocksPlatform::importGPC($_REQUEST['bool'],'integer',1);
  2673. $criteria = new DevblocksSearchCriteria($field,$oper,$bool);
  2674. break;
  2675. default:
  2676. // Custom Fields
  2677. if(substr($field,0,3)=='cf_') {
  2678. $criteria = $this->_doSetCriteriaCustomField($field, substr($field,3));
  2679. }
  2680. break;
  2681. }
  2682. if(!empty($criteria)) {
  2683. $this->params[$field] = $criteria;
  2684. $this->renderPage = 0;
  2685. }
  2686. }
  2687. function doBulkUpdate($filter, $do, $ids=array()) {
  2688. @set_time_limit(600); // [TODO] Temp!
  2689. $change_fields = array();
  2690. $custom_fields = array();
  2691. if(empty($do))
  2692. return;
  2693. // Make sure we have checked items if we want a checked list
  2694. if(0 == strcasecmp($filter,"checks") && empty($ids))
  2695. return;
  2696. if(is_array($do))
  2697. foreach($do as $k => $v) {
  2698. switch($k) {
  2699. case 'is_disabled':
  2700. $change_fields[DAO_Worker::IS_DISABLED] = intval($v);
  2701. break;
  2702. default:
  2703. // Custom fields
  2704. if(substr($k,0,3)=="cf_") {
  2705. $custom_fields[substr($k,3)] = $v;
  2706. }
  2707. break;
  2708. }
  2709. }
  2710. $pg = 0;
  2711. if(empty($ids))
  2712. do {
  2713. list($objects,$null) = DAO_Worker::search(
  2714. array(),
  2715. $this->params,
  2716. 100,
  2717. $pg++,
  2718. SearchFields_Worker::ID,
  2719. true,
  2720. false
  2721. );
  2722. $ids = array_merge($ids, array_keys($objects));
  2723. } while(!empty($objects));
  2724. $batch_total = count($ids);
  2725. for($x=0;$x<=$batch_total;$x+=100) {
  2726. $batch_ids = array_slice($ids,$x,100);
  2727. DAO_Worker::updateAgent($batch_ids, $change_fields);
  2728. // Custom Fields
  2729. self::_doBulkSetCustomFields(ChCustomFieldSource_Worker::ID, $custom_fields, $batch_ids);
  2730. unset($batch_ids);
  2731. }
  2732. unset($ids);
  2733. }
  2734. };
  2735. class C4_WorkerEventView extends C4_AbstractView {
  2736. const DEFAULT_ID = 'worker_events';
  2737. function __construct() {
  2738. $this->id = self::DEFAULT_ID;
  2739. $this->name = 'Worker Events';
  2740. $this->renderLimit = 100;
  2741. $this->renderSortBy = SearchFields_WorkerEvent::CREATED_DATE;
  2742. $this->renderSortAsc = false;
  2743. $this->view_columns = array(
  2744. SearchFields_WorkerEvent::CONTENT,
  2745. SearchFields_WorkerEvent::CREATED_DATE,
  2746. );
  2747. $this->doResetCriteria();
  2748. }
  2749. function getData() {
  2750. $objects = DAO_WorkerEvent::search(
  2751. $this->params,
  2752. $this->renderLimit,
  2753. $this->renderPage,
  2754. $this->renderSortBy,
  2755. $this->renderSortAsc
  2756. );
  2757. return $objects;
  2758. }
  2759. function render() {
  2760. $this->_sanitize();
  2761. $tpl = DevblocksPlatform::getTemplateService();
  2762. $tpl->assign('id', $this->id);
  2763. $tpl->assign('view', $this);
  2764. $workers = DAO_Worker::getAll();
  2765. $tpl->assign('workers', $workers);
  2766. $tpl->assign('view_fields', $this->getColumns());
  2767. $tpl->display('file:' . APP_PATH . '/features/cerberusweb.core/templates/home/tabs/my_events/view.tpl');
  2768. }
  2769. function renderCriteria($field) {
  2770. $tpl = DevblocksPlatform::getTemplateService();
  2771. $tpl->assign('id', $this->id);
  2772. switch($field) {
  2773. case SearchFields_WorkerEvent::TITLE:
  2774. case SearchFields_WorkerEvent::CONTENT:
  2775. case SearchFields_WorkerEvent::URL:
  2776. $tpl->display('file:' . APP_PATH . '/features/cerberusweb.core/templates/internal/views/criteria/__string.tpl');
  2777. break;
  2778. // case SearchFields_WorkerEvent::ID:
  2779. // case SearchFields_WorkerEvent::MESSAGE_ID:
  2780. // case SearchFields_WorkerEvent::TICKET_ID:
  2781. // case SearchFields_WorkerEvent::FILE_SIZE:
  2782. // $tpl->display('file:' . APP_PATH . '/features/cerberusweb.core/templates/internal/views/criteria/__number.tpl');
  2783. // break;
  2784. case SearchFields_WorkerEvent::IS_READ:
  2785. $tpl->display('file:' . APP_PATH . '/features/cerberusweb.core/templates/internal/views/criteria/__bool.tpl');
  2786. break;
  2787. case SearchFields_WorkerEvent::CREATED_DATE:
  2788. $tpl->display('file:' . APP_PATH . '/features/cerberusweb.core/templates/internal/views/criteria/__date.tpl');
  2789. break;
  2790. case SearchFields_WorkerEvent::WORKER_ID:
  2791. $workers = DAO_Worker::getAllActive();
  2792. $tpl->assign('workers', $workers);
  2793. $tpl->display('file:' . APP_PATH . '/features/cerberusweb.core/templates/internal/views/criteria/__worker.tpl');
  2794. break;
  2795. default:
  2796. echo '';
  2797. break;
  2798. }
  2799. }
  2800. function renderCriteriaParam($param) {
  2801. $field = $param->field;
  2802. $values = !is_array($param->value) ? array($param->value) : $param->value;
  2803. switch($field) {
  2804. case SearchFields_WorkerEvent::WORKER_ID:
  2805. $workers = DAO_Worker::getAll();
  2806. $strings = array();
  2807. foreach($values as $val) {
  2808. if(empty($val))
  2809. $strings[] = "Nobody";
  2810. elseif(!isset($workers[$val]))
  2811. continue;
  2812. else
  2813. $strings[] = $workers[$val]->getName();
  2814. }
  2815. echo implode(", ", $strings);
  2816. break;
  2817. default:
  2818. parent::renderCriteriaParam($param);
  2819. break;
  2820. }
  2821. }
  2822. static function getFields() {
  2823. return SearchFields_WorkerEvent::getFields();
  2824. }
  2825. static function getSearchFields() {
  2826. $fields = self::getFields();
  2827. unset($fields[SearchFields_WorkerEvent::ID]);
  2828. return $fields;
  2829. }
  2830. static function getColumns() {
  2831. $fields = self::getFields();
  2832. return $fields;
  2833. }
  2834. function doResetCriteria() {
  2835. parent::doResetCriteria();
  2836. // $this->params = array(
  2837. // SearchFields_WorkerEvent::NUM_NONSPAM => new DevblocksSearchCriteria(SearchFields_WorkerEvent::NUM_NONSPAM,'>',0),
  2838. // );
  2839. }
  2840. function doSetCriteria($field, $oper, $value) {
  2841. $criteria = null;
  2842. switch($field) {
  2843. case SearchFields_WorkerEvent::TITLE:
  2844. case SearchFields_WorkerEvent::CONTENT:
  2845. case SearchFields_WorkerEvent::URL:
  2846. // force wildcards if none used on a LIKE
  2847. if(($oper == DevblocksSearchCriteria::OPER_LIKE || $oper == DevblocksSearchCriteria::OPER_NOT_LIKE)
  2848. && false === (strpos($value,'*'))) {
  2849. $value = '*'.$value.'*';
  2850. }
  2851. $criteria = new DevblocksSearchCriteria($field, $oper, $value);
  2852. break;
  2853. case SearchFields_WorkerEvent::WORKER_ID:
  2854. @$worker_ids = DevblocksPlatform::importGPC($_REQUEST['worker_id'],'array',array());
  2855. $criteria = new DevblocksSearchCriteria($field,$oper,$worker_ids);
  2856. break;
  2857. case SearchFields_WorkerEvent::CREATED_DATE:
  2858. @$from = DevblocksPlatform::importGPC($_REQUEST['from'],'string','');
  2859. @$to = DevblocksPlatform::importGPC($_REQUEST['to'],'string','');
  2860. if(empty($from)) $from = 0;
  2861. if(empty($to)) $to = 'today';
  2862. $criteria = new DevblocksSearchCriteria($field,$oper,array($from,$to));
  2863. break;
  2864. case SearchFields_WorkerEvent::IS_READ:
  2865. @$bool = DevblocksPlatform::importGPC($_REQUEST['bool'],'integer',1);
  2866. $criteria = new DevblocksSearchCriteria($field,$oper,$bool);
  2867. break;
  2868. }
  2869. if(!empty($criteria)) {
  2870. $this->params[$field] = $criteria;
  2871. $this->renderPage = 0;
  2872. }
  2873. }
  2874. // function doBulkUpdate($filter, $do, $ids=array()) {
  2875. // @set_time_limit(600); // [TODO] Temp!
  2876. //
  2877. // $change_fields = array();
  2878. //
  2879. // if(empty($do))
  2880. // return;
  2881. //
  2882. // // Make sure we have checked items if we want a checked list
  2883. // if(0 == strcasecmp($filter,"checks") && empty($ids))
  2884. // return;
  2885. //
  2886. // if(is_array($do))
  2887. // foreach($do as $k => $v) {
  2888. // switch($k) {
  2889. // case 'banned':
  2890. // $change_fields[DAO_Address::IS_BANNED] = intval($v);
  2891. // break;
  2892. // }
  2893. // }
  2894. //
  2895. // $pg = 0;
  2896. //
  2897. // if(empty($ids))
  2898. // do {
  2899. // list($objects,$null) = DAO_Address::search(
  2900. // $this->params,
  2901. // 100,
  2902. // $pg++,
  2903. // SearchFields_Address::ID,
  2904. // true,
  2905. // false
  2906. // );
  2907. //
  2908. // $ids = array_merge($ids, array_keys($objects));
  2909. //
  2910. // } while(!empty($objects));
  2911. //
  2912. // $batch_total = count($ids);
  2913. // for($x=0;$x<=$batch_total;$x+=100) {
  2914. // $batch_ids = array_slice($ids,$x,100);
  2915. // DAO_Address::update($batch_ids, $change_fields);
  2916. // unset($batch_ids);
  2917. // }
  2918. //
  2919. // unset($ids);
  2920. // }
  2921. };
  2922. class Model_ContactOrg {
  2923. public $id;
  2924. public $name;
  2925. public $street;
  2926. public $city;
  2927. public $province;
  2928. public $postal;
  2929. public $country;
  2930. public $phone;
  2931. public $website;
  2932. public $created;
  2933. public $sync_id = '';
  2934. };
  2935. class Model_WorkerWorkspaceList {
  2936. public $id = 0;
  2937. public $worker_id = 0;
  2938. public $workspace = '';
  2939. public $source_extension = '';
  2940. public $list_view = '';
  2941. public $list_pos = 0;
  2942. };
  2943. class Model_WorkerWorkspaceListView {
  2944. public $title = 'New List';
  2945. // public $workspace = '';
  2946. public $columns = array();
  2947. public $num_rows = 10;
  2948. public $params = array();
  2949. public $sort_by = null;
  2950. public $sort_asc = 1;
  2951. };
  2952. class Model_Activity {
  2953. public $translation_code;
  2954. public $params;
  2955. public function __construct($translation_code='activity.default',$params=array()) {
  2956. $this->translation_code = $translation_code;
  2957. $this->params = $params;
  2958. }
  2959. public function toString(CerberusWorker $worker=null) {
  2960. if(null == $worker)
  2961. return;
  2962. $translate = DevblocksPlatform::getTranslationService();
  2963. $params = $this->params;
  2964. // Prepend the worker name to the activity's param list
  2965. array_unshift($params, sprintf("<b>%s</b>%s",
  2966. $worker->getName(),
  2967. (!empty($worker->title)
  2968. ? (' (' . $worker->title . ')')
  2969. : ''
  2970. )
  2971. ));
  2972. return vsprintf(
  2973. $translate->_($this->translation_code),
  2974. $params
  2975. );
  2976. }
  2977. };
  2978. class Model_MailToGroupRule {
  2979. public $id = 0;
  2980. public $pos = 0;
  2981. public $created = 0;
  2982. public $name = '';
  2983. public $criteria = array();
  2984. public $actions = array();
  2985. public $is_sticky = 0;
  2986. public $sticky_order = 0;
  2987. static function getMatches(Model_Address $fromAddress, CerberusParserMessage $message) {
  2988. // print_r($fromAddress);
  2989. // print_r($message);
  2990. $matches = array();
  2991. $rules = DAO_MailToGroupRule::getWhere();
  2992. $message_headers = $message->headers;
  2993. $custom_fields = DAO_CustomField::getAll();
  2994. // Lazy load when needed on criteria basis
  2995. $address_field_values = null;
  2996. $org_field_values = null;
  2997. // Check filters
  2998. if(is_array($rules))
  2999. foreach($rules as $rule) { /* @var $rule Model_MailToGroupRule */
  3000. $passed = 0;
  3001. // check criteria
  3002. foreach($rule->criteria as $crit_key => $crit) {
  3003. @$value = $crit['value'];
  3004. switch($crit_key) {
  3005. case 'dayofweek':
  3006. $current_day = strftime('%w');
  3007. // $current_day = 1;
  3008. // Forced to English abbrevs as indexes
  3009. $days = array('sun','mon','tue','wed','thu','fri','sat');
  3010. // Is the current day enabled?
  3011. if(isset($crit[$days[$current_day]])) {
  3012. $passed++;
  3013. }
  3014. break;
  3015. case 'timeofday':
  3016. $current_hour = strftime('%H');
  3017. $current_min = strftime('%M');
  3018. // $current_hour = 17;
  3019. // $current_min = 5;
  3020. if(null != ($from_time = @$crit['from']))
  3021. list($from_hour, $from_min) = explode(':', $from_time);
  3022. if(null != ($to_time = @$crit['to']))
  3023. if(list($to_hour, $to_min) = explode(':', $to_time));
  3024. // Do we need to wrap around to the next day's hours?
  3025. if($from_hour > $to_hour) { // yes
  3026. $to_hour += 24; // add 24 hrs to the destination (1am = 25th hour)
  3027. }
  3028. // Are we in the right 24 hourly range?
  3029. if((integer)$current_hour >= $from_hour && (integer)$current_hour <= $to_hour) {
  3030. // If we're in the first hour, are we minutes early?
  3031. if($current_hour==$from_hour && (integer)$current_min < $from_min)
  3032. break;
  3033. // If we're in the last hour, are we minutes late?
  3034. if($current_hour==$to_hour && (integer)$current_min > $to_min)
  3035. break;
  3036. $passed++;
  3037. }
  3038. break;
  3039. case 'tocc':
  3040. $tocc = array();
  3041. $destinations = DevblocksPlatform::parseCsvString($value);
  3042. // Build a list of To/Cc addresses on this message
  3043. @$to_list = imap_rfc822_parse_adrlist($message_headers['to'],'localhost');
  3044. @$cc_list = imap_rfc822_parse_adrlist($message_headers['cc'],'localhost');
  3045. if(is_array($to_list))
  3046. foreach($to_list as $addy) {
  3047. $tocc[] = $addy->mailbox . '@' . $addy->host;
  3048. }
  3049. if(is_array($cc_list))
  3050. foreach($cc_list as $addy) {
  3051. $tocc[] = $addy->mailbox . '@' . $addy->host;
  3052. }
  3053. $dest_flag = false; // bail out when true
  3054. if(is_array($destinations) && is_array($tocc))
  3055. foreach($destinations as $dest) {
  3056. if($dest_flag) break;
  3057. $regexp_dest = DevblocksPlatform::strToRegExp($dest);
  3058. foreach($tocc as $addy) {
  3059. if(@preg_match($regexp_dest, $addy)) {
  3060. $passed++;
  3061. $dest_flag = false;
  3062. break;
  3063. }
  3064. }
  3065. }
  3066. break;
  3067. case 'from':
  3068. $regexp_from = DevblocksPlatform::strToRegExp($value);
  3069. if(@preg_match($regexp_from, $fromAddress->email)) {
  3070. $passed++;
  3071. }
  3072. break;
  3073. case 'subject':
  3074. // [TODO] Decode if necessary
  3075. @$subject = $message_headers['subject'];
  3076. $regexp_subject = DevblocksPlatform::strToRegExp($value);
  3077. if(@preg_match($regexp_subject, $subject)) {
  3078. $passed++;
  3079. }
  3080. break;
  3081. case 'body':
  3082. // Line-by-line body scanning (sed-like)
  3083. $lines = preg_split("/[\r\n]/", $message->body);
  3084. if(is_array($lines))
  3085. foreach($lines as $line) {
  3086. if(@preg_match($value, $line)) {
  3087. $passed++;
  3088. break;
  3089. }
  3090. }
  3091. break;
  3092. case 'header1':
  3093. case 'header2':
  3094. case 'header3':
  3095. case 'header4':
  3096. case 'header5':
  3097. @$header = strtolower($crit['header']);
  3098. if(empty($header)) {
  3099. $passed++;
  3100. break;
  3101. }
  3102. if(empty($value)) { // we're checking for null/blanks
  3103. if(!isset($message_headers[$header]) || empty($message_headers[$header])) {
  3104. $passed++;
  3105. }
  3106. } elseif(isset($message_headers[$header]) && !empty($message_headers[$header])) {
  3107. $regexp_header = DevblocksPlatform::strToRegExp($value);
  3108. // Flatten CRLF
  3109. if(@preg_match($regexp_header, str_replace(array("\r","\n"),' ',$message_headers[$header]))) {
  3110. $passed++;
  3111. }
  3112. }
  3113. break;
  3114. default: // ignore invalids
  3115. // Custom Fields
  3116. if(0==strcasecmp('cf_',substr($crit_key,0,3))) {
  3117. $field_id = substr($crit_key,3);
  3118. // Make sure it exists
  3119. if(null == (@$field = $custom_fields[$field_id]))
  3120. continue;
  3121. // Lazy values loader
  3122. $field_values = array();
  3123. switch($field->source_extension) {
  3124. case ChCustomFieldSource_Address::ID:
  3125. if(null == $address_field_values)
  3126. $address_field_values = array_shift(DAO_CustomFieldValue::getValuesBySourceIds(ChCustomFieldSource_Address::ID, $fromAddress->id));
  3127. $field_values =& $address_field_values;
  3128. break;
  3129. case ChCustomFieldSource_Org::ID:
  3130. if(null == $org_field_values)
  3131. $org_field_values = array_shift(DAO_CustomFieldValue::getValuesBySourceIds(ChCustomFieldSource_Org::ID, $fromAddress->contact_org_id));
  3132. $field_values =& $org_field_values;
  3133. break;
  3134. }
  3135. // No values, default.
  3136. if(!isset($field_values[$field_id]))
  3137. continue;
  3138. // Type sensitive value comparisons
  3139. switch($field->type) {
  3140. case 'S': // string
  3141. case 'T': // clob
  3142. case 'U': // URL
  3143. $field_val = isset($field_values[$field_id]) ? $field_values[$field_id] : '';
  3144. $oper = isset($crit['oper']) ? $crit['oper'] : "=";
  3145. if($oper == "=" && @preg_match(DevblocksPlatform::strToRegExp($value, true), $field_val))
  3146. $passed++;
  3147. elseif($oper == "!=" && @!preg_match(DevblocksPlatform::strToRegExp($value, true), $field_val))
  3148. $passed++;
  3149. break;
  3150. case 'N': // number
  3151. if(!isset($field_values[$field_id]))
  3152. break;
  3153. $field_val = isset($field_values[$field_id]) ? $field_values[$field_id] : 0;
  3154. $oper = isset($crit['oper']) ? $crit['oper'] : "=";
  3155. if($oper=="=" && intval($field_val)==intval($value))
  3156. $passed++;
  3157. elseif($oper=="!=" && intval($field_val)!=intval($value))
  3158. $passed++;
  3159. elseif($oper==">" && intval($field_val) > intval($value))
  3160. $passed++;
  3161. elseif($oper=="<" && intval($field_val) < intval($value))
  3162. $passed++;
  3163. break;
  3164. case 'E': // date
  3165. $field_val = isset($field_values[$field_id]) ? intval($field_values[$field_id]) : 0;
  3166. $from = isset($crit['from']) ? $crit['from'] : "0";
  3167. $to = isset($crit['to']) ? $crit['to'] : "now";
  3168. if(intval(@strtotime($from)) <= $field_val && intval(@strtotime($to)) >= $field_val) {
  3169. $passed++;
  3170. }
  3171. break;
  3172. case 'C': // checkbox
  3173. $field_val = isset($field_values[$field_id]) ? $field_values[$field_id] : 0;
  3174. if(intval($value)==intval($field_val))
  3175. $passed++;
  3176. break;
  3177. case 'D': // dropdown
  3178. case 'X': // multi-checkbox
  3179. case 'M': // multi-picklist
  3180. case 'W': // worker
  3181. $field_val = isset($field_values[$field_id]) ? $field_values[$field_id] : array();
  3182. if(!is_array($value)) $value = array($value);
  3183. if(is_array($field_val)) { // if multiple things set
  3184. foreach($field_val as $v) { // loop through possible
  3185. if(isset($value[$v])) { // is any possible set?
  3186. $passed++;
  3187. break;
  3188. }
  3189. }
  3190. } else { // single
  3191. if(isset($value[$field_val])) { // is our set field in possibles?
  3192. $passed++;
  3193. break;
  3194. }
  3195. }
  3196. break;
  3197. }
  3198. }
  3199. break;
  3200. }
  3201. }
  3202. // If our rule matched every criteria, stop and return the filter
  3203. if($passed == count($rule->criteria)) {
  3204. DAO_MailToGroupRule::increment($rule->id); // ++ the times we've matched
  3205. $matches[$rule->id] = $rule;
  3206. // Bail out if this rule had a move action
  3207. if(isset($rule->actions['move']))
  3208. return $matches;
  3209. }
  3210. }
  3211. // If we're at the end of rules and didn't bail out yet
  3212. if(!empty($matches))
  3213. return $matches;
  3214. // No matches
  3215. return NULL;
  3216. }
  3217. /**
  3218. * @param integer[] $ticket_ids
  3219. */
  3220. function run($ticket_ids) {
  3221. if(!is_array($ticket_ids)) $ticket_ids = array($ticket_ids);
  3222. $fields = array();
  3223. $field_values = array();
  3224. $groups = DAO_Group::getAll();
  3225. $buckets = DAO_Bucket::getAll();
  3226. // $workers = DAO_Worker::getAll();
  3227. $custom_fields = DAO_CustomField::getAll();
  3228. // actions
  3229. if(is_array($this->actions))
  3230. foreach($this->actions as $action => $params) {
  3231. switch($action) {
  3232. // case 'status':
  3233. // if(isset($params['is_waiting']))
  3234. // $fields[DAO_Ticket::IS_WAITING] = intval($params['is_waiting']);
  3235. // if(isset($params['is_closed']))
  3236. // $fields[DAO_Ticket::IS_CLOSED] = intval($params['is_closed']);
  3237. // if(isset($params['is_deleted']))
  3238. // $fields[DAO_Ticket::IS_DELETED] = intval($params['is_deleted']);
  3239. // break;
  3240. // case 'assign':
  3241. // if(isset($params['worker_id'])) {
  3242. // $w_id = intval($params['worker_id']);
  3243. // if(0 == $w_id || isset($workers[$w_id]))
  3244. // $fields[DAO_Ticket::NEXT_WORKER_ID] = $w_id;
  3245. // }
  3246. // break;
  3247. case 'move':
  3248. if(isset($params['group_id']) && isset($params['bucket_id'])) {
  3249. $g_id = intval($params['group_id']);
  3250. $b_id = intval($params['bucket_id']);
  3251. if(isset($groups[$g_id]) && (0==$b_id || isset($buckets[$b_id]))) {
  3252. $fields[DAO_Ticket::TEAM_ID] = $g_id;
  3253. $fields[DAO_Ticket::CATEGORY_ID] = $b_id;
  3254. }
  3255. }
  3256. break;
  3257. // case 'spam':
  3258. // if(isset($params['is_spam'])) {
  3259. // if(intval($params['is_spam'])) {
  3260. // foreach($ticket_ids as $ticket_id)
  3261. // CerberusBayes::markTicketAsSpam($ticket_id);
  3262. // } else {
  3263. // foreach($ticket_ids as $ticket_id)
  3264. // CerberusBayes::markTicketAsNotSpam($ticket_id);
  3265. // }
  3266. // }
  3267. // break;
  3268. default:
  3269. // Custom fields
  3270. if(substr($action,0,3)=="cf_") {
  3271. $field_id = intval(substr($action,3));
  3272. if(!isset($custom_fields[$field_id]) || !isset($params['value']))
  3273. break;
  3274. $field_values[$field_id] = $params;
  3275. }
  3276. break;
  3277. }
  3278. }
  3279. if(!empty($ticket_ids)) {
  3280. if(!empty($fields))
  3281. DAO_Ticket::updateTicket($ticket_ids, $fields);
  3282. // Custom Fields
  3283. C4_AbstractView::_doBulkSetCustomFields(ChCustomFieldSource_Ticket::ID, $field_values, $ticket_ids);
  3284. }
  3285. }
  3286. };
  3287. class CerberusVisit extends DevblocksVisit {
  3288. private $worker;
  3289. const KEY_VIEW_LAST_ACTION = 'view_last_action';
  3290. const KEY_MY_WORKSPACE = 'view_my_workspace';
  3291. const KEY_MAIL_MODE = 'mail_mode';
  3292. const KEY_HOME_SELECTED_TAB = 'home_selected_tab';
  3293. const KEY_OVERVIEW_FILTER = 'overview_filter';
  3294. const KEY_WORKFLOW_FILTER = 'workflow_filter';
  3295. public function __construct() {
  3296. $this->worker = null;
  3297. }
  3298. /**
  3299. * @return CerberusWorker
  3300. */
  3301. public function getWorker() {
  3302. return $this->worker;
  3303. }
  3304. public function setWorker(CerberusWorker $worker=null) {
  3305. $this->worker = $worker;
  3306. }
  3307. };
  3308. class CerberusBayesWord {
  3309. public $id = -1;
  3310. public $word = '';
  3311. public $spam = 0;
  3312. public $nonspam = 0;
  3313. public $probability = CerberusBayes::PROBABILITY_UNKNOWN;
  3314. public $interest_rating = 0.0;
  3315. }
  3316. class CerberusWorker {
  3317. public $id;
  3318. public $first_name;
  3319. public $last_name;
  3320. public $email;
  3321. public $pass;
  3322. public $title;
  3323. public $is_superuser=0;
  3324. public $is_disabled=0;
  3325. public $last_activity;
  3326. public $last_activity_date;
  3327. /**
  3328. * @return Model_TeamMember[]
  3329. */
  3330. function getMemberships() {
  3331. return DAO_Worker::getWorkerGroups($this->id);
  3332. }
  3333. function hasPriv($priv_id) {
  3334. // We don't need to do much work if we're a superuser
  3335. if($this->is_superuser)
  3336. return true;
  3337. $settings = DevblocksPlatform::getPluginSettingsService();
  3338. $acl_enabled = $settings->get('cerberusweb.core',CerberusSettings::ACL_ENABLED);
  3339. // ACL is a paid feature (please respect the licensing and support the project!)
  3340. $license = CerberusLicense::getInstance();
  3341. if(!$acl_enabled || !isset($license['serial']) || isset($license['a']))
  3342. return ("core.config"==substr($priv_id,0,11)) ? false : true;
  3343. // Check the aggregated worker privs from roles
  3344. $acl = DAO_WorkerRole::getACL();
  3345. $privs_by_worker = $acl[DAO_WorkerRole::CACHE_KEY_PRIVS_BY_WORKER];
  3346. if(!empty($priv_id) && isset($privs_by_worker[$this->id][$priv_id]))
  3347. return true;
  3348. return false;
  3349. }
  3350. function isTeamManager($team_id) {
  3351. @$memberships = $this->getMemberships();
  3352. $teams = DAO_Group::getAll();
  3353. if(
  3354. empty($team_id) // null
  3355. || !isset($teams[$team_id]) // doesn't exist
  3356. || !isset($memberships[$team_id]) // not a member
  3357. || (!$memberships[$team_id]->is_manager && !$this->is_superuser) // not a manager or superuser
  3358. ){
  3359. return false;
  3360. }
  3361. return true;
  3362. }
  3363. function isTeamMember($team_id) {
  3364. @$memberships = $this->getMemberships();
  3365. $teams = DAO_Group::getAll();
  3366. if(
  3367. empty($team_id) // null
  3368. || !isset($teams[$team_id]) // not a team
  3369. || !isset($memberships[$team_id]) // not a member
  3370. ) {
  3371. return false;
  3372. }
  3373. return true;
  3374. }
  3375. function getName($reverse=false) {
  3376. if(!$reverse) {
  3377. $name = sprintf("%s%s%s",
  3378. $this->first_name,
  3379. (!empty($this->first_name) && !empty($this->last_name)) ? " " : "",
  3380. $this->last_name
  3381. );
  3382. } else {
  3383. $name = sprintf("%s%s%s",
  3384. $this->last_name,
  3385. (!empty($this->first_name) && !empty($this->last_name)) ? ", " : "",
  3386. $this->first_name
  3387. );
  3388. }
  3389. return $name;
  3390. }
  3391. };
  3392. class Model_WorkerRole {
  3393. public $id;
  3394. public $name;
  3395. };
  3396. class Model_WorkerEvent {
  3397. public $id;
  3398. public $created_date;
  3399. public $worker_id;
  3400. public $title;
  3401. public $content;
  3402. public $is_read;
  3403. public $url;
  3404. };
  3405. class Model_ViewRss {
  3406. public $id = 0;
  3407. public $title = '';
  3408. public $hash = '';
  3409. public $worker_id = 0;
  3410. public $created = 0;
  3411. public $source_extension = '';
  3412. public $params = array();
  3413. };
  3414. class Model_TicketViewLastAction {
  3415. // [TODO] Recycle the bulk update constants for these actions?
  3416. const ACTION_NOT_SPAM = 'not_spam';
  3417. const ACTION_SPAM = 'spam';
  3418. const ACTION_CLOSE = 'close';
  3419. const ACTION_DELETE = 'delete';
  3420. const ACTION_MOVE = 'move';
  3421. const ACTION_TAKE = 'take';
  3422. const ACTION_SURRENDER = 'surrender';
  3423. const ACTION_WAITING = 'waiting';
  3424. const ACTION_NOT_WAITING = 'not_waiting';
  3425. public $ticket_ids = array(); // key = ticket id, value=old value
  3426. public $action = ''; // spam/closed/move, etc.
  3427. public $action_params = array(); // DAO Actions Taken
  3428. };
  3429. class CerberusTicketStatus {
  3430. const OPEN = 0;
  3431. const CLOSED = 1;
  3432. };
  3433. class CerberusTicketSpamTraining { // [TODO] Append 'Enum' to class name?
  3434. const BLANK = '';
  3435. const NOT_SPAM = 'N';
  3436. const SPAM = 'S';
  3437. };
  3438. class CerberusTicket {
  3439. public $id;
  3440. public $mask;
  3441. public $subject;
  3442. public $is_waiting = 0;
  3443. public $is_closed = 0;
  3444. public $is_deleted = 0;
  3445. public $team_id;
  3446. public $category_id;
  3447. public $first_message_id;
  3448. public $first_wrote_address_id;
  3449. public $last_wrote_address_id;
  3450. public $created_date;
  3451. public $updated_date;
  3452. public $due_date;
  3453. public $unlock_date;
  3454. public $spam_score;
  3455. public $spam_training;
  3456. public $interesting_words;
  3457. public $last_action_code;
  3458. public $last_worker_id;
  3459. public $next_worker_id;
  3460. function CerberusTicket() {}
  3461. function getMessages() {
  3462. $messages = DAO_Ticket::getMessagesByTicket($this->id);
  3463. return $messages;
  3464. }
  3465. function getRequesters() {
  3466. $requesters = DAO_Ticket::getRequestersByTicket($this->id);
  3467. return $requesters;
  3468. }
  3469. /**
  3470. * @return CloudGlueTag[]
  3471. */
  3472. function getTags() {
  3473. $result = DAO_CloudGlue::getTagsOnContents(array($this->id), CerberusApplication::INDEX_TICKETS);
  3474. $tags = array_shift($result);
  3475. return $tags;
  3476. }
  3477. };
  3478. class CerberusTicketActionCode {
  3479. const TICKET_OPENED = 'O';
  3480. const TICKET_CUSTOMER_REPLY = 'R';
  3481. const TICKET_WORKER_REPLY = 'W';
  3482. };
  3483. class CerberusMessage {
  3484. public $id;
  3485. public $ticket_id;
  3486. public $created_date;
  3487. public $address_id;
  3488. public $is_outgoing;
  3489. public $worker_id;
  3490. function CerberusMessage() {}
  3491. function getContent() {
  3492. return DAO_MessageContent::get($this->id);
  3493. }
  3494. function getHeaders() {
  3495. return DAO_MessageHeader::getAll($this->id);
  3496. }
  3497. /**
  3498. * returns an array of the message's attachments
  3499. *
  3500. * @return Model_Attachment[]
  3501. */
  3502. function getAttachments() {
  3503. $attachments = DAO_Attachment::getByMessageId($this->id);
  3504. return $attachments;
  3505. }
  3506. };
  3507. class Model_MessageNote {
  3508. const TYPE_NOTE = 0;
  3509. const TYPE_WARNING = 1;
  3510. const TYPE_ERROR = 2;
  3511. public $id;
  3512. public $type;
  3513. public $message_id;
  3514. public $created;
  3515. public $worker_id;
  3516. public $content;
  3517. };
  3518. class Model_Note {
  3519. const EXTENSION_ID = 'cerberusweb.note';
  3520. public $id;
  3521. public $source_extension_id;
  3522. public $source_id;
  3523. public $created;
  3524. public $worker_id;
  3525. public $content;
  3526. };
  3527. class Model_Attachment {
  3528. public $id;
  3529. public $message_id;
  3530. public $display_name;
  3531. public $filepath;
  3532. public $file_size = 0;
  3533. public $mime_type = '';
  3534. public function getFileContents() {
  3535. $file_path = APP_STORAGE_PATH . '/attachments/';
  3536. if (!empty($this->filepath))
  3537. return file_get_contents($file_path.$this->filepath,false);
  3538. }
  3539. public function getFileSize() {
  3540. $file_path = APP_STORAGE_PATH . '/attachments/';
  3541. if (!empty($this->filepath))
  3542. return filesize($file_path.$this->filepath);
  3543. }
  3544. public static function saveToFile($file_id, $contents) {
  3545. $attachment_path = APP_STORAGE_PATH . '/attachments/';
  3546. // Make file attachments use buckets so we have a max per directory
  3547. $attachment_bucket = sprintf("%03d/",
  3548. mt_rand(1,100)
  3549. );
  3550. $attachment_file = $file_id;
  3551. if(!file_exists($attachment_path.$attachment_bucket)) {
  3552. @mkdir($attachment_path.$attachment_bucket, 0770, true);
  3553. // [TODO] Needs error checking
  3554. }
  3555. file_put_contents($attachment_path.$attachment_bucket.$attachment_file, $contents);
  3556. return $attachment_bucket.$attachment_file;
  3557. }
  3558. };
  3559. class CerberusTeam {
  3560. public $id;
  3561. public $name;
  3562. public $count;
  3563. public $is_default = 0;
  3564. }
  3565. class Model_TeamMember {
  3566. public $id;
  3567. public $team_id;
  3568. public $is_manager = 0;
  3569. }
  3570. class CerberusCategory {
  3571. public $id;
  3572. public $pos=0;
  3573. public $name = '';
  3574. public $team_id = 0;
  3575. public $is_assignable = 1;
  3576. }
  3577. class CerberusPop3Account {
  3578. public $id;
  3579. public $enabled=1;
  3580. public $nickname;
  3581. public $protocol='pop3';
  3582. public $host;
  3583. public $username;
  3584. public $password;
  3585. public $port=110;
  3586. };
  3587. class Model_MailTemplate {
  3588. const TYPE_COMPOSE = 1;
  3589. const TYPE_REPLY = 2;
  3590. const TYPE_CREATE = 3;
  3591. // const TYPE_CLOSE = 4;
  3592. public $id = 0;
  3593. public $title = '';
  3594. public $description = '';
  3595. public $folder = '';
  3596. public $owner_id = 0;
  3597. public $template_type = 0;
  3598. public $content = '';
  3599. public function getRenderedContent($message_id) {
  3600. $raw = $this->content;
  3601. $replace = array();
  3602. $with = array();
  3603. $replace[] = '#timestamp#';
  3604. $with[] = date('r');
  3605. if(!empty($message_id)) {
  3606. $message = DAO_Ticket::getMessage($message_id);
  3607. $ticket = DAO_Ticket::getTicket($message->ticket_id);
  3608. $sender = DAO_Address::get($message->address_id);
  3609. $sender_org = DAO_ContactOrg::get($sender->contact_org_id);
  3610. $replace[] = '#sender_first_name#';
  3611. $replace[] = '#sender_last_name#';
  3612. $replace[] = '#sender_org#';
  3613. $with[] = $sender->first_name;
  3614. $with[] = $sender->last_name;
  3615. $with[] = (!empty($sender_org)?$sender_org->name:"");
  3616. $replace[] = '#ticket_id#';
  3617. $replace[] = '#ticket_mask#';
  3618. $replace[] = '#ticket_subject#';
  3619. $with[] = $ticket->id;
  3620. $with[] = $ticket->mask;
  3621. $with[] = $ticket->subject;
  3622. }
  3623. if(null != ($active_worker = CerberusApplication::getActiveWorker())) {
  3624. $worker = DAO_Worker::getAgent($active_worker->id); // most recent info (not session)
  3625. $replace[] = '#worker_first_name#';
  3626. $replace[] = '#worker_last_name#';
  3627. $replace[] = '#worker_title#';
  3628. $with[] = $worker->first_name;
  3629. $with[] = $worker->last_name;
  3630. $with[] = $worker->title;
  3631. }
  3632. return str_replace($replace, $with, $raw);
  3633. }
  3634. };
  3635. class Model_TicketComment {
  3636. public $id;
  3637. public $ticket_id;
  3638. public $address_id;
  3639. public $created;
  3640. public $comment;
  3641. public function getAddress() {
  3642. return DAO_Address::get($this->address_id);
  3643. }
  3644. };
  3645. class Model_CustomField {
  3646. const TYPE_CHECKBOX = 'C';
  3647. const TYPE_DROPDOWN = 'D';
  3648. const TYPE_DATE = 'E';
  3649. const TYPE_MULTI_PICKLIST = 'M';
  3650. const TYPE_NUMBER = 'N';
  3651. const TYPE_SINGLE_LINE = 'S';
  3652. const TYPE_MULTI_LINE = 'T';
  3653. const TYPE_URL = 'U';
  3654. const TYPE_WORKER = 'W';
  3655. const TYPE_MULTI_CHECKBOX = 'X';
  3656. public $id = 0;
  3657. public $name = '';
  3658. public $type = '';
  3659. public $group_id = 0;
  3660. public $source_extension = '';
  3661. public $pos = 0;
  3662. public $options = array();
  3663. static function getTypes() {
  3664. return array(
  3665. self::TYPE_SINGLE_LINE => 'Text: Single Line',
  3666. self::TYPE_MULTI_LINE => 'Text: Multi-Line',
  3667. self::TYPE_NUMBER => 'Number',
  3668. self::TYPE_DATE => 'Date',
  3669. self::TYPE_DROPDOWN => 'Picklist',
  3670. self::TYPE_MULTI_PICKLIST => 'Multi-Picklist',
  3671. self::TYPE_CHECKBOX => 'Checkbox',
  3672. self::TYPE_MULTI_CHECKBOX => 'Multi-Checkbox',
  3673. self::TYPE_WORKER => 'Worker',
  3674. self::TYPE_URL => 'URL',
  3675. // self::TYPE_FILE => 'File',
  3676. );
  3677. }
  3678. };
  3679. class Model_Task {
  3680. public $id;
  3681. public $title;
  3682. public $worker_id;
  3683. public $created;
  3684. public $due_date;
  3685. public $is_completed;
  3686. public $completed_date;
  3687. public $source_extension;
  3688. public $source_id;
  3689. };