feat(server)!: add isOwned filter to albums API (#28213)

* feat(server)!: add owned filter to albums API

BREAKING CHANGE: GET /albums with no parameters now returns all accessible albums (owned + shared-with-me) instead of only owned albums.

* document tri-state matrix

* web impl

* collapse to single method and handover branching to sql

* dedupe

* verify that owned, shared, and notShared counts are mapped independently from their respective queries

* refactor(server): add select:['id'] overload to albumRepository.getAll

Avoid fetching full album rows (with albumUsers/sharedLinks subqueries) in map.service where only album IDs are needed.

* focus relevant test filters

* fmt

* Revert "verify that owned, shared, and notShared counts are mapped independently from their respective queries"

This reverts commit 47aab458192c766de4662aada5a6841b091d2a80.

* sync sql

* Revert "document tri-state matrix"

This reverts commit a5b2355d0c.

* address review comments

* inline shared condition and return as ternary

* sync sql

* use [...albums].sort

Array.toSorted() is not supported in Chrome 109

* use isShared and isOwned nomenclature

* fix e2e tests

* add params to sql query
This commit is contained in:
Timon
2026-05-07 18:13:07 +02:00
committed by GitHub
parent 7de73dc176
commit 1fcc2b704b
16 changed files with 284 additions and 327 deletions
+12 -3
View File
@@ -1641,7 +1641,7 @@
"name": "assetId",
"required": false,
"in": "query",
"description": "Filter albums containing this asset ID (ignores shared parameter)",
"description": "Filter albums containing this asset ID (ignores other parameters)",
"schema": {
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
@@ -1649,10 +1649,19 @@
}
},
{
"name": "shared",
"name": "isOwned",
"required": false,
"in": "query",
"description": "Filter by shared status: true = only shared, false = not shared, undefined = all owned albums",
"description": "Filter by ownership: true = only owned, false = only shared-with-me, undefined = no filter",
"schema": {
"type": "boolean"
}
},
{
"name": "isShared",
"required": false,
"in": "query",
"description": "Filter by shared status: true = only shared, false = not shared, undefined = no filter",
"schema": {
"type": "boolean"
}
+5 -3
View File
@@ -3657,16 +3657,18 @@ export function getUserStatisticsAdmin({ id, isFavorite, isTrashed, visibility }
/**
* List all albums
*/
export function getAllAlbums({ assetId, shared }: {
export function getAllAlbums({ assetId, isOwned, isShared }: {
assetId?: string;
shared?: boolean;
isOwned?: boolean;
isShared?: boolean;
}, opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchJson<{
status: 200;
data: AlbumResponseDto[];
}>(`/albums${QS.query(QS.explode({
assetId,
shared
isOwned,
isShared
}))}`, {
...opts
}));