SemanticTasksMailer::mailNotification()   B
last analyzed

Complexity

Conditions 7
Paths 11

Size

Total Lines 51

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 51
rs 8.1357
c 0
b 0
f 0
cc 7
nc 11
nop 5

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
Unused Code introduced by
The parameter $summary is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $watchthis is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $sectionanchor is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
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
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
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
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
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
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
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
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
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
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
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
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
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