Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions apps/dav/appinfo/v1/publicwebdav.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,9 @@
if (!$isReadable) {
$filesDropPlugin->enable();
}

$view = new View($node->getPath());
$filesDropPlugin->setView($view);
$filesDropPlugin->setShare($share);

$view = new View($node->getPath());
return $view;
});

Expand Down
4 changes: 1 addition & 3 deletions apps/dav/appinfo/v2/publicremote.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,9 @@
if (!$isReadable) {
$filesDropPlugin->enable();
}

$view = new View($node->getPath());
$filesDropPlugin->setView($view);
$filesDropPlugin->setShare($share);

$view = new View($node->getPath());
return $view;
});

Expand Down
91 changes: 53 additions & 38 deletions apps/dav/lib/Files/Sharing/FilesDropPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
*/
namespace OCA\DAV\Files\Sharing;

use OC\Files\View;
use OCP\Files\Folder;
use OCP\Files\NotFoundException;
use OCP\Share\IShare;
use Sabre\DAV\Exception\MethodNotAllowed;
use Sabre\DAV\ServerPlugin;
Expand All @@ -17,14 +18,9 @@
*/
class FilesDropPlugin extends ServerPlugin {

private ?View $view = null;
private ?IShare $share = null;
private bool $enabled = false;

public function setView(View $view): void {
$this->view = $view;
}

public function setShare(IShare $share): void {
$this->share = $share;
}
Expand All @@ -33,7 +29,6 @@ public function enable(): void {
$this->enabled = true;
}


/**
* This initializes the plugin.
* It is ONLY initialized by the server on a file drop request.
Expand All @@ -45,7 +40,12 @@ public function initialize(\Sabre\DAV\Server $server): void {
}

public function onMkcol(RequestInterface $request, ResponseInterface $response) {
if (!$this->enabled || $this->share === null || $this->view === null) {
if (!$this->enabled || $this->share === null) {
return;
}

$node = $this->share->getNode();
if (!($node instanceof Folder)) {
return;
}

Expand All @@ -57,7 +57,12 @@ public function onMkcol(RequestInterface $request, ResponseInterface $response)
}

public function beforeMethod(RequestInterface $request, ResponseInterface $response) {
if (!$this->enabled || $this->share === null || $this->view === null) {
if (!$this->enabled || $this->share === null) {
return;
}

$node = $this->share->getNode();
if (!($node instanceof Folder)) {
return;
}

Expand Down Expand Up @@ -127,45 +132,55 @@ public function beforeMethod(RequestInterface $request, ResponseInterface $respo
}

// Create the folders along the way
$folders = $this->getPathSegments(dirname($relativePath));
foreach ($folders as $folder) {
if ($folder === '') {
$folder = $node;
$pathSegments = $this->getPathSegments(dirname($relativePath));
foreach ($pathSegments as $pathSegment) {
if ($pathSegment === '') {
continue;
} // skip empty parts
if (!$this->view->file_exists($folder)) {
$this->view->mkdir($folder);
}

try {
// get the current folder
$currentFolder = $folder->get($pathSegment);
// check target is a folder
if ($currentFolder instanceof Folder) {
$folder = $currentFolder;
} else {
// otherwise look in the parent folder if we already create an unique folder name
foreach ($folder->getDirectoryListing() as $child) {
// we look for folders which match "NAME (SUFFIX)"
if ($child instanceof Folder && str_starts_with($child->getName(), $pathSegment)) {
$suffix = substr($child->getName(), strlen($pathSegment));
if (preg_match('/^ \(\d+\)$/', $suffix)) {
// we found the unique folder name and can use it
$folder = $child;
break;
}
}
}
// no folder found so we need to create a new unique folder name
if (!isset($child) || $child !== $folder) {
$folder = $folder->newFolder($folder->getNonExistingName($pathSegment));
}
}
} catch (NotFoundException) {
// the folder does simply not exist so we create it
$folder = $folder->newFolder($pathSegment);
}
}

// Finally handle conflicts on the end files
$noConflictPath = \OC_Helper::buildNotExistingFileNameForView(dirname($relativePath), basename($relativePath), $this->view);
$path = '/files/' . $token . '/' . $noConflictPath;
$url = $request->getBaseUrl() . str_replace('//', '/', $path);
$uniqueName = $folder->getNonExistingName(basename($relativePath));
$relativePath = substr($folder->getPath(), strlen($node->getPath()));
$path = '/files/' . $token . '/' . $relativePath . '/' . $uniqueName;
$url = rtrim($request->getBaseUrl(), '/') . str_replace('//', '/', $path);
$request->setUrl($url);
}

private function getPathSegments(string $path): array {
// Normalize slashes and remove trailing slash
$path = rtrim(str_replace('\\', '/', $path), '/');

// Handle absolute paths starting with /
$isAbsolute = str_starts_with($path, '/');

$segments = explode('/', $path);

// Add back the leading slash for the first segment if needed
$result = [];
$current = $isAbsolute ? '/' : '';

foreach ($segments as $segment) {
if ($segment === '') {
// skip empty parts
continue;
}
$current = rtrim($current, '/') . '/' . $segment;
$result[] = $current;
}
$path = trim(str_replace('\\', '/', $path), '/');

return $result;
return explode('/', $path);
}
}
Loading
Loading