Skip to content

Commit

Permalink
Show sharing recommendations
Browse files Browse the repository at this point in the history
Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
  • Loading branch information
ChristophWurst authored and rullzer committed Feb 25, 2019
1 parent 5df6400 commit f3023aa
Show file tree
Hide file tree
Showing 25 changed files with 1,074 additions and 197 deletions.
4 changes: 2 additions & 2 deletions apps/accessibility/js/accessibility.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion apps/accessibility/js/accessibility.js.map

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions apps/files_sharing/appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@
'url' => '/api/v1/sharees',
'verb' => 'GET',
],
[
'name' => 'ShareesAPI#findRecommended',
'url' => '/api/v1/sharees_recommended',
'verb' => 'GET',
],
/*
* Remote Shares
*/
Expand Down
158 changes: 157 additions & 1 deletion apps/files_sharing/lib/Controller/ShareesAPIController.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,29 @@
*/
namespace OCA\Files_Sharing\Controller;

use function array_filter;
use function array_slice;
use function array_values;
use Generator;
use OC\Collaboration\Collaborators\SearchResult;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCS\OCSBadRequestException;
use OCP\AppFramework\OCSController;
use OCP\Collaboration\Collaborators\ISearch;
use OCP\Collaboration\Collaborators\ISearchResult;
use OCP\Collaboration\Collaborators\SearchResultType;
use OCP\IRequest;
use OCP\IConfig;
use OCP\IURLGenerator;
use OCP\Share;
use OCP\Share\IManager;
use function usort;

