| @@ -35,41 +35,41 @@ discard block | ||
| 35 | 35 | |
| 36 | 36 | $application = new Application(); | 
| 37 | 37 | $application->registerRoutes($this, [ | 
| 38 | - 'routes' => [ | |
| 39 | - ['name' => 'lost#email', 'url' => '/lostpassword/email', 'verb' => 'POST'], | |
| 40 | -		['name' => 'lost#resetform', 'url' => '/lostpassword/reset/form/{token}/{userId}', 'verb' => 'GET'], | |
| 41 | -		['name' => 'lost#setPassword', 'url' => '/lostpassword/set/{token}/{userId}', 'verb' => 'POST'], | |
| 42 | - ['name' => 'user#getDisplayNames', 'url' => '/displaynames', 'verb' => 'POST'], | |
| 43 | -		['name' => 'avatar#getAvatar', 'url' => '/avatar/{userId}/{size}', 'verb' => 'GET'], | |
| 44 | - ['name' => 'avatar#deleteAvatar', 'url' => '/avatar/', 'verb' => 'DELETE'], | |
| 45 | - ['name' => 'avatar#postCroppedAvatar', 'url' => '/avatar/cropped', 'verb' => 'POST'], | |
| 46 | - ['name' => 'avatar#getTmpAvatar', 'url' => '/avatar/tmp', 'verb' => 'GET'], | |
| 47 | - ['name' => 'avatar#postAvatar', 'url' => '/avatar/', 'verb' => 'POST'], | |
| 48 | - ['name' => 'login#tryLogin', 'url' => '/login', 'verb' => 'POST'], | |
| 49 | - ['name' => 'login#confirmPassword', 'url' => '/login/confirm', 'verb' => 'POST'], | |
| 50 | - ['name' => 'login#showLoginForm', 'url' => '/login', 'verb' => 'GET'], | |
| 51 | - ['name' => 'login#logout', 'url' => '/logout', 'verb' => 'GET'], | |
| 52 | - ['name' => 'ClientFlowLogin#showAuthPickerPage', 'url' => '/login/flow', 'verb' => 'GET'], | |
| 53 | - ['name' => 'ClientFlowLogin#redirectPage', 'url' => '/login/flow/redirect', 'verb' => 'GET'], | |
| 54 | - ['name' => 'ClientFlowLogin#generateAppPassword', 'url' => '/login/flow', 'verb' => 'POST'], | |
| 55 | - ['name' => 'TwoFactorChallenge#selectChallenge', 'url' => '/login/selectchallenge', 'verb' => 'GET'], | |
| 56 | -		['name' => 'TwoFactorChallenge#showChallenge', 'url' => '/login/challenge/{challengeProviderId}', 'verb' => 'GET'], | |
| 57 | -		['name' => 'TwoFactorChallenge#solveChallenge', 'url' => '/login/challenge/{challengeProviderId}', 'verb' => 'POST'], | |
| 58 | - ['name' => 'OCJS#getConfig', 'url' => '/core/js/oc.js', 'verb' => 'GET'], | |
| 59 | - ['name' => 'Preview#getPreview', 'url' => '/core/preview', 'verb' => 'GET'], | |
| 60 | - ['name' => 'Preview#getPreview', 'url' => '/core/preview.png', 'verb' => 'GET'], | |
| 61 | -		['name' => 'Css#getCss', 'url' => '/css/{appName}/{fileName}', 'verb' => 'GET'], | |
| 62 | -		['name' => 'Js#getJs', 'url' => '/js/{appName}/{fileName}', 'verb' => 'GET'], | |
| 63 | - ['name' => 'contactsMenu#index', 'url' => '/contactsmenu/contacts', 'verb' => 'POST'], | |
| 64 | - ['name' => 'contactsMenu#findOne', 'url' => '/contactsmenu/findOne', 'verb' => 'POST'], | |
| 65 | - ['name' => 'AutoComplete#get', 'url' => 'autocomplete/get', 'verb' => 'GET'] | |
| 66 | - ], | |
| 67 | - 'ocs' => [ | |
| 68 | - ['root' => '/cloud', 'name' => 'OCS#getCapabilities', 'url' => '/capabilities', 'verb' => 'GET'], | |
| 69 | - ['root' => '', 'name' => 'OCS#getConfig', 'url' => '/config', 'verb' => 'GET'], | |
| 70 | - ['root' => '/person', 'name' => 'OCS#personCheck', 'url' => '/check', 'verb' => 'POST'], | |
| 71 | -		['root' => '/identityproof', 'name' => 'OCS#getIdentityProof', 'url' => '/key/{cloudId}', 'verb' => 'GET'], | |
| 72 | - ], | |
| 38 | + 'routes' => [ | |
| 39 | + ['name' => 'lost#email', 'url' => '/lostpassword/email', 'verb' => 'POST'], | |
| 40 | +        ['name' => 'lost#resetform', 'url' => '/lostpassword/reset/form/{token}/{userId}', 'verb' => 'GET'], | |
| 41 | +        ['name' => 'lost#setPassword', 'url' => '/lostpassword/set/{token}/{userId}', 'verb' => 'POST'], | |
| 42 | + ['name' => 'user#getDisplayNames', 'url' => '/displaynames', 'verb' => 'POST'], | |
| 43 | +        ['name' => 'avatar#getAvatar', 'url' => '/avatar/{userId}/{size}', 'verb' => 'GET'], | |
| 44 | + ['name' => 'avatar#deleteAvatar', 'url' => '/avatar/', 'verb' => 'DELETE'], | |
| 45 | + ['name' => 'avatar#postCroppedAvatar', 'url' => '/avatar/cropped', 'verb' => 'POST'], | |
| 46 | + ['name' => 'avatar#getTmpAvatar', 'url' => '/avatar/tmp', 'verb' => 'GET'], | |
| 47 | + ['name' => 'avatar#postAvatar', 'url' => '/avatar/', 'verb' => 'POST'], | |
| 48 | + ['name' => 'login#tryLogin', 'url' => '/login', 'verb' => 'POST'], | |
| 49 | + ['name' => 'login#confirmPassword', 'url' => '/login/confirm', 'verb' => 'POST'], | |
| 50 | + ['name' => 'login#showLoginForm', 'url' => '/login', 'verb' => 'GET'], | |
| 51 | + ['name' => 'login#logout', 'url' => '/logout', 'verb' => 'GET'], | |
| 52 | + ['name' => 'ClientFlowLogin#showAuthPickerPage', 'url' => '/login/flow', 'verb' => 'GET'], | |
| 53 | + ['name' => 'ClientFlowLogin#redirectPage', 'url' => '/login/flow/redirect', 'verb' => 'GET'], | |
| 54 | + ['name' => 'ClientFlowLogin#generateAppPassword', 'url' => '/login/flow', 'verb' => 'POST'], | |
| 55 | + ['name' => 'TwoFactorChallenge#selectChallenge', 'url' => '/login/selectchallenge', 'verb' => 'GET'], | |
| 56 | +        ['name' => 'TwoFactorChallenge#showChallenge', 'url' => '/login/challenge/{challengeProviderId}', 'verb' => 'GET'], | |
| 57 | +        ['name' => 'TwoFactorChallenge#solveChallenge', 'url' => '/login/challenge/{challengeProviderId}', 'verb' => 'POST'], | |
| 58 | + ['name' => 'OCJS#getConfig', 'url' => '/core/js/oc.js', 'verb' => 'GET'], | |
| 59 | + ['name' => 'Preview#getPreview', 'url' => '/core/preview', 'verb' => 'GET'], | |
| 60 | + ['name' => 'Preview#getPreview', 'url' => '/core/preview.png', 'verb' => 'GET'], | |
| 61 | +        ['name' => 'Css#getCss', 'url' => '/css/{appName}/{fileName}', 'verb' => 'GET'], | |
| 62 | +        ['name' => 'Js#getJs', 'url' => '/js/{appName}/{fileName}', 'verb' => 'GET'], | |
| 63 | + ['name' => 'contactsMenu#index', 'url' => '/contactsmenu/contacts', 'verb' => 'POST'], | |
| 64 | + ['name' => 'contactsMenu#findOne', 'url' => '/contactsmenu/findOne', 'verb' => 'POST'], | |
| 65 | + ['name' => 'AutoComplete#get', 'url' => 'autocomplete/get', 'verb' => 'GET'] | |
| 66 | + ], | |
| 67 | + 'ocs' => [ | |
| 68 | + ['root' => '/cloud', 'name' => 'OCS#getCapabilities', 'url' => '/capabilities', 'verb' => 'GET'], | |
| 69 | + ['root' => '', 'name' => 'OCS#getConfig', 'url' => '/config', 'verb' => 'GET'], | |
| 70 | + ['root' => '/person', 'name' => 'OCS#personCheck', 'url' => '/check', 'verb' => 'POST'], | |
| 71 | +        ['root' => '/identityproof', 'name' => 'OCS#getIdentityProof', 'url' => '/key/{cloudId}', 'verb' => 'GET'], | |
| 72 | + ], | |
| 73 | 73 | ]); | 
| 74 | 74 | |
| 75 | 75 | // Post installation check | 
| @@ -78,15 +78,15 @@ discard block | ||
| 78 | 78 | // Core ajax actions | 
| 79 | 79 | // Search | 
| 80 | 80 |  $this->create('search_ajax_search', '/core/search') | 
| 81 | -	->actionInclude('core/search/ajax/search.php'); | |
| 81 | +    ->actionInclude('core/search/ajax/search.php'); | |
| 82 | 82 | // Routing | 
| 83 | 83 |  $this->create('core_ajax_update', '/core/ajax/update.php') | 
| 84 | -	->actionInclude('core/ajax/update.php'); | |
| 84 | +    ->actionInclude('core/ajax/update.php'); | |
| 85 | 85 | |
| 86 | 86 | // File routes | 
| 87 | 87 |  $this->create('files.viewcontroller.showFile', '/f/{fileid}')->action(function($urlParams) { | 
| 88 | - $app = new \OCA\Files\AppInfo\Application($urlParams); | |
| 89 | -	$app->dispatch('ViewController', 'index'); | |
| 88 | + $app = new \OCA\Files\AppInfo\Application($urlParams); | |
| 89 | +    $app->dispatch('ViewController', 'index'); | |
| 90 | 90 | }); | 
| 91 | 91 | |
| 92 | 92 | // Call routes | 
| @@ -95,57 +95,57 @@ discard block | ||
| 95 | 95 | * @suppress PhanUndeclaredClassMethod | 
| 96 | 96 | */ | 
| 97 | 97 |  $this->create('spreed.pagecontroller.showCall', '/call/{token}')->action(function($urlParams) { | 
| 98 | -	if (class_exists(\OCA\Spreed\AppInfo\Application::class, false)) { | |
| 99 | - $app = new \OCA\Spreed\AppInfo\Application($urlParams); | |
| 100 | -		$app->dispatch('PageController', 'index'); | |
| 101 | -	} else { | |
| 102 | -		throw new \OC\HintException('App spreed is not enabled'); | |
| 103 | - } | |
| 98 | +    if (class_exists(\OCA\Spreed\AppInfo\Application::class, false)) { | |
| 99 | + $app = new \OCA\Spreed\AppInfo\Application($urlParams); | |
| 100 | +        $app->dispatch('PageController', 'index'); | |
| 101 | +    } else { | |
| 102 | +        throw new \OC\HintException('App spreed is not enabled'); | |
| 103 | + } | |
| 104 | 104 | }); | 
| 105 | 105 | |
| 106 | 106 | // Sharing routes | 
| 107 | 107 |  $this->create('files_sharing.sharecontroller.showShare', '/s/{token}')->action(function($urlParams) { | 
| 108 | -	if (class_exists(\OCA\Files_Sharing\AppInfo\Application::class, false)) { | |
| 109 | - $app = new \OCA\Files_Sharing\AppInfo\Application($urlParams); | |
| 110 | -		$app->dispatch('ShareController', 'showShare'); | |
| 111 | -	} else { | |
| 112 | -		throw new \OC\HintException('App file sharing is not enabled'); | |
| 113 | - } | |
| 108 | +    if (class_exists(\OCA\Files_Sharing\AppInfo\Application::class, false)) { | |
| 109 | + $app = new \OCA\Files_Sharing\AppInfo\Application($urlParams); | |
| 110 | +        $app->dispatch('ShareController', 'showShare'); | |
| 111 | +    } else { | |
| 112 | +        throw new \OC\HintException('App file sharing is not enabled'); | |
| 113 | + } | |
| 114 | 114 | }); | 
| 115 | 115 |  $this->create('files_sharing.sharecontroller.authenticate', '/s/{token}/authenticate')->post()->action(function($urlParams) { | 
| 116 | -	if (class_exists(\OCA\Files_Sharing\AppInfo\Application::class, false)) { | |
| 117 | - $app = new \OCA\Files_Sharing\AppInfo\Application($urlParams); | |
| 118 | -		$app->dispatch('ShareController', 'authenticate'); | |
| 119 | -	} else { | |
| 120 | -		throw new \OC\HintException('App file sharing is not enabled'); | |
| 121 | - } | |
| 116 | +    if (class_exists(\OCA\Files_Sharing\AppInfo\Application::class, false)) { | |
| 117 | + $app = new \OCA\Files_Sharing\AppInfo\Application($urlParams); | |
| 118 | +        $app->dispatch('ShareController', 'authenticate'); | |
| 119 | +    } else { | |
| 120 | +        throw new \OC\HintException('App file sharing is not enabled'); | |
| 121 | + } | |
| 122 | 122 | }); | 
| 123 | 123 |  $this->create('files_sharing.sharecontroller.showAuthenticate', '/s/{token}/authenticate')->get()->action(function($urlParams) { | 
| 124 | -	if (class_exists(\OCA\Files_Sharing\AppInfo\Application::class, false)) { | |
| 125 | - $app = new \OCA\Files_Sharing\AppInfo\Application($urlParams); | |
| 126 | -		$app->dispatch('ShareController', 'showAuthenticate'); | |
| 127 | -	} else { | |
| 128 | -		throw new \OC\HintException('App file sharing is not enabled'); | |
| 129 | - } | |
| 124 | +    if (class_exists(\OCA\Files_Sharing\AppInfo\Application::class, false)) { | |
| 125 | + $app = new \OCA\Files_Sharing\AppInfo\Application($urlParams); | |
| 126 | +        $app->dispatch('ShareController', 'showAuthenticate'); | |
| 127 | +    } else { | |
| 128 | +        throw new \OC\HintException('App file sharing is not enabled'); | |
| 129 | + } | |
| 130 | 130 | }); | 
| 131 | 131 |  $this->create('files_sharing.sharecontroller.downloadShare', '/s/{token}/download')->get()->action(function($urlParams) { | 
| 132 | -	if (class_exists(\OCA\Files_Sharing\AppInfo\Application::class, false)) { | |
| 133 | - $app = new \OCA\Files_Sharing\AppInfo\Application($urlParams); | |
| 134 | -		$app->dispatch('ShareController', 'downloadShare'); | |
| 135 | -	} else { | |
| 136 | -		throw new \OC\HintException('App file sharing is not enabled'); | |
| 137 | - } | |
| 132 | +    if (class_exists(\OCA\Files_Sharing\AppInfo\Application::class, false)) { | |
| 133 | + $app = new \OCA\Files_Sharing\AppInfo\Application($urlParams); | |
| 134 | +        $app->dispatch('ShareController', 'downloadShare'); | |
| 135 | +    } else { | |
| 136 | +        throw new \OC\HintException('App file sharing is not enabled'); | |
| 137 | + } | |
| 138 | 138 | }); | 
| 139 | 139 |  $this->create('files_sharing.publicpreview.directLink', '/s/{token}/preview')->get()->action(function($urlParams) { | 
| 140 | -	if (class_exists(\OCA\Files_Sharing\AppInfo\Application::class, false)) { | |
| 141 | - $app = new \OCA\Files_Sharing\AppInfo\Application($urlParams); | |
| 142 | -		$app->dispatch('PublicPreviewController', 'directLink'); | |
| 143 | -	} else { | |
| 144 | -		throw new \OC\HintException('App file sharing is not enabled'); | |
| 145 | - } | |
| 140 | +    if (class_exists(\OCA\Files_Sharing\AppInfo\Application::class, false)) { | |
| 141 | + $app = new \OCA\Files_Sharing\AppInfo\Application($urlParams); | |
| 142 | +        $app->dispatch('PublicPreviewController', 'directLink'); | |
| 143 | +    } else { | |
| 144 | +        throw new \OC\HintException('App file sharing is not enabled'); | |
| 145 | + } | |
| 146 | 146 | }); | 
| 147 | 147 | |
| 148 | 148 | // used for heartbeat | 
| 149 | 149 |  $this->create('heartbeat', '/heartbeat')->action(function(){ | 
| 150 | - // do nothing | |
| 150 | + // do nothing | |
| 151 | 151 | }); | 
| @@ -35,277 +35,277 @@ | ||
| 35 | 35 | */ | 
| 36 | 36 |  interface ICommentsManager { | 
| 37 | 37 | |
| 38 | - /** | |
| 39 | - * @const DELETED_USER type and id for a user that has been deleted | |
| 40 | - * @see deleteReferencesOfActor | |
| 41 | - * @since 9.0.0 | |
| 42 | - * | |
| 43 | - * To be used as replacement for user type actors in deleteReferencesOfActor(). | |
| 44 | - * | |
| 45 | - * User interfaces shall show "Deleted user" as display name, if needed. | |
| 46 | - */ | |
| 47 | - const DELETED_USER = 'deleted_users'; | |
| 38 | + /** | |
| 39 | + * @const DELETED_USER type and id for a user that has been deleted | |
| 40 | + * @see deleteReferencesOfActor | |
| 41 | + * @since 9.0.0 | |
| 42 | + * | |
| 43 | + * To be used as replacement for user type actors in deleteReferencesOfActor(). | |
| 44 | + * | |
| 45 | + * User interfaces shall show "Deleted user" as display name, if needed. | |
| 46 | + */ | |
| 47 | + const DELETED_USER = 'deleted_users'; | |
| 48 | 48 | |
| 49 | - /** | |
| 50 | - * returns a comment instance | |
| 51 | - * | |
| 52 | - * @param string $id the ID of the comment | |
| 53 | - * @return IComment | |
| 54 | - * @throws NotFoundException | |
| 55 | - * @since 9.0.0 | |
| 56 | - */ | |
| 57 | - public function get($id); | |
| 49 | + /** | |
| 50 | + * returns a comment instance | |
| 51 | + * | |
| 52 | + * @param string $id the ID of the comment | |
| 53 | + * @return IComment | |
| 54 | + * @throws NotFoundException | |
| 55 | + * @since 9.0.0 | |
| 56 | + */ | |
| 57 | + public function get($id); | |
| 58 | 58 | |
| 59 | - /** | |
| 60 | - * returns the comment specified by the id and all it's child comments | |
| 61 | - * | |
| 62 | - * @param string $id | |
| 63 | - * @param int $limit max number of entries to return, 0 returns all | |
| 64 | - * @param int $offset the start entry | |
| 65 | - * @return array | |
| 66 | - * @since 9.0.0 | |
| 67 | - * | |
| 68 | - * The return array looks like this | |
| 69 | - * [ | |
| 70 | - * 'comment' => IComment, // root comment | |
| 71 | - * 'replies' => | |
| 72 | - * [ | |
| 73 | - * 0 => | |
| 74 | - * [ | |
| 75 | - * 'comment' => IComment, | |
| 76 | - * 'replies' => | |
| 77 | - * [ | |
| 78 | - * 0 => | |
| 79 | - * [ | |
| 80 | - * 'comment' => IComment, | |
| 81 | - * 'replies' => [ … ] | |
| 82 | - * ], | |
| 83 | - * … | |
| 84 | - * ] | |
| 85 | - * ] | |
| 86 | - * 1 => | |
| 87 | - * [ | |
| 88 | - * 'comment' => IComment, | |
| 89 | - * 'replies'=> [ … ] | |
| 90 | - * ], | |
| 91 | - * … | |
| 92 | - * ] | |
| 93 | - * ] | |
| 94 | - */ | |
| 95 | - public function getTree($id, $limit = 0, $offset = 0); | |
| 59 | + /** | |
| 60 | + * returns the comment specified by the id and all it's child comments | |
| 61 | + * | |
| 62 | + * @param string $id | |
| 63 | + * @param int $limit max number of entries to return, 0 returns all | |
| 64 | + * @param int $offset the start entry | |
| 65 | + * @return array | |
| 66 | + * @since 9.0.0 | |
| 67 | + * | |
| 68 | + * The return array looks like this | |
| 69 | + * [ | |
| 70 | + * 'comment' => IComment, // root comment | |
| 71 | + * 'replies' => | |
| 72 | + * [ | |
| 73 | + * 0 => | |
| 74 | + * [ | |
| 75 | + * 'comment' => IComment, | |
| 76 | + * 'replies' => | |
| 77 | + * [ | |
| 78 | + * 0 => | |
| 79 | + * [ | |
| 80 | + * 'comment' => IComment, | |
| 81 | + * 'replies' => [ … ] | |
| 82 | + * ], | |
| 83 | + * … | |
| 84 | + * ] | |
| 85 | + * ] | |
| 86 | + * 1 => | |
| 87 | + * [ | |
| 88 | + * 'comment' => IComment, | |
| 89 | + * 'replies'=> [ … ] | |
| 90 | + * ], | |
| 91 | + * … | |
| 92 | + * ] | |
| 93 | + * ] | |
| 94 | + */ | |
| 95 | + public function getTree($id, $limit = 0, $offset = 0); | |
| 96 | 96 | |
| 97 | - /** | |
| 98 | - * returns comments for a specific object (e.g. a file). | |
| 99 | - * | |
| 100 | - * The sort order is always newest to oldest. | |
| 101 | - * | |
| 102 | - * @param string $objectType the object type, e.g. 'files' | |
| 103 | - * @param string $objectId the id of the object | |
| 104 | - * @param int $limit optional, number of maximum comments to be returned. if | |
| 105 | - * not specified, all comments are returned. | |
| 106 | - * @param int $offset optional, starting point | |
| 107 | - * @param \DateTime|null $notOlderThan optional, timestamp of the oldest comments | |
| 108 | - * that may be returned | |
| 109 | - * @return IComment[] | |
| 110 | - * @since 9.0.0 | |
| 111 | - */ | |
| 112 | - public function getForObject( | |
| 113 | - $objectType, | |
| 114 | - $objectId, | |
| 115 | - $limit = 0, | |
| 116 | - $offset = 0, | |
| 117 | - \DateTime $notOlderThan = null | |
| 118 | - ); | |
| 97 | + /** | |
| 98 | + * returns comments for a specific object (e.g. a file). | |
| 99 | + * | |
| 100 | + * The sort order is always newest to oldest. | |
| 101 | + * | |
| 102 | + * @param string $objectType the object type, e.g. 'files' | |
| 103 | + * @param string $objectId the id of the object | |
| 104 | + * @param int $limit optional, number of maximum comments to be returned. if | |
| 105 | + * not specified, all comments are returned. | |
| 106 | + * @param int $offset optional, starting point | |
| 107 | + * @param \DateTime|null $notOlderThan optional, timestamp of the oldest comments | |
| 108 | + * that may be returned | |
| 109 | + * @return IComment[] | |
| 110 | + * @since 9.0.0 | |
| 111 | + */ | |
| 112 | + public function getForObject( | |
| 113 | + $objectType, | |
| 114 | + $objectId, | |
| 115 | + $limit = 0, | |
| 116 | + $offset = 0, | |
| 117 | + \DateTime $notOlderThan = null | |
| 118 | + ); | |
| 119 | 119 | |
| 120 | - /** | |
| 121 | - * @param $objectType string the object type, e.g. 'files' | |
| 122 | - * @param $objectId string the id of the object | |
| 123 | - * @param \DateTime|null $notOlderThan optional, timestamp of the oldest comments | |
| 124 | - * that may be returned | |
| 125 | - * @return Int | |
| 126 | - * @since 9.0.0 | |
| 127 | - */ | |
| 128 | - public function getNumberOfCommentsForObject($objectType, $objectId, \DateTime $notOlderThan = null); | |
| 120 | + /** | |
| 121 | + * @param $objectType string the object type, e.g. 'files' | |
| 122 | + * @param $objectId string the id of the object | |
| 123 | + * @param \DateTime|null $notOlderThan optional, timestamp of the oldest comments | |
| 124 | + * that may be returned | |
| 125 | + * @return Int | |
| 126 | + * @since 9.0.0 | |
| 127 | + */ | |
| 128 | + public function getNumberOfCommentsForObject($objectType, $objectId, \DateTime $notOlderThan = null); | |
| 129 | 129 | |
| 130 | - /** | |
| 131 | - * Get the number of unread comments for all files in a folder | |
| 132 | - * | |
| 133 | - * @param int $folderId | |
| 134 | - * @param IUser $user | |
| 135 | - * @return array [$fileId => $unreadCount] | |
| 136 | - * @since 12.0.0 | |
| 137 | - */ | |
| 138 | - public function getNumberOfUnreadCommentsForFolder($folderId, IUser $user); | |
| 130 | + /** | |
| 131 | + * Get the number of unread comments for all files in a folder | |
| 132 | + * | |
| 133 | + * @param int $folderId | |
| 134 | + * @param IUser $user | |
| 135 | + * @return array [$fileId => $unreadCount] | |
| 136 | + * @since 12.0.0 | |
| 137 | + */ | |
| 138 | + public function getNumberOfUnreadCommentsForFolder($folderId, IUser $user); | |
| 139 | 139 | |
| 140 | - /** | |
| 141 | - * Get the actor types and ID that commented in the tree specified by the ID | |
| 142 | - * | |
| 143 | - * @param string $id | |
| 144 | - * @return array | |
| 145 | - * @since 13.0.0 | |
| 146 | - * | |
| 147 | - * The return array looks like this: | |
| 148 | - * | |
| 149 | - * [ | |
| 150 | - * 'users' => [ | |
| 151 | - * 'alice', | |
| 152 | - * 'bob', | |
| 153 | - * ], | |
| 154 | - * 'robots' => [ | |
| 155 | - * 'r2-d2', | |
| 156 | - * 'c-3po', | |
| 157 | - * ] | |
| 158 | - * ] | |
| 159 | - */ | |
| 160 | - public function getActorsInTree($id); | |
| 140 | + /** | |
| 141 | + * Get the actor types and ID that commented in the tree specified by the ID | |
| 142 | + * | |
| 143 | + * @param string $id | |
| 144 | + * @return array | |
| 145 | + * @since 13.0.0 | |
| 146 | + * | |
| 147 | + * The return array looks like this: | |
| 148 | + * | |
| 149 | + * [ | |
| 150 | + * 'users' => [ | |
| 151 | + * 'alice', | |
| 152 | + * 'bob', | |
| 153 | + * ], | |
| 154 | + * 'robots' => [ | |
| 155 | + * 'r2-d2', | |
| 156 | + * 'c-3po', | |
| 157 | + * ] | |
| 158 | + * ] | |
| 159 | + */ | |
| 160 | + public function getActorsInTree($id); | |
| 161 | 161 | |
| 162 | - /** | |
| 163 | - * creates a new comment and returns it. At this point of time, it is not | |
| 164 | - * saved in the used data storage. Use save() after setting other fields | |
| 165 | - * of the comment (e.g. message or verb). | |
| 166 | - * | |
| 167 | - * @param string $actorType the actor type (e.g. 'users') | |
| 168 | - * @param string $actorId a user id | |
| 169 | - * @param string $objectType the object type the comment is attached to | |
| 170 | - * @param string $objectId the object id the comment is attached to | |
| 171 | - * @return IComment | |
| 172 | - * @since 9.0.0 | |
| 173 | - */ | |
| 174 | - public function create($actorType, $actorId, $objectType, $objectId); | |
| 162 | + /** | |
| 163 | + * creates a new comment and returns it. At this point of time, it is not | |
| 164 | + * saved in the used data storage. Use save() after setting other fields | |
| 165 | + * of the comment (e.g. message or verb). | |
| 166 | + * | |
| 167 | + * @param string $actorType the actor type (e.g. 'users') | |
| 168 | + * @param string $actorId a user id | |
| 169 | + * @param string $objectType the object type the comment is attached to | |
| 170 | + * @param string $objectId the object id the comment is attached to | |
| 171 | + * @return IComment | |
| 172 | + * @since 9.0.0 | |
| 173 | + */ | |
| 174 | + public function create($actorType, $actorId, $objectType, $objectId); | |
| 175 | 175 | |
| 176 | - /** | |
| 177 | - * permanently deletes the comment specified by the ID | |
| 178 | - * | |
| 179 | - * When the comment has child comments, their parent ID will be changed to | |
| 180 | - * the parent ID of the item that is to be deleted. | |
| 181 | - * | |
| 182 | - * @param string $id | |
| 183 | - * @return bool | |
| 184 | - * @since 9.0.0 | |
| 185 | - */ | |
| 186 | - public function delete($id); | |
| 176 | + /** | |
| 177 | + * permanently deletes the comment specified by the ID | |
| 178 | + * | |
| 179 | + * When the comment has child comments, their parent ID will be changed to | |
| 180 | + * the parent ID of the item that is to be deleted. | |
| 181 | + * | |
| 182 | + * @param string $id | |
| 183 | + * @return bool | |
| 184 | + * @since 9.0.0 | |
| 185 | + */ | |
| 186 | + public function delete($id); | |
| 187 | 187 | |
| 188 | - /** | |
| 189 | - * saves the comment permanently | |
| 190 | - * | |
| 191 | - * if the supplied comment has an empty ID, a new entry comment will be | |
| 192 | - * saved and the instance updated with the new ID. | |
| 193 | - * | |
| 194 | - * Otherwise, an existing comment will be updated. | |
| 195 | - * | |
| 196 | - * Throws NotFoundException when a comment that is to be updated does not | |
| 197 | - * exist anymore at this point of time. | |
| 198 | - * | |
| 199 | - * @param IComment $comment | |
| 200 | - * @return bool | |
| 201 | - * @throws NotFoundException | |
| 202 | - * @since 9.0.0 | |
| 203 | - */ | |
| 204 | - public function save(IComment $comment); | |
| 188 | + /** | |
| 189 | + * saves the comment permanently | |
| 190 | + * | |
| 191 | + * if the supplied comment has an empty ID, a new entry comment will be | |
| 192 | + * saved and the instance updated with the new ID. | |
| 193 | + * | |
| 194 | + * Otherwise, an existing comment will be updated. | |
| 195 | + * | |
| 196 | + * Throws NotFoundException when a comment that is to be updated does not | |
| 197 | + * exist anymore at this point of time. | |
| 198 | + * | |
| 199 | + * @param IComment $comment | |
| 200 | + * @return bool | |
| 201 | + * @throws NotFoundException | |
| 202 | + * @since 9.0.0 | |
| 203 | + */ | |
| 204 | + public function save(IComment $comment); | |
| 205 | 205 | |
| 206 | - /** | |
| 207 | - * removes references to specific actor (e.g. on user delete) of a comment. | |
| 208 | - * The comment itself must not get lost/deleted. | |
| 209 | - * | |
| 210 | - * A 'users' type actor (type and id) should get replaced by the | |
| 211 | - * value of the DELETED_USER constant of this interface. | |
| 212 | - * | |
| 213 | - * @param string $actorType the actor type (e.g. 'users') | |
| 214 | - * @param string $actorId a user id | |
| 215 | - * @return boolean | |
| 216 | - * @since 9.0.0 | |
| 217 | - */ | |
| 218 | - public function deleteReferencesOfActor($actorType, $actorId); | |
| 206 | + /** | |
| 207 | + * removes references to specific actor (e.g. on user delete) of a comment. | |
| 208 | + * The comment itself must not get lost/deleted. | |
| 209 | + * | |
| 210 | + * A 'users' type actor (type and id) should get replaced by the | |
| 211 | + * value of the DELETED_USER constant of this interface. | |
| 212 | + * | |
| 213 | + * @param string $actorType the actor type (e.g. 'users') | |
| 214 | + * @param string $actorId a user id | |
| 215 | + * @return boolean | |
| 216 | + * @since 9.0.0 | |
| 217 | + */ | |
| 218 | + public function deleteReferencesOfActor($actorType, $actorId); | |
| 219 | 219 | |
| 220 | - /** | |
| 221 | - * deletes all comments made of a specific object (e.g. on file delete) | |
| 222 | - * | |
| 223 | - * @param string $objectType the object type (e.g. 'files') | |
| 224 | - * @param string $objectId e.g. the file id | |
| 225 | - * @return boolean | |
| 226 | - * @since 9.0.0 | |
| 227 | - */ | |
| 228 | - public function deleteCommentsAtObject($objectType, $objectId); | |
| 220 | + /** | |
| 221 | + * deletes all comments made of a specific object (e.g. on file delete) | |
| 222 | + * | |
| 223 | + * @param string $objectType the object type (e.g. 'files') | |
| 224 | + * @param string $objectId e.g. the file id | |
| 225 | + * @return boolean | |
| 226 | + * @since 9.0.0 | |
| 227 | + */ | |
| 228 | + public function deleteCommentsAtObject($objectType, $objectId); | |
| 229 | 229 | |
| 230 | - /** | |
| 231 | - * sets the read marker for a given file to the specified date for the | |
| 232 | - * provided user | |
| 233 | - * | |
| 234 | - * @param string $objectType | |
| 235 | - * @param string $objectId | |
| 236 | - * @param \DateTime $dateTime | |
| 237 | - * @param \OCP\IUser $user | |
| 238 | - * @since 9.0.0 | |
| 239 | - */ | |
| 240 | - public function setReadMark($objectType, $objectId, \DateTime $dateTime, \OCP\IUser $user); | |
| 230 | + /** | |
| 231 | + * sets the read marker for a given file to the specified date for the | |
| 232 | + * provided user | |
| 233 | + * | |
| 234 | + * @param string $objectType | |
| 235 | + * @param string $objectId | |
| 236 | + * @param \DateTime $dateTime | |
| 237 | + * @param \OCP\IUser $user | |
| 238 | + * @since 9.0.0 | |
| 239 | + */ | |
| 240 | + public function setReadMark($objectType, $objectId, \DateTime $dateTime, \OCP\IUser $user); | |
| 241 | 241 | |
| 242 | - /** | |
| 243 | - * returns the read marker for a given file to the specified date for the | |
| 244 | - * provided user. It returns null, when the marker is not present, i.e. | |
| 245 | - * no comments were marked as read. | |
| 246 | - * | |
| 247 | - * @param string $objectType | |
| 248 | - * @param string $objectId | |
| 249 | - * @param \OCP\IUser $user | |
| 250 | - * @return \DateTime|null | |
| 251 | - * @since 9.0.0 | |
| 252 | - */ | |
| 253 | - public function getReadMark($objectType, $objectId, \OCP\IUser $user); | |
| 242 | + /** | |
| 243 | + * returns the read marker for a given file to the specified date for the | |
| 244 | + * provided user. It returns null, when the marker is not present, i.e. | |
| 245 | + * no comments were marked as read. | |
| 246 | + * | |
| 247 | + * @param string $objectType | |
| 248 | + * @param string $objectId | |
| 249 | + * @param \OCP\IUser $user | |
| 250 | + * @return \DateTime|null | |
| 251 | + * @since 9.0.0 | |
| 252 | + */ | |
| 253 | + public function getReadMark($objectType, $objectId, \OCP\IUser $user); | |
| 254 | 254 | |
| 255 | - /** | |
| 256 | - * deletes the read markers for the specified user | |
| 257 | - * | |
| 258 | - * @param \OCP\IUser $user | |
| 259 | - * @return bool | |
| 260 | - * @since 9.0.0 | |
| 261 | - */ | |
| 262 | - public function deleteReadMarksFromUser(\OCP\IUser $user); | |
| 255 | + /** | |
| 256 | + * deletes the read markers for the specified user | |
| 257 | + * | |
| 258 | + * @param \OCP\IUser $user | |
| 259 | + * @return bool | |
| 260 | + * @since 9.0.0 | |
| 261 | + */ | |
| 262 | + public function deleteReadMarksFromUser(\OCP\IUser $user); | |
| 263 | 263 | |
| 264 | - /** | |
| 265 | - * deletes the read markers on the specified object | |
| 266 | - * | |
| 267 | - * @param string $objectType | |
| 268 | - * @param string $objectId | |
| 269 | - * @return bool | |
| 270 | - * @since 9.0.0 | |
| 271 | - */ | |
| 272 | - public function deleteReadMarksOnObject($objectType, $objectId); | |
| 264 | + /** | |
| 265 | + * deletes the read markers on the specified object | |
| 266 | + * | |
| 267 | + * @param string $objectType | |
| 268 | + * @param string $objectId | |
| 269 | + * @return bool | |
| 270 | + * @since 9.0.0 | |
| 271 | + */ | |
| 272 | + public function deleteReadMarksOnObject($objectType, $objectId); | |
| 273 | 273 | |
| 274 | - /** | |
| 275 | - * registers an Entity to the manager, so event notifications can be send | |
| 276 | - * to consumers of the comments infrastructure | |
| 277 | - * | |
| 278 | - * @param \Closure $closure | |
| 279 | - * @since 11.0.0 | |
| 280 | - */ | |
| 281 | - public function registerEventHandler(\Closure $closure); | |
| 274 | + /** | |
| 275 | + * registers an Entity to the manager, so event notifications can be send | |
| 276 | + * to consumers of the comments infrastructure | |
| 277 | + * | |
| 278 | + * @param \Closure $closure | |
| 279 | + * @since 11.0.0 | |
| 280 | + */ | |
| 281 | + public function registerEventHandler(\Closure $closure); | |
| 282 | 282 | |
| 283 | - /** | |
| 284 | - * registers a method that resolves an ID to a display name for a given type | |
| 285 | - * | |
| 286 | - * @param string $type | |
| 287 | - * @param \Closure $closure | |
| 288 | - * @throws \OutOfBoundsException | |
| 289 | - * @since 11.0.0 | |
| 290 | - * | |
| 291 | - * Only one resolver shall be registered per type. Otherwise a | |
| 292 | - * \OutOfBoundsException has to thrown. | |
| 293 | - */ | |
| 294 | - public function registerDisplayNameResolver($type, \Closure $closure); | |
| 283 | + /** | |
| 284 | + * registers a method that resolves an ID to a display name for a given type | |
| 285 | + * | |
| 286 | + * @param string $type | |
| 287 | + * @param \Closure $closure | |
| 288 | + * @throws \OutOfBoundsException | |
| 289 | + * @since 11.0.0 | |
| 290 | + * | |
| 291 | + * Only one resolver shall be registered per type. Otherwise a | |
| 292 | + * \OutOfBoundsException has to thrown. | |
| 293 | + */ | |
| 294 | + public function registerDisplayNameResolver($type, \Closure $closure); | |
| 295 | 295 | |
| 296 | - /** | |
| 297 | - * resolves a given ID of a given Type to a display name. | |
| 298 | - * | |
| 299 | - * @param string $type | |
| 300 | - * @param string $id | |
| 301 | - * @return string | |
| 302 | - * @throws \OutOfBoundsException | |
| 303 | - * @since 11.0.0 | |
| 304 | - * | |
| 305 | - * If a provided type was not registered, an \OutOfBoundsException shall | |
| 306 | - * be thrown. It is upon the resolver discretion what to return of the | |
| 307 | - * provided ID is unknown. It must be ensured that a string is returned. | |
| 308 | - */ | |
| 309 | - public function resolveDisplayName($type, $id); | |
| 296 | + /** | |
| 297 | + * resolves a given ID of a given Type to a display name. | |
| 298 | + * | |
| 299 | + * @param string $type | |
| 300 | + * @param string $id | |
| 301 | + * @return string | |
| 302 | + * @throws \OutOfBoundsException | |
| 303 | + * @since 11.0.0 | |
| 304 | + * | |
| 305 | + * If a provided type was not registered, an \OutOfBoundsException shall | |
| 306 | + * be thrown. It is upon the resolver discretion what to return of the | |
| 307 | + * provided ID is unknown. It must be ensured that a string is returned. | |
| 308 | + */ | |
| 309 | + public function resolveDisplayName($type, $id); | |
| 310 | 310 | |
| 311 | 311 | } | 
| @@ -30,17 +30,17 @@ | ||
| 30 | 30 | * @since 13.0.0 | 
| 31 | 31 | */ | 
| 32 | 32 |  interface IManager { | 
| 33 | - /** | |
| 34 | - * @param string $className – class name of the ISorter implementation | |
| 35 | - * @since 13.0.0 | |
| 36 | - */ | |
| 37 | - public function registerSorter($className); | |
| 33 | + /** | |
| 34 | + * @param string $className – class name of the ISorter implementation | |
| 35 | + * @since 13.0.0 | |
| 36 | + */ | |
| 37 | + public function registerSorter($className); | |
| 38 | 38 | |
| 39 | - /** | |
| 40 | - * @param array $sorters list of sorter IDs, seperated by "|" | |
| 41 | - * @param array $sortArray array representation of OCP\Collaboration\Collaborators\ISearchResult | |
| 42 | - * @param array $context context info of the search, keys: itemType, itemId | |
| 43 | - * @since 13.0.0 | |
| 44 | - */ | |
| 45 | - public function runSorters(array $sorters, array &$sortArray, array $context); | |
| 39 | + /** | |
| 40 | + * @param array $sorters list of sorter IDs, seperated by "|" | |
| 41 | + * @param array $sortArray array representation of OCP\Collaboration\Collaborators\ISearchResult | |
| 42 | + * @param array $context context info of the search, keys: itemType, itemId | |
| 43 | + * @since 13.0.0 | |
| 44 | + */ | |
| 45 | + public function runSorters(array $sorters, array &$sortArray, array $context); | |
| 46 | 46 | } | 
| @@ -29,7 +29,7 @@ discard block | ||
| 29 | 29 | |
| 30 | 30 |  class Manager implements IManager { | 
| 31 | 31 | /** @var string[] */ | 
| 32 | - protected $sorters =[]; | |
| 32 | + protected $sorters = []; | |
| 33 | 33 | |
| 34 | 34 | /** @var ISorter[] */ | 
| 35 | 35 | protected $sorterInstances = []; | 
| @@ -42,8 +42,8 @@ discard block | ||
| 42 | 42 | |
| 43 | 43 |  	public function runSorters(array $sorters, array &$sortArray, array $context) { | 
| 44 | 44 | $sorterInstances = $this->getSorters(); | 
| 45 | -		while($sorter = array_shift($sorters)) { | |
| 46 | -			if(isset($sorterInstances[$sorter])) { | |
| 45 | +		while ($sorter = array_shift($sorters)) { | |
| 46 | +			if (isset($sorterInstances[$sorter])) { | |
| 47 | 47 | $sorterInstances[$sorter]->sort($sortArray, $context); | 
| 48 | 48 |  			} else { | 
| 49 | 49 |  				$this->c->getLogger()->warning('No sorter for ID "{id}", skipping', [ | 
| @@ -58,17 +58,17 @@ discard block | ||
| 58 | 58 | } | 
| 59 | 59 | |
| 60 | 60 |  	protected function getSorters() { | 
| 61 | -		if(count($this->sorterInstances) === 0) { | |
| 61 | +		if (count($this->sorterInstances) === 0) { | |
| 62 | 62 |  			foreach ($this->sorters as $sorter) { | 
| 63 | 63 | /** @var ISorter $instance */ | 
| 64 | 64 | $instance = $this->c->resolve($sorter); | 
| 65 | -				if(!$instance instanceof ISorter) { | |
| 65 | +				if (!$instance instanceof ISorter) { | |
| 66 | 66 |  					$this->c->getLogger()->notice('Skipping sorter which is not an instance of ISorter. Class name: {class}', | 
| 67 | 67 | ['app' => 'core', 'class' => $sorter]); | 
| 68 | 68 | continue; | 
| 69 | 69 | } | 
| 70 | 70 | $sorterId = trim($instance->getId()); | 
| 71 | -				if(trim($sorterId) === '') { | |
| 71 | +				if (trim($sorterId) === '') { | |
| 72 | 72 |  					$this->c->getLogger()->notice('Skipping sorter with empty ID. Class name: {class}', | 
| 73 | 73 | ['app' => 'core', 'class' => $sorter]); | 
| 74 | 74 | continue; | 
| @@ -28,54 +28,54 @@ | ||
| 28 | 28 | use OCP\IServerContainer; | 
| 29 | 29 | |
| 30 | 30 |  class Manager implements IManager { | 
| 31 | - /** @var string[] */ | |
| 32 | - protected $sorters =[]; | |
| 31 | + /** @var string[] */ | |
| 32 | + protected $sorters =[]; | |
| 33 | 33 | |
| 34 | - /** @var ISorter[] */ | |
| 35 | - protected $sorterInstances = []; | |
| 36 | - /** @var IServerContainer */ | |
| 37 | - private $c; | |
| 34 | + /** @var ISorter[] */ | |
| 35 | + protected $sorterInstances = []; | |
| 36 | + /** @var IServerContainer */ | |
| 37 | + private $c; | |
| 38 | 38 | |
| 39 | -	public function __construct(IServerContainer $container) { | |
| 40 | - $this->c = $container; | |
| 41 | - } | |
| 39 | +    public function __construct(IServerContainer $container) { | |
| 40 | + $this->c = $container; | |
| 41 | + } | |
| 42 | 42 | |
| 43 | -	public function runSorters(array $sorters, array &$sortArray, array $context) { | |
| 44 | - $sorterInstances = $this->getSorters(); | |
| 45 | -		while($sorter = array_shift($sorters)) { | |
| 46 | -			if(isset($sorterInstances[$sorter])) { | |
| 47 | - $sorterInstances[$sorter]->sort($sortArray, $context); | |
| 48 | -			} else { | |
| 49 | -				$this->c->getLogger()->warning('No sorter for ID "{id}", skipping', [ | |
| 50 | - 'app' => 'core', 'id' => $sorter | |
| 51 | - ]); | |
| 52 | - } | |
| 53 | - } | |
| 54 | - } | |
| 43 | +    public function runSorters(array $sorters, array &$sortArray, array $context) { | |
| 44 | + $sorterInstances = $this->getSorters(); | |
| 45 | +        while($sorter = array_shift($sorters)) { | |
| 46 | +            if(isset($sorterInstances[$sorter])) { | |
| 47 | + $sorterInstances[$sorter]->sort($sortArray, $context); | |
| 48 | +            } else { | |
| 49 | +                $this->c->getLogger()->warning('No sorter for ID "{id}", skipping', [ | |
| 50 | + 'app' => 'core', 'id' => $sorter | |
| 51 | + ]); | |
| 52 | + } | |
| 53 | + } | |
| 54 | + } | |
| 55 | 55 | |
| 56 | -	public function registerSorter($className) { | |
| 57 | - $this->sorters[] = $className; | |
| 58 | - } | |
| 56 | +    public function registerSorter($className) { | |
| 57 | + $this->sorters[] = $className; | |
| 58 | + } | |
| 59 | 59 | |
| 60 | -	protected function getSorters() { | |
| 61 | -		if(count($this->sorterInstances) === 0) { | |
| 62 | -			foreach ($this->sorters as $sorter) { | |
| 63 | - /** @var ISorter $instance */ | |
| 64 | - $instance = $this->c->resolve($sorter); | |
| 65 | -				if(!$instance instanceof ISorter) { | |
| 66 | -					$this->c->getLogger()->notice('Skipping sorter which is not an instance of ISorter. Class name: {class}', | |
| 67 | - ['app' => 'core', 'class' => $sorter]); | |
| 68 | - continue; | |
| 69 | - } | |
| 70 | - $sorterId = trim($instance->getId()); | |
| 71 | -				if(trim($sorterId) === '') { | |
| 72 | -					$this->c->getLogger()->notice('Skipping sorter with empty ID. Class name: {class}', | |
| 73 | - ['app' => 'core', 'class' => $sorter]); | |
| 74 | - continue; | |
| 75 | - } | |
| 76 | - $this->sorterInstances[$sorterId] = $instance; | |
| 77 | - } | |
| 78 | - } | |
| 79 | - return $this->sorterInstances; | |
| 80 | - } | |
| 60 | +    protected function getSorters() { | |
| 61 | +        if(count($this->sorterInstances) === 0) { | |
| 62 | +            foreach ($this->sorters as $sorter) { | |
| 63 | + /** @var ISorter $instance */ | |
| 64 | + $instance = $this->c->resolve($sorter); | |
| 65 | +                if(!$instance instanceof ISorter) { | |
| 66 | +                    $this->c->getLogger()->notice('Skipping sorter which is not an instance of ISorter. Class name: {class}', | |
| 67 | + ['app' => 'core', 'class' => $sorter]); | |
| 68 | + continue; | |
| 69 | + } | |
| 70 | + $sorterId = trim($instance->getId()); | |
| 71 | +                if(trim($sorterId) === '') { | |
| 72 | +                    $this->c->getLogger()->notice('Skipping sorter with empty ID. Class name: {class}', | |
| 73 | + ['app' => 'core', 'class' => $sorter]); | |
| 74 | + continue; | |
| 75 | + } | |
| 76 | + $this->sorterInstances[$sorterId] = $instance; | |
| 77 | + } | |
| 78 | + } | |
| 79 | + return $this->sorterInstances; | |
| 80 | + } | |
| 81 | 81 | } | 
| @@ -33,18 +33,18 @@ | ||
| 33 | 33 | */ | 
| 34 | 34 |  interface ISorter { | 
| 35 | 35 | |
| 36 | - /** | |
| 37 | - * @return string The ID of the sorter, e.g. commenters | |
| 38 | - * @since 13.0.0 | |
| 39 | - */ | |
| 40 | - public function getId(); | |
| 36 | + /** | |
| 37 | + * @return string The ID of the sorter, e.g. commenters | |
| 38 | + * @since 13.0.0 | |
| 39 | + */ | |
| 40 | + public function getId(); | |
| 41 | 41 | |
| 42 | - /** | |
| 43 | - * executes the sort action | |
| 44 | - * | |
| 45 | - * @param array $sortArray the array to be sorted, provided as reference | |
| 46 | - * @param array $context carries key 'itemType' and 'itemId' of the source object (e.g. a file) | |
| 47 | - * @since 13.0.0 | |
| 48 | - */ | |
| 49 | - public function sort(array &$sortArray, array $context); | |
| 42 | + /** | |
| 43 | + * executes the sort action | |
| 44 | + * | |
| 45 | + * @param array $sortArray the array to be sorted, provided as reference | |
| 46 | + * @param array $context carries key 'itemType' and 'itemId' of the source object (e.g. a file) | |
| 47 | + * @since 13.0.0 | |
| 48 | + */ | |
| 49 | + public function sort(array &$sortArray, array $context); | |
| 50 | 50 | } | 
| @@ -38,926 +38,926 @@ | ||
| 38 | 38 | |
| 39 | 39 |  class Manager implements ICommentsManager { | 
| 40 | 40 | |
| 41 | - /** @var IDBConnection */ | |
| 42 | - protected $dbConn; | |
| 43 | - | |
| 44 | - /** @var ILogger */ | |
| 45 | - protected $logger; | |
| 46 | - | |
| 47 | - /** @var IConfig */ | |
| 48 | - protected $config; | |
| 49 | - | |
| 50 | - /** @var IComment[] */ | |
| 51 | - protected $commentsCache = []; | |
| 52 | - | |
| 53 | - /** @var \Closure[] */ | |
| 54 | - protected $eventHandlerClosures = []; | |
| 55 | - | |
| 56 | - /** @var ICommentsEventHandler[] */ | |
| 57 | - protected $eventHandlers = []; | |
| 58 | - | |
| 59 | - /** @var \Closure[] */ | |
| 60 | - protected $displayNameResolvers = []; | |
| 61 | - | |
| 62 | - /** | |
| 63 | - * Manager constructor. | |
| 64 | - * | |
| 65 | - * @param IDBConnection $dbConn | |
| 66 | - * @param ILogger $logger | |
| 67 | - * @param IConfig $config | |
| 68 | - */ | |
| 69 | - public function __construct( | |
| 70 | - IDBConnection $dbConn, | |
| 71 | - ILogger $logger, | |
| 72 | - IConfig $config | |
| 73 | -	) { | |
| 74 | - $this->dbConn = $dbConn; | |
| 75 | - $this->logger = $logger; | |
| 76 | - $this->config = $config; | |
| 77 | - } | |
| 78 | - | |
| 79 | - /** | |
| 80 | - * converts data base data into PHP native, proper types as defined by | |
| 81 | - * IComment interface. | |
| 82 | - * | |
| 83 | - * @param array $data | |
| 84 | - * @return array | |
| 85 | - */ | |
| 86 | -	protected function normalizeDatabaseData(array $data) { | |
| 87 | - $data['id'] = strval($data['id']); | |
| 88 | - $data['parent_id'] = strval($data['parent_id']); | |
| 89 | - $data['topmost_parent_id'] = strval($data['topmost_parent_id']); | |
| 90 | - $data['creation_timestamp'] = new \DateTime($data['creation_timestamp']); | |
| 91 | -		if (!is_null($data['latest_child_timestamp'])) { | |
| 92 | - $data['latest_child_timestamp'] = new \DateTime($data['latest_child_timestamp']); | |
| 93 | - } | |
| 94 | - $data['children_count'] = intval($data['children_count']); | |
| 95 | - return $data; | |
| 96 | - } | |
| 97 | - | |
| 98 | - /** | |
| 99 | - * prepares a comment for an insert or update operation after making sure | |
| 100 | - * all necessary fields have a value assigned. | |
| 101 | - * | |
| 102 | - * @param IComment $comment | |
| 103 | - * @return IComment returns the same updated IComment instance as provided | |
| 104 | - * by parameter for convenience | |
| 105 | - * @throws \UnexpectedValueException | |
| 106 | - */ | |
| 107 | -	protected function prepareCommentForDatabaseWrite(IComment $comment) { | |
| 108 | - if (!$comment->getActorType() | |
| 109 | - || !$comment->getActorId() | |
| 110 | - || !$comment->getObjectType() | |
| 111 | - || !$comment->getObjectId() | |
| 112 | - || !$comment->getVerb() | |
| 113 | -		) { | |
| 114 | -			throw new \UnexpectedValueException('Actor, Object and Verb information must be provided for saving'); | |
| 115 | - } | |
| 116 | - | |
| 117 | -		if ($comment->getId() === '') { | |
| 118 | - $comment->setChildrenCount(0); | |
| 119 | -			$comment->setLatestChildDateTime(new \DateTime('0000-00-00 00:00:00', new \DateTimeZone('UTC'))); | |
| 120 | - $comment->setLatestChildDateTime(null); | |
| 121 | - } | |
| 122 | - | |
| 123 | -		if (is_null($comment->getCreationDateTime())) { | |
| 124 | - $comment->setCreationDateTime(new \DateTime()); | |
| 125 | - } | |
| 126 | - | |
| 127 | -		if ($comment->getParentId() !== '0') { | |
| 128 | - $comment->setTopmostParentId($this->determineTopmostParentId($comment->getParentId())); | |
| 129 | -		} else { | |
| 130 | -			$comment->setTopmostParentId('0'); | |
| 131 | - } | |
| 132 | - | |
| 133 | - $this->cache($comment); | |
| 134 | - | |
| 135 | - return $comment; | |
| 136 | - } | |
| 137 | - | |
| 138 | - /** | |
| 139 | - * returns the topmost parent id of a given comment identified by ID | |
| 140 | - * | |
| 141 | - * @param string $id | |
| 142 | - * @return string | |
| 143 | - * @throws NotFoundException | |
| 144 | - */ | |
| 145 | -	protected function determineTopmostParentId($id) { | |
| 146 | - $comment = $this->get($id); | |
| 147 | -		if ($comment->getParentId() === '0') { | |
| 148 | - return $comment->getId(); | |
| 149 | -		} else { | |
| 150 | - return $this->determineTopmostParentId($comment->getId()); | |
| 151 | - } | |
| 152 | - } | |
| 153 | - | |
| 154 | - /** | |
| 155 | - * updates child information of a comment | |
| 156 | - * | |
| 157 | - * @param string $id | |
| 158 | - * @param \DateTime $cDateTime the date time of the most recent child | |
| 159 | - * @throws NotFoundException | |
| 160 | - */ | |
| 161 | -	protected function updateChildrenInformation($id, \DateTime $cDateTime) { | |
| 162 | - $qb = $this->dbConn->getQueryBuilder(); | |
| 163 | -		$query = $qb->select($qb->createFunction('COUNT(`id`)')) | |
| 164 | -			->from('comments') | |
| 165 | -			->where($qb->expr()->eq('parent_id', $qb->createParameter('id'))) | |
| 166 | -			->setParameter('id', $id); | |
| 167 | - | |
| 168 | - $resultStatement = $query->execute(); | |
| 169 | - $data = $resultStatement->fetch(\PDO::FETCH_NUM); | |
| 170 | - $resultStatement->closeCursor(); | |
| 171 | - $children = intval($data[0]); | |
| 172 | - | |
| 173 | - $comment = $this->get($id); | |
| 174 | - $comment->setChildrenCount($children); | |
| 175 | - $comment->setLatestChildDateTime($cDateTime); | |
| 176 | - $this->save($comment); | |
| 177 | - } | |
| 178 | - | |
| 179 | - /** | |
| 180 | - * Tests whether actor or object type and id parameters are acceptable. | |
| 181 | - * Throws exception if not. | |
| 182 | - * | |
| 183 | - * @param string $role | |
| 184 | - * @param string $type | |
| 185 | - * @param string $id | |
| 186 | - * @throws \InvalidArgumentException | |
| 187 | - */ | |
| 188 | -	protected function checkRoleParameters($role, $type, $id) { | |
| 189 | - if ( | |
| 190 | - !is_string($type) || empty($type) | |
| 191 | - || !is_string($id) || empty($id) | |
| 192 | -		) { | |
| 193 | - throw new \InvalidArgumentException($role . ' parameters must be string and not empty'); | |
| 194 | - } | |
| 195 | - } | |
| 196 | - | |
| 197 | - /** | |
| 198 | - * run-time caches a comment | |
| 199 | - * | |
| 200 | - * @param IComment $comment | |
| 201 | - */ | |
| 202 | -	protected function cache(IComment $comment) { | |
| 203 | - $id = $comment->getId(); | |
| 204 | -		if (empty($id)) { | |
| 205 | - return; | |
| 206 | - } | |
| 207 | - $this->commentsCache[strval($id)] = $comment; | |
| 208 | - } | |
| 209 | - | |
| 210 | - /** | |
| 211 | - * removes an entry from the comments run time cache | |
| 212 | - * | |
| 213 | - * @param mixed $id the comment's id | |
| 214 | - */ | |
| 215 | -	protected function uncache($id) { | |
| 216 | - $id = strval($id); | |
| 217 | -		if (isset($this->commentsCache[$id])) { | |
| 218 | - unset($this->commentsCache[$id]); | |
| 219 | - } | |
| 220 | - } | |
| 221 | - | |
| 222 | - /** | |
| 223 | - * returns a comment instance | |
| 224 | - * | |
| 225 | - * @param string $id the ID of the comment | |
| 226 | - * @return IComment | |
| 227 | - * @throws NotFoundException | |
| 228 | - * @throws \InvalidArgumentException | |
| 229 | - * @since 9.0.0 | |
| 230 | - */ | |
| 231 | -	public function get($id) { | |
| 232 | -		if (intval($id) === 0) { | |
| 233 | -			throw new \InvalidArgumentException('IDs must be translatable to a number in this implementation.'); | |
| 234 | - } | |
| 235 | - | |
| 236 | -		if (isset($this->commentsCache[$id])) { | |
| 237 | - return $this->commentsCache[$id]; | |
| 238 | - } | |
| 239 | - | |
| 240 | - $qb = $this->dbConn->getQueryBuilder(); | |
| 241 | -		$resultStatement = $qb->select('*') | |
| 242 | -			->from('comments') | |
| 243 | -			->where($qb->expr()->eq('id', $qb->createParameter('id'))) | |
| 244 | -			->setParameter('id', $id, IQueryBuilder::PARAM_INT) | |
| 245 | - ->execute(); | |
| 246 | - | |
| 247 | - $data = $resultStatement->fetch(); | |
| 248 | - $resultStatement->closeCursor(); | |
| 249 | -		if (!$data) { | |
| 250 | - throw new NotFoundException(); | |
| 251 | - } | |
| 252 | - | |
| 253 | - $comment = new Comment($this->normalizeDatabaseData($data)); | |
| 254 | - $this->cache($comment); | |
| 255 | - return $comment; | |
| 256 | - } | |
| 257 | - | |
| 258 | - /** | |
| 259 | - * returns the comment specified by the id and all it's child comments. | |
| 260 | - * At this point of time, we do only support one level depth. | |
| 261 | - * | |
| 262 | - * @param string $id | |
| 263 | - * @param int $limit max number of entries to return, 0 returns all | |
| 264 | - * @param int $offset the start entry | |
| 265 | - * @return array | |
| 266 | - * @since 9.0.0 | |
| 267 | - * | |
| 268 | - * The return array looks like this | |
| 269 | - * [ | |
| 270 | - * 'comment' => IComment, // root comment | |
| 271 | - * 'replies' => | |
| 272 | - * [ | |
| 273 | - * 0 => | |
| 274 | - * [ | |
| 275 | - * 'comment' => IComment, | |
| 276 | - * 'replies' => [] | |
| 277 | - * ] | |
| 278 | - * 1 => | |
| 279 | - * [ | |
| 280 | - * 'comment' => IComment, | |
| 281 | - * 'replies'=> [] | |
| 282 | - * ], | |
| 283 | - * … | |
| 284 | - * ] | |
| 285 | - * ] | |
| 286 | - */ | |
| 287 | -	public function getTree($id, $limit = 0, $offset = 0) { | |
| 288 | - $tree = []; | |
| 289 | - $tree['comment'] = $this->get($id); | |
| 290 | - $tree['replies'] = []; | |
| 291 | - | |
| 292 | - $qb = $this->dbConn->getQueryBuilder(); | |
| 293 | -		$query = $qb->select('*') | |
| 294 | -			->from('comments') | |
| 295 | -			->where($qb->expr()->eq('topmost_parent_id', $qb->createParameter('id'))) | |
| 296 | -			->orderBy('creation_timestamp', 'DESC') | |
| 297 | -			->setParameter('id', $id); | |
| 298 | - | |
| 299 | -		if ($limit > 0) { | |
| 300 | - $query->setMaxResults($limit); | |
| 301 | - } | |
| 302 | -		if ($offset > 0) { | |
| 303 | - $query->setFirstResult($offset); | |
| 304 | - } | |
| 305 | - | |
| 306 | - $resultStatement = $query->execute(); | |
| 307 | -		while ($data = $resultStatement->fetch()) { | |
| 308 | - $comment = new Comment($this->normalizeDatabaseData($data)); | |
| 309 | - $this->cache($comment); | |
| 310 | - $tree['replies'][] = [ | |
| 311 | - 'comment' => $comment, | |
| 312 | - 'replies' => [] | |
| 313 | - ]; | |
| 314 | - } | |
| 315 | - $resultStatement->closeCursor(); | |
| 316 | - | |
| 317 | - return $tree; | |
| 318 | - } | |
| 319 | - | |
| 320 | - /** | |
| 321 | - * Get the actor types and ID that commented in the tree specified by the ID | |
| 322 | - * | |
| 323 | - * @param string $id | |
| 324 | - * @return array | |
| 325 | - * @since 13.0.0 | |
| 326 | - * | |
| 327 | - * The return array looks like this: | |
| 328 | - * | |
| 329 | - * [ | |
| 330 | - * 'user' => [ | |
| 331 | - * 'alice' => 2, | |
| 332 | - * 'bob' => 3 | |
| 333 | - * ], | |
| 334 | - * 'robot' => [ | |
| 335 | - * 'r2-d2' => 5, | |
| 336 | - * 'c-3po' => 17, | |
| 337 | - * ] | |
| 338 | - * ] | |
| 339 | - */ | |
| 340 | -	public function getActorsInTree($id) { | |
| 341 | - $tree = $this->getTree($id); | |
| 342 | - $actors = []; | |
| 343 | - $this->walkTree($tree, $actors, [$this, 'extractActor']); | |
| 344 | - return $actors; | |
| 345 | - } | |
| 346 | - | |
| 347 | - /** | |
| 348 | - * @param IComment $comment | |
| 349 | - * @param array &$actors | |
| 350 | - * | |
| 351 | - * build an array that looks like: | |
| 352 | - * | |
| 353 | - * [ | |
| 354 | - * 'user' => [ | |
| 355 | - * 'alice' => 2, | |
| 356 | - * 'bob' => 3 | |
| 357 | - * ], | |
| 358 | - * 'robot' => [ | |
| 359 | - * 'r2-d2' => 5, | |
| 360 | - * 'c-3po' => 17, | |
| 361 | - * ] | |
| 362 | - * ] | |
| 363 | - * | |
| 364 | - */ | |
| 365 | -	protected function extractActor(IComment $comment, &$actors) { | |
| 366 | -		if(!isset($actors[$comment->getActorType()])) { | |
| 367 | - $actors[$comment->getActorType()] = []; | |
| 368 | - } | |
| 369 | -		if(!isset($actors[$comment->getActorType()][$comment->getActorId()])) { | |
| 370 | - $actors[$comment->getActorType()][$comment->getActorId()] = 1; | |
| 371 | -		} else { | |
| 372 | - $actors[$comment->getActorType()][$comment->getActorId()] += 1; | |
| 373 | - } | |
| 374 | - } | |
| 375 | - | |
| 376 | - /** | |
| 377 | - * walks through a comment tree (as returned by getTree() and invokes a callback | |
| 378 | - * with the current IComment instance (and optionally custom parameters) | |
| 379 | - * | |
| 380 | - * @param array $node | |
| 381 | - * @param array &$results | |
| 382 | - * @param callable $callback | |
| 383 | - * @param array|null $parameters | |
| 384 | - */ | |
| 385 | -	protected function walkTree($node, array &$results, callable $callback, array $parameters = null) { | |
| 386 | -		if(isset($node['replies'])) { | |
| 387 | -			foreach ($node['replies'] as $subNode) { | |
| 388 | - $this->walkTree($subNode, $results, $callback, $parameters); | |
| 389 | - } | |
| 390 | - } | |
| 391 | -		if(isset($node['comment']) && $node['comment'] instanceof IComment) { | |
| 392 | - $callback($node['comment'], $results, $parameters); | |
| 393 | - } | |
| 394 | - } | |
| 395 | - | |
| 396 | - /** | |
| 397 | - * returns comments for a specific object (e.g. a file). | |
| 398 | - * | |
| 399 | - * The sort order is always newest to oldest. | |
| 400 | - * | |
| 401 | - * @param string $objectType the object type, e.g. 'files' | |
| 402 | - * @param string $objectId the id of the object | |
| 403 | - * @param int $limit optional, number of maximum comments to be returned. if | |
| 404 | - * not specified, all comments are returned. | |
| 405 | - * @param int $offset optional, starting point | |
| 406 | - * @param \DateTime $notOlderThan optional, timestamp of the oldest comments | |
| 407 | - * that may be returned | |
| 408 | - * @return IComment[] | |
| 409 | - * @since 9.0.0 | |
| 410 | - */ | |
| 411 | - public function getForObject( | |
| 412 | - $objectType, | |
| 413 | - $objectId, | |
| 414 | - $limit = 0, | |
| 415 | - $offset = 0, | |
| 416 | - \DateTime $notOlderThan = null | |
| 417 | -	) { | |
| 418 | - $comments = []; | |
| 419 | - | |
| 420 | - $qb = $this->dbConn->getQueryBuilder(); | |
| 421 | -		$query = $qb->select('*') | |
| 422 | -			->from('comments') | |
| 423 | -			->where($qb->expr()->eq('object_type', $qb->createParameter('type'))) | |
| 424 | -			->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id'))) | |
| 425 | -			->orderBy('creation_timestamp', 'DESC') | |
| 426 | -			->setParameter('type', $objectType) | |
| 427 | -			->setParameter('id', $objectId); | |
| 428 | - | |
| 429 | -		if ($limit > 0) { | |
| 430 | - $query->setMaxResults($limit); | |
| 431 | - } | |
| 432 | -		if ($offset > 0) { | |
| 433 | - $query->setFirstResult($offset); | |
| 434 | - } | |
| 435 | -		if (!is_null($notOlderThan)) { | |
| 436 | - $query | |
| 437 | -				->andWhere($qb->expr()->gt('creation_timestamp', $qb->createParameter('notOlderThan'))) | |
| 438 | -				->setParameter('notOlderThan', $notOlderThan, 'datetime'); | |
| 439 | - } | |
| 440 | - | |
| 441 | - $resultStatement = $query->execute(); | |
| 442 | -		while ($data = $resultStatement->fetch()) { | |
| 443 | - $comment = new Comment($this->normalizeDatabaseData($data)); | |
| 444 | - $this->cache($comment); | |
| 445 | - $comments[] = $comment; | |
| 446 | - } | |
| 447 | - $resultStatement->closeCursor(); | |
| 448 | - | |
| 449 | - return $comments; | |
| 450 | - } | |
| 451 | - | |
| 452 | - /** | |
| 453 | - * @param $objectType string the object type, e.g. 'files' | |
| 454 | - * @param $objectId string the id of the object | |
| 455 | - * @param \DateTime $notOlderThan optional, timestamp of the oldest comments | |
| 456 | - * that may be returned | |
| 457 | - * @return Int | |
| 458 | - * @since 9.0.0 | |
| 459 | - */ | |
| 460 | -	public function getNumberOfCommentsForObject($objectType, $objectId, \DateTime $notOlderThan = null) { | |
| 461 | - $qb = $this->dbConn->getQueryBuilder(); | |
| 462 | -		$query = $qb->select($qb->createFunction('COUNT(`id`)')) | |
| 463 | -			->from('comments') | |
| 464 | -			->where($qb->expr()->eq('object_type', $qb->createParameter('type'))) | |
| 465 | -			->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id'))) | |
| 466 | -			->setParameter('type', $objectType) | |
| 467 | -			->setParameter('id', $objectId); | |
| 468 | - | |
| 469 | -		if (!is_null($notOlderThan)) { | |
| 470 | - $query | |
| 471 | -				->andWhere($qb->expr()->gt('creation_timestamp', $qb->createParameter('notOlderThan'))) | |
| 472 | -				->setParameter('notOlderThan', $notOlderThan, 'datetime'); | |
| 473 | - } | |
| 474 | - | |
| 475 | - $resultStatement = $query->execute(); | |
| 476 | - $data = $resultStatement->fetch(\PDO::FETCH_NUM); | |
| 477 | - $resultStatement->closeCursor(); | |
| 478 | - return intval($data[0]); | |
| 479 | - } | |
| 480 | - | |
| 481 | - /** | |
| 482 | - * Get the number of unread comments for all files in a folder | |
| 483 | - * | |
| 484 | - * @param int $folderId | |
| 485 | - * @param IUser $user | |
| 486 | - * @return array [$fileId => $unreadCount] | |
| 487 | - */ | |
| 488 | -	public function getNumberOfUnreadCommentsForFolder($folderId, IUser $user) { | |
| 489 | - $qb = $this->dbConn->getQueryBuilder(); | |
| 490 | -		$query = $qb->select('f.fileid') | |
| 491 | - ->selectAlias( | |
| 492 | -				$qb->createFunction('COUNT(' . $qb->getColumnName('c.id') . ')'), | |
| 493 | - 'num_ids' | |
| 494 | - ) | |
| 495 | -			->from('comments', 'c') | |
| 496 | -			->innerJoin('c', 'filecache', 'f', $qb->expr()->andX( | |
| 497 | -				$qb->expr()->eq('c.object_type', $qb->createNamedParameter('files')), | |
| 498 | -				$qb->expr()->eq('f.fileid', $qb->expr()->castColumn('c.object_id', IQueryBuilder::PARAM_INT)) | |
| 499 | - )) | |
| 500 | -			->leftJoin('c', 'comments_read_markers', 'm', $qb->expr()->andX( | |
| 501 | -				$qb->expr()->eq('m.object_type', $qb->createNamedParameter('files')), | |
| 502 | -				$qb->expr()->eq('m.object_id', 'c.object_id'), | |
| 503 | -				$qb->expr()->eq('m.user_id', $qb->createNamedParameter($user->getUID())) | |
| 504 | - )) | |
| 505 | -			->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($folderId))) | |
| 506 | - ->andWhere($qb->expr()->orX( | |
| 507 | -				$qb->expr()->gt('c.creation_timestamp', 'marker_datetime'), | |
| 508 | -				$qb->expr()->isNull('marker_datetime') | |
| 509 | - )) | |
| 510 | -			->groupBy('f.fileid'); | |
| 511 | - | |
| 512 | - $resultStatement = $query->execute(); | |
| 513 | - | |
| 514 | - $results = []; | |
| 515 | -		while ($row = $resultStatement->fetch()) { | |
| 516 | - $results[$row['fileid']] = (int) $row['num_ids']; | |
| 517 | - } | |
| 518 | - $resultStatement->closeCursor(); | |
| 519 | - return $results; | |
| 520 | - } | |
| 521 | - | |
| 522 | - /** | |
| 523 | - * creates a new comment and returns it. At this point of time, it is not | |
| 524 | - * saved in the used data storage. Use save() after setting other fields | |
| 525 | - * of the comment (e.g. message or verb). | |
| 526 | - * | |
| 527 | - * @param string $actorType the actor type (e.g. 'users') | |
| 528 | - * @param string $actorId a user id | |
| 529 | - * @param string $objectType the object type the comment is attached to | |
| 530 | - * @param string $objectId the object id the comment is attached to | |
| 531 | - * @return IComment | |
| 532 | - * @since 9.0.0 | |
| 533 | - */ | |
| 534 | -	public function create($actorType, $actorId, $objectType, $objectId) { | |
| 535 | - $comment = new Comment(); | |
| 536 | - $comment | |
| 537 | - ->setActor($actorType, $actorId) | |
| 538 | - ->setObject($objectType, $objectId); | |
| 539 | - return $comment; | |
| 540 | - } | |
| 541 | - | |
| 542 | - /** | |
| 543 | - * permanently deletes the comment specified by the ID | |
| 544 | - * | |
| 545 | - * When the comment has child comments, their parent ID will be changed to | |
| 546 | - * the parent ID of the item that is to be deleted. | |
| 547 | - * | |
| 548 | - * @param string $id | |
| 549 | - * @return bool | |
| 550 | - * @throws \InvalidArgumentException | |
| 551 | - * @since 9.0.0 | |
| 552 | - */ | |
| 553 | -	public function delete($id) { | |
| 554 | -		if (!is_string($id)) { | |
| 555 | -			throw new \InvalidArgumentException('Parameter must be string'); | |
| 556 | - } | |
| 557 | - | |
| 558 | -		try { | |
| 559 | - $comment = $this->get($id); | |
| 560 | -		} catch (\Exception $e) { | |
| 561 | - // Ignore exceptions, we just don't fire a hook then | |
| 562 | - $comment = null; | |
| 563 | - } | |
| 564 | - | |
| 565 | - $qb = $this->dbConn->getQueryBuilder(); | |
| 566 | -		$query = $qb->delete('comments') | |
| 567 | -			->where($qb->expr()->eq('id', $qb->createParameter('id'))) | |
| 568 | -			->setParameter('id', $id); | |
| 569 | - | |
| 570 | -		try { | |
| 571 | - $affectedRows = $query->execute(); | |
| 572 | - $this->uncache($id); | |
| 573 | -		} catch (DriverException $e) { | |
| 574 | - $this->logger->logException($e, ['app' => 'core_comments']); | |
| 575 | - return false; | |
| 576 | - } | |
| 577 | - | |
| 578 | -		if ($affectedRows > 0 && $comment instanceof IComment) { | |
| 579 | - $this->sendEvent(CommentsEvent::EVENT_DELETE, $comment); | |
| 580 | - } | |
| 581 | - | |
| 582 | - return ($affectedRows > 0); | |
| 583 | - } | |
| 584 | - | |
| 585 | - /** | |
| 586 | - * saves the comment permanently | |
| 587 | - * | |
| 588 | - * if the supplied comment has an empty ID, a new entry comment will be | |
| 589 | - * saved and the instance updated with the new ID. | |
| 590 | - * | |
| 591 | - * Otherwise, an existing comment will be updated. | |
| 592 | - * | |
| 593 | - * Throws NotFoundException when a comment that is to be updated does not | |
| 594 | - * exist anymore at this point of time. | |
| 595 | - * | |
| 596 | - * @param IComment $comment | |
| 597 | - * @return bool | |
| 598 | - * @throws NotFoundException | |
| 599 | - * @since 9.0.0 | |
| 600 | - */ | |
| 601 | -	public function save(IComment $comment) { | |
| 602 | -		if ($this->prepareCommentForDatabaseWrite($comment)->getId() === '') { | |
| 603 | - $result = $this->insert($comment); | |
| 604 | -		} else { | |
| 605 | - $result = $this->update($comment); | |
| 606 | - } | |
| 607 | - | |
| 608 | -		if ($result && !!$comment->getParentId()) { | |
| 609 | - $this->updateChildrenInformation( | |
| 610 | - $comment->getParentId(), | |
| 611 | - $comment->getCreationDateTime() | |
| 612 | - ); | |
| 613 | - $this->cache($comment); | |
| 614 | - } | |
| 615 | - | |
| 616 | - return $result; | |
| 617 | - } | |
| 618 | - | |
| 619 | - /** | |
| 620 | - * inserts the provided comment in the database | |
| 621 | - * | |
| 622 | - * @param IComment $comment | |
| 623 | - * @return bool | |
| 624 | - */ | |
| 625 | -	protected function insert(IComment &$comment) { | |
| 626 | - $qb = $this->dbConn->getQueryBuilder(); | |
| 627 | - $affectedRows = $qb | |
| 628 | -			->insert('comments') | |
| 629 | - ->values([ | |
| 630 | - 'parent_id' => $qb->createNamedParameter($comment->getParentId()), | |
| 631 | - 'topmost_parent_id' => $qb->createNamedParameter($comment->getTopmostParentId()), | |
| 632 | - 'children_count' => $qb->createNamedParameter($comment->getChildrenCount()), | |
| 633 | - 'actor_type' => $qb->createNamedParameter($comment->getActorType()), | |
| 634 | - 'actor_id' => $qb->createNamedParameter($comment->getActorId()), | |
| 635 | - 'message' => $qb->createNamedParameter($comment->getMessage()), | |
| 636 | - 'verb' => $qb->createNamedParameter($comment->getVerb()), | |
| 637 | - 'creation_timestamp' => $qb->createNamedParameter($comment->getCreationDateTime(), 'datetime'), | |
| 638 | - 'latest_child_timestamp' => $qb->createNamedParameter($comment->getLatestChildDateTime(), 'datetime'), | |
| 639 | - 'object_type' => $qb->createNamedParameter($comment->getObjectType()), | |
| 640 | - 'object_id' => $qb->createNamedParameter($comment->getObjectId()), | |
| 641 | - ]) | |
| 642 | - ->execute(); | |
| 643 | - | |
| 644 | -		if ($affectedRows > 0) { | |
| 645 | - $comment->setId(strval($qb->getLastInsertId())); | |
| 646 | - $this->sendEvent(CommentsEvent::EVENT_ADD, $comment); | |
| 647 | - } | |
| 648 | - | |
| 649 | - return $affectedRows > 0; | |
| 650 | - } | |
| 651 | - | |
| 652 | - /** | |
| 653 | - * updates a Comment data row | |
| 654 | - * | |
| 655 | - * @param IComment $comment | |
| 656 | - * @return bool | |
| 657 | - * @throws NotFoundException | |
| 658 | - */ | |
| 659 | -	protected function update(IComment $comment) { | |
| 660 | - // for properly working preUpdate Events we need the old comments as is | |
| 661 | - // in the DB and overcome caching. Also avoid that outdated information stays. | |
| 662 | - $this->uncache($comment->getId()); | |
| 663 | - $this->sendEvent(CommentsEvent::EVENT_PRE_UPDATE, $this->get($comment->getId())); | |
| 664 | - $this->uncache($comment->getId()); | |
| 665 | - | |
| 666 | - $qb = $this->dbConn->getQueryBuilder(); | |
| 667 | - $affectedRows = $qb | |
| 668 | -			->update('comments') | |
| 669 | -			->set('parent_id', $qb->createNamedParameter($comment->getParentId())) | |
| 670 | -			->set('topmost_parent_id', $qb->createNamedParameter($comment->getTopmostParentId())) | |
| 671 | -			->set('children_count', $qb->createNamedParameter($comment->getChildrenCount())) | |
| 672 | -			->set('actor_type', $qb->createNamedParameter($comment->getActorType())) | |
| 673 | -			->set('actor_id', $qb->createNamedParameter($comment->getActorId())) | |
| 674 | -			->set('message', $qb->createNamedParameter($comment->getMessage())) | |
| 675 | -			->set('verb', $qb->createNamedParameter($comment->getVerb())) | |
| 676 | -			->set('creation_timestamp', $qb->createNamedParameter($comment->getCreationDateTime(), 'datetime')) | |
| 677 | -			->set('latest_child_timestamp', $qb->createNamedParameter($comment->getLatestChildDateTime(), 'datetime')) | |
| 678 | -			->set('object_type', $qb->createNamedParameter($comment->getObjectType())) | |
| 679 | -			->set('object_id', $qb->createNamedParameter($comment->getObjectId())) | |
| 680 | -			->where($qb->expr()->eq('id', $qb->createParameter('id'))) | |
| 681 | -			->setParameter('id', $comment->getId()) | |
| 682 | - ->execute(); | |
| 683 | - | |
| 684 | -		if ($affectedRows === 0) { | |
| 685 | -			throw new NotFoundException('Comment to update does ceased to exist'); | |
| 686 | - } | |
| 687 | - | |
| 688 | - $this->sendEvent(CommentsEvent::EVENT_UPDATE, $comment); | |
| 689 | - | |
| 690 | - return $affectedRows > 0; | |
| 691 | - } | |
| 692 | - | |
| 693 | - /** | |
| 694 | - * removes references to specific actor (e.g. on user delete) of a comment. | |
| 695 | - * The comment itself must not get lost/deleted. | |
| 696 | - * | |
| 697 | - * @param string $actorType the actor type (e.g. 'users') | |
| 698 | - * @param string $actorId a user id | |
| 699 | - * @return boolean | |
| 700 | - * @since 9.0.0 | |
| 701 | - */ | |
| 702 | -	public function deleteReferencesOfActor($actorType, $actorId) { | |
| 703 | -		$this->checkRoleParameters('Actor', $actorType, $actorId); | |
| 704 | - | |
| 705 | - $qb = $this->dbConn->getQueryBuilder(); | |
| 706 | - $affectedRows = $qb | |
| 707 | -			->update('comments') | |
| 708 | -			->set('actor_type', $qb->createNamedParameter(ICommentsManager::DELETED_USER)) | |
| 709 | -			->set('actor_id', $qb->createNamedParameter(ICommentsManager::DELETED_USER)) | |
| 710 | -			->where($qb->expr()->eq('actor_type', $qb->createParameter('type'))) | |
| 711 | -			->andWhere($qb->expr()->eq('actor_id', $qb->createParameter('id'))) | |
| 712 | -			->setParameter('type', $actorType) | |
| 713 | -			->setParameter('id', $actorId) | |
| 714 | - ->execute(); | |
| 715 | - | |
| 716 | - $this->commentsCache = []; | |
| 717 | - | |
| 718 | - return is_int($affectedRows); | |
| 719 | - } | |
| 720 | - | |
| 721 | - /** | |
| 722 | - * deletes all comments made of a specific object (e.g. on file delete) | |
| 723 | - * | |
| 724 | - * @param string $objectType the object type (e.g. 'files') | |
| 725 | - * @param string $objectId e.g. the file id | |
| 726 | - * @return boolean | |
| 727 | - * @since 9.0.0 | |
| 728 | - */ | |
| 729 | -	public function deleteCommentsAtObject($objectType, $objectId) { | |
| 730 | -		$this->checkRoleParameters('Object', $objectType, $objectId); | |
| 731 | - | |
| 732 | - $qb = $this->dbConn->getQueryBuilder(); | |
| 733 | - $affectedRows = $qb | |
| 734 | -			->delete('comments') | |
| 735 | -			->where($qb->expr()->eq('object_type', $qb->createParameter('type'))) | |
| 736 | -			->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id'))) | |
| 737 | -			->setParameter('type', $objectType) | |
| 738 | -			->setParameter('id', $objectId) | |
| 739 | - ->execute(); | |
| 740 | - | |
| 741 | - $this->commentsCache = []; | |
| 742 | - | |
| 743 | - return is_int($affectedRows); | |
| 744 | - } | |
| 745 | - | |
| 746 | - /** | |
| 747 | - * deletes the read markers for the specified user | |
| 748 | - * | |
| 749 | - * @param \OCP\IUser $user | |
| 750 | - * @return bool | |
| 751 | - * @since 9.0.0 | |
| 752 | - */ | |
| 753 | -	public function deleteReadMarksFromUser(IUser $user) { | |
| 754 | - $qb = $this->dbConn->getQueryBuilder(); | |
| 755 | -		$query = $qb->delete('comments_read_markers') | |
| 756 | -			->where($qb->expr()->eq('user_id', $qb->createParameter('user_id'))) | |
| 757 | -			->setParameter('user_id', $user->getUID()); | |
| 758 | - | |
| 759 | -		try { | |
| 760 | - $affectedRows = $query->execute(); | |
| 761 | -		} catch (DriverException $e) { | |
| 762 | - $this->logger->logException($e, ['app' => 'core_comments']); | |
| 763 | - return false; | |
| 764 | - } | |
| 765 | - return ($affectedRows > 0); | |
| 766 | - } | |
| 767 | - | |
| 768 | - /** | |
| 769 | - * sets the read marker for a given file to the specified date for the | |
| 770 | - * provided user | |
| 771 | - * | |
| 772 | - * @param string $objectType | |
| 773 | - * @param string $objectId | |
| 774 | - * @param \DateTime $dateTime | |
| 775 | - * @param IUser $user | |
| 776 | - * @since 9.0.0 | |
| 777 | - * @suppress SqlInjectionChecker | |
| 778 | - */ | |
| 779 | -	public function setReadMark($objectType, $objectId, \DateTime $dateTime, IUser $user) { | |
| 780 | -		$this->checkRoleParameters('Object', $objectType, $objectId); | |
| 781 | - | |
| 782 | - $qb = $this->dbConn->getQueryBuilder(); | |
| 783 | - $values = [ | |
| 784 | - 'user_id' => $qb->createNamedParameter($user->getUID()), | |
| 785 | - 'marker_datetime' => $qb->createNamedParameter($dateTime, 'datetime'), | |
| 786 | - 'object_type' => $qb->createNamedParameter($objectType), | |
| 787 | - 'object_id' => $qb->createNamedParameter($objectId), | |
| 788 | - ]; | |
| 789 | - | |
| 790 | - // Strategy: try to update, if this does not return affected rows, do an insert. | |
| 791 | - $affectedRows = $qb | |
| 792 | -			->update('comments_read_markers') | |
| 793 | -			->set('user_id', $values['user_id']) | |
| 794 | -			->set('marker_datetime', $values['marker_datetime']) | |
| 795 | -			->set('object_type', $values['object_type']) | |
| 796 | -			->set('object_id', $values['object_id']) | |
| 797 | -			->where($qb->expr()->eq('user_id', $qb->createParameter('user_id'))) | |
| 798 | -			->andWhere($qb->expr()->eq('object_type', $qb->createParameter('object_type'))) | |
| 799 | -			->andWhere($qb->expr()->eq('object_id', $qb->createParameter('object_id'))) | |
| 800 | -			->setParameter('user_id', $user->getUID(), IQueryBuilder::PARAM_STR) | |
| 801 | -			->setParameter('object_type', $objectType, IQueryBuilder::PARAM_STR) | |
| 802 | -			->setParameter('object_id', $objectId, IQueryBuilder::PARAM_STR) | |
| 803 | - ->execute(); | |
| 804 | - | |
| 805 | -		if ($affectedRows > 0) { | |
| 806 | - return; | |
| 807 | - } | |
| 808 | - | |
| 809 | -		$qb->insert('comments_read_markers') | |
| 810 | - ->values($values) | |
| 811 | - ->execute(); | |
| 812 | - } | |
| 813 | - | |
| 814 | - /** | |
| 815 | - * returns the read marker for a given file to the specified date for the | |
| 816 | - * provided user. It returns null, when the marker is not present, i.e. | |
| 817 | - * no comments were marked as read. | |
| 818 | - * | |
| 819 | - * @param string $objectType | |
| 820 | - * @param string $objectId | |
| 821 | - * @param IUser $user | |
| 822 | - * @return \DateTime|null | |
| 823 | - * @since 9.0.0 | |
| 824 | - */ | |
| 825 | -	public function getReadMark($objectType, $objectId, IUser $user) { | |
| 826 | - $qb = $this->dbConn->getQueryBuilder(); | |
| 827 | -		$resultStatement = $qb->select('marker_datetime') | |
| 828 | -			->from('comments_read_markers') | |
| 829 | -			->where($qb->expr()->eq('user_id', $qb->createParameter('user_id'))) | |
| 830 | -			->andWhere($qb->expr()->eq('object_type', $qb->createParameter('object_type'))) | |
| 831 | -			->andWhere($qb->expr()->eq('object_id', $qb->createParameter('object_id'))) | |
| 832 | -			->setParameter('user_id', $user->getUID(), IQueryBuilder::PARAM_STR) | |
| 833 | -			->setParameter('object_type', $objectType, IQueryBuilder::PARAM_STR) | |
| 834 | -			->setParameter('object_id', $objectId, IQueryBuilder::PARAM_STR) | |
| 835 | - ->execute(); | |
| 836 | - | |
| 837 | - $data = $resultStatement->fetch(); | |
| 838 | - $resultStatement->closeCursor(); | |
| 839 | -		if (!$data || is_null($data['marker_datetime'])) { | |
| 840 | - return null; | |
| 841 | - } | |
| 842 | - | |
| 843 | - return new \DateTime($data['marker_datetime']); | |
| 844 | - } | |
| 845 | - | |
| 846 | - /** | |
| 847 | - * deletes the read markers on the specified object | |
| 848 | - * | |
| 849 | - * @param string $objectType | |
| 850 | - * @param string $objectId | |
| 851 | - * @return bool | |
| 852 | - * @since 9.0.0 | |
| 853 | - */ | |
| 854 | -	public function deleteReadMarksOnObject($objectType, $objectId) { | |
| 855 | -		$this->checkRoleParameters('Object', $objectType, $objectId); | |
| 856 | - | |
| 857 | - $qb = $this->dbConn->getQueryBuilder(); | |
| 858 | -		$query = $qb->delete('comments_read_markers') | |
| 859 | -			->where($qb->expr()->eq('object_type', $qb->createParameter('object_type'))) | |
| 860 | -			->andWhere($qb->expr()->eq('object_id', $qb->createParameter('object_id'))) | |
| 861 | -			->setParameter('object_type', $objectType) | |
| 862 | -			->setParameter('object_id', $objectId); | |
| 863 | - | |
| 864 | -		try { | |
| 865 | - $affectedRows = $query->execute(); | |
| 866 | -		} catch (DriverException $e) { | |
| 867 | - $this->logger->logException($e, ['app' => 'core_comments']); | |
| 868 | - return false; | |
| 869 | - } | |
| 870 | - return ($affectedRows > 0); | |
| 871 | - } | |
| 872 | - | |
| 873 | - /** | |
| 874 | - * registers an Entity to the manager, so event notifications can be send | |
| 875 | - * to consumers of the comments infrastructure | |
| 876 | - * | |
| 877 | - * @param \Closure $closure | |
| 878 | - */ | |
| 879 | -	public function registerEventHandler(\Closure $closure) { | |
| 880 | - $this->eventHandlerClosures[] = $closure; | |
| 881 | - $this->eventHandlers = []; | |
| 882 | - } | |
| 883 | - | |
| 884 | - /** | |
| 885 | - * registers a method that resolves an ID to a display name for a given type | |
| 886 | - * | |
| 887 | - * @param string $type | |
| 888 | - * @param \Closure $closure | |
| 889 | - * @throws \OutOfBoundsException | |
| 890 | - * @since 11.0.0 | |
| 891 | - * | |
| 892 | - * Only one resolver shall be registered per type. Otherwise a | |
| 893 | - * \OutOfBoundsException has to thrown. | |
| 894 | - */ | |
| 895 | -	public function registerDisplayNameResolver($type, \Closure $closure) { | |
| 896 | -		if (!is_string($type)) { | |
| 897 | -			throw new \InvalidArgumentException('String expected.'); | |
| 898 | - } | |
| 899 | -		if (isset($this->displayNameResolvers[$type])) { | |
| 900 | -			throw new \OutOfBoundsException('Displayname resolver for this type already registered'); | |
| 901 | - } | |
| 902 | - $this->displayNameResolvers[$type] = $closure; | |
| 903 | - } | |
| 904 | - | |
| 905 | - /** | |
| 906 | - * resolves a given ID of a given Type to a display name. | |
| 907 | - * | |
| 908 | - * @param string $type | |
| 909 | - * @param string $id | |
| 910 | - * @return string | |
| 911 | - * @throws \OutOfBoundsException | |
| 912 | - * @since 11.0.0 | |
| 913 | - * | |
| 914 | - * If a provided type was not registered, an \OutOfBoundsException shall | |
| 915 | - * be thrown. It is upon the resolver discretion what to return of the | |
| 916 | - * provided ID is unknown. It must be ensured that a string is returned. | |
| 917 | - */ | |
| 918 | -	public function resolveDisplayName($type, $id) { | |
| 919 | -		if (!is_string($type)) { | |
| 920 | -			throw new \InvalidArgumentException('String expected.'); | |
| 921 | - } | |
| 922 | -		if (!isset($this->displayNameResolvers[$type])) { | |
| 923 | -			throw new \OutOfBoundsException('No Displayname resolver for this type registered'); | |
| 924 | - } | |
| 925 | - return (string)$this->displayNameResolvers[$type]($id); | |
| 926 | - } | |
| 927 | - | |
| 928 | - /** | |
| 929 | - * returns valid, registered entities | |
| 930 | - * | |
| 931 | - * @return \OCP\Comments\ICommentsEventHandler[] | |
| 932 | - */ | |
| 933 | -	private function getEventHandlers() { | |
| 934 | -		if (!empty($this->eventHandlers)) { | |
| 935 | - return $this->eventHandlers; | |
| 936 | - } | |
| 937 | - | |
| 938 | - $this->eventHandlers = []; | |
| 939 | -		foreach ($this->eventHandlerClosures as $name => $closure) { | |
| 940 | - $entity = $closure(); | |
| 941 | -			if (!($entity instanceof ICommentsEventHandler)) { | |
| 942 | -				throw new \InvalidArgumentException('The given entity does not implement the ICommentsEntity interface'); | |
| 943 | - } | |
| 944 | - $this->eventHandlers[$name] = $entity; | |
| 945 | - } | |
| 946 | - | |
| 947 | - return $this->eventHandlers; | |
| 948 | - } | |
| 949 | - | |
| 950 | - /** | |
| 951 | - * sends notifications to the registered entities | |
| 952 | - * | |
| 953 | - * @param $eventType | |
| 954 | - * @param IComment $comment | |
| 955 | - */ | |
| 956 | -	private function sendEvent($eventType, IComment $comment) { | |
| 957 | - $entities = $this->getEventHandlers(); | |
| 958 | - $event = new CommentsEvent($eventType, $comment); | |
| 959 | -		foreach ($entities as $entity) { | |
| 960 | - $entity->handle($event); | |
| 961 | - } | |
| 962 | - } | |
| 41 | + /** @var IDBConnection */ | |
| 42 | + protected $dbConn; | |
| 43 | + | |
| 44 | + /** @var ILogger */ | |
| 45 | + protected $logger; | |
| 46 | + | |
| 47 | + /** @var IConfig */ | |
| 48 | + protected $config; | |
| 49 | + | |
| 50 | + /** @var IComment[] */ | |
| 51 | + protected $commentsCache = []; | |
| 52 | + | |
| 53 | + /** @var \Closure[] */ | |
| 54 | + protected $eventHandlerClosures = []; | |
| 55 | + | |
| 56 | + /** @var ICommentsEventHandler[] */ | |
| 57 | + protected $eventHandlers = []; | |
| 58 | + | |
| 59 | + /** @var \Closure[] */ | |
| 60 | + protected $displayNameResolvers = []; | |
| 61 | + | |
| 62 | + /** | |
| 63 | + * Manager constructor. | |
| 64 | + * | |
| 65 | + * @param IDBConnection $dbConn | |
| 66 | + * @param ILogger $logger | |
| 67 | + * @param IConfig $config | |
| 68 | + */ | |
| 69 | + public function __construct( | |
| 70 | + IDBConnection $dbConn, | |
| 71 | + ILogger $logger, | |
| 72 | + IConfig $config | |
| 73 | +    ) { | |
| 74 | + $this->dbConn = $dbConn; | |
| 75 | + $this->logger = $logger; | |
| 76 | + $this->config = $config; | |
| 77 | + } | |
| 78 | + | |
| 79 | + /** | |
| 80 | + * converts data base data into PHP native, proper types as defined by | |
| 81 | + * IComment interface. | |
| 82 | + * | |
| 83 | + * @param array $data | |
| 84 | + * @return array | |
| 85 | + */ | |
| 86 | +    protected function normalizeDatabaseData(array $data) { | |
| 87 | + $data['id'] = strval($data['id']); | |
| 88 | + $data['parent_id'] = strval($data['parent_id']); | |
| 89 | + $data['topmost_parent_id'] = strval($data['topmost_parent_id']); | |
| 90 | + $data['creation_timestamp'] = new \DateTime($data['creation_timestamp']); | |
| 91 | +        if (!is_null($data['latest_child_timestamp'])) { | |
| 92 | + $data['latest_child_timestamp'] = new \DateTime($data['latest_child_timestamp']); | |
| 93 | + } | |
| 94 | + $data['children_count'] = intval($data['children_count']); | |
| 95 | + return $data; | |
| 96 | + } | |
| 97 | + | |
| 98 | + /** | |
| 99 | + * prepares a comment for an insert or update operation after making sure | |
| 100 | + * all necessary fields have a value assigned. | |
| 101 | + * | |
| 102 | + * @param IComment $comment | |
| 103 | + * @return IComment returns the same updated IComment instance as provided | |
| 104 | + * by parameter for convenience | |
| 105 | + * @throws \UnexpectedValueException | |
| 106 | + */ | |
| 107 | +    protected function prepareCommentForDatabaseWrite(IComment $comment) { | |
| 108 | + if (!$comment->getActorType() | |
| 109 | + || !$comment->getActorId() | |
| 110 | + || !$comment->getObjectType() | |
| 111 | + || !$comment->getObjectId() | |
| 112 | + || !$comment->getVerb() | |
| 113 | +        ) { | |
| 114 | +            throw new \UnexpectedValueException('Actor, Object and Verb information must be provided for saving'); | |
| 115 | + } | |
| 116 | + | |
| 117 | +        if ($comment->getId() === '') { | |
| 118 | + $comment->setChildrenCount(0); | |
| 119 | +            $comment->setLatestChildDateTime(new \DateTime('0000-00-00 00:00:00', new \DateTimeZone('UTC'))); | |
| 120 | + $comment->setLatestChildDateTime(null); | |
| 121 | + } | |
| 122 | + | |
| 123 | +        if (is_null($comment->getCreationDateTime())) { | |
| 124 | + $comment->setCreationDateTime(new \DateTime()); | |
| 125 | + } | |
| 126 | + | |
| 127 | +        if ($comment->getParentId() !== '0') { | |
| 128 | + $comment->setTopmostParentId($this->determineTopmostParentId($comment->getParentId())); | |
| 129 | +        } else { | |
| 130 | +            $comment->setTopmostParentId('0'); | |
| 131 | + } | |
| 132 | + | |
| 133 | + $this->cache($comment); | |
| 134 | + | |
| 135 | + return $comment; | |
| 136 | + } | |
| 137 | + | |
| 138 | + /** | |
| 139 | + * returns the topmost parent id of a given comment identified by ID | |
| 140 | + * | |
| 141 | + * @param string $id | |
| 142 | + * @return string | |
| 143 | + * @throws NotFoundException | |
| 144 | + */ | |
| 145 | +    protected function determineTopmostParentId($id) { | |
| 146 | + $comment = $this->get($id); | |
| 147 | +        if ($comment->getParentId() === '0') { | |
| 148 | + return $comment->getId(); | |
| 149 | +        } else { | |
| 150 | + return $this->determineTopmostParentId($comment->getId()); | |
| 151 | + } | |
| 152 | + } | |
| 153 | + | |
| 154 | + /** | |
| 155 | + * updates child information of a comment | |
| 156 | + * | |
| 157 | + * @param string $id | |
| 158 | + * @param \DateTime $cDateTime the date time of the most recent child | |
| 159 | + * @throws NotFoundException | |
| 160 | + */ | |
| 161 | +    protected function updateChildrenInformation($id, \DateTime $cDateTime) { | |
| 162 | + $qb = $this->dbConn->getQueryBuilder(); | |
| 163 | +        $query = $qb->select($qb->createFunction('COUNT(`id`)')) | |
| 164 | +            ->from('comments') | |
| 165 | +            ->where($qb->expr()->eq('parent_id', $qb->createParameter('id'))) | |
| 166 | +            ->setParameter('id', $id); | |
| 167 | + | |
| 168 | + $resultStatement = $query->execute(); | |
| 169 | + $data = $resultStatement->fetch(\PDO::FETCH_NUM); | |
| 170 | + $resultStatement->closeCursor(); | |
| 171 | + $children = intval($data[0]); | |
| 172 | + | |
| 173 | + $comment = $this->get($id); | |
| 174 | + $comment->setChildrenCount($children); | |
| 175 | + $comment->setLatestChildDateTime($cDateTime); | |
| 176 | + $this->save($comment); | |
| 177 | + } | |
| 178 | + | |
| 179 | + /** | |
| 180 | + * Tests whether actor or object type and id parameters are acceptable. | |
| 181 | + * Throws exception if not. | |
| 182 | + * | |
| 183 | + * @param string $role | |
| 184 | + * @param string $type | |
| 185 | + * @param string $id | |
| 186 | + * @throws \InvalidArgumentException | |
| 187 | + */ | |
| 188 | +    protected function checkRoleParameters($role, $type, $id) { | |
| 189 | + if ( | |
| 190 | + !is_string($type) || empty($type) | |
| 191 | + || !is_string($id) || empty($id) | |
| 192 | +        ) { | |
| 193 | + throw new \InvalidArgumentException($role . ' parameters must be string and not empty'); | |
| 194 | + } | |
| 195 | + } | |
| 196 | + | |
| 197 | + /** | |
| 198 | + * run-time caches a comment | |
| 199 | + * | |
| 200 | + * @param IComment $comment | |
| 201 | + */ | |
| 202 | +    protected function cache(IComment $comment) { | |
| 203 | + $id = $comment->getId(); | |
| 204 | +        if (empty($id)) { | |
| 205 | + return; | |
| 206 | + } | |
| 207 | + $this->commentsCache[strval($id)] = $comment; | |
| 208 | + } | |
| 209 | + | |
| 210 | + /** | |
| 211 | + * removes an entry from the comments run time cache | |
| 212 | + * | |
| 213 | + * @param mixed $id the comment's id | |
| 214 | + */ | |
| 215 | +    protected function uncache($id) { | |
| 216 | + $id = strval($id); | |
| 217 | +        if (isset($this->commentsCache[$id])) { | |
| 218 | + unset($this->commentsCache[$id]); | |
| 219 | + } | |
| 220 | + } | |
| 221 | + | |
| 222 | + /** | |
| 223 | + * returns a comment instance | |
| 224 | + * | |
| 225 | + * @param string $id the ID of the comment | |
| 226 | + * @return IComment | |
| 227 | + * @throws NotFoundException | |
| 228 | + * @throws \InvalidArgumentException | |
| 229 | + * @since 9.0.0 | |
| 230 | + */ | |
| 231 | +    public function get($id) { | |
| 232 | +        if (intval($id) === 0) { | |
| 233 | +            throw new \InvalidArgumentException('IDs must be translatable to a number in this implementation.'); | |
| 234 | + } | |
| 235 | + | |
| 236 | +        if (isset($this->commentsCache[$id])) { | |
| 237 | + return $this->commentsCache[$id]; | |
| 238 | + } | |
| 239 | + | |
| 240 | + $qb = $this->dbConn->getQueryBuilder(); | |
| 241 | +        $resultStatement = $qb->select('*') | |
| 242 | +            ->from('comments') | |
| 243 | +            ->where($qb->expr()->eq('id', $qb->createParameter('id'))) | |
| 244 | +            ->setParameter('id', $id, IQueryBuilder::PARAM_INT) | |
| 245 | + ->execute(); | |
| 246 | + | |
| 247 | + $data = $resultStatement->fetch(); | |
| 248 | + $resultStatement->closeCursor(); | |
| 249 | +        if (!$data) { | |
| 250 | + throw new NotFoundException(); | |
| 251 | + } | |
| 252 | + | |
| 253 | + $comment = new Comment($this->normalizeDatabaseData($data)); | |
| 254 | + $this->cache($comment); | |
| 255 | + return $comment; | |
| 256 | + } | |
| 257 | + | |
| 258 | + /** | |
| 259 | + * returns the comment specified by the id and all it's child comments. | |
| 260 | + * At this point of time, we do only support one level depth. | |
| 261 | + * | |
| 262 | + * @param string $id | |
| 263 | + * @param int $limit max number of entries to return, 0 returns all | |
| 264 | + * @param int $offset the start entry | |
| 265 | + * @return array | |
| 266 | + * @since 9.0.0 | |
| 267 | + * | |
| 268 | + * The return array looks like this | |
| 269 | + * [ | |
| 270 | + * 'comment' => IComment, // root comment | |
| 271 | + * 'replies' => | |
| 272 | + * [ | |
| 273 | + * 0 => | |
| 274 | + * [ | |
| 275 | + * 'comment' => IComment, | |
| 276 | + * 'replies' => [] | |
| 277 | + * ] | |
| 278 | + * 1 => | |
| 279 | + * [ | |
| 280 | + * 'comment' => IComment, | |
| 281 | + * 'replies'=> [] | |
| 282 | + * ], | |
| 283 | + * … | |
| 284 | + * ] | |
| 285 | + * ] | |
| 286 | + */ | |
| 287 | +    public function getTree($id, $limit = 0, $offset = 0) { | |
| 288 | + $tree = []; | |
| 289 | + $tree['comment'] = $this->get($id); | |
| 290 | + $tree['replies'] = []; | |
| 291 | + | |
| 292 | + $qb = $this->dbConn->getQueryBuilder(); | |
| 293 | +        $query = $qb->select('*') | |
| 294 | +            ->from('comments') | |
| 295 | +            ->where($qb->expr()->eq('topmost_parent_id', $qb->createParameter('id'))) | |
| 296 | +            ->orderBy('creation_timestamp', 'DESC') | |
| 297 | +            ->setParameter('id', $id); | |
| 298 | + | |
| 299 | +        if ($limit > 0) { | |
| 300 | + $query->setMaxResults($limit); | |
| 301 | + } | |
| 302 | +        if ($offset > 0) { | |
| 303 | + $query->setFirstResult($offset); | |
| 304 | + } | |
| 305 | + | |
| 306 | + $resultStatement = $query->execute(); | |
| 307 | +        while ($data = $resultStatement->fetch()) { | |
| 308 | + $comment = new Comment($this->normalizeDatabaseData($data)); | |
| 309 | + $this->cache($comment); | |
| 310 | + $tree['replies'][] = [ | |
| 311 | + 'comment' => $comment, | |
| 312 | + 'replies' => [] | |
| 313 | + ]; | |
| 314 | + } | |
| 315 | + $resultStatement->closeCursor(); | |
| 316 | + | |
| 317 | + return $tree; | |
| 318 | + } | |
| 319 | + | |
| 320 | + /** | |
| 321 | + * Get the actor types and ID that commented in the tree specified by the ID | |
| 322 | + * | |
| 323 | + * @param string $id | |
| 324 | + * @return array | |
| 325 | + * @since 13.0.0 | |
| 326 | + * | |
| 327 | + * The return array looks like this: | |
| 328 | + * | |
| 329 | + * [ | |
| 330 | + * 'user' => [ | |
| 331 | + * 'alice' => 2, | |
| 332 | + * 'bob' => 3 | |
| 333 | + * ], | |
| 334 | + * 'robot' => [ | |
| 335 | + * 'r2-d2' => 5, | |
| 336 | + * 'c-3po' => 17, | |
| 337 | + * ] | |
| 338 | + * ] | |
| 339 | + */ | |
| 340 | +    public function getActorsInTree($id) { | |
| 341 | + $tree = $this->getTree($id); | |
| 342 | + $actors = []; | |
| 343 | + $this->walkTree($tree, $actors, [$this, 'extractActor']); | |
| 344 | + return $actors; | |
| 345 | + } | |
| 346 | + | |
| 347 | + /** | |
| 348 | + * @param IComment $comment | |
| 349 | + * @param array &$actors | |
| 350 | + * | |
| 351 | + * build an array that looks like: | |
| 352 | + * | |
| 353 | + * [ | |
| 354 | + * 'user' => [ | |
| 355 | + * 'alice' => 2, | |
| 356 | + * 'bob' => 3 | |
| 357 | + * ], | |
| 358 | + * 'robot' => [ | |
| 359 | + * 'r2-d2' => 5, | |
| 360 | + * 'c-3po' => 17, | |
| 361 | + * ] | |
| 362 | + * ] | |
| 363 | + * | |
| 364 | + */ | |
| 365 | +    protected function extractActor(IComment $comment, &$actors) { | |
| 366 | +        if(!isset($actors[$comment->getActorType()])) { | |
| 367 | + $actors[$comment->getActorType()] = []; | |
| 368 | + } | |
| 369 | +        if(!isset($actors[$comment->getActorType()][$comment->getActorId()])) { | |
| 370 | + $actors[$comment->getActorType()][$comment->getActorId()] = 1; | |
| 371 | +        } else { | |
| 372 | + $actors[$comment->getActorType()][$comment->getActorId()] += 1; | |
| 373 | + } | |
| 374 | + } | |
| 375 | + | |
| 376 | + /** | |
| 377 | + * walks through a comment tree (as returned by getTree() and invokes a callback | |
| 378 | + * with the current IComment instance (and optionally custom parameters) | |
| 379 | + * | |
| 380 | + * @param array $node | |
| 381 | + * @param array &$results | |
| 382 | + * @param callable $callback | |
| 383 | + * @param array|null $parameters | |
| 384 | + */ | |
| 385 | +    protected function walkTree($node, array &$results, callable $callback, array $parameters = null) { | |
| 386 | +        if(isset($node['replies'])) { | |
| 387 | +            foreach ($node['replies'] as $subNode) { | |
| 388 | + $this->walkTree($subNode, $results, $callback, $parameters); | |
| 389 | + } | |
| 390 | + } | |
| 391 | +        if(isset($node['comment']) && $node['comment'] instanceof IComment) { | |
| 392 | + $callback($node['comment'], $results, $parameters); | |
| 393 | + } | |
| 394 | + } | |
| 395 | + | |
| 396 | + /** | |
| 397 | + * returns comments for a specific object (e.g. a file). | |
| 398 | + * | |
| 399 | + * The sort order is always newest to oldest. | |
| 400 | + * | |
| 401 | + * @param string $objectType the object type, e.g. 'files' | |
| 402 | + * @param string $objectId the id of the object | |
| 403 | + * @param int $limit optional, number of maximum comments to be returned. if | |
| 404 | + * not specified, all comments are returned. | |
| 405 | + * @param int $offset optional, starting point | |
| 406 | + * @param \DateTime $notOlderThan optional, timestamp of the oldest comments | |
| 407 | + * that may be returned | |
| 408 | + * @return IComment[] | |
| 409 | + * @since 9.0.0 | |
| 410 | + */ | |
| 411 | + public function getForObject( | |
| 412 | + $objectType, | |
| 413 | + $objectId, | |
| 414 | + $limit = 0, | |
| 415 | + $offset = 0, | |
| 416 | + \DateTime $notOlderThan = null | |
| 417 | +    ) { | |
| 418 | + $comments = []; | |
| 419 | + | |
| 420 | + $qb = $this->dbConn->getQueryBuilder(); | |
| 421 | +        $query = $qb->select('*') | |
| 422 | +            ->from('comments') | |
| 423 | +            ->where($qb->expr()->eq('object_type', $qb->createParameter('type'))) | |
| 424 | +            ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id'))) | |
| 425 | +            ->orderBy('creation_timestamp', 'DESC') | |
| 426 | +            ->setParameter('type', $objectType) | |
| 427 | +            ->setParameter('id', $objectId); | |
| 428 | + | |
| 429 | +        if ($limit > 0) { | |
| 430 | + $query->setMaxResults($limit); | |
| 431 | + } | |
| 432 | +        if ($offset > 0) { | |
| 433 | + $query->setFirstResult($offset); | |
| 434 | + } | |
| 435 | +        if (!is_null($notOlderThan)) { | |
| 436 | + $query | |
| 437 | +                ->andWhere($qb->expr()->gt('creation_timestamp', $qb->createParameter('notOlderThan'))) | |
| 438 | +                ->setParameter('notOlderThan', $notOlderThan, 'datetime'); | |
| 439 | + } | |
| 440 | + | |
| 441 | + $resultStatement = $query->execute(); | |
| 442 | +        while ($data = $resultStatement->fetch()) { | |
| 443 | + $comment = new Comment($this->normalizeDatabaseData($data)); | |
| 444 | + $this->cache($comment); | |
| 445 | + $comments[] = $comment; | |
| 446 | + } | |
| 447 | + $resultStatement->closeCursor(); | |
| 448 | + | |
| 449 | + return $comments; | |
| 450 | + } | |
| 451 | + | |
| 452 | + /** | |
| 453 | + * @param $objectType string the object type, e.g. 'files' | |
| 454 | + * @param $objectId string the id of the object | |
| 455 | + * @param \DateTime $notOlderThan optional, timestamp of the oldest comments | |
| 456 | + * that may be returned | |
| 457 | + * @return Int | |
| 458 | + * @since 9.0.0 | |
| 459 | + */ | |
| 460 | +    public function getNumberOfCommentsForObject($objectType, $objectId, \DateTime $notOlderThan = null) { | |
| 461 | + $qb = $this->dbConn->getQueryBuilder(); | |
| 462 | +        $query = $qb->select($qb->createFunction('COUNT(`id`)')) | |
| 463 | +            ->from('comments') | |
| 464 | +            ->where($qb->expr()->eq('object_type', $qb->createParameter('type'))) | |
| 465 | +            ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id'))) | |
| 466 | +            ->setParameter('type', $objectType) | |
| 467 | +            ->setParameter('id', $objectId); | |
| 468 | + | |
| 469 | +        if (!is_null($notOlderThan)) { | |
| 470 | + $query | |
| 471 | +                ->andWhere($qb->expr()->gt('creation_timestamp', $qb->createParameter('notOlderThan'))) | |
| 472 | +                ->setParameter('notOlderThan', $notOlderThan, 'datetime'); | |
| 473 | + } | |
| 474 | + | |
| 475 | + $resultStatement = $query->execute(); | |
| 476 | + $data = $resultStatement->fetch(\PDO::FETCH_NUM); | |
| 477 | + $resultStatement->closeCursor(); | |
| 478 | + return intval($data[0]); | |
| 479 | + } | |
| 480 | + | |
| 481 | + /** | |
| 482 | + * Get the number of unread comments for all files in a folder | |
| 483 | + * | |
| 484 | + * @param int $folderId | |
| 485 | + * @param IUser $user | |
| 486 | + * @return array [$fileId => $unreadCount] | |
| 487 | + */ | |
| 488 | +    public function getNumberOfUnreadCommentsForFolder($folderId, IUser $user) { | |
| 489 | + $qb = $this->dbConn->getQueryBuilder(); | |
| 490 | +        $query = $qb->select('f.fileid') | |
| 491 | + ->selectAlias( | |
| 492 | +                $qb->createFunction('COUNT(' . $qb->getColumnName('c.id') . ')'), | |
| 493 | + 'num_ids' | |
| 494 | + ) | |
| 495 | +            ->from('comments', 'c') | |
| 496 | +            ->innerJoin('c', 'filecache', 'f', $qb->expr()->andX( | |
| 497 | +                $qb->expr()->eq('c.object_type', $qb->createNamedParameter('files')), | |
| 498 | +                $qb->expr()->eq('f.fileid', $qb->expr()->castColumn('c.object_id', IQueryBuilder::PARAM_INT)) | |
| 499 | + )) | |
| 500 | +            ->leftJoin('c', 'comments_read_markers', 'm', $qb->expr()->andX( | |
| 501 | +                $qb->expr()->eq('m.object_type', $qb->createNamedParameter('files')), | |
| 502 | +                $qb->expr()->eq('m.object_id', 'c.object_id'), | |
| 503 | +                $qb->expr()->eq('m.user_id', $qb->createNamedParameter($user->getUID())) | |
| 504 | + )) | |
| 505 | +            ->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($folderId))) | |
| 506 | + ->andWhere($qb->expr()->orX( | |
| 507 | +                $qb->expr()->gt('c.creation_timestamp', 'marker_datetime'), | |
| 508 | +                $qb->expr()->isNull('marker_datetime') | |
| 509 | + )) | |
| 510 | +            ->groupBy('f.fileid'); | |
| 511 | + | |
| 512 | + $resultStatement = $query->execute(); | |
| 513 | + | |
| 514 | + $results = []; | |
| 515 | +        while ($row = $resultStatement->fetch()) { | |
| 516 | + $results[$row['fileid']] = (int) $row['num_ids']; | |
| 517 | + } | |
| 518 | + $resultStatement->closeCursor(); | |
| 519 | + return $results; | |
| 520 | + } | |
| 521 | + | |
| 522 | + /** | |
| 523 | + * creates a new comment and returns it. At this point of time, it is not | |
| 524 | + * saved in the used data storage. Use save() after setting other fields | |
| 525 | + * of the comment (e.g. message or verb). | |
| 526 | + * | |
| 527 | + * @param string $actorType the actor type (e.g. 'users') | |
| 528 | + * @param string $actorId a user id | |
| 529 | + * @param string $objectType the object type the comment is attached to | |
| 530 | + * @param string $objectId the object id the comment is attached to | |
| 531 | + * @return IComment | |
| 532 | + * @since 9.0.0 | |
| 533 | + */ | |
| 534 | +    public function create($actorType, $actorId, $objectType, $objectId) { | |
| 535 | + $comment = new Comment(); | |
| 536 | + $comment | |
| 537 | + ->setActor($actorType, $actorId) | |
| 538 | + ->setObject($objectType, $objectId); | |
| 539 | + return $comment; | |
| 540 | + } | |
| 541 | + | |
| 542 | + /** | |
| 543 | + * permanently deletes the comment specified by the ID | |
| 544 | + * | |
| 545 | + * When the comment has child comments, their parent ID will be changed to | |
| 546 | + * the parent ID of the item that is to be deleted. | |
| 547 | + * | |
| 548 | + * @param string $id | |
| 549 | + * @return bool | |
| 550 | + * @throws \InvalidArgumentException | |
| 551 | + * @since 9.0.0 | |
| 552 | + */ | |
| 553 | +    public function delete($id) { | |
| 554 | +        if (!is_string($id)) { | |
| 555 | +            throw new \InvalidArgumentException('Parameter must be string'); | |
| 556 | + } | |
| 557 | + | |
| 558 | +        try { | |
| 559 | + $comment = $this->get($id); | |
| 560 | +        } catch (\Exception $e) { | |
| 561 | + // Ignore exceptions, we just don't fire a hook then | |
| 562 | + $comment = null; | |
| 563 | + } | |
| 564 | + | |
| 565 | + $qb = $this->dbConn->getQueryBuilder(); | |
| 566 | +        $query = $qb->delete('comments') | |
| 567 | +            ->where($qb->expr()->eq('id', $qb->createParameter('id'))) | |
| 568 | +            ->setParameter('id', $id); | |
| 569 | + | |
| 570 | +        try { | |
| 571 | + $affectedRows = $query->execute(); | |
| 572 | + $this->uncache($id); | |
| 573 | +        } catch (DriverException $e) { | |
| 574 | + $this->logger->logException($e, ['app' => 'core_comments']); | |
| 575 | + return false; | |
| 576 | + } | |
| 577 | + | |
| 578 | +        if ($affectedRows > 0 && $comment instanceof IComment) { | |
| 579 | + $this->sendEvent(CommentsEvent::EVENT_DELETE, $comment); | |
| 580 | + } | |
| 581 | + | |
| 582 | + return ($affectedRows > 0); | |
| 583 | + } | |
| 584 | + | |
| 585 | + /** | |
| 586 | + * saves the comment permanently | |
| 587 | + * | |
| 588 | + * if the supplied comment has an empty ID, a new entry comment will be | |
| 589 | + * saved and the instance updated with the new ID. | |
| 590 | + * | |
| 591 | + * Otherwise, an existing comment will be updated. | |
| 592 | + * | |
| 593 | + * Throws NotFoundException when a comment that is to be updated does not | |
| 594 | + * exist anymore at this point of time. | |
| 595 | + * | |
| 596 | + * @param IComment $comment | |
| 597 | + * @return bool | |
| 598 | + * @throws NotFoundException | |
| 599 | + * @since 9.0.0 | |
| 600 | + */ | |
| 601 | +    public function save(IComment $comment) { | |
| 602 | +        if ($this->prepareCommentForDatabaseWrite($comment)->getId() === '') { | |
| 603 | + $result = $this->insert($comment); | |
| 604 | +        } else { | |
| 605 | + $result = $this->update($comment); | |
| 606 | + } | |
| 607 | + | |
| 608 | +        if ($result && !!$comment->getParentId()) { | |
| 609 | + $this->updateChildrenInformation( | |
| 610 | + $comment->getParentId(), | |
| 611 | + $comment->getCreationDateTime() | |
| 612 | + ); | |
| 613 | + $this->cache($comment); | |
| 614 | + } | |
| 615 | + | |
| 616 | + return $result; | |
| 617 | + } | |
| 618 | + | |
| 619 | + /** | |
| 620 | + * inserts the provided comment in the database | |
| 621 | + * | |
| 622 | + * @param IComment $comment | |
| 623 | + * @return bool | |
| 624 | + */ | |
| 625 | +    protected function insert(IComment &$comment) { | |
| 626 | + $qb = $this->dbConn->getQueryBuilder(); | |
| 627 | + $affectedRows = $qb | |
| 628 | +            ->insert('comments') | |
| 629 | + ->values([ | |
| 630 | + 'parent_id' => $qb->createNamedParameter($comment->getParentId()), | |
| 631 | + 'topmost_parent_id' => $qb->createNamedParameter($comment->getTopmostParentId()), | |
| 632 | + 'children_count' => $qb->createNamedParameter($comment->getChildrenCount()), | |
| 633 | + 'actor_type' => $qb->createNamedParameter($comment->getActorType()), | |
| 634 | + 'actor_id' => $qb->createNamedParameter($comment->getActorId()), | |
| 635 | + 'message' => $qb->createNamedParameter($comment->getMessage()), | |
| 636 | + 'verb' => $qb->createNamedParameter($comment->getVerb()), | |
| 637 | + 'creation_timestamp' => $qb->createNamedParameter($comment->getCreationDateTime(), 'datetime'), | |
| 638 | + 'latest_child_timestamp' => $qb->createNamedParameter($comment->getLatestChildDateTime(), 'datetime'), | |
| 639 | + 'object_type' => $qb->createNamedParameter($comment->getObjectType()), | |
| 640 | + 'object_id' => $qb->createNamedParameter($comment->getObjectId()), | |
| 641 | + ]) | |
| 642 | + ->execute(); | |
| 643 | + | |
| 644 | +        if ($affectedRows > 0) { | |
| 645 | + $comment->setId(strval($qb->getLastInsertId())); | |
| 646 | + $this->sendEvent(CommentsEvent::EVENT_ADD, $comment); | |
| 647 | + } | |
| 648 | + | |
| 649 | + return $affectedRows > 0; | |
| 650 | + } | |
| 651 | + | |
| 652 | + /** | |
| 653 | + * updates a Comment data row | |
| 654 | + * | |
| 655 | + * @param IComment $comment | |
| 656 | + * @return bool | |
| 657 | + * @throws NotFoundException | |
| 658 | + */ | |
| 659 | +    protected function update(IComment $comment) { | |
| 660 | + // for properly working preUpdate Events we need the old comments as is | |
| 661 | + // in the DB and overcome caching. Also avoid that outdated information stays. | |
| 662 | + $this->uncache($comment->getId()); | |
| 663 | + $this->sendEvent(CommentsEvent::EVENT_PRE_UPDATE, $this->get($comment->getId())); | |
| 664 | + $this->uncache($comment->getId()); | |
| 665 | + | |
| 666 | + $qb = $this->dbConn->getQueryBuilder(); | |
| 667 | + $affectedRows = $qb | |
| 668 | +            ->update('comments') | |
| 669 | +            ->set('parent_id', $qb->createNamedParameter($comment->getParentId())) | |
| 670 | +            ->set('topmost_parent_id', $qb->createNamedParameter($comment->getTopmostParentId())) | |
| 671 | +            ->set('children_count', $qb->createNamedParameter($comment->getChildrenCount())) | |
| 672 | +            ->set('actor_type', $qb->createNamedParameter($comment->getActorType())) | |
| 673 | +            ->set('actor_id', $qb->createNamedParameter($comment->getActorId())) | |
| 674 | +            ->set('message', $qb->createNamedParameter($comment->getMessage())) | |
| 675 | +            ->set('verb', $qb->createNamedParameter($comment->getVerb())) | |
| 676 | +            ->set('creation_timestamp', $qb->createNamedParameter($comment->getCreationDateTime(), 'datetime')) | |
| 677 | +            ->set('latest_child_timestamp', $qb->createNamedParameter($comment->getLatestChildDateTime(), 'datetime')) | |
| 678 | +            ->set('object_type', $qb->createNamedParameter($comment->getObjectType())) | |
| 679 | +            ->set('object_id', $qb->createNamedParameter($comment->getObjectId())) | |
| 680 | +            ->where($qb->expr()->eq('id', $qb->createParameter('id'))) | |
| 681 | +            ->setParameter('id', $comment->getId()) | |
| 682 | + ->execute(); | |
| 683 | + | |
| 684 | +        if ($affectedRows === 0) { | |
| 685 | +            throw new NotFoundException('Comment to update does ceased to exist'); | |
| 686 | + } | |
| 687 | + | |
| 688 | + $this->sendEvent(CommentsEvent::EVENT_UPDATE, $comment); | |
| 689 | + | |
| 690 | + return $affectedRows > 0; | |
| 691 | + } | |
| 692 | + | |
| 693 | + /** | |
| 694 | + * removes references to specific actor (e.g. on user delete) of a comment. | |
| 695 | + * The comment itself must not get lost/deleted. | |
| 696 | + * | |
| 697 | + * @param string $actorType the actor type (e.g. 'users') | |
| 698 | + * @param string $actorId a user id | |
| 699 | + * @return boolean | |
| 700 | + * @since 9.0.0 | |
| 701 | + */ | |
| 702 | +    public function deleteReferencesOfActor($actorType, $actorId) { | |
| 703 | +        $this->checkRoleParameters('Actor', $actorType, $actorId); | |
| 704 | + | |
| 705 | + $qb = $this->dbConn->getQueryBuilder(); | |
| 706 | + $affectedRows = $qb | |
| 707 | +            ->update('comments') | |
| 708 | +            ->set('actor_type', $qb->createNamedParameter(ICommentsManager::DELETED_USER)) | |
| 709 | +            ->set('actor_id', $qb->createNamedParameter(ICommentsManager::DELETED_USER)) | |
| 710 | +            ->where($qb->expr()->eq('actor_type', $qb->createParameter('type'))) | |
| 711 | +            ->andWhere($qb->expr()->eq('actor_id', $qb->createParameter('id'))) | |
| 712 | +            ->setParameter('type', $actorType) | |
| 713 | +            ->setParameter('id', $actorId) | |
| 714 | + ->execute(); | |
| 715 | + | |
| 716 | + $this->commentsCache = []; | |
| 717 | + | |
| 718 | + return is_int($affectedRows); | |
| 719 | + } | |
| 720 | + | |
| 721 | + /** | |
| 722 | + * deletes all comments made of a specific object (e.g. on file delete) | |
| 723 | + * | |
| 724 | + * @param string $objectType the object type (e.g. 'files') | |
| 725 | + * @param string $objectId e.g. the file id | |
| 726 | + * @return boolean | |
| 727 | + * @since 9.0.0 | |
| 728 | + */ | |
| 729 | +    public function deleteCommentsAtObject($objectType, $objectId) { | |
| 730 | +        $this->checkRoleParameters('Object', $objectType, $objectId); | |
| 731 | + | |
| 732 | + $qb = $this->dbConn->getQueryBuilder(); | |
| 733 | + $affectedRows = $qb | |
| 734 | +            ->delete('comments') | |
| 735 | +            ->where($qb->expr()->eq('object_type', $qb->createParameter('type'))) | |
| 736 | +            ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id'))) | |
| 737 | +            ->setParameter('type', $objectType) | |
| 738 | +            ->setParameter('id', $objectId) | |
| 739 | + ->execute(); | |
| 740 | + | |
| 741 | + $this->commentsCache = []; | |
| 742 | + | |
| 743 | + return is_int($affectedRows); | |
| 744 | + } | |
| 745 | + | |
| 746 | + /** | |
| 747 | + * deletes the read markers for the specified user | |
| 748 | + * | |
| 749 | + * @param \OCP\IUser $user | |
| 750 | + * @return bool | |
| 751 | + * @since 9.0.0 | |
| 752 | + */ | |
| 753 | +    public function deleteReadMarksFromUser(IUser $user) { | |
| 754 | + $qb = $this->dbConn->getQueryBuilder(); | |
| 755 | +        $query = $qb->delete('comments_read_markers') | |
| 756 | +            ->where($qb->expr()->eq('user_id', $qb->createParameter('user_id'))) | |
| 757 | +            ->setParameter('user_id', $user->getUID()); | |
| 758 | + | |
| 759 | +        try { | |
| 760 | + $affectedRows = $query->execute(); | |
| 761 | +        } catch (DriverException $e) { | |
| 762 | + $this->logger->logException($e, ['app' => 'core_comments']); | |
| 763 | + return false; | |
| 764 | + } | |
| 765 | + return ($affectedRows > 0); | |
| 766 | + } | |
| 767 | + | |
| 768 | + /** | |
| 769 | + * sets the read marker for a given file to the specified date for the | |
| 770 | + * provided user | |
| 771 | + * | |
| 772 | + * @param string $objectType | |
| 773 | + * @param string $objectId | |
| 774 | + * @param \DateTime $dateTime | |
| 775 | + * @param IUser $user | |
| 776 | + * @since 9.0.0 | |
| 777 | + * @suppress SqlInjectionChecker | |
| 778 | + */ | |
| 779 | +    public function setReadMark($objectType, $objectId, \DateTime $dateTime, IUser $user) { | |
| 780 | +        $this->checkRoleParameters('Object', $objectType, $objectId); | |
| 781 | + | |
| 782 | + $qb = $this->dbConn->getQueryBuilder(); | |
| 783 | + $values = [ | |
| 784 | + 'user_id' => $qb->createNamedParameter($user->getUID()), | |
| 785 | + 'marker_datetime' => $qb->createNamedParameter($dateTime, 'datetime'), | |
| 786 | + 'object_type' => $qb->createNamedParameter($objectType), | |
| 787 | + 'object_id' => $qb->createNamedParameter($objectId), | |
| 788 | + ]; | |
| 789 | + | |
| 790 | + // Strategy: try to update, if this does not return affected rows, do an insert. | |
| 791 | + $affectedRows = $qb | |
| 792 | +            ->update('comments_read_markers') | |
| 793 | +            ->set('user_id', $values['user_id']) | |
| 794 | +            ->set('marker_datetime', $values['marker_datetime']) | |
| 795 | +            ->set('object_type', $values['object_type']) | |
| 796 | +            ->set('object_id', $values['object_id']) | |
| 797 | +            ->where($qb->expr()->eq('user_id', $qb->createParameter('user_id'))) | |
| 798 | +            ->andWhere($qb->expr()->eq('object_type', $qb->createParameter('object_type'))) | |
| 799 | +            ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('object_id'))) | |
| 800 | +            ->setParameter('user_id', $user->getUID(), IQueryBuilder::PARAM_STR) | |
| 801 | +            ->setParameter('object_type', $objectType, IQueryBuilder::PARAM_STR) | |
| 802 | +            ->setParameter('object_id', $objectId, IQueryBuilder::PARAM_STR) | |
| 803 | + ->execute(); | |
| 804 | + | |
| 805 | +        if ($affectedRows > 0) { | |
| 806 | + return; | |
| 807 | + } | |
| 808 | + | |
| 809 | +        $qb->insert('comments_read_markers') | |
| 810 | + ->values($values) | |
| 811 | + ->execute(); | |
| 812 | + } | |
| 813 | + | |
| 814 | + /** | |
| 815 | + * returns the read marker for a given file to the specified date for the | |
| 816 | + * provided user. It returns null, when the marker is not present, i.e. | |
| 817 | + * no comments were marked as read. | |
| 818 | + * | |
| 819 | + * @param string $objectType | |
| 820 | + * @param string $objectId | |
| 821 | + * @param IUser $user | |
| 822 | + * @return \DateTime|null | |
| 823 | + * @since 9.0.0 | |
| 824 | + */ | |
| 825 | +    public function getReadMark($objectType, $objectId, IUser $user) { | |
| 826 | + $qb = $this->dbConn->getQueryBuilder(); | |
| 827 | +        $resultStatement = $qb->select('marker_datetime') | |
| 828 | +            ->from('comments_read_markers') | |
| 829 | +            ->where($qb->expr()->eq('user_id', $qb->createParameter('user_id'))) | |
| 830 | +            ->andWhere($qb->expr()->eq('object_type', $qb->createParameter('object_type'))) | |
| 831 | +            ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('object_id'))) | |
| 832 | +            ->setParameter('user_id', $user->getUID(), IQueryBuilder::PARAM_STR) | |
| 833 | +            ->setParameter('object_type', $objectType, IQueryBuilder::PARAM_STR) | |
| 834 | +            ->setParameter('object_id', $objectId, IQueryBuilder::PARAM_STR) | |
| 835 | + ->execute(); | |
| 836 | + | |
| 837 | + $data = $resultStatement->fetch(); | |
| 838 | + $resultStatement->closeCursor(); | |
| 839 | +        if (!$data || is_null($data['marker_datetime'])) { | |
| 840 | + return null; | |
| 841 | + } | |
| 842 | + | |
| 843 | + return new \DateTime($data['marker_datetime']); | |
| 844 | + } | |
| 845 | + | |
| 846 | + /** | |
| 847 | + * deletes the read markers on the specified object | |
| 848 | + * | |
| 849 | + * @param string $objectType | |
| 850 | + * @param string $objectId | |
| 851 | + * @return bool | |
| 852 | + * @since 9.0.0 | |
| 853 | + */ | |
| 854 | +    public function deleteReadMarksOnObject($objectType, $objectId) { | |
| 855 | +        $this->checkRoleParameters('Object', $objectType, $objectId); | |
| 856 | + | |
| 857 | + $qb = $this->dbConn->getQueryBuilder(); | |
| 858 | +        $query = $qb->delete('comments_read_markers') | |
| 859 | +            ->where($qb->expr()->eq('object_type', $qb->createParameter('object_type'))) | |
| 860 | +            ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('object_id'))) | |
| 861 | +            ->setParameter('object_type', $objectType) | |
| 862 | +            ->setParameter('object_id', $objectId); | |
| 863 | + | |
| 864 | +        try { | |
| 865 | + $affectedRows = $query->execute(); | |
| 866 | +        } catch (DriverException $e) { | |
| 867 | + $this->logger->logException($e, ['app' => 'core_comments']); | |
| 868 | + return false; | |
| 869 | + } | |
| 870 | + return ($affectedRows > 0); | |
| 871 | + } | |
| 872 | + | |
| 873 | + /** | |
| 874 | + * registers an Entity to the manager, so event notifications can be send | |
| 875 | + * to consumers of the comments infrastructure | |
| 876 | + * | |
| 877 | + * @param \Closure $closure | |
| 878 | + */ | |
| 879 | +    public function registerEventHandler(\Closure $closure) { | |
| 880 | + $this->eventHandlerClosures[] = $closure; | |
| 881 | + $this->eventHandlers = []; | |
| 882 | + } | |
| 883 | + | |
| 884 | + /** | |
| 885 | + * registers a method that resolves an ID to a display name for a given type | |
| 886 | + * | |
| 887 | + * @param string $type | |
| 888 | + * @param \Closure $closure | |
| 889 | + * @throws \OutOfBoundsException | |
| 890 | + * @since 11.0.0 | |
| 891 | + * | |
| 892 | + * Only one resolver shall be registered per type. Otherwise a | |
| 893 | + * \OutOfBoundsException has to thrown. | |
| 894 | + */ | |
| 895 | +    public function registerDisplayNameResolver($type, \Closure $closure) { | |
| 896 | +        if (!is_string($type)) { | |
| 897 | +            throw new \InvalidArgumentException('String expected.'); | |
| 898 | + } | |
| 899 | +        if (isset($this->displayNameResolvers[$type])) { | |
| 900 | +            throw new \OutOfBoundsException('Displayname resolver for this type already registered'); | |
| 901 | + } | |
| 902 | + $this->displayNameResolvers[$type] = $closure; | |
| 903 | + } | |
| 904 | + | |
| 905 | + /** | |
| 906 | + * resolves a given ID of a given Type to a display name. | |
| 907 | + * | |
| 908 | + * @param string $type | |
| 909 | + * @param string $id | |
| 910 | + * @return string | |
| 911 | + * @throws \OutOfBoundsException | |
| 912 | + * @since 11.0.0 | |
| 913 | + * | |
| 914 | + * If a provided type was not registered, an \OutOfBoundsException shall | |
| 915 | + * be thrown. It is upon the resolver discretion what to return of the | |
| 916 | + * provided ID is unknown. It must be ensured that a string is returned. | |
| 917 | + */ | |
| 918 | +    public function resolveDisplayName($type, $id) { | |
| 919 | +        if (!is_string($type)) { | |
| 920 | +            throw new \InvalidArgumentException('String expected.'); | |
| 921 | + } | |
| 922 | +        if (!isset($this->displayNameResolvers[$type])) { | |
| 923 | +            throw new \OutOfBoundsException('No Displayname resolver for this type registered'); | |
| 924 | + } | |
| 925 | + return (string)$this->displayNameResolvers[$type]($id); | |
| 926 | + } | |
| 927 | + | |
| 928 | + /** | |
| 929 | + * returns valid, registered entities | |
| 930 | + * | |
| 931 | + * @return \OCP\Comments\ICommentsEventHandler[] | |
| 932 | + */ | |
| 933 | +    private function getEventHandlers() { | |
| 934 | +        if (!empty($this->eventHandlers)) { | |
| 935 | + return $this->eventHandlers; | |
| 936 | + } | |
| 937 | + | |
| 938 | + $this->eventHandlers = []; | |
| 939 | +        foreach ($this->eventHandlerClosures as $name => $closure) { | |
| 940 | + $entity = $closure(); | |
| 941 | +            if (!($entity instanceof ICommentsEventHandler)) { | |
| 942 | +                throw new \InvalidArgumentException('The given entity does not implement the ICommentsEntity interface'); | |
| 943 | + } | |
| 944 | + $this->eventHandlers[$name] = $entity; | |
| 945 | + } | |
| 946 | + | |
| 947 | + return $this->eventHandlers; | |
| 948 | + } | |
| 949 | + | |
| 950 | + /** | |
| 951 | + * sends notifications to the registered entities | |
| 952 | + * | |
| 953 | + * @param $eventType | |
| 954 | + * @param IComment $comment | |
| 955 | + */ | |
| 956 | +    private function sendEvent($eventType, IComment $comment) { | |
| 957 | + $entities = $this->getEventHandlers(); | |
| 958 | + $event = new CommentsEvent($eventType, $comment); | |
| 959 | +        foreach ($entities as $entity) { | |
| 960 | + $entity->handle($event); | |
| 961 | + } | |
| 962 | + } | |
| 963 | 963 | } | 
| @@ -190,7 +190,7 @@ discard block | ||
| 190 | 190 | !is_string($type) || empty($type) | 
| 191 | 191 | || !is_string($id) || empty($id) | 
| 192 | 192 |  		) { | 
| 193 | - throw new \InvalidArgumentException($role . ' parameters must be string and not empty'); | |
| 193 | + throw new \InvalidArgumentException($role.' parameters must be string and not empty'); | |
| 194 | 194 | } | 
| 195 | 195 | } | 
| 196 | 196 | |
| @@ -363,10 +363,10 @@ discard block | ||
| 363 | 363 | * | 
| 364 | 364 | */ | 
| 365 | 365 |  	protected function extractActor(IComment $comment, &$actors) { | 
| 366 | -		if(!isset($actors[$comment->getActorType()])) { | |
| 366 | +		if (!isset($actors[$comment->getActorType()])) { | |
| 367 | 367 | $actors[$comment->getActorType()] = []; | 
| 368 | 368 | } | 
| 369 | -		if(!isset($actors[$comment->getActorType()][$comment->getActorId()])) { | |
| 369 | +		if (!isset($actors[$comment->getActorType()][$comment->getActorId()])) { | |
| 370 | 370 | $actors[$comment->getActorType()][$comment->getActorId()] = 1; | 
| 371 | 371 |  		} else { | 
| 372 | 372 | $actors[$comment->getActorType()][$comment->getActorId()] += 1; | 
| @@ -383,12 +383,12 @@ discard block | ||
| 383 | 383 | * @param array|null $parameters | 
| 384 | 384 | */ | 
| 385 | 385 |  	protected function walkTree($node, array &$results, callable $callback, array $parameters = null) { | 
| 386 | -		if(isset($node['replies'])) { | |
| 386 | +		if (isset($node['replies'])) { | |
| 387 | 387 |  			foreach ($node['replies'] as $subNode) { | 
| 388 | 388 | $this->walkTree($subNode, $results, $callback, $parameters); | 
| 389 | 389 | } | 
| 390 | 390 | } | 
| 391 | -		if(isset($node['comment']) && $node['comment'] instanceof IComment) { | |
| 391 | +		if (isset($node['comment']) && $node['comment'] instanceof IComment) { | |
| 392 | 392 | $callback($node['comment'], $results, $parameters); | 
| 393 | 393 | } | 
| 394 | 394 | } | 
| @@ -489,7 +489,7 @@ discard block | ||
| 489 | 489 | $qb = $this->dbConn->getQueryBuilder(); | 
| 490 | 490 |  		$query = $qb->select('f.fileid') | 
| 491 | 491 | ->selectAlias( | 
| 492 | -				$qb->createFunction('COUNT(' . $qb->getColumnName('c.id') . ')'), | |
| 492 | +				$qb->createFunction('COUNT('.$qb->getColumnName('c.id').')'), | |
| 493 | 493 | 'num_ids' | 
| 494 | 494 | ) | 
| 495 | 495 |  			->from('comments', 'c') | 
| @@ -622,7 +622,7 @@ discard block | ||
| 622 | 622 | * @param IComment $comment | 
| 623 | 623 | * @return bool | 
| 624 | 624 | */ | 
| 625 | -	protected function insert(IComment &$comment) { | |
| 625 | +	protected function insert(IComment & $comment) { | |
| 626 | 626 | $qb = $this->dbConn->getQueryBuilder(); | 
| 627 | 627 | $affectedRows = $qb | 
| 628 | 628 |  			->insert('comments') | 
| @@ -922,7 +922,7 @@ discard block | ||
| 922 | 922 |  		if (!isset($this->displayNameResolvers[$type])) { | 
| 923 | 923 |  			throw new \OutOfBoundsException('No Displayname resolver for this type registered'); | 
| 924 | 924 | } | 
| 925 | - return (string)$this->displayNameResolvers[$type]($id); | |
| 925 | + return (string) $this->displayNameResolvers[$type]($id); | |
| 926 | 926 | } | 
| 927 | 927 | |
| 928 | 928 | /** | 
| @@ -29,76 +29,76 @@ | ||
| 29 | 29 | |
| 30 | 30 |  class CommentersSorter implements ISorter { | 
| 31 | 31 | |
| 32 | - /** @var ICommentsManager */ | |
| 33 | - private $commentsManager; | |
| 34 | - | |
| 35 | -	public function __construct(ICommentsManager $commentsManager) { | |
| 36 | - $this->commentsManager = $commentsManager; | |
| 37 | - } | |
| 38 | - | |
| 39 | -	public function getId() { | |
| 40 | - return 'commenters'; | |
| 41 | - } | |
| 42 | - | |
| 43 | - /** | |
| 44 | - * Sorts people who commented on the given item atop (descelating) of the | |
| 45 | - * others | |
| 46 | - * | |
| 47 | - * @param array $sortArray | |
| 48 | - * @param array $context | |
| 49 | - */ | |
| 50 | -	public function sort(array &$sortArray, array $context) { | |
| 51 | - $commenters = $this->retrieveCommentsInformation($context['itemType'], $context['itemId']); | |
| 52 | -		if(count($commenters) === 0) { | |
| 53 | - return; | |
| 54 | - } | |
| 55 | - | |
| 56 | -		foreach ($sortArray as $type => &$byType) { | |
| 57 | -			if(!isset($commenters[$type])) { | |
| 58 | - continue; | |
| 59 | - } | |
| 60 | - | |
| 61 | - // at least on PHP 5.6 usort turned out to be not stable. So we add | |
| 62 | - // the current index to the value and compare it on a draw | |
| 63 | - $i = 0; | |
| 64 | -			$workArray = array_map(function($element) use (&$i) { | |
| 65 | - return [$i++, $element]; | |
| 66 | - }, $byType); | |
| 67 | - | |
| 68 | -			usort($workArray, function ($a, $b) use ($commenters, $type) { | |
| 69 | - $r = $this->compare($a[1], $b[1], $commenters[$type]); | |
| 70 | -				if($r === 0) { | |
| 71 | - $r = $a[0] - $b[0]; | |
| 72 | - } | |
| 73 | - return $r; | |
| 74 | - }); | |
| 75 | - | |
| 76 | - // and remove the index values again | |
| 77 | - $byType = array_column($workArray, 1); | |
| 78 | - } | |
| 79 | - } | |
| 80 | - | |
| 81 | - /** | |
| 82 | - * @param $type | |
| 83 | - * @param $id | |
| 84 | - * @return array | |
| 85 | - */ | |
| 86 | -	protected function retrieveCommentsInformation($type, $id) { | |
| 87 | - $comments = $this->commentsManager->getForObject($type, $id, 1); | |
| 88 | -		if(count($comments) === 0) { | |
| 89 | - return []; | |
| 90 | - } | |
| 91 | - | |
| 92 | - return $this->commentsManager->getActorsInTree($comments[0]->getTopmostParentId()); | |
| 93 | - } | |
| 94 | - | |
| 95 | -	protected function compare(array $a, array $b, array $commenters) { | |
| 96 | - $a = $a['value']['shareWith']; | |
| 97 | - $b = $b['value']['shareWith']; | |
| 98 | - | |
| 99 | - $valueA = isset($commenters[$a]) ? $commenters[$a] : 0; | |
| 100 | - $valueB = isset($commenters[$b]) ? $commenters[$b] : 0; | |
| 101 | - | |
| 102 | - return $valueB - $valueA; | |
| 103 | - } | |
| 32 | + /** @var ICommentsManager */ | |
| 33 | + private $commentsManager; | |
| 34 | + | |
| 35 | +    public function __construct(ICommentsManager $commentsManager) { | |
| 36 | + $this->commentsManager = $commentsManager; | |
| 37 | + } | |
| 38 | + | |
| 39 | +    public function getId() { | |
| 40 | + return 'commenters'; | |
| 41 | + } | |
| 42 | + | |
| 43 | + /** | |
| 44 | + * Sorts people who commented on the given item atop (descelating) of the | |
| 45 | + * others | |
| 46 | + * | |
| 47 | + * @param array $sortArray | |
| 48 | + * @param array $context | |
| 49 | + */ | |
| 50 | +    public function sort(array &$sortArray, array $context) { | |
| 51 | + $commenters = $this->retrieveCommentsInformation($context['itemType'], $context['itemId']); | |
| 52 | +        if(count($commenters) === 0) { | |
| 53 | + return; | |
| 54 | + } | |
| 55 | + | |
| 56 | +        foreach ($sortArray as $type => &$byType) { | |
| 57 | +            if(!isset($commenters[$type])) { | |
| 58 | + continue; | |
| 59 | + } | |
| 60 | + | |
| 61 | + // at least on PHP 5.6 usort turned out to be not stable. So we add | |
| 62 | + // the current index to the value and compare it on a draw | |
| 63 | + $i = 0; | |
| 64 | +            $workArray = array_map(function($element) use (&$i) { | |
| 65 | + return [$i++, $element]; | |
| 66 | + }, $byType); | |
| 67 | + | |
| 68 | +            usort($workArray, function ($a, $b) use ($commenters, $type) { | |
| 69 | + $r = $this->compare($a[1], $b[1], $commenters[$type]); | |
| 70 | +                if($r === 0) { | |
| 71 | + $r = $a[0] - $b[0]; | |
| 72 | + } | |
| 73 | + return $r; | |
| 74 | + }); | |
| 75 | + | |
| 76 | + // and remove the index values again | |
| 77 | + $byType = array_column($workArray, 1); | |
| 78 | + } | |
| 79 | + } | |
| 80 | + | |
| 81 | + /** | |
| 82 | + * @param $type | |
| 83 | + * @param $id | |
| 84 | + * @return array | |
| 85 | + */ | |
| 86 | +    protected function retrieveCommentsInformation($type, $id) { | |
| 87 | + $comments = $this->commentsManager->getForObject($type, $id, 1); | |
| 88 | +        if(count($comments) === 0) { | |
| 89 | + return []; | |
| 90 | + } | |
| 91 | + | |
| 92 | + return $this->commentsManager->getActorsInTree($comments[0]->getTopmostParentId()); | |
| 93 | + } | |
| 94 | + | |
| 95 | +    protected function compare(array $a, array $b, array $commenters) { | |
| 96 | + $a = $a['value']['shareWith']; | |
| 97 | + $b = $b['value']['shareWith']; | |
| 98 | + | |
| 99 | + $valueA = isset($commenters[$a]) ? $commenters[$a] : 0; | |
| 100 | + $valueB = isset($commenters[$b]) ? $commenters[$b] : 0; | |
| 101 | + | |
| 102 | + return $valueB - $valueA; | |
| 103 | + } | |
| 104 | 104 | } | 
| @@ -49,12 +49,12 @@ discard block | ||
| 49 | 49 | */ | 
| 50 | 50 |  	public function sort(array &$sortArray, array $context) { | 
| 51 | 51 | $commenters = $this->retrieveCommentsInformation($context['itemType'], $context['itemId']); | 
| 52 | -		if(count($commenters) === 0) { | |
| 52 | +		if (count($commenters) === 0) { | |
| 53 | 53 | return; | 
| 54 | 54 | } | 
| 55 | 55 | |
| 56 | 56 |  		foreach ($sortArray as $type => &$byType) { | 
| 57 | -			if(!isset($commenters[$type])) { | |
| 57 | +			if (!isset($commenters[$type])) { | |
| 58 | 58 | continue; | 
| 59 | 59 | } | 
| 60 | 60 | |
| @@ -65,9 +65,9 @@ discard block | ||
| 65 | 65 | return [$i++, $element]; | 
| 66 | 66 | }, $byType); | 
| 67 | 67 | |
| 68 | -			usort($workArray, function ($a, $b) use ($commenters, $type) { | |
| 68 | +			usort($workArray, function($a, $b) use ($commenters, $type) { | |
| 69 | 69 | $r = $this->compare($a[1], $b[1], $commenters[$type]); | 
| 70 | -				if($r === 0) { | |
| 70 | +				if ($r === 0) { | |
| 71 | 71 | $r = $a[0] - $b[0]; | 
| 72 | 72 | } | 
| 73 | 73 | return $r; | 
| @@ -85,7 +85,7 @@ discard block | ||
| 85 | 85 | */ | 
| 86 | 86 |  	protected function retrieveCommentsInformation($type, $id) { | 
| 87 | 87 | $comments = $this->commentsManager->getForObject($type, $id, 1); | 
| 88 | -		if(count($comments) === 0) { | |
| 88 | +		if (count($comments) === 0) { | |
| 89 | 89 | return []; | 
| 90 | 90 | } | 
| 91 | 91 | |
| @@ -6,52 +6,52 @@ | ||
| 6 | 6 | $baseDir = $vendorDir; | 
| 7 | 7 | |
| 8 | 8 | return array( | 
| 9 | - 'OCA\\Files_Sharing\\Activity\\Filter' => $baseDir . '/../lib/Activity/Filter.php', | |
| 10 | - 'OCA\\Files_Sharing\\Activity\\Providers\\Base' => $baseDir . '/../lib/Activity/Providers/Base.php', | |
| 11 | - 'OCA\\Files_Sharing\\Activity\\Providers\\Downloads' => $baseDir . '/../lib/Activity/Providers/Downloads.php', | |
| 12 | - 'OCA\\Files_Sharing\\Activity\\Providers\\Groups' => $baseDir . '/../lib/Activity/Providers/Groups.php', | |
| 13 | - 'OCA\\Files_Sharing\\Activity\\Providers\\PublicLinks' => $baseDir . '/../lib/Activity/Providers/PublicLinks.php', | |
| 14 | - 'OCA\\Files_Sharing\\Activity\\Providers\\RemoteShares' => $baseDir . '/../lib/Activity/Providers/RemoteShares.php', | |
| 15 | - 'OCA\\Files_Sharing\\Activity\\Providers\\Users' => $baseDir . '/../lib/Activity/Providers/Users.php', | |
| 16 | - 'OCA\\Files_Sharing\\Activity\\Settings\\PublicLinks' => $baseDir . '/../lib/Activity/Settings/PublicLinks.php', | |
| 17 | - 'OCA\\Files_Sharing\\Activity\\Settings\\RemoteShare' => $baseDir . '/../lib/Activity/Settings/RemoteShare.php', | |
| 18 | - 'OCA\\Files_Sharing\\Activity\\Settings\\Shared' => $baseDir . '/../lib/Activity/Settings/Shared.php', | |
| 19 | - 'OCA\\Files_Sharing\\AppInfo\\Application' => $baseDir . '/../lib/AppInfo/Application.php', | |
| 20 | - 'OCA\\Files_Sharing\\Cache' => $baseDir . '/../lib/Cache.php', | |
| 21 | - 'OCA\\Files_Sharing\\Capabilities' => $baseDir . '/../lib/Capabilities.php', | |
| 22 | - 'OCA\\Files_Sharing\\Collaboration\\ShareRecipientSorter' => $baseDir . '/../lib/Collaboration/ShareRecipientSorter.php', | |
| 23 | - 'OCA\\Files_Sharing\\Command\\CleanupRemoteStorages' => $baseDir . '/../lib/Command/CleanupRemoteStorages.php', | |
| 24 | - 'OCA\\Files_Sharing\\Controller\\ExternalSharesController' => $baseDir . '/../lib/Controller/ExternalSharesController.php', | |
| 25 | - 'OCA\\Files_Sharing\\Controller\\PublicPreviewController' => $baseDir . '/../lib/Controller/PublicPreviewController.php', | |
| 26 | - 'OCA\\Files_Sharing\\Controller\\RemoteController' => $baseDir . '/../lib/Controller/RemoteController.php', | |
| 27 | - 'OCA\\Files_Sharing\\Controller\\ShareAPIController' => $baseDir . '/../lib/Controller/ShareAPIController.php', | |
| 28 | - 'OCA\\Files_Sharing\\Controller\\ShareController' => $baseDir . '/../lib/Controller/ShareController.php', | |
| 29 | - 'OCA\\Files_Sharing\\Controller\\ShareInfoController' => $baseDir . '/../lib/Controller/ShareInfoController.php', | |
| 30 | - 'OCA\\Files_Sharing\\Controller\\ShareesAPIController' => $baseDir . '/../lib/Controller/ShareesAPIController.php', | |
| 31 | - 'OCA\\Files_Sharing\\DeleteOrphanedSharesJob' => $baseDir . '/../lib/DeleteOrphanedSharesJob.php', | |
| 32 | - 'OCA\\Files_Sharing\\Exceptions\\BrokenPath' => $baseDir . '/../lib/Exceptions/BrokenPath.php', | |
| 33 | - 'OCA\\Files_Sharing\\Exceptions\\S2SException' => $baseDir . '/../lib/Exceptions/S2SException.php', | |
| 34 | - 'OCA\\Files_Sharing\\ExpireSharesJob' => $baseDir . '/../lib/ExpireSharesJob.php', | |
| 35 | - 'OCA\\Files_Sharing\\External\\Cache' => $baseDir . '/../lib/External/Cache.php', | |
| 36 | - 'OCA\\Files_Sharing\\External\\Manager' => $baseDir . '/../lib/External/Manager.php', | |
| 37 | - 'OCA\\Files_Sharing\\External\\Mount' => $baseDir . '/../lib/External/Mount.php', | |
| 38 | - 'OCA\\Files_Sharing\\External\\MountProvider' => $baseDir . '/../lib/External/MountProvider.php', | |
| 39 | - 'OCA\\Files_Sharing\\External\\Scanner' => $baseDir . '/../lib/External/Scanner.php', | |
| 40 | - 'OCA\\Files_Sharing\\External\\Storage' => $baseDir . '/../lib/External/Storage.php', | |
| 41 | - 'OCA\\Files_Sharing\\External\\Watcher' => $baseDir . '/../lib/External/Watcher.php', | |
| 42 | - 'OCA\\Files_Sharing\\Helper' => $baseDir . '/../lib/Helper.php', | |
| 43 | - 'OCA\\Files_Sharing\\Hooks' => $baseDir . '/../lib/Hooks.php', | |
| 44 | - 'OCA\\Files_Sharing\\ISharedStorage' => $baseDir . '/../lib/ISharedStorage.php', | |
| 45 | - 'OCA\\Files_Sharing\\Middleware\\OCSShareAPIMiddleware' => $baseDir . '/../lib/Middleware/OCSShareAPIMiddleware.php', | |
| 46 | - 'OCA\\Files_Sharing\\Middleware\\ShareInfoMiddleware' => $baseDir . '/../lib/Middleware/ShareInfoMiddleware.php', | |
| 47 | - 'OCA\\Files_Sharing\\Middleware\\SharingCheckMiddleware' => $baseDir . '/../lib/Middleware/SharingCheckMiddleware.php', | |
| 48 | - 'OCA\\Files_Sharing\\Migration\\OwncloudGuestShareType' => $baseDir . '/../lib/Migration/OwncloudGuestShareType.php', | |
| 49 | - 'OCA\\Files_Sharing\\Migration\\SetPasswordColumn' => $baseDir . '/../lib/Migration/SetPasswordColumn.php', | |
| 50 | - 'OCA\\Files_Sharing\\MountProvider' => $baseDir . '/../lib/MountProvider.php', | |
| 51 | - 'OCA\\Files_Sharing\\Scanner' => $baseDir . '/../lib/Scanner.php', | |
| 52 | - 'OCA\\Files_Sharing\\ShareBackend\\File' => $baseDir . '/../lib/ShareBackend/File.php', | |
| 53 | - 'OCA\\Files_Sharing\\ShareBackend\\Folder' => $baseDir . '/../lib/ShareBackend/Folder.php', | |
| 54 | - 'OCA\\Files_Sharing\\SharedMount' => $baseDir . '/../lib/SharedMount.php', | |
| 55 | - 'OCA\\Files_Sharing\\SharedStorage' => $baseDir . '/../lib/SharedStorage.php', | |
| 56 | - 'OCA\\Files_Sharing\\Updater' => $baseDir . '/../lib/Updater.php', | |
| 9 | + 'OCA\\Files_Sharing\\Activity\\Filter' => $baseDir.'/../lib/Activity/Filter.php', | |
| 10 | + 'OCA\\Files_Sharing\\Activity\\Providers\\Base' => $baseDir.'/../lib/Activity/Providers/Base.php', | |
| 11 | + 'OCA\\Files_Sharing\\Activity\\Providers\\Downloads' => $baseDir.'/../lib/Activity/Providers/Downloads.php', | |
| 12 | + 'OCA\\Files_Sharing\\Activity\\Providers\\Groups' => $baseDir.'/../lib/Activity/Providers/Groups.php', | |
| 13 | + 'OCA\\Files_Sharing\\Activity\\Providers\\PublicLinks' => $baseDir.'/../lib/Activity/Providers/PublicLinks.php', | |
| 14 | + 'OCA\\Files_Sharing\\Activity\\Providers\\RemoteShares' => $baseDir.'/../lib/Activity/Providers/RemoteShares.php', | |
| 15 | + 'OCA\\Files_Sharing\\Activity\\Providers\\Users' => $baseDir.'/../lib/Activity/Providers/Users.php', | |
| 16 | + 'OCA\\Files_Sharing\\Activity\\Settings\\PublicLinks' => $baseDir.'/../lib/Activity/Settings/PublicLinks.php', | |
| 17 | + 'OCA\\Files_Sharing\\Activity\\Settings\\RemoteShare' => $baseDir.'/../lib/Activity/Settings/RemoteShare.php', | |
| 18 | + 'OCA\\Files_Sharing\\Activity\\Settings\\Shared' => $baseDir.'/../lib/Activity/Settings/Shared.php', | |
| 19 | + 'OCA\\Files_Sharing\\AppInfo\\Application' => $baseDir.'/../lib/AppInfo/Application.php', | |
| 20 | + 'OCA\\Files_Sharing\\Cache' => $baseDir.'/../lib/Cache.php', | |
| 21 | + 'OCA\\Files_Sharing\\Capabilities' => $baseDir.'/../lib/Capabilities.php', | |
| 22 | + 'OCA\\Files_Sharing\\Collaboration\\ShareRecipientSorter' => $baseDir.'/../lib/Collaboration/ShareRecipientSorter.php', | |
| 23 | + 'OCA\\Files_Sharing\\Command\\CleanupRemoteStorages' => $baseDir.'/../lib/Command/CleanupRemoteStorages.php', | |
| 24 | + 'OCA\\Files_Sharing\\Controller\\ExternalSharesController' => $baseDir.'/../lib/Controller/ExternalSharesController.php', | |
| 25 | + 'OCA\\Files_Sharing\\Controller\\PublicPreviewController' => $baseDir.'/../lib/Controller/PublicPreviewController.php', | |
| 26 | + 'OCA\\Files_Sharing\\Controller\\RemoteController' => $baseDir.'/../lib/Controller/RemoteController.php', | |
| 27 | + 'OCA\\Files_Sharing\\Controller\\ShareAPIController' => $baseDir.'/../lib/Controller/ShareAPIController.php', | |
| 28 | + 'OCA\\Files_Sharing\\Controller\\ShareController' => $baseDir.'/../lib/Controller/ShareController.php', | |
| 29 | + 'OCA\\Files_Sharing\\Controller\\ShareInfoController' => $baseDir.'/../lib/Controller/ShareInfoController.php', | |
| 30 | + 'OCA\\Files_Sharing\\Controller\\ShareesAPIController' => $baseDir.'/../lib/Controller/ShareesAPIController.php', | |
| 31 | + 'OCA\\Files_Sharing\\DeleteOrphanedSharesJob' => $baseDir.'/../lib/DeleteOrphanedSharesJob.php', | |
| 32 | + 'OCA\\Files_Sharing\\Exceptions\\BrokenPath' => $baseDir.'/../lib/Exceptions/BrokenPath.php', | |
| 33 | + 'OCA\\Files_Sharing\\Exceptions\\S2SException' => $baseDir.'/../lib/Exceptions/S2SException.php', | |
| 34 | + 'OCA\\Files_Sharing\\ExpireSharesJob' => $baseDir.'/../lib/ExpireSharesJob.php', | |
| 35 | + 'OCA\\Files_Sharing\\External\\Cache' => $baseDir.'/../lib/External/Cache.php', | |
| 36 | + 'OCA\\Files_Sharing\\External\\Manager' => $baseDir.'/../lib/External/Manager.php', | |
| 37 | + 'OCA\\Files_Sharing\\External\\Mount' => $baseDir.'/../lib/External/Mount.php', | |
| 38 | + 'OCA\\Files_Sharing\\External\\MountProvider' => $baseDir.'/../lib/External/MountProvider.php', | |
| 39 | + 'OCA\\Files_Sharing\\External\\Scanner' => $baseDir.'/../lib/External/Scanner.php', | |
| 40 | + 'OCA\\Files_Sharing\\External\\Storage' => $baseDir.'/../lib/External/Storage.php', | |
| 41 | + 'OCA\\Files_Sharing\\External\\Watcher' => $baseDir.'/../lib/External/Watcher.php', | |
| 42 | + 'OCA\\Files_Sharing\\Helper' => $baseDir.'/../lib/Helper.php', | |
| 43 | + 'OCA\\Files_Sharing\\Hooks' => $baseDir.'/../lib/Hooks.php', | |
| 44 | + 'OCA\\Files_Sharing\\ISharedStorage' => $baseDir.'/../lib/ISharedStorage.php', | |
| 45 | + 'OCA\\Files_Sharing\\Middleware\\OCSShareAPIMiddleware' => $baseDir.'/../lib/Middleware/OCSShareAPIMiddleware.php', | |
| 46 | + 'OCA\\Files_Sharing\\Middleware\\ShareInfoMiddleware' => $baseDir.'/../lib/Middleware/ShareInfoMiddleware.php', | |
| 47 | + 'OCA\\Files_Sharing\\Middleware\\SharingCheckMiddleware' => $baseDir.'/../lib/Middleware/SharingCheckMiddleware.php', | |
| 48 | + 'OCA\\Files_Sharing\\Migration\\OwncloudGuestShareType' => $baseDir.'/../lib/Migration/OwncloudGuestShareType.php', | |
| 49 | + 'OCA\\Files_Sharing\\Migration\\SetPasswordColumn' => $baseDir.'/../lib/Migration/SetPasswordColumn.php', | |
| 50 | + 'OCA\\Files_Sharing\\MountProvider' => $baseDir.'/../lib/MountProvider.php', | |
| 51 | + 'OCA\\Files_Sharing\\Scanner' => $baseDir.'/../lib/Scanner.php', | |
| 52 | + 'OCA\\Files_Sharing\\ShareBackend\\File' => $baseDir.'/../lib/ShareBackend/File.php', | |
| 53 | + 'OCA\\Files_Sharing\\ShareBackend\\Folder' => $baseDir.'/../lib/ShareBackend/Folder.php', | |
| 54 | + 'OCA\\Files_Sharing\\SharedMount' => $baseDir.'/../lib/SharedMount.php', | |
| 55 | + 'OCA\\Files_Sharing\\SharedStorage' => $baseDir.'/../lib/SharedStorage.php', | |
| 56 | + 'OCA\\Files_Sharing\\Updater' => $baseDir.'/../lib/Updater.php', | |
| 57 | 57 | ); | 
| @@ -6,74 +6,74 @@ | ||
| 6 | 6 | |
| 7 | 7 | class ComposerStaticInitf32f03f7cd82bff20d6a51be16689441 | 
| 8 | 8 |  { | 
| 9 | - public static $prefixLengthsPsr4 = array ( | |
| 9 | + public static $prefixLengthsPsr4 = array( | |
| 10 | 10 | 'O' => | 
| 11 | - array ( | |
| 11 | + array( | |
| 12 | 12 | 'OCA\\Files_Sharing\\' => 18, | 
| 13 | 13 | ), | 
| 14 | 14 | ); | 
| 15 | 15 | |
| 16 | - public static $prefixDirsPsr4 = array ( | |
| 16 | + public static $prefixDirsPsr4 = array( | |
| 17 | 17 | 'OCA\\Files_Sharing\\' => | 
| 18 | - array ( | |
| 19 | - 0 => __DIR__ . '/..' . '/../lib', | |
| 18 | + array( | |
| 19 | + 0 => __DIR__.'/..'.'/../lib', | |
| 20 | 20 | ), | 
| 21 | 21 | ); | 
| 22 | 22 | |
| 23 | - public static $classMap = array ( | |
| 24 | - 'OCA\\Files_Sharing\\Activity\\Filter' => __DIR__ . '/..' . '/../lib/Activity/Filter.php', | |
| 25 | - 'OCA\\Files_Sharing\\Activity\\Providers\\Base' => __DIR__ . '/..' . '/../lib/Activity/Providers/Base.php', | |
| 26 | - 'OCA\\Files_Sharing\\Activity\\Providers\\Downloads' => __DIR__ . '/..' . '/../lib/Activity/Providers/Downloads.php', | |
| 27 | - 'OCA\\Files_Sharing\\Activity\\Providers\\Groups' => __DIR__ . '/..' . '/../lib/Activity/Providers/Groups.php', | |
| 28 | - 'OCA\\Files_Sharing\\Activity\\Providers\\PublicLinks' => __DIR__ . '/..' . '/../lib/Activity/Providers/PublicLinks.php', | |
| 29 | - 'OCA\\Files_Sharing\\Activity\\Providers\\RemoteShares' => __DIR__ . '/..' . '/../lib/Activity/Providers/RemoteShares.php', | |
| 30 | - 'OCA\\Files_Sharing\\Activity\\Providers\\Users' => __DIR__ . '/..' . '/../lib/Activity/Providers/Users.php', | |
| 31 | - 'OCA\\Files_Sharing\\Activity\\Settings\\PublicLinks' => __DIR__ . '/..' . '/../lib/Activity/Settings/PublicLinks.php', | |
| 32 | - 'OCA\\Files_Sharing\\Activity\\Settings\\RemoteShare' => __DIR__ . '/..' . '/../lib/Activity/Settings/RemoteShare.php', | |
| 33 | - 'OCA\\Files_Sharing\\Activity\\Settings\\Shared' => __DIR__ . '/..' . '/../lib/Activity/Settings/Shared.php', | |
| 34 | - 'OCA\\Files_Sharing\\AppInfo\\Application' => __DIR__ . '/..' . '/../lib/AppInfo/Application.php', | |
| 35 | - 'OCA\\Files_Sharing\\Cache' => __DIR__ . '/..' . '/../lib/Cache.php', | |
| 36 | - 'OCA\\Files_Sharing\\Capabilities' => __DIR__ . '/..' . '/../lib/Capabilities.php', | |
| 37 | - 'OCA\\Files_Sharing\\Collaboration\\ShareRecipientSorter' => __DIR__ . '/..' . '/../lib/Collaboration/ShareRecipientSorter.php', | |
| 38 | - 'OCA\\Files_Sharing\\Command\\CleanupRemoteStorages' => __DIR__ . '/..' . '/../lib/Command/CleanupRemoteStorages.php', | |
| 39 | - 'OCA\\Files_Sharing\\Controller\\ExternalSharesController' => __DIR__ . '/..' . '/../lib/Controller/ExternalSharesController.php', | |
| 40 | - 'OCA\\Files_Sharing\\Controller\\PublicPreviewController' => __DIR__ . '/..' . '/../lib/Controller/PublicPreviewController.php', | |
| 41 | - 'OCA\\Files_Sharing\\Controller\\RemoteController' => __DIR__ . '/..' . '/../lib/Controller/RemoteController.php', | |
| 42 | - 'OCA\\Files_Sharing\\Controller\\ShareAPIController' => __DIR__ . '/..' . '/../lib/Controller/ShareAPIController.php', | |
| 43 | - 'OCA\\Files_Sharing\\Controller\\ShareController' => __DIR__ . '/..' . '/../lib/Controller/ShareController.php', | |
| 44 | - 'OCA\\Files_Sharing\\Controller\\ShareInfoController' => __DIR__ . '/..' . '/../lib/Controller/ShareInfoController.php', | |
| 45 | - 'OCA\\Files_Sharing\\Controller\\ShareesAPIController' => __DIR__ . '/..' . '/../lib/Controller/ShareesAPIController.php', | |
| 46 | - 'OCA\\Files_Sharing\\DeleteOrphanedSharesJob' => __DIR__ . '/..' . '/../lib/DeleteOrphanedSharesJob.php', | |
| 47 | - 'OCA\\Files_Sharing\\Exceptions\\BrokenPath' => __DIR__ . '/..' . '/../lib/Exceptions/BrokenPath.php', | |
| 48 | - 'OCA\\Files_Sharing\\Exceptions\\S2SException' => __DIR__ . '/..' . '/../lib/Exceptions/S2SException.php', | |
| 49 | - 'OCA\\Files_Sharing\\ExpireSharesJob' => __DIR__ . '/..' . '/../lib/ExpireSharesJob.php', | |
| 50 | - 'OCA\\Files_Sharing\\External\\Cache' => __DIR__ . '/..' . '/../lib/External/Cache.php', | |
| 51 | - 'OCA\\Files_Sharing\\External\\Manager' => __DIR__ . '/..' . '/../lib/External/Manager.php', | |
| 52 | - 'OCA\\Files_Sharing\\External\\Mount' => __DIR__ . '/..' . '/../lib/External/Mount.php', | |
| 53 | - 'OCA\\Files_Sharing\\External\\MountProvider' => __DIR__ . '/..' . '/../lib/External/MountProvider.php', | |
| 54 | - 'OCA\\Files_Sharing\\External\\Scanner' => __DIR__ . '/..' . '/../lib/External/Scanner.php', | |
| 55 | - 'OCA\\Files_Sharing\\External\\Storage' => __DIR__ . '/..' . '/../lib/External/Storage.php', | |
| 56 | - 'OCA\\Files_Sharing\\External\\Watcher' => __DIR__ . '/..' . '/../lib/External/Watcher.php', | |
| 57 | - 'OCA\\Files_Sharing\\Helper' => __DIR__ . '/..' . '/../lib/Helper.php', | |
| 58 | - 'OCA\\Files_Sharing\\Hooks' => __DIR__ . '/..' . '/../lib/Hooks.php', | |
| 59 | - 'OCA\\Files_Sharing\\ISharedStorage' => __DIR__ . '/..' . '/../lib/ISharedStorage.php', | |
| 60 | - 'OCA\\Files_Sharing\\Middleware\\OCSShareAPIMiddleware' => __DIR__ . '/..' . '/../lib/Middleware/OCSShareAPIMiddleware.php', | |
| 61 | - 'OCA\\Files_Sharing\\Middleware\\ShareInfoMiddleware' => __DIR__ . '/..' . '/../lib/Middleware/ShareInfoMiddleware.php', | |
| 62 | - 'OCA\\Files_Sharing\\Middleware\\SharingCheckMiddleware' => __DIR__ . '/..' . '/../lib/Middleware/SharingCheckMiddleware.php', | |
| 63 | - 'OCA\\Files_Sharing\\Migration\\OwncloudGuestShareType' => __DIR__ . '/..' . '/../lib/Migration/OwncloudGuestShareType.php', | |
| 64 | - 'OCA\\Files_Sharing\\Migration\\SetPasswordColumn' => __DIR__ . '/..' . '/../lib/Migration/SetPasswordColumn.php', | |
| 65 | - 'OCA\\Files_Sharing\\MountProvider' => __DIR__ . '/..' . '/../lib/MountProvider.php', | |
| 66 | - 'OCA\\Files_Sharing\\Scanner' => __DIR__ . '/..' . '/../lib/Scanner.php', | |
| 67 | - 'OCA\\Files_Sharing\\ShareBackend\\File' => __DIR__ . '/..' . '/../lib/ShareBackend/File.php', | |
| 68 | - 'OCA\\Files_Sharing\\ShareBackend\\Folder' => __DIR__ . '/..' . '/../lib/ShareBackend/Folder.php', | |
| 69 | - 'OCA\\Files_Sharing\\SharedMount' => __DIR__ . '/..' . '/../lib/SharedMount.php', | |
| 70 | - 'OCA\\Files_Sharing\\SharedStorage' => __DIR__ . '/..' . '/../lib/SharedStorage.php', | |
| 71 | - 'OCA\\Files_Sharing\\Updater' => __DIR__ . '/..' . '/../lib/Updater.php', | |
| 23 | + public static $classMap = array( | |
| 24 | + 'OCA\\Files_Sharing\\Activity\\Filter' => __DIR__.'/..'.'/../lib/Activity/Filter.php', | |
| 25 | + 'OCA\\Files_Sharing\\Activity\\Providers\\Base' => __DIR__.'/..'.'/../lib/Activity/Providers/Base.php', | |
| 26 | + 'OCA\\Files_Sharing\\Activity\\Providers\\Downloads' => __DIR__.'/..'.'/../lib/Activity/Providers/Downloads.php', | |
| 27 | + 'OCA\\Files_Sharing\\Activity\\Providers\\Groups' => __DIR__.'/..'.'/../lib/Activity/Providers/Groups.php', | |
| 28 | + 'OCA\\Files_Sharing\\Activity\\Providers\\PublicLinks' => __DIR__.'/..'.'/../lib/Activity/Providers/PublicLinks.php', | |
| 29 | + 'OCA\\Files_Sharing\\Activity\\Providers\\RemoteShares' => __DIR__.'/..'.'/../lib/Activity/Providers/RemoteShares.php', | |
| 30 | + 'OCA\\Files_Sharing\\Activity\\Providers\\Users' => __DIR__.'/..'.'/../lib/Activity/Providers/Users.php', | |
| 31 | + 'OCA\\Files_Sharing\\Activity\\Settings\\PublicLinks' => __DIR__.'/..'.'/../lib/Activity/Settings/PublicLinks.php', | |
| 32 | + 'OCA\\Files_Sharing\\Activity\\Settings\\RemoteShare' => __DIR__.'/..'.'/../lib/Activity/Settings/RemoteShare.php', | |
| 33 | + 'OCA\\Files_Sharing\\Activity\\Settings\\Shared' => __DIR__.'/..'.'/../lib/Activity/Settings/Shared.php', | |
| 34 | + 'OCA\\Files_Sharing\\AppInfo\\Application' => __DIR__.'/..'.'/../lib/AppInfo/Application.php', | |
| 35 | + 'OCA\\Files_Sharing\\Cache' => __DIR__.'/..'.'/../lib/Cache.php', | |
| 36 | + 'OCA\\Files_Sharing\\Capabilities' => __DIR__.'/..'.'/../lib/Capabilities.php', | |
| 37 | + 'OCA\\Files_Sharing\\Collaboration\\ShareRecipientSorter' => __DIR__.'/..'.'/../lib/Collaboration/ShareRecipientSorter.php', | |
| 38 | + 'OCA\\Files_Sharing\\Command\\CleanupRemoteStorages' => __DIR__.'/..'.'/../lib/Command/CleanupRemoteStorages.php', | |
| 39 | + 'OCA\\Files_Sharing\\Controller\\ExternalSharesController' => __DIR__.'/..'.'/../lib/Controller/ExternalSharesController.php', | |
| 40 | + 'OCA\\Files_Sharing\\Controller\\PublicPreviewController' => __DIR__.'/..'.'/../lib/Controller/PublicPreviewController.php', | |
| 41 | + 'OCA\\Files_Sharing\\Controller\\RemoteController' => __DIR__.'/..'.'/../lib/Controller/RemoteController.php', | |
| 42 | + 'OCA\\Files_Sharing\\Controller\\ShareAPIController' => __DIR__.'/..'.'/../lib/Controller/ShareAPIController.php', | |
| 43 | + 'OCA\\Files_Sharing\\Controller\\ShareController' => __DIR__.'/..'.'/../lib/Controller/ShareController.php', | |
| 44 | + 'OCA\\Files_Sharing\\Controller\\ShareInfoController' => __DIR__.'/..'.'/../lib/Controller/ShareInfoController.php', | |
| 45 | + 'OCA\\Files_Sharing\\Controller\\ShareesAPIController' => __DIR__.'/..'.'/../lib/Controller/ShareesAPIController.php', | |
| 46 | + 'OCA\\Files_Sharing\\DeleteOrphanedSharesJob' => __DIR__.'/..'.'/../lib/DeleteOrphanedSharesJob.php', | |
| 47 | + 'OCA\\Files_Sharing\\Exceptions\\BrokenPath' => __DIR__.'/..'.'/../lib/Exceptions/BrokenPath.php', | |
| 48 | + 'OCA\\Files_Sharing\\Exceptions\\S2SException' => __DIR__.'/..'.'/../lib/Exceptions/S2SException.php', | |
| 49 | + 'OCA\\Files_Sharing\\ExpireSharesJob' => __DIR__.'/..'.'/../lib/ExpireSharesJob.php', | |
| 50 | + 'OCA\\Files_Sharing\\External\\Cache' => __DIR__.'/..'.'/../lib/External/Cache.php', | |
| 51 | + 'OCA\\Files_Sharing\\External\\Manager' => __DIR__.'/..'.'/../lib/External/Manager.php', | |
| 52 | + 'OCA\\Files_Sharing\\External\\Mount' => __DIR__.'/..'.'/../lib/External/Mount.php', | |
| 53 | + 'OCA\\Files_Sharing\\External\\MountProvider' => __DIR__.'/..'.'/../lib/External/MountProvider.php', | |
| 54 | + 'OCA\\Files_Sharing\\External\\Scanner' => __DIR__.'/..'.'/../lib/External/Scanner.php', | |
| 55 | + 'OCA\\Files_Sharing\\External\\Storage' => __DIR__.'/..'.'/../lib/External/Storage.php', | |
| 56 | + 'OCA\\Files_Sharing\\External\\Watcher' => __DIR__.'/..'.'/../lib/External/Watcher.php', | |
| 57 | + 'OCA\\Files_Sharing\\Helper' => __DIR__.'/..'.'/../lib/Helper.php', | |
| 58 | + 'OCA\\Files_Sharing\\Hooks' => __DIR__.'/..'.'/../lib/Hooks.php', | |
| 59 | + 'OCA\\Files_Sharing\\ISharedStorage' => __DIR__.'/..'.'/../lib/ISharedStorage.php', | |
| 60 | + 'OCA\\Files_Sharing\\Middleware\\OCSShareAPIMiddleware' => __DIR__.'/..'.'/../lib/Middleware/OCSShareAPIMiddleware.php', | |
| 61 | + 'OCA\\Files_Sharing\\Middleware\\ShareInfoMiddleware' => __DIR__.'/..'.'/../lib/Middleware/ShareInfoMiddleware.php', | |
| 62 | + 'OCA\\Files_Sharing\\Middleware\\SharingCheckMiddleware' => __DIR__.'/..'.'/../lib/Middleware/SharingCheckMiddleware.php', | |
| 63 | + 'OCA\\Files_Sharing\\Migration\\OwncloudGuestShareType' => __DIR__.'/..'.'/../lib/Migration/OwncloudGuestShareType.php', | |
| 64 | + 'OCA\\Files_Sharing\\Migration\\SetPasswordColumn' => __DIR__.'/..'.'/../lib/Migration/SetPasswordColumn.php', | |
| 65 | + 'OCA\\Files_Sharing\\MountProvider' => __DIR__.'/..'.'/../lib/MountProvider.php', | |
| 66 | + 'OCA\\Files_Sharing\\Scanner' => __DIR__.'/..'.'/../lib/Scanner.php', | |
| 67 | + 'OCA\\Files_Sharing\\ShareBackend\\File' => __DIR__.'/..'.'/../lib/ShareBackend/File.php', | |
| 68 | + 'OCA\\Files_Sharing\\ShareBackend\\Folder' => __DIR__.'/..'.'/../lib/ShareBackend/Folder.php', | |
| 69 | + 'OCA\\Files_Sharing\\SharedMount' => __DIR__.'/..'.'/../lib/SharedMount.php', | |
| 70 | + 'OCA\\Files_Sharing\\SharedStorage' => __DIR__.'/..'.'/../lib/SharedStorage.php', | |
| 71 | + 'OCA\\Files_Sharing\\Updater' => __DIR__.'/..'.'/../lib/Updater.php', | |
| 72 | 72 | ); | 
| 73 | 73 | |
| 74 | 74 | public static function getInitializer(ClassLoader $loader) | 
| 75 | 75 |      { | 
| 76 | -        return \Closure::bind(function () use ($loader) { | |
| 76 | +        return \Closure::bind(function() use ($loader) { | |
| 77 | 77 | $loader->prefixLengthsPsr4 = ComposerStaticInitf32f03f7cd82bff20d6a51be16689441::$prefixLengthsPsr4; | 
| 78 | 78 | $loader->prefixDirsPsr4 = ComposerStaticInitf32f03f7cd82bff20d6a51be16689441::$prefixDirsPsr4; | 
| 79 | 79 | $loader->classMap = ComposerStaticInitf32f03f7cd82bff20d6a51be16689441::$classMap; |