Skip to content

Commit 02468db

Browse files
a-schildclaude
andcommitted
Add Group Folders app support (issue #109)
New groupfolders package with a GroupFolders connector (create/rename/delete/ list folders, grant/revoke group access, set group permissions, set quota), wired into NextcloudConnector. Reimplemented against the current Jakarta-based code, based on the implementation in Denis Verkhovsky's fork. The test container now installs the groupfolders app, and TestGroupFolders exercises the full lifecycle. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 52f6b22 commit 02468db

10 files changed

Lines changed: 703 additions & 10 deletions

File tree

Changelog.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog for nextcloud api
22

3+
## Version 14.2.0
4+
- Add support for the Group Folders app: create, rename, delete and list group
5+
folders, grant/revoke group access, set group permissions and set the folder
6+
quota via the new `GroupFolders` connector and `NextcloudConnector` methods
7+
(issue #109). Thanks to Denis Verkhovsky for the original implementation the
8+
port is based on.
9+
310
## Version 14.1.6
411
- 2026-07-24
512
- Add optional `expireDate` parameter to `doShare` / `doShareAsync`, so an

src/main/java/org/aarboard/nextcloud/api/NextcloudConnector.java

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
import org.aarboard.nextcloud.api.filesharing.ShareType;
3232
import org.aarboard.nextcloud.api.filesharing.SharesXMLAnswer;
3333
import org.aarboard.nextcloud.api.filesharing.SingleShareXMLAnswer;
34+
import org.aarboard.nextcloud.api.groupfolders.GroupFolderInfo;
35+
import org.aarboard.nextcloud.api.groupfolders.GroupFolders;
3436
import org.aarboard.nextcloud.api.provisioning.*;
3537
import org.aarboard.nextcloud.api.utils.*;
3638
import org.aarboard.nextcloud.api.webdav.Files;
@@ -48,6 +50,7 @@ public class NextcloudConnector implements AutoCloseable {
4850
private final ConfigConnector cc;
4951
private final Folders fd;
5052
private final Files fl;
53+
private final GroupFolders gf;
5154

5255
/**
5356
*
@@ -110,6 +113,7 @@ public NextcloudConnector(String originalServiceUrl, AuthenticationConfig authen
110113
cc = new ConfigConnector(this.serverConfig);
111114
fd = new Folders(this.serverConfig);
112115
fl = new Files(this.serverConfig);
116+
gf = new GroupFolders(this.serverConfig);
113117

114118
} catch (MalformedURLException e) {
115119
throw new IllegalArgumentException(e);
@@ -131,6 +135,7 @@ public NextcloudConnector(String serverName, boolean useHTTPS, int port,
131135
cc = new ConfigConnector(this.serverConfig);
132136
fd = new Folders(this.serverConfig);
133137
fl = new Files(this.serverConfig);
138+
gf = new GroupFolders(this.serverConfig);
134139
}
135140

136141
/**
@@ -189,6 +194,84 @@ public void shutdown() throws IOException {
189194
ConnectorCommon.shutdown();
190195
}
191196

197+
/**
198+
* Creates a new group folder (Group Folders app must be installed).
199+
*
200+
* @param mountPoint name/mount point of the group folder
201+
* @return the id of the newly created group folder
202+
*/
203+
public int createGroupFolder(String mountPoint) {
204+
return gf.createGroupFolder(mountPoint);
205+
}
206+
207+
/**
208+
* Renames (changes the mount point of) a group folder.
209+
*
210+
* @param groupFolderId id of the group folder
211+
* @param newMountPoint new name/mount point
212+
*/
213+
public void renameGroupFolder(int groupFolderId, String newMountPoint) {
214+
gf.renameGroupFolder(groupFolderId, newMountPoint);
215+
}
216+
217+
/**
218+
* Deletes a group folder.
219+
*
220+
* @param groupFolderId id of the group folder
221+
*/
222+
public void deleteGroupFolder(int groupFolderId) {
223+
gf.deleteGroupFolder(groupFolderId);
224+
}
225+
226+
/**
227+
* @return all group folders visible to the current user
228+
*/
229+
public Collection<GroupFolderInfo> getGroupFolders() {
230+
return gf.getGroupFolders();
231+
}
232+
233+
/**
234+
* Grants a group access to a group folder.
235+
*
236+
* @param groupFolderId id of the group folder
237+
* @param group group id to grant access to
238+
*/
239+
public void grantAccessToGroupFolder(int groupFolderId, String group) {
240+
gf.grantAccess(groupFolderId, group);
241+
}
242+
243+
/**
244+
* Revokes a group's access to a group folder.
245+
*
246+
* @param groupFolderId id of the group folder
247+
* @param group group id to revoke access from
248+
*/
249+
public void revokeAccessToGroupFolder(int groupFolderId, String group) {
250+
gf.revokeAccess(groupFolderId, group);
251+
}
252+
253+
/**
254+
* Sets the permissions a group has on a group folder.
255+
*
256+
* @param groupFolderId id of the group folder
257+
* @param group group id
258+
* @param permissions permission bit mask (1 = read, 2 = update, 4 =
259+
* create, 8 = delete, 16 = share, 31 = all)
260+
*/
261+
public void setGroupFolderPermissions(int groupFolderId, String group, int permissions) {
262+
gf.setGroupPermissions(groupFolderId, group, permissions);
263+
}
264+
265+
/**
266+
* Sets the quota of a group folder.
267+
*
268+
* @param groupFolderId id of the group folder
269+
* @param quota quota in bytes, or {@code -3} for an unlimited quota
270+
*/
271+
public void setGroupFolderQuota(int groupFolderId, long quota) {
272+
gf.setQuota(groupFolderId, quota);
273+
}
274+
192275
/**
193276
* Close the HTTP client. Perform this to cleanly shut down this
194277
* application.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright (C) 2026 a.schild
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
package org.aarboard.nextcloud.api.groupfolders;
18+
19+
import com.fasterxml.jackson.annotation.JsonIgnore;
20+
import com.fasterxml.jackson.annotation.JsonProperty;
21+
import org.aarboard.nextcloud.api.utils.JsonAnswer;
22+
23+
/**
24+
* Answer of the "create group folder" call, carrying the id of the new folder.
25+
*/
26+
public class GroupFolderAnswer extends JsonAnswer {
27+
28+
@JsonProperty
29+
private Data data;
30+
31+
@JsonIgnore
32+
public Integer getId() {
33+
if (data != null) {
34+
return data.id;
35+
}
36+
return null;
37+
}
38+
39+
public static class Data {
40+
@JsonProperty
41+
public Integer id;
42+
}
43+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright (C) 2026 a.schild
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
package org.aarboard.nextcloud.api.groupfolders;
18+
19+
import com.fasterxml.jackson.annotation.JsonIgnore;
20+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
21+
import com.fasterxml.jackson.annotation.JsonProperty;
22+
import java.util.Map;
23+
24+
/**
25+
* Information about a single group folder as returned by the
26+
* <a href="https://github.com/nextcloud/groupfolders">Group Folders</a> app.
27+
*/
28+
@JsonIgnoreProperties(ignoreUnknown = true)
29+
public class GroupFolderInfo {
30+
31+
@JsonProperty
32+
private Integer id;
33+
@JsonProperty
34+
private String mount_point;
35+
@JsonProperty
36+
private Map<String, Integer> groups;
37+
@JsonProperty
38+
private Long quota;
39+
40+
/**
41+
* @return the id of the group folder
42+
*/
43+
@JsonIgnore
44+
public Integer getId() {
45+
return id;
46+
}
47+
48+
/**
49+
* @return the mount point (name) of the group folder
50+
*/
51+
@JsonIgnore
52+
public String getMountPoint() {
53+
return mount_point;
54+
}
55+
56+
/**
57+
* @return the assigned groups mapped to their permission bit mask
58+
*/
59+
@JsonIgnore
60+
public Map<String, Integer> getAssignedGroups() {
61+
return groups;
62+
}
63+
64+
/**
65+
* @return the quota of the group folder in bytes, or {@code -3} for an
66+
* unlimited quota (see the Group Folders app documentation)
67+
*/
68+
@JsonIgnore
69+
public Long getQuota() {
70+
return quota;
71+
}
72+
}

0 commit comments

Comments
 (0)