PageRenderTime 29ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/extensions/SemanticTasks/SemanticTasks.classes.php

https://github.com/ChuguluGames/mediawiki-svn
PHP | 439 lines | 288 code | 75 blank | 76 comment | 49 complexity | 5c19c3d73248cbc7c5f37f423e87fe2c MD5 | raw file
  1. <?php
  2. if ( !defined( 'MEDIAWIKI' ) ) {
  3. echo "Not a valid entry point";
  4. exit( 1 );
  5. }
  6. if ( !defined( 'SMW_VERSION' ) ) {
  7. echo "This extension requires Semantic MediaWiki to be installed.";
  8. exit( 1 );
  9. }
  10. // constants for message type
  11. define( "NEWTASK", 0 );
  12. define( "UPDATE", 1 );
  13. define( "ASSIGNED", 2 );
  14. define( "CLOSED", 3 );
  15. /**
  16. * This class handles the creation and sending of notification emails.
  17. */
  18. class SemanticTasksMailer {
  19. private static $task_assignees;
  20. private static $task_status;
  21. function findOldValues( &$article, &$user, &$text, &$summary, $minor, $watch, $sectionanchor, &$flags ) {
  22. $title = $article->getTitle();
  23. $title_text = $title->getFullText();
  24. $assignees = self::getAssignees( 'Assigned to', $title_text, $user );
  25. $status = self::getStatus( 'Status', $title_text, $user );
  26. self::printDebug( "Old assignees: ", $assignees );
  27. self::printDebug( "Old status: " , $status );
  28. self::$task_assignees = $assignees;
  29. if ( count( $status ) > 0 ) {
  30. self::$task_status = $status[0];
  31. } else {
  32. self::$task_status = "";
  33. }
  34. return true;
  35. }
  36. function mailAssigneesUpdatedTask( $article, $current_user, $text, $summary, $minoredit, $watchthis, $sectionanchor, $flags, $revision ) {
  37. if ( !$minoredit ) {
  38. // Get the revision count to determine if new article
  39. $rev = $article->estimateRevisionCount();
  40. if ( $rev == 1 ) {
  41. $title = $article->getTitle();
  42. if ( $title->isTalkPage() ) {
  43. $status = UPDATE;
  44. } else {
  45. $status = NEWTASK;
  46. }
  47. } else {
  48. $status = UPDATE;
  49. }
  50. self::mailAssignees( $article, $text, $current_user, $status );
  51. }
  52. return true;
  53. }
  54. static function mailAssignees( $article, $text, $user, $status ) {
  55. self::printDebug( "Saved assignees:", self::$task_assignees );
  56. self::printDebug( "Saved task status: " . self::$task_status );
  57. $title = $article->getTitle();
  58. $title_text = $title->getPrefixedText();
  59. self::printDebug( "Title text: $title_text" );
  60. $assignees_to_task = array();
  61. $current_assignees = self::getAssignees( 'Assigned to', $title_text, $user );
  62. self::printDebug( "Previous assignees: ", self::$task_assignees );
  63. self::printDebug( "New assignees: ", $current_assignees );
  64. foreach ( $current_assignees as $assignee ) {
  65. if ( !in_array( $assignee, self::$task_assignees ) ) {
  66. array_push( $assignees_to_task, $assignee );
  67. }
  68. }
  69. self::printDebug( "Assignees to task: ", $assignees_to_task );
  70. // Send notification of an assigned task to assignees
  71. // Treat task as new
  72. $assignees_to_task = self::getAssigneeAddresses( $assignees_to_task );
  73. self::mailNotification( $assignees_to_task, $text, $title, $user, ASSIGNED );
  74. // Only send group notifications on new tasks
  75. if ( $status == NEWTASK ) {
  76. $groups = self::getGroupAssignees( 'Assigned to group', $title_text, $user );
  77. } else {
  78. $groups = array();
  79. }
  80. $copies = self::getAssignees( 'Carbon copy', $title_text, $user );
  81. $current_task_status = self::getStatus( 'Status', $title_text, $user );
  82. self::printDebug( "New status: ", $current_task_status );
  83. if ( count( $current_task_status ) > 0 ) {
  84. $current_task_status = $current_task_status[0];
  85. if ( $current_task_status == "Closed" && self::$task_status != "Closed" ) {
  86. $close_mailto = self::getAssigneeAddresses( $copies );
  87. self::mailNotification( $close_mailto, $text, $title, $user, CLOSED );
  88. }
  89. }
  90. $mailto = array_merge( $current_assignees, $copies, $groups );
  91. $mailto = array_unique( $mailto );
  92. $mailto = self::getAssigneeAddresses( $mailto );
  93. // Send notifications to assignees, ccs, and groups
  94. self::mailNotification( $mailto, $text, $title, $user, $status );
  95. return true;
  96. }
  97. /**
  98. * Returns an array of properties based on $query_word
  99. * @param $query_word String: the property that designate the users to notify.
  100. */
  101. static function getAssignees( $query_word, $title_text, $user ) {
  102. // Array of assignees to return
  103. $assignee_arr = array();
  104. // get the result of the query "[[$title]][[$query_word::+]]"
  105. $properties_to_display = array();
  106. $properties_to_display[0] = $query_word;
  107. $results = self::getQueryResults( "[[$title_text]][[$query_word::+]]", $properties_to_display, false );
  108. // In theory, there is only one row
  109. while ( $row = $results->getNext() ) {
  110. $task_assignees = $row[0];
  111. }
  112. // If not any row, do nothing
  113. if ( !empty( $task_assignees ) ) {
  114. while ( $task_assignee = $task_assignees->getNextObject() ) {
  115. $assignee_name = $task_assignee->getTitle();
  116. $assignee_name = $assignee_name->getText();
  117. $assignee_name = explode( ":", $assignee_name );
  118. $assignee_name = $assignee_name[0];
  119. array_push( $assignee_arr, $assignee_name );
  120. }
  121. }
  122. return $assignee_arr;
  123. }
  124. /**
  125. * Returns an array of properties based on $query_word
  126. * @param $query_word String: the property that designate the users to notify.
  127. */
  128. static function getStatus( $query_word, $title_text, $user ) {
  129. // Array of assignees to return
  130. $assignee_arr = array();
  131. // get the result of the query "[[$title]][[$query_word::+]]"
  132. $properties_to_display = array();
  133. $properties_to_display[0] = $query_word;
  134. $results = self::getQueryResults( "[[$title_text]][[$query_word::+]]", $properties_to_display, false );
  135. // In theory, there is only one row
  136. while ( $row = $results->getNext() ) {
  137. $task_assignees = $row[0];
  138. }
  139. // If not any row, do nothing
  140. if ( !empty( $task_assignees ) ) {
  141. while ( $task_assignee = $task_assignees->getNextObject() ) {
  142. $assignee_name = $task_assignee->getWikiValue();
  143. $assignee_name = $assignee_name;
  144. array_push( $assignee_arr, $assignee_name );
  145. }
  146. }
  147. return $assignee_arr;
  148. }
  149. /**
  150. /**
  151. * Returns an array of assignees based on $query_word
  152. * @param $query_word String: the property that designate the users to notify.
  153. */
  154. function getGroupAssignees( $query_word, $title_text, $user ) {
  155. // Array of assignees to return
  156. $assignee_arr = array();
  157. // get the result of the query "[[$title]][[$query_word::+]]"
  158. $properties_to_display = array();
  159. $properties_to_display[0] = $query_word;
  160. $results = self::getQueryResults( "[[$title_text]][[$query_word::+]]", $properties_to_display, false );
  161. // In theory, there is only one row
  162. while ( $row = $results->getNext() ) {
  163. $group_assignees = $row[0];
  164. }
  165. // If not any row, do nothing
  166. if ( !empty( $group_assignees ) ) {
  167. while ( $group_assignee = $group_assignees->getNextObject() ) {
  168. $group_assignee = $group_assignee->getTitle();
  169. $group_name = $group_assignee->getText();
  170. $query_word = "Has assignee";
  171. $properties_to_display = array();
  172. $properties_to_display[0] = $query_word;
  173. self::printDebug( $group_name );
  174. $results = self::getQueryResults( "[[$group_name]][[$query_word::+]]", $properties_to_display, false );
  175. // In theory, there is only one row
  176. while ( $row = $results->getNext() ) {
  177. $task_assignees = $row[0];
  178. }
  179. if ( !empty( $task_assignees ) ) {
  180. while ( $task_assignee = $task_assignees->getNextObject() ) {
  181. $assignee_name = $task_assignee->getTitle();
  182. $assignee_name = $assignee_name->getText();
  183. $assignee_name = explode( ":", $assignee_name );
  184. $assignee_name = $assignee_name[0];
  185. self::printDebug( "Groupadd: " . $assignee_name );
  186. array_push( $assignee_arr, $assignee_name );
  187. }
  188. }
  189. }
  190. }
  191. return $assignee_arr;
  192. }
  193. static function getAssigneeAddresses( $assignees ) {
  194. $assignee_arr = array();
  195. foreach ( $assignees as $assignee_name ) {
  196. $assignee = User::newFromName( $assignee_name );
  197. // if assignee is the current user, do nothing
  198. # if ( $assignee->getID() != $user->getID() ) {
  199. $assignee_mail = new MailAddress( $assignee->getEmail(), $assignee_name );
  200. array_push( $assignee_arr, $assignee_mail );
  201. self::printDebug( $assignee_name );
  202. # }
  203. }
  204. return $assignee_arr;
  205. }
  206. /**
  207. * Sends mail notifications
  208. */
  209. function mailNotification( $assignees, $text, $title, $user, $status ) {
  210. global $wgSitename;
  211. if ( !empty( $assignees ) ) {
  212. // i18n
  213. wfLoadExtensionMessages( 'SemanticTasks' );
  214. $title_text = $title->getFullText();
  215. $from = new MailAddress( $user->getEmail(), $user->getName() );
  216. $link = $title->escapeFullURL();
  217. if ( $status == NEWTASK ) {
  218. $subject = '[' . $wgSitename . '] ' . wfMsg( 'semantictasks-newtask' ) . ' ' . $title_text;
  219. $message = 'semantictasks-newtask-msg';
  220. $body = wfMsg( $message , $title_text ) . " " . $link;
  221. $body .= "\n \n" . wfMsg( 'semantictasks-text-message' ) . "\n" . $text;
  222. } elseif ( $status == UPDATE ) {
  223. $subject = '[' . $wgSitename . '] ' . wfMsg( 'semantictasks-taskupdated' ) . ' ' . $title_text;
  224. $message = 'semantictasks-updatedtoyou-msg2';
  225. $body = wfMsg( $message , $title_text ) . " " . $link;
  226. $body .= "\n \n" . wfMsg( 'semantictasks-diff-message' ) . "\n" . self::generateDiffBodyTxt( $title );
  227. } elseif ( $status == CLOSED ) {
  228. $subject = '[' . $wgSitename . '] ' . wfMsg( 'semantictasks-taskclosed' ) . ' ' . $title_text;
  229. $message = 'semantictasks-taskclosed-msg';
  230. $body = wfMsg( $message , $title_text ) . " " . $link;
  231. $body .= "\n \n" . wfMsg( 'semantictasks-text-message' ) . "\n" . $text;
  232. } else {
  233. // status == ASSIGNED
  234. $subject = '[' . $wgSitename . '] ' . wfMsg( 'semantictasks-taskassigned' ) . ' ' . $title_text;
  235. $message = 'semantictasks-assignedtoyou-msg2';
  236. $body = wfMsg( $message , $title_text ) . " " . $link;
  237. $body .= "\n \n" . wfMsg( 'semantictasks-text-message' ) . "\n" . $text;
  238. }
  239. $user_mailer = new UserMailer();
  240. $user_mailer->send( $assignees, $from, $subject, $body );
  241. }
  242. }
  243. /**
  244. * Generates a diff txt
  245. * @param Title $title
  246. * @return string
  247. */
  248. function generateDiffBodyTxt( $title ) {
  249. $revision = Revision::newFromTitle( $title, 0 );
  250. $diff = new DifferenceEngine( $title, $revision->getId(), 'prev' );
  251. // The getDiffBody() method generates html, so let's generate the txt diff manualy:
  252. global $wgContLang;
  253. $diff->loadText();
  254. $otext = str_replace( "\r\n", "\n", $diff->mOldtext );
  255. $ntext = str_replace( "\r\n", "\n", $diff->mNewtext );
  256. $ota = explode( "\n", $wgContLang->segmentForDiff( $otext ) );
  257. $nta = explode( "\n", $wgContLang->segmentForDiff( $ntext ) );
  258. // We use here the php diff engine included in MediaWiki
  259. $diffs = new Diff( $ota, $nta );
  260. // And we ask for a txt formatted diff
  261. $formatter = new UnifiedDiffFormatter();
  262. $diff_text = $wgContLang->unsegmentForDiff( $formatter->format( $diffs ) );
  263. return $diff_text;
  264. }
  265. /**
  266. * This function returns to results of a certain query
  267. * Thank you Yaron Koren for advices concerning this code
  268. * @param $query_string String : the query
  269. * @param $properties_to_display array(String): array of property names to display
  270. * @param $display_title Boolean : add the page title in the result
  271. * @return TODO
  272. */
  273. static function getQueryResults( $query_string, $properties_to_display, $display_title ) {
  274. // i18n
  275. wfLoadExtensionMessages( 'SemanticTasks' );
  276. // We use the Semantic MediaWiki Processor
  277. // $smwgIP is defined by Semantic MediaWiki, and we don't allow
  278. // this file to be sourced unless Semantic MediaWiki is included.
  279. global $smwgIP;
  280. include_once( $smwgIP . "/includes/SMW_QueryProcessor.php" );
  281. $params = array();
  282. $inline = true;
  283. $format = 'auto';
  284. $printlabel = "";
  285. $printouts = array();
  286. // add the page name to the printouts
  287. if ( $display_title ) {
  288. $to_push = new SMWPrintRequest( SMWPrintRequest::PRINT_THIS, $printlabel );
  289. array_push( $printouts, $to_push );
  290. }
  291. // Push the properties to display in the printout array.
  292. foreach ( $properties_to_display as $property ) {
  293. if ( class_exists( 'SMWPropertyValue' ) ) { // SMW 1.4
  294. $to_push = new SMWPrintRequest( SMWPrintRequest::PRINT_PROP, $printlabel, SMWPropertyValue::makeProperty( $property ) );
  295. } else {
  296. $to_push = new SMWPrintRequest( SMWPrintRequest::PRINT_PROP, $printlabel, Title::newFromText( $property, SMW_NS_PROPERTY ) );
  297. }
  298. array_push( $printouts, $to_push );
  299. }
  300. $query = SMWQueryProcessor::createQuery( $query_string, $params, $inline, $format, $printouts );
  301. $results = smwfGetStore()->getQueryResult( $query );
  302. return $results;
  303. }
  304. function remindAssignees( $wiki_url ) {
  305. global $wgSitename, $wgServer, $wgNoReplyAddress;
  306. $user_mailer = new UserMailer();
  307. $t = getdate();
  308. $today = date( 'F d Y', $t[0] );
  309. $query_string = "[[Reminder at::+]][[Status::New||In Progress]][[Target date::> $today]]";
  310. $properties_to_display = array( 'Reminder at', 'Assigned to', 'Target date' );
  311. $results = self::getQueryResults( $query_string, $properties_to_display, true );
  312. if ( empty( $results ) ) {
  313. return FALSE;
  314. }
  315. $sender = new MailAddress( $wgNoReplyAddress, $wgSitename );
  316. while ( $row = $results->getNext() ) {
  317. $task_name = $row[0]->getNextObject()->getTitle();
  318. $subject = '[' . $wgSitename . '] ' . wfMsg( 'semantictasks-reminder' ) . $task_name;
  319. // The following doesn't work, maybe because we use a cron job.
  320. // $link = $task_name->escapeFullURL();
  321. // So let's do it manually
  322. $link = $wiki_url . $task_name->getPartialURL();
  323. $target_date = $row[3]->getNextObject();
  324. $tg_date = new DateTime( $target_date->getShortHTMLText() );
  325. while ( $reminder = $row[1]->getNextObject() ) {
  326. $remind_me_in = $reminder->getShortHTMLText();
  327. $date = new DateTime( $today );
  328. $date->modify( "+$remind_me_in day" );
  329. if ( $tg_date-> format( 'F d Y' ) == $date-> format( 'F d Y' ) ) {
  330. global $wgLang;
  331. while ( $task_assignee = $row[2]->getNextObject() ) {
  332. $assignee_username = $task_assignee->getTitle();
  333. $assignee_user_name = explode( ":", $assignee_username );
  334. $assignee_name = $assignee_user_name[1];
  335. $assignee = User::newFromName( $assignee_name );
  336. $assignee_mail = new MailAddress( $assignee->getEmail(), $assignee_name );
  337. $body = wfMsgExt( 'semantictasks-reminder-message2', 'parsemag', $task_name, $wgLang->formatNum( $remind_me_in ), $link );
  338. $user_mailer->send( $assignee_mail, $sender, $subject, $body );
  339. }
  340. }
  341. }
  342. }
  343. return TRUE;
  344. }
  345. /**
  346. * Prints debugging information. $debugText is what you want to print, $debugVal
  347. * is the level at which you want to print the information.
  348. *
  349. * @param string $debugText
  350. * @param string $debugVal
  351. * @access private
  352. */
  353. static function printDebug( $debugText, $debugArr = null ) {
  354. global $wgSemanticTasksDebug;
  355. if ( $wgSemanticTasksDebug ) {
  356. if ( isset( $debugArr ) ) {
  357. $text = $debugText . " " . implode( "::", $debugArr );
  358. wfDebugLog( 'semantic-tasks', $text, false );
  359. } else {
  360. wfDebugLog( 'semantic-tasks', $debugText, false );
  361. }
  362. }
  363. }
  364. }