Skip to content
Open
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
26 changes: 23 additions & 3 deletions lib/Controller/FolderController.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ private function formatFolder(FolderWithMappingsAndCache $folder): array {
* @param 'mount_point'|'quota'|'groups'|'acl' $orderBy The key to order by
* @param 'asc'|'desc' $order Sort ascending or descending
* @param ?string $mountpoint Only return folders with a given mount point
* @param 'all'|'group'|'team' $folderType Only return folders of the given type
* @return DataResponse<Http::STATUS_OK, array<string, GroupFoldersFolder>, array{}>
* @throws OCSNotFoundException Storage not found
* @throws OCSBadRequestException Wrong limit used
Expand All @@ -139,6 +140,7 @@ public function getFolders(
string $orderBy = 'mount_point',
string $order = 'asc',
?string $mountpoint = null,
string $folderType = 'all',
): DataResponse {
/**
* @phpstan-ignore smallerOrEqual.alwaysFalse, booleanAnd.alwaysFalse
Expand All @@ -161,6 +163,8 @@ public function getFolders(
throw new OCSBadRequestException('The order is not allowed.');
}

$folderType = $this->validateFolderType($folderType);

$storageId = $this->getRootFolderStorageId();
if ($storageId === null) {
throw new OCSNotFoundException();
Expand All @@ -171,7 +175,7 @@ public function getFolders(
$folders = [];
$i = 0;
/** @var string $id */
foreach ($this->manager->getAllFoldersWithSize($offset, $limit, $orderBy, $order, $mountpoint) as $id => $folder) {
foreach ($this->manager->getAllFoldersWithSize($offset, $limit, $orderBy, $order, $mountpoint, $folderType) as $id => $folder) {
// Make them string-indexed for OpenAPI JSON output
// JavaScript doesn't preserve JSON object key orders, so we need to manually add this information.
$folders[(string)$id] = array_merge($this->formatFolder($folder), [
Expand All @@ -195,6 +199,18 @@ public function getFolders(
return new DataResponse($folders);
}

/**
* @return 'all'|'group'|'team'
* @throws OCSBadRequestException
*/
private function validateFolderType(string $folderType): string {
if (!in_array($folderType, ['all', 'group', 'team'], true)) {
throw new OCSBadRequestException('The folderType is not allowed.');
}

return $folderType;
}

/**
* Gets a Groupfolder by ID
*
Expand Down Expand Up @@ -640,14 +656,18 @@ public function aclMappingSearch(int $id, string $search = ''): DataResponse {
/**
* Gets the total number of Groupfolders
*
* @param 'all'|'group'|'team' $folderType Only count folders of the given type
* @return DataResponse<Http::STATUS_OK, array{count: int}, array{}>
* @throws OCSBadRequestException Invalid folder type
*
* 200: Groupfolder count returned
*/
#[RequireGroupFolderAdmin]
#[NoAdminRequired]
#[FrontpageRoute(verb: 'GET', url: '/folders/count')]
public function getFoldersCount(): DataResponse {
return new DataResponse(['count' => $this->manager->countAllFolders()]);
public function getFoldersCount(string $folderType = 'all'): DataResponse {
$folderType = $this->validateFolderType($folderType);

return new DataResponse(['count' => $this->manager->countAllFolders($folderType)]);
}
}
24 changes: 21 additions & 3 deletions lib/Folder/FolderManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ private function selectWithFileCache(?IQueryBuilder $query = null): IQueryBuilde
}

/**
* @param 'all'|'group'|'team' $folderType
* @return array<int, FolderWithMappingsAndCache>
* @throws Exception
*/
Expand All @@ -164,10 +165,12 @@ public function getAllFoldersWithSize(
string $orderBy = 'mount_point',
\SortDirection $order = \SortDirection::Ascending,
?string $mountPoint = null,
string $folderType = 'all',
): array {
$query = $this->selectWithFileCache();
$query->setFirstResult($offset);
$query->setMaxResults($limit);
$this->applyFolderTypeFilter($query, $folderType);
if ($orderBy === 'groups') {
$query
->leftJoin('f', 'group_folders_groups', 'g', $query->expr()->eq('f.folder_id', 'g.folder_id'))
Expand All @@ -178,7 +181,7 @@ public function getAllFoldersWithSize(
}

if ($mountPoint !== null) {
$query->where($query->expr()->eq('mount_point', $query->createNamedParameter($mountPoint)));
$query->andWhere($query->expr()->eq('mount_point', $query->createNamedParameter($mountPoint)));
}

// Fallback in case two rows are the same after ordering by the $orderBy
Expand Down Expand Up @@ -1600,11 +1603,26 @@ private function invalidateFolderAclCache(int $folderId): void {
$this->canManageACLCache = [];
}

public function countAllFolders(): int {
/**
* @param 'all'|'group'|'team' $folderType
*/
public function countAllFolders(string $folderType = 'all'): int {
$query = $this->connection->getQueryBuilder();
$query->select($query->func()->count('folder_id'))
->from('group_folders');
->from('group_folders', 'f');
$this->applyFolderTypeFilter($query, $folderType);
$result = $query->executeQuery()->fetchOne();
return is_numeric($result) ? (int)$result : 0;
}

/**
* @param 'all'|'group'|'team' $folderType
*/
private function applyFolderTypeFilter(IQueryBuilder $query, string $folderType): void {
if ($folderType === 'group') {
$query->andWhere($query->expr()->isNull('f.team_circle_id'));
} elseif ($folderType === 'team') {
$query->andWhere($query->expr()->isNotNull('f.team_circle_id'));
}
}
}
56 changes: 56 additions & 0 deletions openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,20 @@
"default": null
}
},
{
"name": "folderType",
"in": "query",
"description": "Only return folders of the given type",
"schema": {
"type": "string",
"default": "all",
"enum": [
"all",
"group",
"team"
]
}
},
{
"name": "OCS-APIRequest",
"in": "header",
Expand Down Expand Up @@ -2762,6 +2776,20 @@
}
],
"parameters": [
{
"name": "folderType",
"in": "query",
"description": "Only count folders of the given type",
"schema": {
"type": "string",
"default": "all",
"enum": [
"all",
"group",
"team"
]
}
},
{
"name": "OCS-APIRequest",
"in": "header",
Expand Down Expand Up @@ -2813,6 +2841,34 @@
}
}
},
"400": {
"description": "Invalid folder type",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"ocs"
],
"properties": {
"ocs": {
"type": "object",
"required": [
"meta",
"data"
],
"properties": {
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
"data": {}
}
}
}
}
}
}
},
"401": {
"description": "Current user is not logged in",
"content": {
Expand Down
11 changes: 8 additions & 3 deletions src/settings/Api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,22 @@ import type { Folder, Group, User, AclManage, DelegationCircle, DelegationGroup,

addPasswordConfirmationInterceptors(axios)

type FolderType = 'all' | 'group' | 'team'

export class Api {

getUrl(endpoint: string): string {
return generateUrl(`apps/groupfolders/${endpoint}`)
}

async listFolders(offset = 0, limit?: number, orderBy?: string, order?: string): Promise<Folder[]> {
async listFolders(offset = 0, limit?: number, orderBy?: string, order?: string, folderType: FolderType = 'all'): Promise<Folder[]> {
const response = await axios.get<OCSResponse<Folder[]>>(this.getUrl('folders'), {
params: {
offset,
limit,
orderBy,
order,
folderType,
},
})
return Object.values(response.data.ocs.data)
Expand Down Expand Up @@ -153,8 +156,10 @@ export class Api {
}
}

async countFolders(): Promise<number> {
const response = await axios.get<OCSResponse<{ count: number }>>(this.getUrl('folders/count'))
async countFolders(folderType: FolderType = 'all'): Promise<number> {
const response = await axios.get<OCSResponse<{ count: number }>>(this.getUrl('folders/count'), {
params: { folderType },
})
return response.data.ocs.data.count
}

Expand Down
39 changes: 0 additions & 39 deletions src/settings/App.scss
Original file line number Diff line number Diff line change
Expand Up @@ -282,51 +282,12 @@
}
}

.folder-filter-tabs {
display: flex;
gap: var(--default-grid-baseline);
margin: 10px 0;

button {
padding: 6px 14px;
border: 1px solid var(--color-border);
border-radius: var(--border-radius-large);
background: var(--color-main-background);
color: var(--color-text-lighter);
cursor: pointer;
font-size: 0.9em;

&:hover {
color: var(--color-main-text);
border-color: var(--color-border-dark);
}

&.active {
color: var(--color-primary-element-text);
background: var(--color-primary-element);
border-color: var(--color-primary-element);
}
}
}

.folder-list-empty td {
padding: 32px 16px;
color: var(--color-text-maxcontrast);
text-align: center;
}

.team-space-badge {
display: inline-block;
margin-right: 6px;
padding: 1px 6px;
border-radius: var(--border-radius);
background: var(--color-background-dark);
color: var(--color-text-maxcontrast);
font-size: 0.75em;
font-weight: 600;
vertical-align: middle;
}

.team-space-locked {
color: var(--color-text-maxcontrast);
cursor: default;
Expand Down
Loading
Loading