class ShareesAPIController extends OCSController {

/** @var userId */
protected $userId;

/** @var IConfig */
protected $config;

Expand Down Expand Up @@ -87,6 +99,7 @@ class ShareesAPIController extends OCSController {
private $collaboratorSearch;

/**
* @param string $UserId
* @param string $appName
* @param IRequest $request
* @param IConfig $config
Expand All @@ -95,6 +108,7 @@ class ShareesAPIController extends OCSController {
* @param ISearch $collaboratorSearch
*/
public function __construct(
$UserId,
string $appName,
IRequest $request,
IConfig $config,
Expand All @@ -103,7 +117,7 @@ public function __construct(
ISearch $collaboratorSearch
) {
parent::__construct($appName, $request);

$this->userId = $UserId;
$this->config = $config;
$this->urlGenerator = $urlGenerator;
$this->shareManager = $shareManager;
Expand Down Expand Up @@ -212,6 +226,148 @@ public function search(string $search = '', string $itemType = null, int $page =
return $response;
}

/**
* @param string $user
* @param int $shareType
*
* @return Generator<array<string>>
*/
private function getAllShareesByType(string $user, int $shareType): Generator {
$offset = 0;
$pageSize = 50;

while (count($page = $this->shareManager->getSharesBy(
$user,
$shareType,
null,
false,
$pageSize,
$offset
))) {
foreach ($page as $share) {
yield [$share->getSharedWith(), $share->getSharedWithDisplayName() ?? $share->getSharedWith()];
}

$offset += $pageSize;
}
}

private function sortShareesByFrequency(array $sharees): array {
usort($sharees, function(array $s1, array $s2) {
return $s2['count'] - $s1['count'];
});
return $sharees;
}

private $searchResultTypeMap = [
Share::SHARE_TYPE_USER => 'users',
Share::SHARE_TYPE_GROUP => 'groups',
Share::SHARE_TYPE_REMOTE => 'remotes',
Share::SHARE_TYPE_REMOTE_GROUP => 'remote_groups',
Share::SHARE_TYPE_EMAIL => 'emails',
];

private function getAllSharees(string $user, array $shareTypes): ISearchResult {
$result = [];
foreach ($shareTypes as $shareType) {
$sharees = $this->getAllShareesByType($user, $shareType);
$shareTypeResults = [];
foreach ($sharees as list($sharee, $displayname)) {
if (!isset($this->searchResultTypeMap[$shareType])) {
continue;
}

if (!isset($shareTypeResults[$sharee])) {
$shareTypeResults[$sharee] = [
'count' => 1,
'label' => $displayname,
'value' => [
'shareType' => $shareType,
'shareWith' => $sharee,
],
];
} else {
$shareTypeResults[$sharee]['count']++;
}
}
$result = array_merge($result, array_values($shareTypeResults));
}

$top5 = array_slice(
$this->sortShareesByFrequency($result),
0,
5
);

$searchResult = new SearchResult();
foreach ($this->searchResultTypeMap as $int => $str) {
$searchResult->addResultSet(new SearchResultType($str), [], []);
foreach ($top5 as $x) {
if ($x['value']['shareType'] === $int) {
$searchResult->addResultSet(new SearchResultType($str), [], [$x]);
}
}
}
return $searchResult;
}

/**
* @NoAdminRequired
*
* @param string $itemType
* @return DataResponse
* @throws OCSBadRequestException
*/
public function findRecommended(string $itemType = null, $shareType = null): DataResponse {
$shareTypes = [
Share::SHARE_TYPE_USER,
];

if ($itemType === null) {
throw new OCSBadRequestException('Missing itemType');
} elseif ($itemType === 'file' || $itemType === 'folder') {
if ($this->shareManager->allowGroupSharing()) {
$shareTypes[] = Share::SHARE_TYPE_GROUP;
}

if ($this->isRemoteSharingAllowed($itemType)) {
$shareTypes[] = Share::SHARE_TYPE_REMOTE;
}

if ($this->isRemoteGroupSharingAllowed($itemType)) {
$shareTypes[] = Share::SHARE_TYPE_REMOTE_GROUP;
}

if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) {
$shareTypes[] = Share::SHARE_TYPE_EMAIL;
}

if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_ROOM)) {
$shareTypes[] = Share::SHARE_TYPE_ROOM;
}
} else {
$shareTypes[] = Share::SHARE_TYPE_GROUP;
$shareTypes[] = Share::SHARE_TYPE_EMAIL;
}

// FIXME: DI
if (\OC::$server->getAppManager()->isEnabledForUser('circles') && class_exists('\OCA\Circles\ShareByCircleProvider')) {
$shareTypes[] = Share::SHARE_TYPE_CIRCLE;
}

if (isset($_GET['shareType']) && is_array($_GET['shareType'])) {
$shareTypes = array_intersect($shareTypes, $_GET['shareType']);
sort($shareTypes);
} else if (is_numeric($shareType)) {
$shareTypes = array_intersect($shareTypes, [(int) $shareType]);
sort($shareTypes);
}

return new DataResponse(
$this->getAllSharees($this->userId, $shareTypes)->asArray()
);
}

/**
* Method to get out the static call for better testing
*
Expand Down
11 changes: 11 additions & 0 deletions apps/files_sharing/tests/Controller/ShareesAPIControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ class ShareesAPIControllerTest extends TestCase {
/** @var ShareesAPIController */
protected $sharees;

/** @var string */
protected $uid;

/** @var IRequest|\PHPUnit_Framework_MockObject_MockObject */
protected $request;

Expand All @@ -62,6 +65,7 @@ class ShareesAPIControllerTest extends TestCase {
protected function setUp() {
parent::setUp();

$this->uid = 'test123';
$this->request = $this->createMock(IRequest::class);
$this->shareManager = $this->createMock(IManager::class);

Expand All @@ -74,6 +78,7 @@ protected function setUp() {
$this->collaboratorSearch = $this->createMock(ISearch::class);

$this->sharees = new ShareesAPIController(
$this->uid,
'files_sharing',
$this->request,
$configMock,
Expand Down Expand Up @@ -243,6 +248,8 @@ public function testSearch($getData, $apiSetting, $enumSetting, $remoteSharingEn
->method('allowGroupSharing')
->willReturn($allowGroupSharing);

/** @var string */
$uid = 'test123';
/** @var IRequest|\PHPUnit_Framework_MockObject_MockObject $request */
$request = $this->createMock(IRequest::class);
/** @var IURLGenerator|\PHPUnit_Framework_MockObject_MockObject $urlGenerator */
Expand All @@ -251,6 +258,7 @@ public function testSearch($getData, $apiSetting, $enumSetting, $remoteSharingEn
/** @var \PHPUnit_Framework_MockObject_MockObject|\OCA\Files_Sharing\Controller\ShareesAPIController $sharees */
$sharees = $this->getMockBuilder('\OCA\Files_Sharing\Controller\ShareesAPIController')
->setConstructorArgs([
$uid,
'files_sharing',
$request,
$config,
Expand Down Expand Up @@ -335,6 +343,8 @@ public function testSearchInvalid($getData, $message) {
$config->expects($this->never())
->method('getAppValue');

/** @var string */
$uid = 'test123';
/** @var IRequest|\PHPUnit_Framework_MockObject_MockObject $request */
$request = $this->createMock(IRequest::class);
/** @var IURLGenerator|\PHPUnit_Framework_MockObject_MockObject $urlGenerator */
Expand All @@ -343,6 +353,7 @@ public function testSearchInvalid($getData, $message) {
/** @var \PHPUnit_Framework_MockObject_MockObject|\OCA\Files_Sharing\Controller\ShareesAPIController $sharees */
$sharees = $this->getMockBuilder('\OCA\Files_Sharing\Controller\ShareesAPIController')
->setConstructorArgs([
$uid,
'files_sharing',
$request,
$config,
Expand Down
16 changes: 5 additions & 11 deletions apps/twofactor_backupcodes/js/settings.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion apps/twofactor_backupcodes/js/settings.js.map

Large diffs are not rendered by default.

Loading

0 comments on commit f3023aa

Please sign in to comment.