Browse Source
Allow to search by comments
Allow to search by comments
Signed-off-by: Joas Schilling <coding@schilljs.com>pull/9222/head
committed by
Daniel Calviño Sánchez
10 changed files with 403 additions and 1 deletions
-
2apps/comments/composer/composer/autoload_classmap.php
-
2apps/comments/composer/composer/autoload_static.php
-
1apps/comments/js/merged.json
-
132apps/comments/js/search.js
-
7apps/comments/lib/AppInfo/Application.php
-
93apps/comments/lib/Search/Provider.php
-
109apps/comments/lib/Search/Result.php
-
42lib/private/Comments/Manager.php
-
12lib/public/Comments/ICommentsManager.php
-
4tests/lib/Comments/FakeManager.php
@ -0,0 +1,132 @@ |
|||||
|
/* |
||||
|
* Copyright (c) 2014 |
||||
|
* |
||||
|
* This file is licensed under the Affero General Public License version 3 |
||||
|
* or later. |
||||
|
* |
||||
|
* See the COPYING-README file. |
||||
|
* |
||||
|
*/ |
||||
|
(function(OC, OCA, $) { |
||||
|
"use strict"; |
||||
|
|
||||
|
/** |
||||
|
* Construct a new FileActions instance |
||||
|
* @constructs Files |
||||
|
*/ |
||||
|
var Comment = function() { |
||||
|
this.initialize(); |
||||
|
}; |
||||
|
|
||||
|
Comment.prototype = { |
||||
|
|
||||
|
fileList: null, |
||||
|
|
||||
|
/** |
||||
|
* Initialize the file search |
||||
|
*/ |
||||
|
initialize: function() { |
||||
|
|
||||
|
var self = this; |
||||
|
|
||||
|
this.fileAppLoaded = function() { |
||||
|
return !!OCA.Files && !!OCA.Files.App; |
||||
|
}; |
||||
|
function inFileList($row, result) { |
||||
|
return false; |
||||
|
|
||||
|
if (! self.fileAppLoaded()) { |
||||
|
return false; |
||||
|
} |
||||
|
var dir = self.fileList.getCurrentDirectory().replace(/\/+$/,''); |
||||
|
var resultDir = OC.dirname(result.path); |
||||
|
return dir === resultDir && self.fileList.inList(result.name); |
||||
|
} |
||||
|
function hideNoFilterResults() { |
||||
|
var $nofilterresults = $('.nofilterresults'); |
||||
|
if ( ! $nofilterresults.hasClass('hidden') ) { |
||||
|
$nofilterresults.addClass('hidden'); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* |
||||
|
* @param {jQuery} $row |
||||
|
* @param {Object} result |
||||
|
* @param {int} result.id |
||||
|
* @param {string} result.comment |
||||
|
* @param {string} result.authorId |
||||
|
* @param {string} result.authorName |
||||
|
* @param {string} result.link |
||||
|
* @param {string} result.fileName |
||||
|
* @param {string} result.path |
||||
|
* @returns {*} |
||||
|
*/ |
||||
|
this.renderCommentResult = function($row, result) { |
||||
|
if (inFileList($row, result)) { |
||||
|
return null; |
||||
|
} |
||||
|
hideNoFilterResults(); |
||||
|
/*render preview icon, show path beneath filename, |
||||
|
show size and last modified date on the right */ |
||||
|
this.updateLegacyMimetype(result); |
||||
|
|
||||
|
var $pathDiv = $('<div>').addClass('path').text(result.path); |
||||
|
|
||||
|
var $avatar = $('<div>'); |
||||
|
$avatar.addClass('avatar') |
||||
|
.css('display', 'inline-block') |
||||
|
.css('vertical-align', 'middle') |
||||
|
.css('margin', '0 5px 2px 3px'); |
||||
|
|
||||
|
if (result.authorName) { |
||||
|
$avatar.avatar(result.authorId, 21, undefined, false, undefined, result.authorName); |
||||
|
} else { |
||||
|
$avatar.avatar(result.authorId, 21); |
||||
|
} |
||||
|
|
||||
|
$row.find('td.info div.name').after($pathDiv).text(result.comment).prepend($('<span>').addClass('path').css('margin-right', '5px').text(result.authorName)).prepend($avatar); |
||||
|
$row.find('td.result a').attr('href', result.link); |
||||
|
|
||||
|
$row.find('td.icon').css('background-image', 'url(' + OC.imagePath('core', 'actions/comment') + ')'); |
||||
|
var dir = OC.dirname(result.path); |
||||
|
if (dir === '') { |
||||
|
dir = '/'; |
||||
|
} |
||||
|
$row.find('td.info a').attr('href', |
||||
|
OC.generateUrl('/apps/files/?dir={dir}&scrollto={scrollto}', {dir: dir, scrollto: result.fileName}) |
||||
|
); |
||||
|
|
||||
|
return $row; |
||||
|
}; |
||||
|
|
||||
|
this.handleCommentClick = function($row, result, event) { |
||||
|
if (self.fileAppLoaded() && self.fileList.id === 'files') { |
||||
|
self.fileList.changeDirectory(OC.dirname(result.path)); |
||||
|
self.fileList.scrollTo(result.name); |
||||
|
return false; |
||||
|
} else { |
||||
|
return true; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
this.updateLegacyMimetype = function (result) { |
||||
|
// backward compatibility:
|
||||
|
if (!result.mime && result.mime_type) { |
||||
|
result.mime = result.mime_type; |
||||
|
} |
||||
|
}; |
||||
|
this.setFileList = function (fileList) { |
||||
|
this.fileList = fileList; |
||||
|
}; |
||||
|
|
||||
|
OC.Plugins.register('OCA.Search.Core', this); |
||||
|
}, |
||||
|
attach: function(search) { |
||||
|
search.setRenderer('comment', this.renderCommentResult.bind(this)); |
||||
|
search.setHandler('comment', this.handleCommentClick.bind(this)); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
OCA.Search.comment = new Comment(); |
||||
|
})(OC, OCA, $); |
@ -0,0 +1,93 @@ |
|||||
|
<?php |
||||
|
/** |
||||
|
* @copyright Copyright (c) 2018 Joas Schilling <coding@schilljs.com> |
||||
|
* |
||||
|
* @license GNU AGPL version 3 or any later version |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU Affero General Public License as |
||||
|
* published by the Free Software Foundation, either version 3 of the |
||||
|
* License, or (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU Affero General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU Affero General Public License |
||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
* |
||||
|
*/ |
||||
|
|
||||
|
namespace OCA\Comments\Search; |
||||
|
|
||||
|
use OCP\Comments\IComment; |
||||
|
use OCP\Files\Folder; |
||||
|
use OCP\Files\Node; |
||||
|
use OCP\Files\NotFoundException; |
||||
|
use OCP\IUser; |
||||
|
|
||||
|
class Provider extends \OCP\Search\Provider { |
||||
|
|
||||
|
/** |
||||
|
* Search for $query |
||||
|
* |
||||
|
* @param string $query |
||||
|
* @return array An array of OCP\Search\Result's |
||||
|
* @since 7.0.0 |
||||
|
*/ |
||||
|
public function search($query): array { |
||||
|
$cm = \OC::$server->getCommentsManager(); |
||||
|
$us = \OC::$server->getUserSession(); |
||||
|
|
||||
|
$user = $us->getUser(); |
||||
|
if (!$user instanceof IUser) { |
||||
|
return []; |
||||
|
} |
||||
|
$uf = \OC::$server->getUserFolder($user->getUID()); |
||||
|
|
||||
|
if ($uf === null) { |
||||
|
return []; |
||||
|
} |
||||
|
|
||||
|
/** @var IComment[] $comments */ |
||||
|
$comments = $cm->search($query, 'files', '', 'comment'); |
||||
|
|
||||
|
$result = []; |
||||
|
foreach ($comments as $comment) { |
||||
|
if ($comment->getActorType() !== 'users') { |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
$displayName = $cm->resolveDisplayName('user', $comment->getActorId()); |
||||
|
|
||||
|
try { |
||||
|
$file = $this->getFileForComment($uf, $comment); |
||||
|
$result[] = new Result($query, |
||||
|
$comment, |
||||
|
$displayName, |
||||
|
$file->getPath() |
||||
|
); |
||||
|
} catch (NotFoundException $e) { |
||||
|
continue; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return $result; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @param Folder $userFolder |
||||
|
* @param IComment $comment |
||||
|
* @return Node |
||||
|
* @throws NotFoundException |
||||
|
*/ |
||||
|
protected function getFileForComment(Folder $userFolder, IComment $comment): Node { |
||||
|
$nodes = $userFolder->getById((int) $comment->getObjectId()); |
||||
|
if (empty($nodes)) { |
||||
|
throw new NotFoundException('File not found'); |
||||
|
} |
||||
|
|
||||
|
return array_shift($nodes); |
||||
|
} |
||||
|
} |
@ -0,0 +1,109 @@ |
|||||
|
<?php |
||||
|
/** |
||||
|
* @copyright Copyright (c) 2018 Joas Schilling <coding@schilljs.com> |
||||
|
* |
||||
|
* @license GNU AGPL version 3 or any later version |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU Affero General Public License as |
||||
|
* published by the Free Software Foundation, either version 3 of the |
||||
|
* License, or (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU Affero General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU Affero General Public License |
||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
* |
||||
|
*/ |
||||
|
|
||||
|
namespace OCA\Comments\Search; |
||||
|
|
||||
|
use OCP\Comments\IComment; |
||||
|
use OCP\Files\NotFoundException; |
||||
|
use OCP\Search\Result as BaseResult; |
||||
|
|
||||
|
class Result extends BaseResult { |
||||
|
|
||||
|
public $type = 'comment'; |
||||
|
public $comment; |
||||
|
public $authorId; |
||||
|
public $authorName; |
||||
|
public $path; |
||||
|
public $fileName; |
||||
|
|
||||
|
/** |
||||
|
* @param string $search |
||||
|
* @param IComment $comment |
||||
|
* @param string $authorName |
||||
|
* @param string $path |
||||
|
* @throws NotFoundException |
||||
|
*/ |
||||
|
public function __construct(string $search, |
||||
|
IComment $comment, |
||||
|
string $authorName, |
||||
|
string $path) { |
||||
|
parent::__construct( |
||||
|
(int) $comment->getId(), |
||||
|
$comment->getMessage() |
||||
|
/* @todo , [link to file] */ |
||||
|
); |
||||
|
|
||||
|
$this->comment = $this->getRelevantMessagePart($comment->getMessage(), $search); |
||||
|
$this->authorId = $comment->getActorId(); |
||||
|
$this->authorName = $authorName; |
||||
|
$this->fileName = basename($path); |
||||
|
$this->path = $this->getVisiblePath($path); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @param string $path |
||||
|
* @return string |
||||
|
* @throws NotFoundException |
||||
|
*/ |
||||
|
protected function getVisiblePath(string $path): string { |
||||
|
$segments = explode('/', trim($path, '/'), 3); |
||||
|
|
||||
|
if (!isset($segments[2])) { |
||||
|
throw new NotFoundException('Path not inside visible section'); |
||||
|
} |
||||
|
|
||||
|
return $segments[2]; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @param string $message |
||||
|
* @param string $search |
||||
|
* @return string |
||||
|
* @throws NotFoundException |
||||
|
*/ |
||||
|
protected function getRelevantMessagePart(string $message, string $search): string { |
||||
|
$start = stripos($message, $search); |
||||
|
if ($start === false) { |
||||
|
throw new NotFoundException('Comment section not found'); |
||||
|
} |
||||
|
|
||||
|
$end = $start + strlen($search); |
||||
|
|
||||
|
if ($start <= 25) { |
||||
|
$start = 0; |
||||
|
$prefix = ''; |
||||
|
} else { |
||||
|
$start -= 25; |
||||
|
$prefix = '…'; |
||||
|
} |
||||
|
|
||||
|
if ((strlen($message) - $end) <= 25) { |
||||
|
$end = strlen($message); |
||||
|
$suffix = ''; |
||||
|
} else { |
||||
|
$end += 25; |
||||
|
$suffix = '…'; |
||||
|
} |
||||
|
|
||||
|
return $prefix . substr($message, $start, $end - $start) . $suffix; |
||||
|
} |
||||
|
|
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue