Browse Source

Merge pull request #28157 from Bibo-Joshi/share-folder-per-user

pull/28743/head
John Molakvoæ 5 years ago
committed by GitHub
parent
commit
b79f1eb6ae
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 11
      apps/files_sharing/appinfo/routes.php
  2. 8
      apps/files_sharing/js/dist/additionalScripts.js
  3. 2
      apps/files_sharing/js/dist/additionalScripts.js.map
  4. 2
      apps/files_sharing/js/dist/collaboration.js
  5. 2
      apps/files_sharing/js/dist/collaboration.js.map
  6. 4
      apps/files_sharing/js/dist/files_sharing.js
  7. 2
      apps/files_sharing/js/dist/files_sharing.js.map
  8. 108
      apps/files_sharing/js/dist/files_sharing_tab.js
  9. 2
      apps/files_sharing/js/dist/files_sharing_tab.js.map
  10. 2
      apps/files_sharing/js/dist/main.js
  11. 2
      apps/files_sharing/js/dist/main.js.map
  12. 6
      apps/files_sharing/js/dist/personal-settings.js
  13. 2
      apps/files_sharing/js/dist/personal-settings.js.map
  14. 22
      apps/files_sharing/lib/Controller/SettingsController.php
  15. 2
      apps/files_sharing/lib/External/Manager.php
  16. 20
      apps/files_sharing/lib/Helper.php
  17. 7
      apps/files_sharing/lib/Settings/Personal.php
  18. 2
      apps/files_sharing/lib/SharedMount.php
  19. 45
      apps/files_sharing/src/components/PersonalSettings.vue
  20. 125
      apps/files_sharing/src/components/SelectShareFolderDialogue.vue
  21. 5
      config/config.sample.php
  22. 11
      lib/private/Share20/Manager.php

11
apps/files_sharing/appinfo/routes.php

