Merge pull request #9909 from nextcloud/feature/2192/allow_group_share_undeletion

Add API to undelete delete group shares
This commit is contained in:
Morris Jobke 2018-07-05 13:31:58 +02:00 committed by GitHub
commit cbfcfb236f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 443 additions and 18 deletions

View File

@ -38,6 +38,7 @@ use OCP\IConfig;
use OCP\IL10N;
use OCP\ILogger;
use OCP\IUserManager;
use OCP\Share\Exceptions\GenericShareException;
use OCP\Share\IShare;
use OCP\Share\IShareProvider;
use OC\Share20\Exception\InvalidShare;
@ -585,6 +586,10 @@ class FederatedShareProvider implements IShareProvider {
// TODO move this code over to this app
}
public function restore(IShare $share, string $recipient): IShare {
throw new GenericShareException('not implemented');
}
public function getSharesInFolder($userId, Folder $node, $reshares) {
$qb = $this->dbConnection->getQueryBuilder();

View File

@ -105,6 +105,9 @@
.nav-icon-trashbin {
background-image: url('../img/delete.svg?v=1');
}
.nav-icon-deletedshares {
background-image: url('../img/unshare.svg?v=1');
}
#app-navigation .nav-files a.nav-icon-files {
width: auto;

View File

@ -0,0 +1 @@
<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="m12.5 1a2.5 2.5 0 0 0-2.5 2.5 2.5 2.5 0 0 0 0.003906 0.12891l-4.9023 2.4512a2.5 2.5 0 0 0-1.6016-0.58008 2.5 2.5 0 0 0-2.5 2.5 2.5 2.5 0 0 0 2.5 2.5 2.5 2.5 0 0 0 0.30469-0.021484l3.4395-1.7246-1.25-0.625a2.5 2.5 0 0 0 0.0058594-0.12891 2.5 2.5 0 0 0-0.0039062-0.12891l4.9023-2.4512a2.5 2.5 0 0 0 1.6016 0.58008 2.5 2.5 0 0 0 0.26562-0.013672l1.5625-0.7832a2.5 2.5 0 0 0 0.67188-1.7031 2.5 2.5 0 0 0-2.5-2.5zm0.25391 9.0156-3.7246 1.8672 0.97656 0.48828a2.5 2.5 0 0 0-0.005859 0.12891 2.5 2.5 0 0 0 2.5 2.5 2.5 2.5 0 0 0 2.5-2.5 2.5 2.5 0 0 0-2.2461-2.4844z"/><rect transform="rotate(-26.63)" x="-1.0586" y="11.891" width="11.687" height="2.0029" ry="0" style="paint-order:normal"/></svg>

After

Width:  |  Height:  |  Size: 795 B

View File

@ -206,6 +206,17 @@ class ViewControllerTest extends TestCase {
'type' => 'link',
'classes' => '',
],
[
'id' => 'deletedshares',
'appname' => 'files_sharing',
'script' => 'list.php',
'order' => 18,
'name' => \OC::$server->getL10N('files_sharing')->t('Deleted shares'),
'active' => false,
'icon' => '',
'type' => 'link',
'classes' => '',
],
[
'id' => 'systemtagsfilter',
'appname' => 'systemtags',
@ -269,6 +280,10 @@ class ViewControllerTest extends TestCase {
'id' => 'sharinglinks',
'content' => null,
],
[
'id' => 'deletedshares',
'content' => null,
],
[
'id' => 'systemtagsfilter',
'content' => null,

View File

@ -48,6 +48,9 @@ $eventDispatcher->addListener(
);
$config = \OC::$server->getConfig();
$shareManager = \OC::$server->getShareManager();
$userSession = \OC::$server->getUserSession();
if ($config->getAppValue('core', 'shareapi_enabled', 'yes') === 'yes') {
\OCA\Files\App::getNavigationManager()->add(function () {
$l = \OC::$server->getL10N('files_sharing');
@ -59,6 +62,17 @@ if ($config->getAppValue('core', 'shareapi_enabled', 'yes') === 'yes') {
'name' => $l->t('Shared with you'),
];
});
\OCA\Files\App::getNavigationManager()->add(function () {
$l = \OC::$server->getL10N('files_sharing');
return [
'id' => 'deletedshares',
'appname' => 'files_sharing',
'script' => 'list.php',
'order' => 18,
'name' => $l->t('Deleted shares'),
];
});
if (\OCP\Util::isSharingDisabledForUser() === false) {
\OCA\Files\App::getNavigationManager()->add(function () {

View File

@ -73,6 +73,19 @@ return [
'url' => '/api/v1/shares/{id}',
'verb' => 'DELETE',
],
/*
* Deleted Shares
*/
[
'name' => 'DeletedShareAPI#index',
'url' => '/api/v1/deletedshares',
'verb' => 'GET',
],
[
'name' => 'DeletedShareAPI#undelete',
'url' => '/api/v1/deletedshares/{id}',
'verb' => 'POST',
],
/*
* OCS Sharee API
*/

View File

@ -22,6 +22,7 @@ return array(
'OCA\\Files_Sharing\\Capabilities' => $baseDir . '/../lib/Capabilities.php',
'OCA\\Files_Sharing\\Collaboration\\ShareRecipientSorter' => $baseDir . '/../lib/Collaboration/ShareRecipientSorter.php',
'OCA\\Files_Sharing\\Command\\CleanupRemoteStorages' => $baseDir . '/../lib/Command/CleanupRemoteStorages.php',
'OCA\\Files_Sharing\\Controller\\DeletedShareAPIController' => $baseDir . '/../lib/Controller/DeletedShareAPIController.php',
'OCA\\Files_Sharing\\Controller\\ExternalSharesController' => $baseDir . '/../lib/Controller/ExternalSharesController.php',
'OCA\\Files_Sharing\\Controller\\PublicPreviewController' => $baseDir . '/../lib/Controller/PublicPreviewController.php',
'OCA\\Files_Sharing\\Controller\\RemoteController' => $baseDir . '/../lib/Controller/RemoteController.php',

View File

@ -37,6 +37,7 @@ class ComposerStaticInitFiles_Sharing
'OCA\\Files_Sharing\\Capabilities' => __DIR__ . '/..' . '/../lib/Capabilities.php',
'OCA\\Files_Sharing\\Collaboration\\ShareRecipientSorter' => __DIR__ . '/..' . '/../lib/Collaboration/ShareRecipientSorter.php',
'OCA\\Files_Sharing\\Command\\CleanupRemoteStorages' => __DIR__ . '/..' . '/../lib/Command/CleanupRemoteStorages.php',
'OCA\\Files_Sharing\\Controller\\DeletedShareAPIController' => __DIR__ . '/..' . '/../lib/Controller/DeletedShareAPIController.php',
'OCA\\Files_Sharing\\Controller\\ExternalSharesController' => __DIR__ . '/..' . '/../lib/Controller/ExternalSharesController.php',
'OCA\\Files_Sharing\\Controller\\PublicPreviewController' => __DIR__ . '/..' . '/../lib/Controller/PublicPreviewController.php',
'OCA\\Files_Sharing\\Controller\\RemoteController' => __DIR__ . '/..' . '/../lib/Controller/RemoteController.php',

View File

@ -92,6 +92,30 @@ OCA.Sharing.App = {
return this._linkFileList;
},
initSharingDeleted: function($el) {
if (this._deletedFileList) {
return this._deletedFileList;
}
this._deletedFileList = new OCA.Sharing.FileList(
$el,
{
id: 'shares.deleted',
scrollContainer: $('#app-content'),
showDeleted: true,
sharedWithUser: true,
fileActions: this._restoreShareAction(),
config: OCA.Files.App.getFilesConfig()
}
);
this._extendFileList(this._deletedFileList);
this._deletedFileList.appName = t('files_sharing', 'Deleted shares');
this._deletedFileList.$el.find('#emptycontent').html('<div class="icon-share"></div>' +
'<h2>' + t('files_sharing', 'No deleted shares') + '</h2>' +
'<p>' + t('files_sharing', 'Shares you deleted will show up here') + '</p>');
return this._deletedFileList;
},
removeSharingIn: function() {
if (this._inFileList) {
this._inFileList.$fileList.empty();
@ -110,6 +134,12 @@ OCA.Sharing.App = {
}
},
removeSharingDeleted: function() {
if (this._deletedFileList) {
this._deletedFileList.$fileList.empty();
}
},
/**
* Destroy the app
*/
@ -151,6 +181,29 @@ OCA.Sharing.App = {
return fileActions;
},
_restoreShareAction: function() {
var fileActions = new OCA.Files.FileActions();
fileActions.registerAction({
name: 'Restore',
displayName: '',
altText: t('files_sharing', 'Restore share'),
mime: 'all',
permissions: OC.PERMISSION_ALL,
iconClass: 'icon-history',
type: OCA.Files.FileActions.TYPE_INLINE,
actionHandler: function(fileName, context) {
var shareId = context.$file.data('shareId');
$.post(OC.linkToOCS('apps/files_sharing/api/v1/deletedshares', 2) + shareId)
.success(function(result) {
context.fileList.remove(context.fileInfoModel.attributes.name);
}).fail(function() {
OC.Notification.showTemporary(t('files_sharing', 'Something happened. Unable to restore the share.'));
});
}
});
return fileActions;
},
_onActionsUpdated: function(ev) {
_.each([this._inFileList, this._outFileList, this._linkFileList], function(list) {
if (!list) {
@ -193,4 +246,10 @@ $(document).ready(function() {
$('#app-content-sharinglinks').on('hide', function() {
OCA.Sharing.App.removeSharingLinks();
});
$('#app-content-deletedshares').on('show', function(e) {
OCA.Sharing.App.initSharingDeleted($(e.target));
});
$('#app-content-deletedshares').on('hide', function() {
OCA.Sharing.App.removeSharingDeleted();
});
});

View File

@ -42,6 +42,12 @@
var fileActions = fileList.fileActions;
var oldCreateRow = fileList._createRow;
fileList._createRow = function(fileData) {
if (fileData.permissions === 0) {
// no permission, disabling sidebar
delete fileActions.actions.all.Details;
}
var tr = oldCreateRow.apply(this, arguments);
var sharePermissions = OCA.Sharing.Util.getSharePermissions(fileData);
tr.attr('data-share-permissions', sharePermissions);
@ -158,11 +164,15 @@
permissions: OC.PERMISSION_ALL,
iconClass: 'icon-shared',
type: OCA.Files.FileActions.TYPE_INLINE,
actionHandler: function(fileName) {
fileList.showDetailsView(fileName, 'shareTabView');
actionHandler: function(fileName, context) {
// do not open sidebar if permission is set and equal to 0
var permissions = parseInt(context.$file.data('share-permissions'), 10);
if (isNaN(permissions) || permissions > 0) {
fileList.showDetailsView(fileName, 'shareTabView');
}
},
render: function(actionSpec, isDefault, context) {
var permissions = parseInt(context.$file.attr('data-permissions'), 10);
var permissions = parseInt(context.$file.data('permissions'), 10);
// if no share permissions but share owner exists, still show the link
if ((permissions & OC.PERMISSION_SHARE) !== 0 || context.$file.attr('data-share-owner')) {
return fileActions._defaultRenderAction.call(fileActions, actionSpec, isDefault, context);

View File

@ -37,6 +37,7 @@
*/
_sharedWithUser: false,
_linksOnly: false,
_showDeleted: false,
_clientSideSort: true,
_allowSelection: false,
@ -56,6 +57,9 @@
if (options && options.linksOnly) {
this._linksOnly = true;
}
if (options && options.showDeleted) {
this._showDeleted = true;
}
},
_renderRow: function() {
@ -78,7 +82,11 @@
var permission = parseInt($tr.attr('data-permissions')) | OC.PERMISSION_DELETE;
$tr.attr('data-permissions', permission);
}
if (this._showDeleted) {
var permission = fileData.permissions;
$tr.attr('data-share-permissions', permission);
}
// add row with expiration date for link only shares - influenced by _createRow of filelist
if (this._linksOnly) {
var expirationTimestamp = 0;
@ -183,20 +191,36 @@
// there is only root
this._setCurrentDir('/', false);
if (this._showDeleted) {
var shares = $.ajax({
url: OC.linkToOCS('apps/files_sharing/api/v1', 2) + 'deletedshares',
/* jshint camelcase: false */
data: {
format: 'json',
include_tags: true
},
type: 'GET',
beforeSend: function(xhr) {
xhr.setRequestHeader('OCS-APIREQUEST', 'true');
},
});
} else {
var shares = $.ajax({
url: OC.linkToOCS('apps/files_sharing/api/v1') + 'shares',
/* jshint camelcase: false */
data: {
format: 'json',
shared_with_me: !!this._sharedWithUser,
include_tags: true
},
type: 'GET',
beforeSend: function(xhr) {
xhr.setRequestHeader('OCS-APIREQUEST', 'true');
},
});
}
var promises = [];
var shares = $.ajax({
url: OC.linkToOCS('apps/files_sharing/api/v1') + 'shares',
/* jshint camelcase: false */
data: {
format: 'json',
shared_with_me: !!this._sharedWithUser,
include_tags: true
},
type: 'GET',
beforeSend: function(xhr) {
xhr.setRequestHeader('OCS-APIREQUEST', 'true');
},
});
promises.push(shares);
if (!!this._sharedWithUser) {

View File

@ -0,0 +1,168 @@
<?php
declare(strict_types=1);
/**
* @Copyright 2018, Roeland Jago Douma <roeland@famdouma.nl>
* @Copyright 2018, John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
*
* @author John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @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\Files_Sharing\Controller;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCS\OCSException;
use OCP\AppFramework\OCS\OCSNotFoundException;
use OCP\AppFramework\OCSController;
use OCP\Files\IRootFolder;
use OCP\Files\NotFoundException;
use OCP\IGroupManager;
use OCP\IRequest;
use OCP\IUserManager;
use OCP\Share\Exceptions\GenericShareException;
use OCP\Share\Exceptions\ShareNotFound;
use OCP\Share\IManager as ShareManager;
use OCP\Share\IShare;
class DeletedShareAPIController extends OCSController {
/** @var ShareManager */
private $shareManager;
/** @var string */
private $userId;
/** @var IUserManager */
private $userManager;
/** @var IGroupManager */
private $groupManager;
/** @var IRootFolder */
private $rootFolder;
public function __construct(string $appName,
IRequest $request,
ShareManager $shareManager,
string $UserId,
IUserManager $userManager,
IGroupManager $groupManager,
IRootFolder $rootFolder) {
parent::__construct($appName, $request);
$this->shareManager = $shareManager;
$this->userId = $UserId;
$this->userManager = $userManager;
$this->groupManager = $groupManager;
$this->rootFolder = $rootFolder;
}
private function formatShare(IShare $share): array {
$result = [
'id' => $share->getFullId(),
'share_type' => $share->getShareType(),
'uid_owner' => $share->getSharedBy(),
'displayname_owner' => $this->userManager->get($share->getSharedBy())->getDisplayName(),
'permissions' => 0,
'stime' => $share->getShareTime()->getTimestamp(),
'parent' => null,
'expiration' => null,
'token' => null,
'uid_file_owner' => $share->getShareOwner(),
'displayname_file_owner' => $this->userManager->get($share->getShareOwner())->getDisplayName(),
'path' => $share->getTarget(),
];
$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
$nodes = $userFolder->getById($share->getNodeId());
if (empty($nodes)) {
// fallback to guessing the path
$node = $userFolder->get($share->getTarget());
if ($node === null || $share->getTarget() === '') {
throw new NotFoundException();
}
} else {
$node = $nodes[0];
}
$result['path'] = $userFolder->getRelativePath($node->getPath());
if ($node instanceOf \OCP\Files\Folder) {
$result['item_type'] = 'folder';
} else {
$result['item_type'] = 'file';
}
$result['mimetype'] = $node->getMimetype();
$result['storage_id'] = $node->getStorage()->getId();
$result['storage'] = $node->getStorage()->getCache()->getNumericStorageId();
$result['item_source'] = $node->getId();
$result['file_source'] = $node->getId();
$result['file_parent'] = $node->getParent()->getId();
$result['file_target'] = $share->getTarget();
$expiration = $share->getExpirationDate();
if ($expiration !== null) {
$result['expiration'] = $expiration->format('Y-m-d 00:00:00');
}
$group = $this->groupManager->get($share->getSharedWith());
$result['share_with'] = $share->getSharedWith();
$result['share_with_displayname'] = $group !== null ? $group->getDisplayName() : $share->getSharedWith();
return $result;
}
/**
* @NoAdminRequired
*/
public function index(): DataResponse {
$shares = $this->shareManager->getDeletedSharedWith($this->userId, \OCP\Share::SHARE_TYPE_GROUP, null, -1, 0);
$shares = array_map(function (IShare $share) {
return $this->formatShare($share);
}, $shares);
return new DataResponse($shares);
}
/**
* @NoAdminRequired
*
* @throws OCSException
*/
public function undelete(string $id): DataResponse {
try {
$share = $this->shareManager->getShareById($id, $this->userId);
} catch (ShareNotFound $e) {
throw new OCSNotFoundException('Share not found');
}
if ($share->getPermissions() !== 0) {
throw new OCSNotFoundException('No deleted share found');
}
try {
$this->shareManager->restoreShare($share, $this->userId);
} catch (GenericShareException $e) {
throw new OCSException('Something went wrong');
}
return new DataResponse([]);
}
}

View File

@ -151,7 +151,6 @@ class ShareAPIController extends OCSController {
$node = $recipientNode;
} else {
$nodes = $userFolder->getById($share->getNodeId());
if (empty($nodes)) {
// fallback to guessing the path
$node = $userFolder->get($share->getTarget());

View File

@ -42,6 +42,7 @@ use OCP\Mail\IMailer;
use OCP\Security\IHasher;
use OCP\Security\ISecureRandom;
use OC\Share20\Share;
use OCP\Share\Exceptions\GenericShareException;
use OCP\Share\Exceptions\ShareNotFound;
use OCP\Share\IShare;
use OCP\Share\IShareProvider;
@ -692,6 +693,10 @@ class ShareByMailProvider implements IShareProvider {
// nothing to do here, mail shares are only outgoing shares
}
public function restore(IShare $share, string $recipient): IShare {
throw new GenericShareException('not implemented');
}
/**
* @inheritdoc
*/

View File

@ -31,6 +31,7 @@ namespace OC\Share20;
use OC\Files\Cache\Cache;
use OCP\Files\Folder;
use OCP\Share\IShare;
use OCP\Share\IShareProvider;
use OC\Share20\Exception\InvalidShare;
use OC\Share20\Exception\ProviderException;
@ -410,6 +411,41 @@ class DefaultShareProvider implements IShareProvider {
}
}
/**
* @inheritdoc
*
* For now this only works for group shares
* If this gets implemented for normal shares we have to extend it
*/
public function restore(IShare $share, string $recipient): IShare {
$qb = $this->dbConn->getQueryBuilder();
$qb->select('permissions')
->from('share')
->where(
$qb->expr()->eq('id', $qb->createNamedParameter($share->getId()))
);
$cursor = $qb->execute();
$data = $cursor->fetch();
$cursor->closeCursor();
$originalPermission = $data['permissions'];
$qb = $this->dbConn->getQueryBuilder();
$qb->update('share')
->set('permissions', $qb->createNamedParameter($originalPermission))
->where(
$qb->expr()->eq('parent', $qb->createNamedParameter($share->getParent()))
)->andWhere(
$qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP))
)->andWhere(
$qb->expr()->eq('share_with', $qb->createNamedParameter($recipient))
);
$qb->execute();
return $this->getShareById($share->getId(), $recipient);
}
/**
* @inheritdoc
*/
@ -922,6 +958,7 @@ class DefaultShareProvider implements IShareProvider {
while($data = $stmt->fetch()) {
$shareMap[$data['parent']]->setPermissions((int)$data['permissions']);
$shareMap[$data['parent']]->setTarget($data['file_target']);
$shareMap[$data['parent']]->setParent($data['parent']);
}
$stmt->closeCursor();

View File

@ -61,6 +61,7 @@ use OCP\Share\Exceptions\GenericShareException;
use OCP\Share\Exceptions\ShareNotFound;
use OCP\Share\IManager;
use OCP\Share\IProviderFactory;
use OCP\Share\IShare;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\EventDispatcher\GenericEvent;
use OCP\Share\IShareProvider;
@ -978,6 +979,13 @@ class Manager implements IManager {
$this->eventDispatcher->dispatch('OCP\Share::postUnshareFromSelf', $event);
}
public function restoreShare(IShare $share, string $recipientId): IShare {
list($providerId, ) = $this->splitFullId($share->getFullId());
$provider = $this->factory->getProvider($providerId);
return $provider->restore($share, $recipientId);
}
/**
* @inheritdoc
*/
@ -1121,6 +1129,25 @@ class Manager implements IManager {
return $shares;
}
/**
* @inheritdoc
*/
public function getDeletedSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0) {
$shares = $this->getSharedWith($userId, $shareType, $node, $limit, $offset);
// Only get deleted shares
$shares = array_filter($shares, function(IShare $share) {
return $share->getPermissions() === 0;
});
// Only get shares where the owner still exists
$shares = array_filter($shares, function (IShare $share) {
return $this->userManager->userExists($share->getShareOwner());
});
return $shares;
}
/**
* @inheritdoc
*/

View File

@ -29,6 +29,7 @@ namespace OCP\Share;
use OCP\Files\Folder;
use OCP\Files\Node;
use OCP\Share\Exceptions\GenericShareException;
use OCP\Share\Exceptions\ShareNotFound;
/**
@ -83,6 +84,20 @@ interface IManager {
*/
public function deleteFromSelf(IShare $share, $recipientId);
/**
* Restore the share when it has been deleted
* Certain share types can be restored when they have been deleted
* but the provider should properly handle this\
*
* @param IShare $share The share to restore
* @param string $recipientId The user to restore the share for
* @return IShare The restored share object
* @throws GenericShareException In case restoring the share failed
*
* @since 14.0.0
*/
public function restoreShare(IShare $share, string $recipientId): IShare;
/**
* Move the share as a recipient of the share.
* This is updating the share target. So where the recipient has the share mounted.
@ -134,6 +149,20 @@ interface IManager {
*/
public function getSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0);
/**
* Get deleted shares shared with $user.
* Filter by $node if provided
*
* @param string $userId
* @param int $shareType
* @param Node|null $node
* @param int $limit The maximum number of shares returned, -1 for all
* @param int $offset
* @return IShare[]
* @since 14.0.0
*/
public function getDeletedSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0);
/**
* Retrieve a share by the share id.
* If the recipient is set make sure to retrieve the file for that user.

View File

@ -25,6 +25,8 @@
namespace OCP\Share;
use OCP\Files\Folder;
use OCP\Share\Exceptions\GenericShareException;
use OCP\Share\Exceptions\ShareNotFound;
use OCP\Files\Node;
/**
@ -80,6 +82,18 @@ interface IShareProvider {
*/
public function deleteFromSelf(\OCP\Share\IShare $share, $recipient);
/**
* Restore a share for a given recipient. The implementation could be provider independant.
*
* @param IShare $share
* @param string $recipient
* @return IShare The restored share object
*
* @since 14.0.0
* @throws GenericShareException In case the share could not be restored
*/
public function restore(IShare $share, string $recipient): IShare;
/**
* Move a share as a recipient.
* This is updating the share target. Thus the mount point of the recipient.