SemanticMediaWiki /
SemanticTasks
This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | |||
| 3 | namespace ST; |
||
| 4 | |||
| 5 | use Content; |
||
| 6 | use ContentHandler; |
||
| 7 | use Exception; |
||
| 8 | use IContextSource; |
||
| 9 | use Language; |
||
| 10 | use MediaWiki\Diff\ComplexityException; |
||
| 11 | use MWException; |
||
| 12 | use ParserOutput; |
||
| 13 | use SMW\ApplicationFactory; |
||
| 14 | use SMW\DIWikiPage; |
||
| 15 | use SMWDataItem; |
||
| 16 | use SMWPrintRequest; |
||
| 17 | use Title; |
||
| 18 | use User; |
||
| 19 | use WikiPage; |
||
| 20 | |||
| 21 | if ( !defined( 'MEDIAWIKI' ) ) { |
||
| 22 | echo 'Not a valid entry point'; |
||
| 23 | exit( 1 ); |
||
| 24 | } |
||
| 25 | |||
| 26 | if ( !defined( 'SMW_VERSION' ) ) { |
||
| 27 | echo 'This extension requires Semantic MediaWiki to be installed.'; |
||
| 28 | exit( 1 ); |
||
| 29 | } |
||
| 30 | |||
| 31 | // constants for message type |
||
| 32 | if ( !defined( 'ST_NEWTASK' ) ) { |
||
| 33 | define( 'ST_NEWTASK', 0 ); |
||
| 34 | define( 'ST_UPDATE', 1 ); |
||
| 35 | define( 'ST_ASSIGNED', 2 ); |
||
| 36 | define( 'ST_CLOSED', 3 ); |
||
| 37 | define( 'ST_UNASSIGNED', 4 ); |
||
| 38 | } |
||
| 39 | |||
| 40 | /** |
||
| 41 | * This class handles the creation and sending of notification emails. |
||
| 42 | */ |
||
| 43 | class SemanticTasksMailer { |
||
| 44 | |||
| 45 | private static $user_mailer; |
||
| 46 | |||
| 47 | /** |
||
| 48 | * Mails the assignees when the task is modified |
||
| 49 | * |
||
| 50 | * @param Assignees $assignees |
||
| 51 | * @param WikiPage $article |
||
| 52 | * @param User $current_user |
||
| 53 | * @param Content $text |
||
| 54 | * @param string $summary Unused |
||
| 55 | * @param bool $minoredit |
||
| 56 | * @param null $watchthis Unused |
||
| 57 | * @param null $sectionanchor Unused |
||
| 58 | * @param $flags |
||
| 59 | * @return boolean |
||
| 60 | * @throws ComplexityException |
||
| 61 | * @throws MWException |
||
| 62 | */ |
||
| 63 | public static function mailAssigneesUpdatedTask( Assignees $assignees, WikiPage $article, User $current_user, $text, |
||
| 64 | $summary, $minoredit, $watchthis, $sectionanchor, $flags, $revision ) { |
||
|
0 ignored issues
–
show
|
|||
| 65 | if ( $minoredit ) { |
||
| 66 | return true; |
||
| 67 | } |
||
| 68 | $status = ST_UPDATE; |
||
| 69 | if ( ( $flags & EDIT_NEW ) && !$article->getTitle()->isTalkPage() ) { |
||
| 70 | $status = ST_NEWTASK; |
||
| 71 | } |
||
| 72 | |||
| 73 | return self::mailAssignees( $article, $text, $current_user, $status, $assignees, $revision ); |
||
| 74 | } |
||
| 75 | |||
| 76 | /** |
||
| 77 | * |
||
| 78 | * @param WikiPage $article |
||
| 79 | * @param Content $content |
||
| 80 | * @param User $user |
||
| 81 | * @param integer $status |
||
| 82 | * @param Assignees $assignees |
||
| 83 | * @return boolean |
||
| 84 | * @throws ComplexityException |
||
| 85 | * @throws MWException |
||
| 86 | * @global boolean $wgSemanticTasksNotifyIfUnassigned |
||
| 87 | */ |
||
| 88 | static function mailAssignees( WikiPage $article, Content $content, User $user, $status, Assignees $assignees, |
||
|
0 ignored issues
–
show
|
|||
| 89 | $revision ) { |
||
| 90 | $text = ContentHandler::getContentText( $content ); |
||
| 91 | $title = $article->getTitle(); |
||
| 92 | |||
| 93 | // Notify those unassigned from this task |
||
| 94 | global $wgSemanticTasksNotifyIfUnassigned; |
||
| 95 | if ( $wgSemanticTasksNotifyIfUnassigned ) { |
||
| 96 | $removedAssignees = $assignees->getRemovedAssignees( $article, $revision ); |
||
| 97 | $removedAssignees = Assignees::getAssigneeAddresses( $removedAssignees ); |
||
| 98 | self::mailNotification( $removedAssignees, $text, $title, $user, ST_UNASSIGNED ); |
||
| 99 | } |
||
| 100 | |||
| 101 | // Send notification of an assigned task to assignees |
||
| 102 | // Treat task as new |
||
| 103 | $newAssignees = $assignees->getNewAssignees( $article, $revision ); |
||
| 104 | $newAssignees = Assignees::getAssigneeAddresses( $newAssignees ); |
||
| 105 | self::mailNotification( $newAssignees, $text, $title, $user, ST_ASSIGNED ); |
||
| 106 | |||
| 107 | $copies = $assignees->getCurrentCarbonCopy( $article, $revision ); |
||
| 108 | $currentStatus = $assignees->getCurrentStatus( $article, $revision ); |
||
| 109 | $oldStatus = $assignees->getSavedStatus(); |
||
| 110 | if ( $currentStatus === "Closed" && $oldStatus !== "Closed" ) { |
||
| 111 | $close_mailto = Assignees::getAssigneeAddresses( $copies ); |
||
| 112 | self::mailNotification( $close_mailto, $text, $title, $user, ST_CLOSED ); |
||
| 113 | } |
||
| 114 | |||
| 115 | $currentAssignees = $assignees->getCurrentAssignees( $article, $revision ); |
||
| 116 | |||
| 117 | // Only send group notifications on new tasks |
||
| 118 | $groups = array(); |
||
| 119 | if ( $status === ST_NEWTASK ) { |
||
| 120 | $groups = $assignees->getGroupAssignees( $article ); |
||
| 121 | } |
||
| 122 | |||
| 123 | $mailto = array_merge( $currentAssignees, $copies, $groups ); |
||
| 124 | $mailto = array_unique( $mailto ); |
||
| 125 | $mailto = Assignees::getAssigneeAddresses( $mailto ); |
||
| 126 | |||
| 127 | // Send notifications to assignees, ccs, and groups |
||
| 128 | self::mailNotification( $mailto, $text, $title, $user, $status ); |
||
| 129 | |||
| 130 | return true; |
||
| 131 | } |
||
| 132 | |||
| 133 | /** |
||
| 134 | * Sends mail notifications |
||
| 135 | * |
||
| 136 | * @param array $assignees |
||
| 137 | * @param string $text |
||
| 138 | * @param Title $title |
||
| 139 | * @param User $user |
||
| 140 | * @param integer $status |
||
| 141 | * @throws MWException |
||
| 142 | * @throws ComplexityException |
||
| 143 | * @global string $wgSitename |
||
| 144 | */ |
||
| 145 | static function mailNotification( array $assignees, $text, Title $title, User $user, $status ) { |
||
|
0 ignored issues
–
show
|
|||
| 146 | global $wgSitename; |
||
| 147 | |||
| 148 | if ( empty( $assignees ) ) { |
||
| 149 | return; |
||
| 150 | } |
||
| 151 | $title_text = $title->getFullText(); |
||
| 152 | $from = new \MailAddress( $user->getEmail(), $user->getName() ); |
||
| 153 | $link = htmlspecialchars( $title->getFullURL() ); |
||
| 154 | |||
| 155 | /** @todo This should probably be refactored */ |
||
| 156 | if ( $status == ST_NEWTASK ) { |
||
| 157 | $subject = '[' . $wgSitename . '] ' . wfMessage( 'semantictasks-newtask' )->text() . ' ' . |
||
| 158 | $title_text; |
||
| 159 | $message = 'semantictasks-newtask-msg'; |
||
| 160 | $body = wfMessage( $message, $title_text )->text() . " " . $link; |
||
| 161 | $body .= "\n \n" . wfMessage( 'semantictasks-text-message' )->text() . "\n" . $text; |
||
| 162 | } elseif ( $status == ST_UPDATE ) { |
||
| 163 | $subject = '[' . $wgSitename . '] ' . wfMessage( 'semantictasks-taskupdated' )->text() . ' ' . |
||
| 164 | $title_text; |
||
| 165 | $message = 'semantictasks-updatedtoyou-msg2'; |
||
| 166 | $body = wfMessage( $message, $title_text )->text() . " " . $link; |
||
| 167 | $body .= "\n \n" . wfMessage( 'semantictasks-diff-message' )->text() . "\n" . |
||
| 168 | self::generateDiffBodyTxt( $title ); |
||
| 169 | } elseif ( $status == ST_CLOSED ) { |
||
| 170 | $subject = '[' . $wgSitename . '] ' . wfMessage( 'semantictasks-taskclosed' )->text() . ' ' . |
||
| 171 | $title_text; |
||
| 172 | $message = 'semantictasks-taskclosed-msg'; |
||
| 173 | $body = wfMessage( $message, $title_text )->text() . " " . $link; |
||
| 174 | $body .= "\n \n" . wfMessage( 'semantictasks-text-message' )->text() . "\n" . $text; |
||
| 175 | } elseif ( $status == ST_UNASSIGNED ) { |
||
| 176 | $subject = '[' . $wgSitename . '] ' . wfMessage( 'semantictasks-taskunassigned' )->text() . ' ' . |
||
| 177 | $title_text; |
||
| 178 | $message = 'semantictasks-unassignedtoyou-msg2'; |
||
| 179 | $body = wfMessage( $message, $title_text )->text() . " " . $link; |
||
| 180 | $body .= "\n \n" . wfMessage( 'semantictasks-text-message' )->text() . "\n" . $text; |
||
| 181 | } else { |
||
| 182 | // status == ASSIGNED |
||
| 183 | $subject = '[' . $wgSitename . '] ' . wfMessage( 'semantictasks-taskassigned' )->text() . ' ' . |
||
| 184 | $title_text; |
||
| 185 | $message = 'semantictasks-assignedtoyou-msg2'; |
||
| 186 | $body = wfMessage( $message, $title_text )->text() . " " . $link; |
||
| 187 | $body .= "\n \n" . wfMessage( 'semantictasks-text-message' )->text() . "\n" . $text; |
||
| 188 | } |
||
| 189 | |||
| 190 | if (!self::$user_mailer) { |
||
| 191 | self::$user_mailer = new \ST\UserMailer(new \UserMailer()); |
||
| 192 | } |
||
| 193 | |||
| 194 | self::$user_mailer->send( $assignees, $from, $subject, $body ); |
||
| 195 | } |
||
| 196 | |||
| 197 | static function setUserMailer(\ST\UserMailer $user_mailer) { |
||
|
0 ignored issues
–
show
|
|||
| 198 | self::$user_mailer = $user_mailer; |
||
| 199 | } |
||
| 200 | |||
| 201 | /** |
||
| 202 | * Generates a diff txt |
||
| 203 | * |
||
| 204 | * Code is similar to DifferenceEngine::generateTextDiffBody |
||
| 205 | * @param Title $title |
||
| 206 | * @param IContextSource $context |
||
| 207 | * @return string |
||
| 208 | * @throws ComplexityException |
||
| 209 | * @throws MWException |
||
| 210 | */ |
||
| 211 | static function generateDiffBodyTxt( Title $title, IContextSource $context = null) { |
||
|
0 ignored issues
–
show
|
|||
| 212 | $revision = \Revision::newFromTitle( $title, 0 ); |
||
| 213 | if ($revision === null) { |
||
| 214 | return ''; |
||
| 215 | } |
||
| 216 | /** @todo The first parameter should be a Context. */ |
||
| 217 | $diff = new \DifferenceEngine( $context, $revision->getId(), 'prev' ); |
||
| 218 | // The DifferenceEngine::getDiffBody() method generates html, |
||
| 219 | // so let's generate the txt diff manually: |
||
| 220 | global $wgContLang; |
||
| 221 | $diff->loadText(); |
||
| 222 | $otext = ''; |
||
| 223 | $ntext = ''; |
||
| 224 | if ( version_compare( MW_VERSION, '1.32', '<' ) ) { |
||
| 225 | $otext = str_replace( "\r\n", "\n", \ContentHandler::getContentText( $diff->mOldContent ) ); |
||
| 226 | $ntext = str_replace( "\r\n", "\n", \ContentHandler::getContentText( $diff->mNewContent ) ); |
||
| 227 | } else { |
||
| 228 | if ($diff->getOldRevision()) { |
||
| 229 | $otext = str_replace( "\r\n", "\n", ContentHandler::getContentText( $diff->getOldRevision()->getContent( 'main' ) ) ); |
||
| 230 | } |
||
| 231 | if ($diff->getNewRevision()) { |
||
| 232 | $ntext = str_replace( "\r\n", "\n", ContentHandler::getContentText( $diff->getNewRevision()->getContent( 'main' ) ) ); |
||
| 233 | } |
||
| 234 | } |
||
| 235 | $ota = explode( "\n", $wgContLang->segmentForDiff( $otext ) ); |
||
| 236 | $nta = explode( "\n", $wgContLang->segmentForDiff( $ntext ) ); |
||
| 237 | // We use here the php diff engine included in MediaWiki |
||
| 238 | $diffs = new \Diff( $ota, $nta ); |
||
| 239 | // And we ask for a txt formatted diff |
||
| 240 | $formatter = new \UnifiedDiffFormatter(); |
||
| 241 | $diff_text = $wgContLang->unsegmentForDiff( $formatter->format( $diffs ) ); |
||
| 242 | return $diff_text; |
||
| 243 | } |
||
| 244 | |||
| 245 | /** |
||
| 246 | * Run by the maintenance script to remind the assignees |
||
| 247 | * |
||
| 248 | * @return boolean |
||
| 249 | * @throws Exception |
||
| 250 | * @global string $wgSitename |
||
| 251 | * @global Language $wgLang |
||
| 252 | */ |
||
| 253 | static function remindAssignees() { |
||
|
0 ignored issues
–
show
|
|||
| 254 | global $wgSitename; |
||
| 255 | global $stgPropertyReminderAt; |
||
| 256 | global $stgPropertyAssignedTo; |
||
| 257 | global $stgPropertyTargetDate; |
||
| 258 | global $stgPropertyStatus; |
||
| 259 | |||
| 260 | # Make this equal to midnight. Rational is that if users set today as the Target date with |
||
| 261 | # reminders set to "0" so that the reminder happens on the deadline, the reminders will go |
||
| 262 | # out even though now it is after the beginning of today and technically past the |
||
| 263 | # target date. |
||
| 264 | $today = wfTimestamp( TS_ISO_8601, strtotime( 'today midnight' ) ); |
||
| 265 | |||
| 266 | # Get tasks where a reminder is called for, whose status is either new or in progress, and |
||
| 267 | # whose target date is in the future. |
||
| 268 | $query_string = "[[$stgPropertyReminderAt::+]][[$stgPropertyStatus::New||In Progress]][[$stgPropertyTargetDate::≥ $today]]"; |
||
| 269 | $properties_to_display = array( $stgPropertyReminderAt, $stgPropertyAssignedTo, $stgPropertyTargetDate ); |
||
| 270 | |||
| 271 | $results = Query::getQueryResults( $query_string, $properties_to_display, true ); |
||
| 272 | if ( empty( $results ) ) { |
||
| 273 | return false; |
||
| 274 | } |
||
| 275 | |||
| 276 | while ( $row = $results->getNext() ) { |
||
| 277 | $task_name = $row[0]->getNextObject()->getTitle(); |
||
| 278 | $subject = '[' . $wgSitename . '] ' . wfMessage( 'semantictasks-reminder' )->text() . $task_name; |
||
| 279 | // The following doesn't work, maybe because we use a cron job. |
||
| 280 | // $link = $task_name->getFullURL(); |
||
| 281 | // So let's do it manually |
||
| 282 | //$link = $wiki_url . $task_name->getPartialURL(); |
||
| 283 | // You know what? Let's try it again. |
||
| 284 | $link = $task_name->getFullURL(); |
||
| 285 | |||
| 286 | $target_date = $row[3]->getNextObject(); |
||
| 287 | $tg_date = new DateTime( $target_date->getShortHTMLText() ); |
||
| 288 | |||
| 289 | while ( $reminder = $row[1]->getNextObject() ) { |
||
| 290 | $remind_me_in = $reminder->getShortHTMLText(); |
||
| 291 | $date = new DateTime( 'today midnight' ); |
||
| 292 | $date->modify( "+$remind_me_in day" ); |
||
| 293 | |||
| 294 | if ( $tg_date === $date ) { |
||
| 295 | global $wgLang; |
||
| 296 | while ( $task_assignee = $row[2]->getNextObject() ) { |
||
| 297 | $assignee_username = $task_assignee->getTitle()->getText(); |
||
| 298 | $assignee = User::newFromName( $assignee_username ); |
||
| 299 | |||
| 300 | $body = wfMessage( 'semantictasks-reminder-message2', $task_name, |
||
| 301 | $wgLang->formatNum( $remind_me_in ), $link )->text(); |
||
| 302 | $assignee->sendMail( $subject, $body ); |
||
| 303 | } |
||
| 304 | } |
||
| 305 | } |
||
| 306 | } |
||
| 307 | return true; |
||
| 308 | } |
||
| 309 | |||
| 310 | /** |
||
| 311 | * Prints debugging information. $debugText is what you want to print, $debugVal |
||
| 312 | * is the level at which you want to print the information. |
||
| 313 | * |
||
| 314 | * @global boolean $wgSemanticTasksDebug |
||
| 315 | * @param string $debugText |
||
| 316 | * @param string $debugArr |
||
| 317 | * @access private |
||
| 318 | */ |
||
| 319 | static function printDebug( $debugText, $debugArr = null ) { |
||
|
0 ignored issues
–
show
|
|||
| 320 | global $wgSemanticTasksDebug; |
||
| 321 | |||
| 322 | if ( $wgSemanticTasksDebug ) { |
||
| 323 | if ( isset( $debugArr ) ) { |
||
| 324 | $text = $debugText . ' ' . implode( '::', $debugArr ); |
||
| 325 | wfDebugLog( 'semantic-tasks', $text, false ); |
||
| 326 | } else { |
||
| 327 | wfDebugLog( 'semantic-tasks', $debugText, false ); |
||
| 328 | } |
||
| 329 | } |
||
| 330 | } |
||
| 331 | |||
| 332 | } |
||
| 333 |
This check looks from parameters that have been defined for a function or method, but which are not used in the method body.