@ -9,6 +9,7 @@
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Maxence Lange <maxence@artificial-owl.com>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Hinrich Mahler <nextcloud@mahlerhome.de>
*
* @license AGPL-3.0
*
@ -82,6 +83,16 @@ return [
'url' => '/settings/defaultAccept',
'verb' => 'PUT',
],
[
'name' => 'Settings#setUserShareFolder',
'url' => '/settings/shareFolder',
'verb' => 'PUT',
],
[
'name' => 'Settings#resetUserShareFolder',
'url' => '/settings/shareFolder',
'verb' => 'DELETE',
],
[
'name' => 'Accept#accept',
'url' => '/accept/{shareId}',

8
apps/files_sharing/js/dist/additionalScripts.js
File diff suppressed because it is too large
View File

2
apps/files_sharing/js/dist/additionalScripts.js.map
File diff suppressed because it is too large
View File

2
apps/files_sharing/js/dist/collaboration.js

@ -1,4 +1,4 @@
!function(e){var n={};function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=e,t.c=n,t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:r})},t.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.t=function(e,n){if(1&n&&(e=t(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(t.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var o in e)t.d(r,o,function(n){return e[n]}.bind(null,o));return r},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},t.p="/js/",t(t.s=154)}({154:function(e,n,r){
!function(e){var n={};function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=e,t.c=n,t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:r})},t.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.t=function(e,n){if(1&n&&(e=t(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(t.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var o in e)t.d(r,o,function(n){return e[n]}.bind(null,o));return r},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},t.p="/js/",t(t.s=155)}({155:function(e,n,r){
/**
* @copyright Copyright (c) 2016 John Molakvoæ <skjnldsv@protonmail.com>
*

2
apps/files_sharing/js/dist/collaboration.js.map
File diff suppressed because it is too large
View File

4
apps/files_sharing/js/dist/files_sharing.js
File diff suppressed because it is too large
View File

2
apps/files_sharing/js/dist/files_sharing.js.map
File diff suppressed because it is too large
View File

108
apps/files_sharing/js/dist/files_sharing_tab.js
File diff suppressed because it is too large
View File

2
apps/files_sharing/js/dist/files_sharing_tab.js.map
File diff suppressed because it is too large
View File

2
apps/files_sharing/js/dist/main.js

@ -1,4 +1,4 @@
!function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="/js/",r(r.s=498)}({498:function(e,t){
!function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="/js/",r(r.s=502)}({502:function(e,t){
/**
* @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com>
*

2
apps/files_sharing/js/dist/main.js.map
File diff suppressed because it is too large
View File

6
apps/files_sharing/js/dist/personal-settings.js
File diff suppressed because it is too large
View File

2
apps/files_sharing/js/dist/personal-settings.js.map
File diff suppressed because it is too large
View File

22
apps/files_sharing/lib/Controller/SettingsController.php

@ -6,6 +6,7 @@ declare(strict_types=1);
* @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl>
*
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Hinrich Mahler <nextcloud@mahlerhome.de>
*
* @license GNU AGPL version 3 or any later version
*
@ -35,10 +36,13 @@ class SettingsController extends Controller {
/** @var IConfig */
private $config;
/** @var string */
private $userId;
public function __construct(IRequest $request, IConfig $config, string $userId) {
public function __construct(IRequest $request,
IConfig $config,
string $userId) {
parent::__construct(Application::APP_ID, $request);
$this->config = $config;
@ -52,4 +56,20 @@ class SettingsController extends Controller {
$this->config->setUserValue($this->userId, Application::APP_ID, 'default_accept', $accept ? 'yes' : 'no');
return new JSONResponse();
}
/**
* @NoAdminRequired
*/
public function setUserShareFolder(string $shareFolder): JSONResponse {
$this->config->setUserValue($this->userId, Application::APP_ID, 'share_folder', $shareFolder);
return new JSONResponse();
}
/**
* @NoAdminRequired
*/
public function resetUserShareFolder(): JSONResponse {
$this->config->deleteUserValue($this->userId, Application::APP_ID, 'share_folder');
return new JSONResponse();
}
}

2
apps/files_sharing/lib/External/Manager.php

@ -309,7 +309,7 @@ class Manager {
if ($share) {
\OC_Util::setupFS($this->uid);
$shareFolder = Helper::getShareFolder();
$shareFolder = Helper::getShareFolder(null, $this->uid);
$mountPoint = Files::buildNotExistingFileName($shareFolder, $share['name']);
$mountPoint = Filesystem::normalizePath($mountPoint);
$hash = md5($mountPoint);

20
apps/files_sharing/lib/Helper.php

@ -29,6 +29,7 @@ namespace OCA\Files_Sharing;
use OC\Files\Filesystem;
use OC\Files\View;
use OCA\Files_Sharing\AppInfo\Application;
class Helper {
public static function registerHooks() {
@ -63,16 +64,29 @@ class Helper {
/**
* get default share folder
*
* @param \OC\Files\View $view
* @param \OC\Files\View|null $view
* @param string|null $userId
* @return string
*/
public static function getShareFolder($view = null) {
public static function getShareFolder(View $view = null, string $userId = null): string {
if ($view === null) {
$view = Filesystem::getView();
}
$shareFolder = \OC::$server->getConfig()->getSystemValue('share_folder', '/');
$config = \OC::$server->getConfig();
$systemDefault = $config->getSystemValue('share_folder', '/');
$allowCustomShareFolder = $config->getSystemValueBool('sharing.allow_custom_share_folder', true);
// Init custom shareFolder
$shareFolder = $systemDefault;
if ($userId !== null && $allowCustomShareFolder) {
$shareFolder = $config->getUserValue($userId, Application::APP_ID, 'share_folder', $systemDefault);
}
// Verify and sanitize path
$shareFolder = Filesystem::normalizePath($shareFolder);
// Init path if folder doesn't exists
if (!$view->file_exists($shareFolder)) {
$dir = '';
$subdirs = explode('/', $shareFolder);

7
apps/files_sharing/lib/Settings/Personal.php

@ -7,6 +7,7 @@ declare(strict_types=1);
*
* @author Julius Härtl <jus@bitgrid.net>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Hinrich Mahler <nextcloud@mahlerhome.de>
*
* @license GNU AGPL version 3 or any later version
*
@ -49,10 +50,16 @@ class Personal implements ISettings {
public function getForm(): TemplateResponse {
$defaultAcceptSystemConfig = $this->config->getSystemValueBool('sharing.enable_share_accept', false) ? 'no' : 'yes';
$shareFolderSystemConfig = $this->config->getSystemValue('share_folder', '/');
$acceptDefault = $this->config->getUserValue($this->userId, Application::APP_ID, 'default_accept', $defaultAcceptSystemConfig) === 'yes';
$enforceAccept = $this->config->getSystemValueBool('sharing.force_share_accept', false);
$allowCustomDirectory = $this->config->getSystemValueBool('sharing.allow_custom_share_folder', true);
$shareFolderDefault = $this->config->getUserValue($this->userId, Application::APP_ID, 'share_folder', $shareFolderSystemConfig);
$this->initialState->provideInitialState('accept_default', $acceptDefault);
$this->initialState->provideInitialState('enforce_accept', $enforceAccept);
$this->initialState->provideInitialState('allow_custom_share_folder', $allowCustomDirectory);
$this->initialState->provideInitialState('share_folder', $shareFolderDefault);
$this->initialState->provideInitialState('default_share_folder', $shareFolderSystemConfig);
return new TemplateResponse('files_sharing', 'Settings/personal');
}

2
apps/files_sharing/lib/SharedMount.php

@ -105,7 +105,7 @@ class SharedMount extends MountPoint implements MoveableMount {
$folderExistCache->set($parent, $parentExists);
}
if (!$parentExists) {
$parent = Helper::getShareFolder($this->recipientView);
$parent = Helper::getShareFolder($this->recipientView, $this->user);
}
$newMountPoint = $this->generateUniqueTarget(

45
apps/files_sharing/src/components/PersonalSettings.vue

@ -2,6 +2,7 @@
- @copyright 2019 Roeland Jago Douma <roeland@famdouma.nl>
-
- @author 2019 Roeland Jago Douma <roeland@famdouma.nl>
- @author Hinrich Mahler <nextcloud@mahlerhome.de>
-
- @license GNU AGPL version 3 or any later version
-
@ -20,9 +21,9 @@
-->
<template>
<div v-if="!enforceAcceptShares" id="files-sharing-personal-settings" class="section">
<div v-if="!enforceAcceptShares || allowCustomDirectory" id="files-sharing-personal-settings" class="section">
<h2>{{ t('files_sharing', 'Sharing') }}</h2>
<p>
<p v-if="!enforceAcceptShares">
<input id="files-sharing-personal-settings-accept"
v-model="accepting"
class="checkbox"
@ -30,31 +31,55 @@
@change="toggleEnabled">
<label for="files-sharing-personal-settings-accept">{{ t('files_sharing', 'Accept user and group shares by default') }}</label>
</p>
<p v-if="allowCustomDirectory">
<SelectShareFolderDialogue />
</p>
</div>
</template>
<script>
import axios from '@nextcloud/axios'
import { loadState } from '@nextcloud/initial-state'
import { generateUrl } from '@nextcloud/router'
import { loadState } from '@nextcloud/initial-state'
import { showError } from '@nextcloud/dialogs'
import axios from '@nextcloud/axios'
import SelectShareFolderDialogue from './SelectShareFolderDialogue'
export default {
name: 'PersonalSettings',
components: {
SelectShareFolderDialogue,
},
data() {
return {
// Share acceptance config
accepting: loadState('files_sharing', 'accept_default'),
enforceAcceptShares: loadState('files_sharing', 'enforce_accept'),
// Receiving share folder config
allowCustomDirectory: loadState('files_sharing', 'allow_custom_share_folder'),
}
},
methods: {
toggleEnabled() {
axios.put(
generateUrl('/apps/files_sharing/settings/defaultAccept'),
{
async toggleEnabled() {
try {
await axios.put(generateUrl('/apps/files_sharing/settings/defaultAccept'), {
accept: this.accepting,
}
)
})
} catch (error) {
showError(t('sharing', 'Error while toggling options'))
console.error(error)
}
},
},
}
</script>
<style scoped lang="scss">
p {
margin-top: 12px;
margin-bottom: 12px;
}
</style>

125
apps/files_sharing/src/components/SelectShareFolderDialogue.vue

@ -0,0 +1,125 @@
<!--
- @copyright 2021 Hinrich Mahler <nextcloud@mahlerhome.de>
-
- @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/>.
-->
<template>
<div class="share-folder">
<span>{{ t('files', 'Set default folder for accepted shares') }} </span>
<!-- Folder picking form -->
<form class="share-folder__form" @reset.prevent.stop="resetFolder">
<input class="share-folder__picker"
type="text"
:placeholder="readableDirectory"
@click.prevent="pickFolder">
<!-- Show reset button if folder is different -->
<input v-if="readableDirectory !== defaultDirectory"
class="share-folder__reset"
type="reset"
:value="t('files', 'Reset')"
:aria-label="t('files', 'Reset folder to system default')">
</form>
</div>
</template>
<script>
import axios from '@nextcloud/axios'
import path from 'path'
import { generateUrl } from '@nextcloud/router'
import { getFilePickerBuilder, showError } from '@nextcloud/dialogs'
import { loadState } from '@nextcloud/initial-state'
const defaultDirectory = loadState('files_sharing', 'default_share_folder', '/')
const directory = loadState('files_sharing', 'share_folder', defaultDirectory)
export default {
name: 'SelectShareFolderDialogue',
data() {
return {
directory,
defaultDirectory,
}
},
computed: {
readableDirectory() {
if (!this.directory) {
return '/'
}
return this.directory
},
},
methods: {
async pickFolder() {
// Setup file picker
const picker = getFilePickerBuilder(t('files', 'Choose a default folder for accepted shares'))
.startAt(this.readableDirectory)
.setMultiSelect(false)
.setModal(true)
.setType(1)
.setMimeTypeFilter(['httpd/unix-directory'])
.allowDirectories()
.build()
try {
// Init user folder picking
const dir = await picker.pick() || '/'
if (!dir.startsWith('/')) {
throw new Error(t('files', 'Invalid path selected'))
}
// Fix potential path issues and save results
this.directory = path.normalize(dir)
await axios.put(generateUrl('/apps/files_sharing/settings/shareFolder'), {
shareFolder: this.directory,
})
} catch (error) {
showError(error.message || t('files', 'Unknown error'))
}
},
resetFolder() {
this.directory = this.defaultDirectory
axios.delete(generateUrl('/apps/files_sharing/settings/shareFolder'))
},
},
}
</script>
<style scoped lang="scss">
.share-folder {
&__form {
display: flex;
}
&__picker {
cursor: pointer;
min-width: 266px;
}
// Make the reset button looks like text
&__reset {
background-color: transparent;
border: none;
font-weight: normal;
text-decoration: underline;
font-size: inherit;
}
}
</style>

5
config/config.sample.php

@ -1485,6 +1485,11 @@ $CONFIG = [
*/
'sharing.force_share_accept' => false,
/**
* Set to false to prevent users from setting a custom share_folder
*/
'sharing.allow_custom_share_folder' => true,
/**
* Set to false to stop sending a mail when users receive a share
*/

11
lib/private/Share20/Manager.php

@ -44,6 +44,7 @@ namespace OC\Share20;
use OC\Cache\CappedMemoryCache;
use OC\Files\Mount\MoveableMount;
use OC\Share20\Exception\ProviderException;
use OCA\Files_Sharing\AppInfo\Application;
use OCA\Files_Sharing\ISharedStorage;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\File;
@ -788,7 +789,15 @@ class Manager implements IManager {
}
// Generate the target
$target = $this->config->getSystemValue('share_folder', '/') . '/' . $share->getNode()->getName();
$defaultShareFolder = $this->config->getSystemValue('share_folder', '/');
$allowCustomShareFolder = $this->config->getSystemValueBool('sharing.allow_custom_share_folder', true);
if ($allowCustomShareFolder) {
$shareFolder = $this->config->getUserValue($share->getSharedWith(), Application::APP_ID, 'share_folder', $defaultShareFolder);
} else {
$shareFolder = $defaultShareFolder;
}
$target = $shareFolder . '/' . $share->getNode()->getName();
$target = \OC\Files\Filesystem::normalizePath($target);
$share->setTarget($target);

Loading…
Cancel
Save