Completed
Pull Request — master (#1926)
by Joas
26:30 queued 13:36
created

Extension::convertParameterToComment()   B

Complexity

Conditions 6
Paths 20

Size

Total Lines 33
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 21
nc 20
nop 1
dl 0
loc 33
rs 8.439
c 0
b 0
f 0
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Joas Schilling <[email protected]>
6
 *
7
 * @license AGPL-3.0
8
 *
9
 * This code is free software: you can redistribute it and/or modify
10
 * it under the terms of the GNU Affero General Public License, version 3,
11
 * as published by the Free Software Foundation.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
 * GNU Affero General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Affero General Public License, version 3,
19
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
20
 *
21
 */
22
23
namespace OCA\Comments\Activity;
24
25
use OCP\Activity\IExtension;
26
use OCP\Activity\IManager;
27
use OCP\Comments\ICommentsManager;
28
use OCP\Comments\NotFoundException;
29
use OCP\IL10N;
30
use OCP\IURLGenerator;
31
use OCP\L10N\IFactory;
32
use OCP\Util;
33
34
/**
35
 * Class Extension
36
 *
37
 * @package OCA\Comments\Activity
38
 */
39
class Extension implements IExtension {
40
	const APP_NAME = 'comments';
41
42
	const ADD_COMMENT_SUBJECT = 'add_comment_subject';
43
	const ADD_COMMENT_MESSAGE = 'add_comment_message';
44
45
	/** @var IFactory */
46
	protected $languageFactory;
47
48
	/** @var IManager */
49
	protected $activityManager;
50
51
	/** @var ICommentsManager */
52
	protected $commentsManager;
53
54
	/** @var IURLGenerator */
55
	protected $URLGenerator;
56
57
	/**
58
	 * @param IFactory $languageFactory
59
	 * @param IManager $activityManager
60
	 * @param ICommentsManager $commentsManager
61
	 * @param IURLGenerator $URLGenerator
62
	 */
63
	public function __construct(IFactory $languageFactory, IManager $activityManager, ICommentsManager $commentsManager, IURLGenerator $URLGenerator) {
64
		$this->languageFactory = $languageFactory;
65
		$this->activityManager = $activityManager;
66
		$this->commentsManager = $commentsManager;
67
		$this->URLGenerator = $URLGenerator;
68
	}
69
70
	protected function getL10N($languageCode = null) {
71
		return $this->languageFactory->get(self::APP_NAME, $languageCode);
72
	}
73
74
	/**
75
	 * The extension can return an array of additional notification types.
76
	 * If no additional types are to be added false is to be returned
77
	 *
78
	 * @param string $languageCode
79
	 * @return array|false
80
	 */
81
	public function getNotificationTypes($languageCode) {
82
		$l = $this->getL10N($languageCode);
83
84
		return array(
85
			self::APP_NAME => [
86
				'desc' => (string) $l->t('<strong>Comments</strong> for files'),
87
				'methods' => [self::METHOD_MAIL, self::METHOD_STREAM],
88
			],
89
		);
90
	}
91
92
	/**
93
	 * For a given method additional types to be displayed in the settings can be returned.
94
	 * In case no additional types are to be added false is to be returned.
95
	 *
96
	 * @param string $method
97
	 * @return array|false
98
	 */
99
	public function getDefaultTypes($method) {
100
		return $method === self::METHOD_STREAM ? [self::APP_NAME] : false;
101
	}
102
103
	/**
104
	 * A string naming the css class for the icon to be used can be returned.
105
	 * If no icon is known for the given type false is to be returned.
106
	 *
107
	 * @param string $type
108
	 * @return string|false
109
	 */
110
	public function getTypeIcon($type) {
111
		switch ($type) {
112
			case self::APP_NAME:
113
				return 'icon-comment';
114
		}
115
116
		return false;
117
	}
118
119
	/**
120
	 * The extension can translate a given message to the requested languages.
121
	 * If no translation is available false is to be returned.
122
	 *
123
	 * @param string $app
124
	 * @param string $text
125
	 * @param array $params
126
	 * @param boolean $stripPath
127
	 * @param boolean $highlightParams
128
	 * @param string $languageCode
129
	 * @return string|false
130
	 */
131 View Code Duplication
	public function translate($app, $text, $params, $stripPath, $highlightParams, $languageCode) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
132
		if ($app !== self::APP_NAME) {
133
			return false;
134
		}
135
136
		$l = $this->getL10N($languageCode);
137
138
		if ($this->activityManager->isFormattingFilteredObject()) {
139
			$translation = $this->translateShort($text, $l, $params);
140
			if ($translation !== false) {
141
				return $translation;
142
			}
143
		}
144
145
		return $this->translateLong($text, $l, $params);
146
	}
147
148
	/**
149
	 * @param string $text
150
	 * @param IL10N $l
151
	 * @param array $params
152
	 * @return bool|string
153
	 */
154
	protected function translateShort($text, IL10N $l, array $params) {
155
156
		switch ($text) {
157
			case self::ADD_COMMENT_SUBJECT:
158
				if ($this->authorIsCurrentUser($params[0])) {
159
					return (string) $l->t('You commented');
160
				}
161
				return (string) $l->t('%1$s commented', $params);
162
			case self::ADD_COMMENT_MESSAGE:
163
				return $this->convertParameterToComment($params[0]);
164
		}
165
166
		return false;
167
	}
168
169
	/**
170
	 * @param string $text
171
	 * @param IL10N $l
172
	 * @param array $params
173
	 * @return bool|string
174
	 */
175
	protected function translateLong($text, IL10N $l, array $params) {
176
177
		switch ($text) {
178
			case self::ADD_COMMENT_SUBJECT:
179
				if ($this->authorIsCurrentUser($params[0])) {
180
					return (string) $l->t('You commented on %2$s', $params);
181
				}
182
				return (string) $l->t('%1$s commented on %2$s', $params);
183
			case self::ADD_COMMENT_MESSAGE:
184
				return $this->convertParameterToComment($params[0]);
185
		}
186
187
		return false;
188
	}
189
190
	/**
191
	 * Check if the author is the current user
192
	 *
193
	 * @param string $user Parameter e.g. `<user display-name="admin">admin</user>`
194
	 * @return bool
195
	 */
196
	protected function authorIsCurrentUser($user) {
197
		try {
198
			return strip_tags($user) === $this->activityManager->getCurrentUserId();
199
		} catch (\UnexpectedValueException $e) {
200
			return false;
201
		}
202
	}
203
204
	/**
205
	 * The extension can define the type of parameters for translation
206
	 *
207
	 * Currently known types are:
208
	 * * file		=> will strip away the path of the file and add a tooltip with it
209
	 * * username	=> will add the avatar of the user
210
	 *
211
	 * @param string $app
212
	 * @param string $text
213
	 * @return array|false
214
	 */
215
	public function getSpecialParameterList($app, $text) {
216
		if ($app === self::APP_NAME) {
217
			switch ($text) {
218
				case self::ADD_COMMENT_SUBJECT:
219
					return [
220
						0 => 'username',
221
						1 => 'file',
222
					];
223
			}
224
		}
225
226
		return false;
227
	}
228
229
	/**
230
	 * The extension can define the parameter grouping by returning the index as integer.
231
	 * In case no grouping is required false is to be returned.
232
	 *
233
	 * @param array $activity
234
	 * @return integer|false
235
	 */
236
	public function getGroupParameter($activity) {
237
		return false;
238
	}
239
240
	/**
241
	 * The extension can define additional navigation entries. The array returned has to contain two keys 'top'
242
	 * and 'apps' which hold arrays with the relevant entries.
243
	 * If no further entries are to be added false is no be returned.
244
	 *
245
	 * @return array|false
246
	 */
247 View Code Duplication
	public function getNavigation() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
248
		$l = $this->getL10N();
249
		return [
250
			'apps' => [
251
				self::APP_NAME => [
252
					'id' => self::APP_NAME,
253
					'icon' => 'icon-comment',
254
					'name' => (string) $l->t('Comments'),
255
					'url' => $this->URLGenerator->linkToRoute('activity.Activities.showList', ['filter' => self::APP_NAME]),
256
				],
257
			],
258
			'top' => [],
259
		];
260
	}
