From 776891a3ea1d5cecc73ac72865f327e0507452bb Mon Sep 17 00:00:00 2001
From: Pascal Bleser
Date: Tue, 7 Oct 2025 09:29:30 +0200
Subject: [PATCH] groupware: add bootstrapping on / with quotas for all
accounts
---
pkg/jmap/jmap_api_bootstrap.go | 70 +++++++++++++++++++
.../pkg/groupware/groupware_api_account.go | 38 ----------
.../pkg/groupware/groupware_api_index.go | 14 ++--
.../pkg/groupware/groupware_route.go | 1 -
4 files changed, 79 insertions(+), 44 deletions(-)
create mode 100644 pkg/jmap/jmap_api_bootstrap.go
diff --git a/pkg/jmap/jmap_api_bootstrap.go b/pkg/jmap/jmap_api_bootstrap.go
new file mode 100644
index 0000000000..405506ac86
--- /dev/null
+++ b/pkg/jmap/jmap_api_bootstrap.go
@@ -0,0 +1,70 @@
+package jmap
+
+import (
+ "context"
+
+ "github.com/opencloud-eu/opencloud/pkg/log"
+ "github.com/opencloud-eu/opencloud/pkg/structs"
+)
+
+type AccountBootstrapResult struct {
+ Identities []Identity `json:"identities,omitempty"`
+ Quotas []Quota `json:"quotas,omitempty"`
+}
+
+func (j *Client) GetBootstrap(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (map[string]AccountBootstrapResult, SessionState, Language, Error) {
+ uniqueAccountIds := structs.Uniq(accountIds)
+
+ logger = j.logger("GetIdentities", session, logger)
+
+ calls := make([]Invocation, len(uniqueAccountIds)*2)
+ for i, accountId := range uniqueAccountIds {
+ calls[i*2+0] = invocation(CommandIdentityGet, IdentityGetCommand{AccountId: accountId}, mcid(accountId, "I"))
+ calls[i*2+1] = invocation(CommandQuotaGet, QuotaGetCommand{AccountId: accountId}, mcid(accountId, "Q"))
+ }
+
+ cmd, err := j.request(session, logger, calls...)
+ if err != nil {
+ return nil, "", "", err
+ }
+ return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (map[string]AccountBootstrapResult, Error) {
+ identityPerAccount := map[string][]Identity{}
+ quotaPerAccount := map[string][]Quota{}
+ for _, accountId := range uniqueAccountIds {
+ var identityResponse IdentityGetResponse
+ err = retrieveResponseMatchParameters(logger, body, CommandIdentityGet, mcid(accountId, "I"), &identityResponse)
+ if err != nil {
+ return nil, err
+ } else {
+ identityPerAccount[accountId] = identityResponse.List
+ }
+
+ var quotaResponse QuotaGetResponse
+ err = retrieveResponseMatchParameters(logger, body, CommandQuotaGet, mcid(accountId, "Q"), "aResponse)
+ if err != nil {
+ return nil, err
+ } else {
+ quotaPerAccount[accountId] = quotaResponse.List
+ }
+ }
+
+ result := map[string]AccountBootstrapResult{}
+ for accountId, value := range identityPerAccount {
+ r, ok := result[accountId]
+ if !ok {
+ r = AccountBootstrapResult{}
+ }
+ r.Identities = value
+ result[accountId] = r
+ }
+ for accountId, value := range quotaPerAccount {
+ r, ok := result[accountId]
+ if !ok {
+ r = AccountBootstrapResult{}
+ }
+ r.Quotas = value
+ result[accountId] = r
+ }
+ return result, nil
+ })
+}
diff --git a/services/groupware/pkg/groupware/groupware_api_account.go b/services/groupware/pkg/groupware/groupware_api_account.go
index 613c4a3890..1909f2fde2 100644
--- a/services/groupware/pkg/groupware/groupware_api_account.go
+++ b/services/groupware/pkg/groupware/groupware_api_account.go
@@ -4,8 +4,6 @@ import (
"net/http"
"github.com/opencloud-eu/opencloud/pkg/jmap"
- "github.com/opencloud-eu/opencloud/pkg/log"
- "github.com/opencloud-eu/opencloud/pkg/structs"
)
// When the request succeeds.
@@ -88,39 +86,3 @@ type SwaggerAccountBootstrapResponse struct {
*AccountBootstrapResponse
}
}
-
-// swagger:route GET /groupware/accounts/{account}/bootstrap account accountbootstrap
-// Get account bootstrapping.
-//
-// responses:
-//
-// 200: GetAccountBootstrapResponse200
-// 400: ErrorResponse400
-// 404: ErrorResponse404
-// 500: ErrorResponse500
-func (g *Groupware) GetAccountBootstrap(w http.ResponseWriter, r *http.Request) {
- g.respond(w, r, func(req Request) Response {
- mailAccountId, err := req.GetAccountIdForMail()
- if err != nil {
- return errorResponse(err)
- }
- logger := log.From(req.logger.With().Str(logAccountId, mailAccountId))
- accountIds := structs.Keys(req.session.Accounts)
-
- resp, sessionState, lang, jerr := g.jmap.GetIdentitiesAndMailboxes(mailAccountId, accountIds, req.session, req.ctx, logger, req.language())
- if jerr != nil {
- return req.errorResponseFromJmap(jerr)
- }
-
- return response(AccountBootstrapResponse{
- Version: Version,
- Capabilities: Capabilities,
- Limits: buildIndexLimits(req.session),
- Accounts: buildIndexAccount(req.session, resp.Identities),
- PrimaryAccounts: buildIndexPrimaryAccounts(req.session),
- Mailboxes: map[string][]jmap.Mailbox{
- mailAccountId: resp.Mailboxes,
- },
- }, sessionState, lang)
- })
-}
diff --git a/services/groupware/pkg/groupware/groupware_api_index.go b/services/groupware/pkg/groupware/groupware_api_index.go
index b5594e5f14..fbe6a2c7f0 100644
--- a/services/groupware/pkg/groupware/groupware_api_index.go
+++ b/services/groupware/pkg/groupware/groupware_api_index.go
@@ -104,6 +104,9 @@ type IndexAccount struct {
// The identities associated with this account.
Identities []jmap.Identity `json:"identities,omitempty"`
+
+ // The quotas for this account.
+ Quotas []jmap.Quota `json:"quotas,omitempty"`
}
type IndexPrimaryAccounts struct {
@@ -152,7 +155,7 @@ func (g *Groupware) Index(w http.ResponseWriter, r *http.Request) {
g.respond(w, r, func(req Request) Response {
accountIds := structs.Keys(req.session.Accounts)
- identitiesResponse, sessionState, lang, err := g.jmap.GetIdentities(accountIds, req.session, req.ctx, req.logger, req.language())
+ boot, sessionState, lang, err := g.jmap.GetBootstrap(accountIds, req.session, req.ctx, req.logger, req.language())
if err != nil {
return req.errorResponseFromJmap(err)
}
@@ -161,7 +164,7 @@ func (g *Groupware) Index(w http.ResponseWriter, r *http.Request) {
Version: Version,
Capabilities: Capabilities,
Limits: buildIndexLimits(req.session),
- Accounts: buildIndexAccount(req.session, identitiesResponse.Identities),
+ Accounts: buildIndexAccount(req.session, boot),
PrimaryAccounts: buildIndexPrimaryAccounts(req.session),
}, sessionState, lang)
})
@@ -186,7 +189,7 @@ func buildIndexPrimaryAccounts(session *jmap.Session) IndexPrimaryAccounts {
}
}
-func buildIndexAccount(session *jmap.Session, identities map[string][]jmap.Identity) map[string]IndexAccount {
+func buildIndexAccount(session *jmap.Session, boot map[string]jmap.AccountBootstrapResult) map[string]IndexAccount {
accounts := make(map[string]IndexAccount, len(session.Accounts))
for accountId, account := range session.Accounts {
indexAccount := IndexAccount{
@@ -210,8 +213,9 @@ func buildIndexAccount(session *jmap.Session, identities map[string][]jmap.Ident
},
},
}
- if identity, ok := identities[accountId]; ok {
- indexAccount.Identities = identity
+ if b, ok := boot[accountId]; ok {
+ indexAccount.Identities = b.Identities
+ indexAccount.Quotas = b.Quotas
}
accounts[accountId] = indexAccount
}
diff --git a/services/groupware/pkg/groupware/groupware_route.go b/services/groupware/pkg/groupware/groupware_route.go
index d2b3586ae0..878fd4dddf 100644
--- a/services/groupware/pkg/groupware/groupware_route.go
+++ b/services/groupware/pkg/groupware/groupware_route.go
@@ -69,7 +69,6 @@ func (g *Groupware) Route(r chi.Router) {
})
r.Route("/accounts/{accountid}", func(r chi.Router) {
r.Get("/", g.GetAccount)
- r.Get("/bootstrap", g.GetAccountBootstrap)
r.Get("/identities", g.GetIdentities)
r.Get("/vacation", g.GetVacation)
r.Put("/vacation", g.SetVacation)