activity.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. <?php
  2. /**
  3. * @author Joas Schilling <nickvergessen@owncloud.com>
  4. * @author Morris Jobke <hey@morrisjobke.de>
  5. * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
  6. *
  7. * @copyright Copyright (c) 2016, ownCloud, Inc.
  8. * @license AGPL-3.0
  9. *
  10. * This code is free software: you can redistribute it and/or modify
  11. * it under the terms of the GNU Affero General Public License, version 3,
  12. * as published by the Free Software Foundation.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU Affero General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Affero General Public License, version 3,
  20. * along with this program. If not, see <http://www.gnu.org/licenses/>
  21. *
  22. */
  23. namespace OCA\Files;
  24. use OCP\IDBConnection;
  25. use OCP\L10N\IFactory;
  26. use OCP\Activity\IExtension;
  27. use OCP\Activity\IManager;
  28. use OCP\IConfig;
  29. use OCP\IL10N;
  30. use OCP\IURLGenerator;
  31. class Activity implements IExtension {
  32. const APP_FILES = 'files';
  33. const FILTER_FILES = 'files';
  34. const FILTER_FAVORITES = 'files_favorites';
  35. const TYPE_SHARE_CREATED = 'file_created';
  36. const TYPE_SHARE_CHANGED = 'file_changed';
  37. const TYPE_SHARE_DELETED = 'file_deleted';
  38. const TYPE_SHARE_RESTORED = 'file_restored';
  39. const TYPE_FAVORITES = 'files_favorites';
  40. /** @var IL10N */
  41. protected $l;
  42. /** @var IFactory */
  43. protected $languageFactory;
  44. /** @var IURLGenerator */
  45. protected $URLGenerator;
  46. /** @var \OCP\Activity\IManager */
  47. protected $activityManager;
  48. /** @var \OCP\IDBConnection */
  49. protected $connection;
  50. /** @var \OCP\IConfig */
  51. protected $config;
  52. /** @var \OCA\Files\ActivityHelper */
  53. protected $helper;
  54. /**
  55. * @param IFactory $languageFactory
  56. * @param IURLGenerator $URLGenerator
  57. * @param IManager $activityManager
  58. * @param ActivityHelper $helper
  59. * @param IDBConnection $connection
  60. * @param IConfig $config
  61. */
  62. public function __construct(IFactory $languageFactory, IURLGenerator $URLGenerator, IManager $activityManager, ActivityHelper $helper, IDBConnection $connection, IConfig $config) {
  63. $this->languageFactory = $languageFactory;
  64. $this->URLGenerator = $URLGenerator;
  65. $this->l = $this->getL10N();
  66. $this->activityManager = $activityManager;
  67. $this->helper = $helper;
  68. $this->connection = $connection;
  69. $this->config = $config;
  70. }
  71. /**
  72. * @param string|null $languageCode
  73. * @return IL10N
  74. */
  75. protected function getL10N($languageCode = null) {
  76. return $this->languageFactory->get(self::APP_FILES, $languageCode);
  77. }
  78. /**
  79. * The extension can return an array of additional notification types.
  80. * If no additional types are to be added false is to be returned
  81. *
  82. * @param string $languageCode
  83. * @return array|false Array "stringID of the type" => "translated string description for the setting"
  84. * or Array "stringID of the type" => [
  85. * 'desc' => "translated string description for the setting"
  86. * 'methods' => [self::METHOD_*],
  87. * ]
  88. */
  89. public function getNotificationTypes($languageCode) {
  90. $l = $this->getL10N($languageCode);
  91. return [
  92. self::TYPE_SHARE_CREATED => (string) $l->t('A new file or folder has been <strong>created</strong>'),
  93. self::TYPE_SHARE_CHANGED => (string) $l->t('A file or folder has been <strong>changed</strong>'),
  94. self::TYPE_FAVORITES => [
  95. 'desc' => (string) $l->t('Limit notifications about creation and changes to your <strong>favorite files</strong> <em>(Stream only)</em>'),
  96. 'methods' => [self::METHOD_STREAM],
  97. ],
  98. self::TYPE_SHARE_DELETED => (string) $l->t('A file or folder has been <strong>deleted</strong>'),
  99. self::TYPE_SHARE_RESTORED => (string) $l->t('A file or folder has been <strong>restored</strong>'),
  100. ];
  101. }
  102. /**
  103. * For a given method additional types to be displayed in the settings can be returned.
  104. * In case no additional types are to be added false is to be returned.
  105. *
  106. * @param string $method
  107. * @return array|false
  108. */
  109. public function getDefaultTypes($method) {
  110. if ($method === self::METHOD_STREAM) {
  111. $settings = array();
  112. $settings[] = self::TYPE_SHARE_CREATED;
  113. $settings[] = self::TYPE_SHARE_CHANGED;
  114. $settings[] = self::TYPE_SHARE_DELETED;
  115. $settings[] = self::TYPE_SHARE_RESTORED;
  116. return $settings;
  117. }
  118. return false;
  119. }
  120. /**
  121. * The extension can translate a given message to the requested languages.
  122. * If no translation is available false is to be returned.
  123. *
  124. * @param string $app
  125. * @param string $text
  126. * @param array $params
  127. * @param boolean $stripPath
  128. * @param boolean $highlightParams
  129. * @param string $languageCode
  130. * @return string|false
  131. */
  132. public function translate($app, $text, $params, $stripPath, $highlightParams, $languageCode) {
  133. if ($app !== self::APP_FILES) {
  134. return false;
  135. }
  136. $l = $this->getL10N($languageCode);
  137. if ($this->activityManager->isFormattingFilteredObject()) {
  138. $translation = $this->translateShort($text, $l, $params);
  139. if ($translation !== false) {
  140. return $translation;
  141. }
  142. }
  143. return $this->translateLong($text, $l, $params);
  144. }
  145. /**
  146. * @param string $text
  147. * @param IL10N $l
  148. * @param array $params
  149. * @return string|false
  150. */
  151. protected function translateLong($text, IL10N $l, array $params) {
  152. switch ($text) {
  153. case 'created_self':
  154. return (string) $l->t('You created %1$s', $params);
  155. case 'created_by':
  156. return (string) $l->t('%2$s created %1$s', $params);
  157. case 'created_public':
  158. return (string) $l->t('%1$s was created in a public folder', $params);
  159. case 'changed_self':
  160. return (string) $l->t('You changed %1$s', $params);
  161. case 'changed_by':
  162. return (string) $l->t('%2$s changed %1$s', $params);
  163. case 'deleted_self':
  164. return (string) $l->t('You deleted %1$s', $params);
  165. case 'deleted_by':
  166. return (string) $l->t('%2$s deleted %1$s', $params);
  167. case 'restored_self':
  168. return (string) $l->t('You restored %1$s', $params);
  169. case 'restored_by':
  170. return (string) $l->t('%2$s restored %1$s', $params);
  171. default:
  172. return false;
  173. }
  174. }
  175. /**
  176. * @param string $text
  177. * @param IL10N $l
  178. * @param array $params
  179. * @return string|false
  180. */
  181. protected function translateShort($text, IL10N $l, array $params) {
  182. switch ($text) {
  183. case 'changed_by':
  184. return (string) $l->t('Changed by %2$s', $params);
  185. case 'deleted_by':
  186. return (string) $l->t('Deleted by %2$s', $params);
  187. case 'restored_by':
  188. return (string) $l->t('Restored by %2$s', $params);
  189. default:
  190. return false;
  191. }
  192. }
  193. /**
  194. * The extension can define the type of parameters for translation
  195. *
  196. * Currently known types are:
  197. * * file => will strip away the path of the file and add a tooltip with it
  198. * * username => will add the avatar of the user
  199. *
  200. * @param string $app
  201. * @param string $text
  202. * @return array|false
  203. */
  204. function getSpecialParameterList($app, $text) {
  205. if ($app === self::APP_FILES) {
  206. switch ($text) {
  207. case 'created_self':
  208. case 'created_by':
  209. case 'created_public':
  210. case 'changed_self':
  211. case 'changed_by':
  212. case 'deleted_self':
  213. case 'deleted_by':
  214. case 'restored_self':
  215. case 'restored_by':
  216. return [
  217. 0 => 'file',
  218. 1 => 'username',
  219. ];
  220. }
  221. }
  222. return false;
  223. }
  224. /**
  225. * A string naming the css class for the icon to be used can be returned.
  226. * If no icon is known for the given type false is to be returned.
  227. *
  228. * @param string $type
  229. * @return string|false
  230. */
  231. public function getTypeIcon($type) {
  232. switch ($type) {
  233. case self::TYPE_SHARE_CHANGED:
  234. return 'icon-change';
  235. case self::TYPE_SHARE_CREATED:
  236. return 'icon-add-color';
  237. case self::TYPE_SHARE_DELETED:
  238. return 'icon-delete-color';
  239. default:
  240. return false;
  241. }
  242. }
  243. /**
  244. * The extension can define the parameter grouping by returning the index as integer.
  245. * In case no grouping is required false is to be returned.
  246. *
  247. * @param array $activity
  248. * @return integer|false
  249. */
  250. public function getGroupParameter($activity) {
  251. if ($activity['app'] === self::APP_FILES) {
  252. switch ($activity['subject']) {
  253. case 'created_self':
  254. case 'created_by':
  255. case 'changed_self':
  256. case 'changed_by':
  257. case 'deleted_self':
  258. case 'deleted_by':
  259. case 'restored_self':
  260. case 'restored_by':
  261. return 0;
  262. }
  263. }
  264. return false;
  265. }
  266. /**
  267. * The extension can define additional navigation entries. The array returned has to contain two keys 'top'
  268. * and 'apps' which hold arrays with the relevant entries.
  269. * If no further entries are to be added false is no be returned.
  270. *
  271. * @return array|false
  272. */
  273. public function getNavigation() {
  274. return [
  275. 'top' => [
  276. self::FILTER_FAVORITES => [
  277. 'id' => self::FILTER_FAVORITES,
  278. 'name' => (string) $this->l->t('Favorites'),
  279. 'url' => $this->URLGenerator->linkToRoute('activity.Activities.showList', ['filter' => self::FILTER_FAVORITES]),
  280. ],
  281. ],
  282. 'apps' => [
  283. self::FILTER_FILES => [
  284. 'id' => self::FILTER_FILES,
  285. 'name' => (string) $this->l->t('Files'),
  286. 'url' => $this->URLGenerator->linkToRoute('activity.Activities.showList', ['filter' => self::FILTER_FILES]),
  287. ],
  288. ],
  289. ];
  290. }
  291. /**
  292. * The extension can check if a customer filter (given by a query string like filter=abc) is valid or not.
  293. *
  294. * @param string $filterValue
  295. * @return boolean
  296. */
  297. public function isFilterValid($filterValue) {
  298. return $filterValue === self::FILTER_FILES || $filterValue === self::FILTER_FAVORITES;
  299. }
  300. /**
  301. * The extension can filter the types based on the filter if required.
  302. * In case no filter is to be applied false is to be returned unchanged.
  303. *
  304. * @param array $types
  305. * @param string $filter
  306. * @return array|false
  307. */
  308. public function filterNotificationTypes($types, $filter) {
  309. if ($filter === self::FILTER_FILES || $filter === self::FILTER_FAVORITES) {
  310. return array_intersect([
  311. self::TYPE_SHARE_CREATED,
  312. self::TYPE_SHARE_CHANGED,
  313. self::TYPE_SHARE_DELETED,
  314. self::TYPE_SHARE_RESTORED,
  315. ], $types);
  316. }
  317. return false;
  318. }
  319. /**
  320. * For a given filter the extension can specify the sql query conditions including parameters for that query.
  321. * In case the extension does not know the filter false is to be returned.
  322. * The query condition and the parameters are to be returned as array with two elements.
  323. * E.g. return array('`app` = ? and `message` like ?', array('mail', 'ownCloud%'));
  324. *
  325. * @param string $filter
  326. * @return array|false
  327. */
  328. public function getQueryForFilter($filter) {
  329. $user = $this->activityManager->getCurrentUserId();
  330. // Display actions from all files
  331. if ($filter === self::FILTER_FILES) {
  332. return ['`app` = ?', [self::APP_FILES]];
  333. }
  334. if (!$user) {
  335. // Remaining filters only work with a user/token
  336. return false;
  337. }
  338. // Display actions from favorites only
  339. if ($filter === self::FILTER_FAVORITES || in_array($filter, ['all', 'by', 'self']) && $this->userSettingFavoritesOnly($user)) {
  340. try {
  341. $favorites = $this->helper->getFavoriteFilePaths($user);
  342. } catch (\RuntimeException $e) {
  343. // Too many favorites, can not put them into one query anymore...
  344. return ['`app` = ?', [self::APP_FILES]];
  345. }
  346. /*
  347. * Display activities only, when they are not `type` create/change
  348. * or `file` is a favorite or in a favorite folder
  349. */
  350. $parameters = $fileQueryList = [];
  351. $parameters[] = self::APP_FILES;
  352. $parameters[] = self::APP_FILES;
  353. $fileQueryList[] = '(`type` <> ? AND `type` <> ?)';
  354. $parameters[] = self::TYPE_SHARE_CREATED;
  355. $parameters[] = self::TYPE_SHARE_CHANGED;
  356. foreach ($favorites['items'] as $favorite) {
  357. $fileQueryList[] = '`file` = ?';
  358. $parameters[] = $favorite;
  359. }
  360. foreach ($favorites['folders'] as $favorite) {
  361. $fileQueryList[] = '`file` LIKE ?';
  362. $parameters[] = $this->connection->escapeLikeParameter($favorite) . '/%';
  363. }
  364. return [
  365. ' CASE '
  366. . 'WHEN `app` <> ? THEN 1 '
  367. . 'WHEN `app` = ? AND (' . implode(' OR ', $fileQueryList) . ') THEN 1 '
  368. . 'ELSE 0 '
  369. . 'END = 1 ',
  370. $parameters,
  371. ];
  372. }
  373. return false;
  374. }
  375. /**
  376. * Is the file actions favorite limitation enabled?
  377. *
  378. * @param string $user
  379. * @return bool
  380. */
  381. protected function userSettingFavoritesOnly($user) {
  382. return (bool) $this->config->getUserValue($user, 'activity', 'notify_' . self::METHOD_STREAM . '_' . self::TYPE_FAVORITES, false);
  383. }
  384. }