261
262
	/**
263
	 * The extension can check if a custom filter (given by a query string like filter=abc) is valid or not.
264
	 *
265
	 * @param string $filterValue
266
	 * @return boolean
267
	 */
268
	public function isFilterValid($filterValue) {
269
		return $filterValue === self::APP_NAME;
270
	}
271
272
	/**
273
	 * The extension can filter the types based on the filter if required.
274
	 * In case no filter is to be applied false is to be returned unchanged.
275
	 *
276
	 * @param array $types
277
	 * @param string $filter
278
	 * @return array|false
279
	 */
280
	public function filterNotificationTypes($types, $filter) {
281
		if ($filter === self::APP_NAME) {
282
			return array_intersect($types, [self::APP_NAME]);
283
		}
284
		return false;
285
	}
286
287
	/**
288
	 * For a given filter the extension can specify the sql query conditions including parameters for that query.
289
	 * In case the extension does not know the filter false is to be returned.
290
	 * The query condition and the parameters are to be returned as array with two elements.
291
	 * E.g. return array('`app` = ? and `message` like ?', array('mail', 'ownCloud%'));
292
	 *
293
	 * @param string $filter
294
	 * @return array|false
295
	 */
296
	public function getQueryForFilter($filter) {
297
		return false;
298
	}
299
300
	/**
301
	 * @param string $parameter
302
	 * @return string
303
	 */
304
	protected function convertParameterToComment($parameter) {
305
		if (preg_match('/^\<parameter\>(\d*)\<\/parameter\>$/', $parameter, $matches)) {
306
			try {
307
				$comment = $this->commentsManager->get((int) $matches[1]);
308
				$message = $comment->getMessage();
309
				$message = str_replace("\n", '<br />', str_replace(['<', '>'], ['&lt;', '&gt;'], $message));
310
311
				foreach ($comment->getMentions() as $mention) {
312
					if ($mention['type'] !== 'user') {
313
						continue;
314
					}
315
316
					try {
317
						$displayName = $this->commentsManager->resolveDisplayName($mention['type'], $mention['id']);
318
					} catch (\OutOfBoundsException $e) {
319
						// No displayname, upon client's discretion what to display.
320
						$displayName = $mention['id'];
321
					}
322
323
					$message = preg_replace(
324
						'/(^|\s)(' . '@' . $mention['id'] . ')(\b)/',
325
						'${1}' . $this->regexSafeUser($mention['id'], $displayName) . '${3}',
326
						$message
327
					);
328
				}
329
				return $message;
330
			} catch (NotFoundException $e) {
331
				return '';
332
			}
333
		}
334
335
		return '';
336
	}
337
338
	protected function regexSafeUser($uid, $displayName) {
339
		// FIXME evil internal API hackery, do NOT copy this
340
		return str_replace('$', '\$', '<user display-name="' . Util::sanitizeHTML($displayName) . '">' . Util::sanitizeHTML($uid) . '</user>');
341
	}
342
}
343