Completed
Push — stable9 ( ea327c...49a916 )
by Lukas
25s
created

SharedMount::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 7
c 1
b 0
f 0
nc 1
nop 4
dl 0
loc 8
rs 9.4285
1
<?php
2
/**
3
 * @author Björn Schießle <[email protected]>
4
 * @author Joas Schilling <[email protected]>
5
 * @author Morris Jobke <[email protected]>
6
 * @author Robin Appelman <[email protected]>
7
 * @author Roeland Jago Douma <[email protected]>
8
 *
9
 * @copyright Copyright (c) 2016, ownCloud, Inc.
10
 * @license AGPL-3.0
11
 *
12
 * This code is free software: you can redistribute it and/or modify
13
 * it under the terms of the GNU Affero General Public License, version 3,
14
 * as published by the Free Software Foundation.
15
 *
16
 * This program is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
 * GNU Affero General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU Affero General Public License, version 3,
22
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
23
 *
24
 */
25
26
namespace OCA\Files_Sharing;
27
28
use OC\Files\Filesystem;
29
use OC\Files\Mount\MountPoint;
30
use OC\Files\Mount\MoveableMount;
31
use OC\Files\View;
32
33
/**
34
 * Shared mount points can be moved by the user
35
 */
36
class SharedMount extends MountPoint implements MoveableMount {
37
	/**
38
	 * @var \OC\Files\Storage\Shared $storage
39
	 */
40
	protected $storage = null;
41
42
	/**
43
	 * @var \OC\Files\View
44
	 */
45
	private $recipientView;
46
47
	/**
48
	 * @var string
49
	 */
50
	private $user;
51
52
	/**
53
	 * @param string $storage
54
	 * @param SharedMount[] $mountpoints
55
	 * @param array|null $arguments
56
	 * @param \OCP\Files\Storage\IStorageFactory $loader
57
	 */
58
	public function __construct($storage, array $mountpoints, $arguments = null, $loader = null) {
59
		$this->user = $arguments['user'];
60
		$this->recipientView = new View('/' . $this->user . '/files');
61
		$newMountPoint = $this->verifyMountPoint($arguments['share'], $mountpoints);
62
		$absMountPoint = '/' . $this->user . '/files' . $newMountPoint;
63
		$arguments['ownerView'] = new View('/' . $arguments['share']['uid_owner'] . '/files');
64
		parent::__construct($storage, $absMountPoint, $arguments, $loader);
65
	}
66
67
	/**
68
	 * check if the parent folder exists otherwise move the mount point up
69
	 *
70
	 * @param array $share
71
	 * @param SharedMount[] $mountpoints
72
	 * @return string
73
	 */
74
	private function verifyMountPoint(&$share, array $mountpoints) {
75
76
		$mountPoint = basename($share['file_target']);
77
		$parent = dirname($share['file_target']);
78
79
		if (!$this->recipientView->is_dir($parent)) {
80
			$parent = Helper::getShareFolder($this->recipientView);
81
		}
82
83
		$newMountPoint = $this->generateUniqueTarget(
84
			\OC\Files\Filesystem::normalizePath($parent . '/' . $mountPoint),
85
			$this->recipientView,
86
			$mountpoints
87
		);
88
89
		if ($newMountPoint !== $share['file_target']) {
90
			$this->updateFileTarget($newMountPoint, $share);
91
			$share['file_target'] = $newMountPoint;
92
			$share['unique_name'] = true;
93
		}
94
95
		return $newMountPoint;
96
	}
97
98
	/**
99
	 * @param string $path
100
	 * @param View $view
101
	 * @param SharedMount[] $mountpoints
102
	 * @return mixed
103
	 */
104
	private function generateUniqueTarget($path, $view, array $mountpoints) {
105
		$pathinfo = pathinfo($path);
106
		$ext = (isset($pathinfo['extension'])) ? '.'.$pathinfo['extension'] : '';
107
		$name = $pathinfo['filename'];
108
		$dir = $pathinfo['dirname'];
109
110
		// Helper function to find existing mount points
111
		$mountpointExists = function($path) use ($mountpoints) {
112
			foreach ($mountpoints as $mountpoint) {
113
				if ($mountpoint->getShare()['file_target'] === $path) {
114
					return true;
115
				}
116
			}
117
			return false;
118
		};
119
120
		$i = 2;
121 View Code Duplication
		while ($view->file_exists($path) || $mountpointExists($path)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
122
			$path = Filesystem::normalizePath($dir . '/' . $name . ' ('.$i.')' . $ext);
123
			$i++;
124
		}
125
126
		return $path;
127
	}
128
129
	/**
130
	 * update fileTarget in the database if the mount point changed
131
	 *
132
	 * @param string $newPath
133
	 * @param array $share reference to the share which should be modified
134
	 * @return bool
135
	 */
136
	private function updateFileTarget($newPath, &$share) {
137
		// if the user renames a mount point from a group share we need to create a new db entry
138
		// for the unique name
139
		if ($share['share_type'] === \OCP\Share::SHARE_TYPE_GROUP && empty($share['unique_name'])) {
140
			$query = \OCP\DB::prepare('INSERT INTO `*PREFIX*share` (`item_type`, `item_source`, `item_target`,'
0 ignored issues
show
Deprecated Code introduced by
The method OCP\DB::prepare() has been deprecated with message: 8.1.0 use prepare() of \OCP\IDBConnection - \OC::$server->getDatabaseConnection()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
141
			.' `share_type`, `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`,'
142
			.' `file_target`, `token`, `parent`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)');
143
			$arguments = array($share['item_type'], $share['item_source'], $share['item_target'],
144
				2, $this->user, $share['uid_owner'], $share['permissions'], $share['stime'], $share['file_source'],
145
				$newPath, $share['token'], $share['id']);
146
		} else {
147
			// rename mount point
148
			$query = \OCP\DB::prepare(
0 ignored issues
show
Deprecated Code introduced by
The method OCP\DB::prepare() has been deprecated with message: 8.1.0 use prepare() of \OCP\IDBConnection - \OC::$server->getDatabaseConnection()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
149
					'Update `*PREFIX*share`
150
						SET `file_target` = ?
151
						WHERE `id` = ?'
152
			);
153
			$arguments = array($newPath, $share['id']);
154
		}
155
156
		$result = $query->execute($arguments);
157
158
		return $result === 1 ? true : false;
159
	}
160
161
	/**
162
	 * Format a path to be relative to the /user/files/ directory
163
	 *
164
	 * @param string $path the absolute path
165
	 * @return string e.g. turns '/admin/files/test.txt' into '/test.txt'
166
	 * @throws \OCA\Files_Sharing\Exceptions\BrokenPath
167
	 */
168
	protected function stripUserFilesPath($path) {
169
		$trimmed = ltrim($path, '/');
170
		$split = explode('/', $trimmed);
171
172
		// it is not a file relative to data/user/files
173
		if (count($split) < 3 || $split[1] !== 'files') {
174
			\OCP\Util::writeLog('file sharing',
175
				'Can not strip userid and "files/" from path: ' . $path,
176
				\OCP\Util::ERROR);
177
			throw new \OCA\Files_Sharing\Exceptions\BrokenPath('Path does not start with /user/files', 10);
178
		}
179
180
		// skip 'user' and 'files'
181
		$sliced = array_slice($split, 2);
182
		$relPath = implode('/', $sliced);
183
184
		return '/' . $relPath;
185
	}
186
187
	/**
188
	 * Move the mount point to $target
189
	 *
190
	 * @param string $target the target mount point
191
	 * @return bool
192
	 */
193
	public function moveMount($target) {
194
195
		$relTargetPath = $this->stripUserFilesPath($target);
196
		$share = $this->storage->getShare();
197
198
		$result = true;
199
200
		if (!empty($share['grouped'])) {
201
			foreach ($share['grouped'] as $s) {
202
				$result = $this->updateFileTarget($relTargetPath, $s) && $result;
203
			}
204
		} else {
205
			$result = $this->updateFileTarget($relTargetPath, $share) && $result;
206
		}
207
208
		if ($result) {
209
			$this->setMountPoint($target);
210
			$this->storage->setUniqueName();
211
			$this->storage->setMountPoint($relTargetPath);
212
213
		} else {
214
			\OCP\Util::writeLog('file sharing',
215
				'Could not rename mount point for shared folder "' . $this->getMountPoint() . '" to "' . $target . '"',
216
				\OCP\Util::ERROR);
217
		}
218
219
		return $result;
220
	}
221
222
	/**
223
	 * Remove the mount points
224
	 *
225
	 * @return bool
226
	 */
227
	public function removeMount() {
228
		$mountManager = \OC\Files\Filesystem::getMountManager();
229
		/** @var $storage \OC\Files\Storage\Shared */
230
		$storage = $this->getStorage();
231
		$result = $storage->unshareStorage();
232
		$mountManager->removeMount($this->mountPoint);
233
234
		return $result;
235
	}
236
237
	/**
238
	 * @return array
239
	 */
240
	public function getShare() {
241
		/** @var $storage \OC\Files\Storage\Shared */
242
		$storage = $this->getStorage();
243
		return $storage->getShare();
244
	}
245
}
246