Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use OCS Capabilities API #15876

Merged
merged 13 commits into from
Apr 30, 2024
2 changes: 2 additions & 0 deletions defaults/src/main/resources/default.properties
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,8 @@ webdav.microsoftiis.header.translate=true
webdav.list.handler.sax=true
webdav.lock.enable=true
webdav.listing.chunksize=20
nextcloud.root.default=/remote.php/dav
owncloud.root.default=/remote.php/dav

smb.domain.default=WORKGROUP
# Enable distributed filesystem path resolver
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
import ch.cyberduck.core.ListProgressListener;
import ch.cyberduck.core.Path;
import ch.cyberduck.core.PathAttributes;
import ch.cyberduck.core.URIEncoder;
import ch.cyberduck.core.dav.DAVAttributesFinderFeature;
import ch.cyberduck.core.dav.DAVPathEncoder;
import ch.cyberduck.core.dav.DAVSession;
import ch.cyberduck.core.dav.DAVTimestampFeature;
import ch.cyberduck.core.exception.BackgroundException;
Expand Down Expand Up @@ -92,17 +92,17 @@ protected PathAttributes head(final Path file) {
}

@Override
protected List<DavResource> list(final Path file) throws IOException {
final String url;
protected List<DavResource> list(final Path file) throws IOException, BackgroundException {
final String path;
if(StringUtils.isNotBlank(file.attributes().getVersionId())) {
url = String.format("%sversions/%s/%s",
new DAVPathEncoder().encode(new NextcloudHomeFeature(session.getHost()).find(NextcloudHomeFeature.Context.versions)),
path = String.format("%s/versions/%s/%s",
new NextcloudHomeFeature(session.getHost()).find(NextcloudHomeFeature.Context.versions).getAbsolute(),
file.attributes().getFileId(), file.attributes().getVersionId());
}
else {
url = new DAVPathEncoder().encode(file);
path = file.getAbsolute();
}
return session.getClient().list(url, 0,
return session.getClient().list(URIEncoder.encode(path), 0,
Stream.of(OC_FILEID_CUSTOM_NAMESPACE, OC_CHECKSUMS_CUSTOM_NAMESPACE, OC_SIZE_CUSTOM_NAMESPACE,
DAVTimestampFeature.LAST_MODIFIED_CUSTOM_NAMESPACE,
DAVTimestampFeature.LAST_MODIFIED_SERVER_CUSTOM_NAMESPACE).collect(Collectors.toSet()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@

import ch.cyberduck.core.Host;
import ch.cyberduck.core.Path;
import ch.cyberduck.core.exception.BackgroundException;
import ch.cyberduck.core.features.Home;
import ch.cyberduck.core.preferences.HostPreferences;
import ch.cyberduck.core.shared.AbstractHomeFeature;
import ch.cyberduck.core.shared.DefaultPathHomeFeature;
import ch.cyberduck.core.shared.DelegatingHomeFeature;

import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
Expand All @@ -28,27 +33,51 @@
public class NextcloudHomeFeature extends AbstractHomeFeature {
private static final Logger log = LogManager.getLogger(NextcloudHomeFeature.class);

private final Home delegate;
private final Host bookmark;
private final String root;

public NextcloudHomeFeature(final Host bookmark) {
this(new DefaultPathHomeFeature(bookmark), bookmark);
}

public NextcloudHomeFeature(final Home delegate, final Host bookmark) {
this(delegate, bookmark, new HostPreferences(bookmark).getProperty("nextcloud.root.default"));
}

/**
* @param root WebDAV root
*/
public NextcloudHomeFeature(final Home delegate, final Host bookmark, final String root) {
this.delegate = delegate;
this.bookmark = bookmark;
this.root = root;
}

@Override
public Path find() {
public Path find() throws BackgroundException {
return this.find(Context.files);
}

public Path find(final Context files) {
String username = bookmark.getCredentials().getUsername();
public Path find(final Context files) throws BackgroundException {
final String username = bookmark.getCredentials().getUsername();
if(StringUtils.isBlank(username)) {
if(log.isWarnEnabled()) {
log.warn(String.format("Missing username for %s", bookmark));
}
return null;
return delegate.find();
}
// Custom path setting
final Path workdir;
final Path defaultpath = new DelegatingHomeFeature(delegate).find();
if(!defaultpath.isRoot() && StringUtils.isNotBlank(StringUtils.removeStart(defaultpath.getAbsolute(), root))) {
workdir = new Path(new Path(String.format("%s/%s/%s", root, files.name(), username), EnumSet.of(Path.Type.directory)),
StringUtils.removeStart(defaultpath.getAbsolute(), root), EnumSet.of(Path.Type.directory));
}
else {
workdir = new Path(new Path(String.format("%s/%s", root, files.name()), EnumSet.of(Path.Type.directory)),
username, EnumSet.of(Path.Type.directory));
}
final Path workdir = new Path(new Path(String.format("/remote.php/dav/%s", files.name()), EnumSet.of(Path.Type.directory)),
username, EnumSet.of(Path.Type.directory));
if(log.isDebugEnabled()) {
log.debug(String.format("Use home directory %s", workdir));
}
Expand All @@ -57,6 +86,7 @@ public Path find(final Context files) {

public enum Context {
files,
versions
versions,
meta
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@
*/

import ch.cyberduck.core.Path;
import ch.cyberduck.core.dav.DAVPathEncoder;
import ch.cyberduck.core.URIEncoder;
import ch.cyberduck.core.dav.DAVReadFeature;
import ch.cyberduck.core.dav.DAVSession;
import ch.cyberduck.core.exception.BackgroundException;
import ch.cyberduck.core.transfer.TransferStatus;

import org.apache.commons.lang3.StringUtils;
Expand All @@ -36,12 +37,12 @@ public NextcloudReadFeature(final DAVSession session) {
}

@Override
protected HttpRequestBase toRequest(final Path file, final TransferStatus status) {
protected HttpRequestBase toRequest(final Path file, final TransferStatus status) throws BackgroundException {
final HttpRequestBase request = super.toRequest(file, status);
if(StringUtils.isNotBlank(file.attributes().getVersionId())) {
request.setURI(URI.create(String.format("%sversions/%s/%s",
new DAVPathEncoder().encode(new NextcloudHomeFeature(session.getHost()).find(NextcloudHomeFeature.Context.versions)),
file.attributes().getFileId(), file.attributes().getVersionId())));
request.setURI(URI.create(URIEncoder.encode(String.format("%s/versions/%s/%s",
new NextcloudHomeFeature(session.getHost()).find(NextcloudHomeFeature.Context.versions).getAbsolute(),
file.attributes().getFileId(), file.attributes().getVersionId()))));
}
return request;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,41 +15,80 @@
* GNU General Public License for more details.
*/

import ch.cyberduck.core.DefaultIOExceptionMappingService;
import ch.cyberduck.core.Host;
import ch.cyberduck.core.HostKeyCallback;
import ch.cyberduck.core.ListService;
import ch.cyberduck.core.LoginCallback;
import ch.cyberduck.core.UrlProvider;
import ch.cyberduck.core.dav.DAVClient;
import ch.cyberduck.core.dav.DAVDirectoryFeature;
import ch.cyberduck.core.dav.DAVSession;
import ch.cyberduck.core.dav.DAVTouchFeature;
import ch.cyberduck.core.exception.BackgroundException;
import ch.cyberduck.core.features.AttributesFinder;
import ch.cyberduck.core.features.Delete;
import ch.cyberduck.core.features.Directory;
import ch.cyberduck.core.features.Home;
import ch.cyberduck.core.features.Lock;
import ch.cyberduck.core.features.Read;
import ch.cyberduck.core.features.Share;
import ch.cyberduck.core.features.Timestamp;
import ch.cyberduck.core.features.Touch;
import ch.cyberduck.core.features.Upload;
import ch.cyberduck.core.features.Versioning;
import ch.cyberduck.core.features.Write;
import ch.cyberduck.core.http.DefaultHttpResponseExceptionMappingService;
import ch.cyberduck.core.http.HttpUploadFeature;
import ch.cyberduck.core.shared.DefaultPathHomeFeature;
import ch.cyberduck.core.ocs.OcsCapabilities;
import ch.cyberduck.core.ocs.OcsCapabilitiesRequest;
import ch.cyberduck.core.ocs.OcsCapabilitiesResponseHandler;
import ch.cyberduck.core.proxy.Proxy;
import ch.cyberduck.core.shared.DelegatingHomeFeature;
import ch.cyberduck.core.shared.WorkdirHomeFeature;
import ch.cyberduck.core.ssl.X509KeyManager;
import ch.cyberduck.core.ssl.X509TrustManager;
import ch.cyberduck.core.threading.CancelCallback;

import org.apache.http.client.HttpResponseException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.IOException;

public class NextcloudSession extends DAVSession {
private static final Logger log = LogManager.getLogger(NextcloudSession.class);

protected final OcsCapabilities ocs = new OcsCapabilities();

public NextcloudSession(final Host host, final X509TrustManager trust, final X509KeyManager key) {
super(host, trust, key);
}

@Override
protected DAVClient connect(final Proxy proxy, final HostKeyCallback key, final LoginCallback prompt, final CancelCallback cancel) throws BackgroundException {
return super.connect(proxy, key, prompt, cancel);
}

@Override
public void login(final Proxy proxy, final LoginCallback prompt, final CancelCallback cancel) throws BackgroundException {
super.login(proxy, prompt, cancel);
try {
client.execute(new OcsCapabilitiesRequest(host), new OcsCapabilitiesResponseHandler(ocs));
}
catch(HttpResponseException e) {
throw new DefaultHttpResponseExceptionMappingService().map(e);
}
catch(IOException e) {
throw new DefaultIOExceptionMappingService().map(e);
}
}

@Override
@SuppressWarnings("unchecked")
public <T> T _getFeature(final Class<T> type) {
if(type == Home.class) {
return (T) new DelegatingHomeFeature(new WorkdirHomeFeature(host), new DefaultPathHomeFeature(host), new NextcloudHomeFeature(host));
return (T) new DelegatingHomeFeature(new WorkdirHomeFeature(host), new NextcloudHomeFeature(host));
}
if(type == ListService.class) {
return (T) new NextcloudListService(this);
Expand All @@ -63,6 +102,11 @@ public <T> T _getFeature(final Class<T> type) {
if(type == AttributesFinder.class) {
return (T) new NextcloudAttributesFinderFeature(this);
}
if(type == Lock.class) {
if(!ocs.locking) {
return null;
}
}
if(type == Upload.class) {
return (T) new HttpUploadFeature(new NextcloudWriteFeature(this));
}
Expand All @@ -76,6 +120,9 @@ public <T> T _getFeature(final Class<T> type) {
return (T) new NextcloudShareFeature(this);
}
if(type == Versioning.class) {
if(!ocs.versioning) {
return null;
}
return (T) new NextcloudVersioningFeature(this);
}
if(type == Delete.class) {
Expand Down
Loading