action.class.inc.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. <?php
  2. // Copyright (C) 2010 Combodo SARL
  3. //
  4. // This program is free software; you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation; version 3 of the License.
  7. //
  8. // This program is distributed in the hope that it will be useful,
  9. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. // GNU General Public License for more details.
  12. //
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program; if not, write to the Free Software
  15. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  16. /**
  17. * Persistent classes (internal): user defined actions
  18. *
  19. * @author Erwan Taloc <erwan.taloc@combodo.com>
  20. * @author Romain Quetiez <romain.quetiez@combodo.com>
  21. * @author Denis Flaven <denis.flaven@combodo.com>
  22. * @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
  23. */
  24. require_once('../core/email.class.inc.php');
  25. /**
  26. * A user defined action, to customize the application
  27. *
  28. * @package iTopORM
  29. */
  30. abstract class Action extends cmdbAbstractObject
  31. {
  32. public static function Init()
  33. {
  34. $aParams = array
  35. (
  36. "category" => "core/cmdb",
  37. "key_type" => "autoincrement",
  38. "key_label" => "",
  39. "name_attcode" => "name",
  40. "state_attcode" => "",
  41. "reconc_keys" => array(),
  42. "db_table" => "priv_action",
  43. "db_key_field" => "id",
  44. "db_finalclass_field" => "realclass",
  45. "display_template" => "",
  46. );
  47. MetaModel::Init_Params($aParams);
  48. //MetaModel::Init_InheritAttributes();
  49. MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
  50. MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
  51. MetaModel::Init_AddAttribute(new AttributeEnum("status", array("allowed_values"=>new ValueSetEnum(array('test'=>'Being tested' ,'enabled'=>'In production', 'disabled'=>'Inactive')), "sql"=>"status", "default_value"=>"test", "is_null_allowed"=>false, "depends_on"=>array())));
  52. MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("related_triggers", array("linked_class"=>"lnkTriggerAction", "ext_key_to_me"=>"action_id", "ext_key_to_remote"=>"trigger_id", "allowed_values"=>null, "count_min"=>0, "count_max"=>0, "depends_on"=>array())));
  53. // Display lists
  54. MetaModel::Init_SetZListItems('details', array('name', 'description', 'status')); // Attributes to be displayed for the complete details
  55. MetaModel::Init_SetZListItems('list', array('finalclass', 'name', 'description', 'status')); // Attributes to be displayed for a list
  56. // Search criteria
  57. // MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
  58. // MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
  59. }
  60. abstract public function DoExecute($oTrigger, $aContextArgs);
  61. public function IsActive()
  62. {
  63. switch($this->Get('status'))
  64. {
  65. case 'enabled':
  66. case 'test':
  67. return true;
  68. default:
  69. return false;
  70. }
  71. }
  72. public function IsBeingTested()
  73. {
  74. switch($this->Get('status'))
  75. {
  76. case 'test':
  77. return true;
  78. default:
  79. return false;
  80. }
  81. }
  82. }
  83. /**
  84. * A notification
  85. *
  86. * @package iTopORM
  87. */
  88. abstract class ActionNotification extends Action
  89. {
  90. public static function Init()
  91. {
  92. $aParams = array
  93. (
  94. "category" => "core/cmdb",
  95. "key_type" => "autoincrement",
  96. "key_label" => "",
  97. "name_attcode" => "name",
  98. "state_attcode" => "",
  99. "reconc_keys" => array(),
  100. "db_table" => "priv_action_notification",
  101. "db_key_field" => "id",
  102. "db_finalclass_field" => "",
  103. "display_template" => "",
  104. );
  105. MetaModel::Init_Params($aParams);
  106. MetaModel::Init_InheritAttributes();
  107. // Display lists
  108. MetaModel::Init_SetZListItems('details', array('name', 'description', 'status')); // Attributes to be displayed for the complete details
  109. MetaModel::Init_SetZListItems('list', array('finalclass', 'name', 'description', 'status')); // Attributes to be displayed for a list
  110. // Search criteria
  111. // MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
  112. // MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
  113. }
  114. }
  115. /**
  116. * An email notification
  117. *
  118. * @package iTopORM
  119. */
  120. class ActionEmail extends ActionNotification
  121. {
  122. public static function Init()
  123. {
  124. $aParams = array
  125. (
  126. "category" => "core/cmdb",
  127. "key_type" => "autoincrement",
  128. "key_label" => "",
  129. "name_attcode" => "name",
  130. "state_attcode" => "",
  131. "reconc_keys" => array(),
  132. "db_table" => "priv_action_email",
  133. "db_key_field" => "id",
  134. "db_finalclass_field" => "",
  135. "display_template" => "",
  136. );
  137. MetaModel::Init_Params($aParams);
  138. MetaModel::Init_InheritAttributes();
  139. MetaModel::Init_AddAttribute(new AttributeEmailAddress("test_recipient", array("allowed_values"=>null, "sql"=>"test_recipient", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
  140. MetaModel::Init_AddAttribute(new AttributeString("from", array("allowed_values"=>null, "sql"=>"from", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
  141. MetaModel::Init_AddAttribute(new AttributeString("reply_to", array("allowed_values"=>null, "sql"=>"reply_to", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
  142. MetaModel::Init_AddAttribute(new AttributeOQL("to", array("allowed_values"=>null, "sql"=>"to", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
  143. MetaModel::Init_AddAttribute(new AttributeOQL("cc", array("allowed_values"=>null, "sql"=>"cc", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
  144. MetaModel::Init_AddAttribute(new AttributeOQL("bcc", array("allowed_values"=>null, "sql"=>"bcc", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
  145. MetaModel::Init_AddAttribute(new AttributeTemplateString("subject", array("allowed_values"=>null, "sql"=>"subject", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
  146. MetaModel::Init_AddAttribute(new AttributeTemplateText("body", array("allowed_values"=>null, "sql"=>"body", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
  147. MetaModel::Init_AddAttribute(new AttributeEnum("importance", array("allowed_values"=>new ValueSetEnum('low,normal,high'), "sql"=>"importance", "default_value"=>'normal', "is_null_allowed"=>false, "depends_on"=>array())));
  148. // Display lists
  149. MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'test_recipient', 'from', 'reply_to', 'to', 'cc', 'bcc', 'subject', 'body', 'importance')); // Attributes to be displayed for the complete details
  150. MetaModel::Init_SetZListItems('list', array('name', 'status', 'to', 'subject')); // Attributes to be displayed for a list
  151. // Search criteria
  152. // MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
  153. // MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
  154. }
  155. // count the recipients found
  156. protected $m_iRecipients;
  157. // Errors management : not that simple because we need that function to be
  158. // executed in the background, while making sure that any issue would be reported clearly
  159. protected $m_aMailErrors; //array of strings explaining the issue
  160. // returns a the list of emails as a string, or a detailed error description
  161. protected function FindRecipients($sRecipAttCode, $aArgs)
  162. {
  163. $sOQL = $this->Get($sRecipAttCode);
  164. if (strlen($sOQL) == '') return '';
  165. try
  166. {
  167. $oSearch = DBObjectSearch::FromOQL($sOQL);
  168. }
  169. catch (OQLException $e)
  170. {
  171. $this->m_aMailErrors[] = "query syntax error for recipient '$sRecipAttCode'";
  172. return $e->getMessage();
  173. }
  174. $sClass = $oSearch->GetClass();
  175. // Determine the email attribute (the first one will be our choice)
  176. foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
  177. {
  178. if ($oAttDef instanceof AttributeEmailAddress)
  179. {
  180. $sEmailAttCode = $sAttCode;
  181. // we've got one, exit the loop
  182. break;
  183. }
  184. }
  185. if (!isset($sEmailAttCode))
  186. {
  187. $this->m_aMailErrors[] = "wrong target for recipient '$sRecipAttCode'";
  188. return "The objects of the class '$sClass' do not have any email attribute";
  189. }
  190. $oSet = new DBObjectSet($oSearch, array() /* order */, $aArgs);
  191. $aRecipients = array();
  192. while ($oObj = $oSet->Fetch())
  193. {
  194. $aRecipients[] = $oObj->Get($sEmailAttCode);
  195. $this->m_iRecipients++;
  196. }
  197. return implode(', ', $aRecipients);
  198. }
  199. public function DoExecute($oTrigger, $aContextArgs)
  200. {
  201. $this->m_iRecipients = 0;
  202. $this->m_aMailErrors = array();
  203. $bRes = false; // until we do succeed in sending the email
  204. try
  205. {
  206. // Determine recicipients
  207. //
  208. $sTo = $this->FindRecipients('to', $aContextArgs);
  209. $sCC = $this->FindRecipients('cc', $aContextArgs);
  210. $sBCC = $this->FindRecipients('bcc', $aContextArgs);
  211. $sFrom = $this->Get('from');
  212. $sReplyTo = $this->Get('reply_to');
  213. $sSubject = MetaModel::ApplyParams($this->Get('subject'), $aContextArgs);
  214. $sBody = MetaModel::ApplyParams($this->Get('body'), $aContextArgs);
  215. $oEmail = new EMail();
  216. if ($this->IsBeingTested())
  217. {
  218. $oEmail->SetSubject('TEST['.$sSubject.']');
  219. $sTestBody = $sBody;
  220. $sTestBody .= "<div style=\"border: dashed;\">\n";
  221. $sTestBody .= "<h1>Testing email notification ".$this->GetHyperlink()."</h1>\n";
  222. $sTestBody .= "<p>The email should be sent with the following properties\n";
  223. $sTestBody .= "<ul>\n";
  224. $sTestBody .= "<li>TO: $sTo</li>\n";
  225. $sTestBody .= "<li>CC: $sCC</li>\n";
  226. $sTestBody .= "<li>BCC: $sBCC</li>\n";
  227. $sTestBody .= "<li>From: $sFrom</li>\n";
  228. $sTestBody .= "<li>Reply-To: $sReplyTo</li>\n";
  229. $sTestBody .= "</ul>\n";
  230. $sTestBody .= "</p>\n";
  231. $sTestBody .= "</div>\n";
  232. $oEmail->SetBody($sTestBody);
  233. $oEmail->SetRecipientTO($this->Get('test_recipient'));
  234. $oEmail->SetRecipientFrom($this->Get('test_recipient'));
  235. }
  236. else
  237. {
  238. $oEmail->SetSubject($sSubject);
  239. $oEmail->SetBody($sBody);
  240. $oEmail->SetRecipientTO($sTo);
  241. $oEmail->SetRecipientCC($sCC);
  242. $oEmail->SetRecipientBCC($sBCC);
  243. $oEmail->SetRecipientFrom($sFrom);
  244. $oEmail->SetRecipientReplyTo($sReplyTo);
  245. }
  246. if (empty($this->m_aMailErrors))
  247. {
  248. if ($this->m_iRecipients == 0)
  249. {
  250. $this->m_aMailErrors[] = 'No recipient';
  251. }
  252. else
  253. {
  254. $this->m_aMailErrors = array_merge($this->m_aMailErrors, $oEmail->Send());
  255. }
  256. }
  257. }
  258. catch (Exception $e)
  259. {
  260. $this->m_aMailErrors[] = $e->getMessage();
  261. }
  262. if (MetaModel::IsLogEnabledNotification())
  263. {
  264. $oLog = new EventNotificationEmail();
  265. if (empty($this->m_aMailErrors))
  266. {
  267. if ($this->IsBeingTested())
  268. {
  269. $oLog->Set('message', 'TEST - Notification sent ('.$this->Get('test_recipient').')');
  270. }
  271. else
  272. {
  273. $oLog->Set('message', 'Notification sent');
  274. }
  275. }
  276. else
  277. {
  278. if (is_array($this->m_aMailErrors) && count($this->m_aMailErrors) > 0)
  279. {
  280. $sError = implode(', ', $this->m_aMailErrors);
  281. }
  282. else
  283. {
  284. $sError = 'Unknown reason';
  285. }
  286. if ($this->IsBeingTested())
  287. {
  288. $oLog->Set('message', 'TEST - Notification was not sent: '.$sError);
  289. }
  290. else
  291. {
  292. $oLog->Set('message', 'Notification was not sent: '.$sError);
  293. }
  294. }
  295. $oLog->Set('userinfo', UserRights::GetUser());
  296. $oLog->Set('trigger_id', $oTrigger->GetKey());
  297. $oLog->Set('action_id', $this->GetKey());
  298. $oLog->Set('object_id', $aContextArgs['this->id']);
  299. // Note: we have to secure this because those values are calculated
  300. // inside the try statement, and we would like to keep track of as
  301. // many data as we could while some variables may still be undefined
  302. if (isset($sTo)) $oLog->Set('to', $sTo);
  303. if (isset($sCC)) $oLog->Set('cc', $sCC);
  304. if (isset($sBCC)) $oLog->Set('bcc', $sBCC);
  305. if (isset($sFrom)) $oLog->Set('from', $sFrom);
  306. if (isset($sSubject)) $oLog->Set('subject', $sSubject);
  307. if (isset($sBody)) $oLog->Set('body', $sBody);
  308. $oLog->DBInsertNoReload();
  309. }
  310. }
  311. }
  312. ?>