groupware: add identities of all accounts to the index resource

This commit is contained in:
Pascal Bleser
2025-08-07 23:28:12 +02:00
parent e2e8bcd4c1
commit 2e4bc60f87
5 changed files with 143 additions and 15 deletions

View File

@@ -2,8 +2,10 @@ package jmap
import (
"context"
"strconv"
"github.com/opencloud-eu/opencloud/pkg/log"
"github.com/rs/zerolog"
)
// https://jmap.io/spec-mail.html#identityget
@@ -20,3 +22,49 @@ func (j *Client) GetIdentity(accountId string, session *Session, ctx context.Con
return response, simpleError(err, JmapErrorInvalidJmapResponsePayload)
})
}
type IdentitiesGetResponse struct {
State string `json:"state"`
Identities map[string][]Identity `json:"identities,omitempty"`
NotFound []string `json:"notFound,omitempty"`
}
func (j *Client) GetIdentities(accountIds []string, session *Session, ctx context.Context, logger *log.Logger) (IdentitiesGetResponse, Error) {
uniqueAccountIds := uniq(accountIds)
logger = j.loggerParams("", "GetIdentities", session, logger, func(l zerolog.Context) zerolog.Context {
return l.Array(logAccountId, logstrarray(uniqueAccountIds))
})
calls := make([]Invocation, len(uniqueAccountIds))
for i, accountId := range uniqueAccountIds {
calls[i] = invocation(IdentityGet, IdentityGetCommand{AccountId: accountId}, strconv.Itoa(i))
}
cmd, err := request(calls...)
if err != nil {
return IdentitiesGetResponse{}, SimpleError{code: JmapErrorInvalidJmapRequestPayload, err: err}
}
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, func(body *Response) (IdentitiesGetResponse, Error) {
identities := make(map[string][]Identity, len(uniqueAccountIds))
lastState := ""
notFound := []string{}
for i, accountId := range uniqueAccountIds {
var response IdentityGetResponse
err = retrieveResponseMatchParameters(body, IdentityGet, strconv.Itoa(i), &response)
if err != nil {
return IdentitiesGetResponse{}, simpleError(err, JmapErrorInvalidJmapResponsePayload)
} else {
identities[accountId] = response.List
}
lastState = response.State
notFound = append(notFound, response.NotFound...)
}
return IdentitiesGetResponse{
Identities: identities,
State: lastState,
NotFound: uniq(notFound),
}, nil
})
}

View File

@@ -1568,7 +1568,7 @@ type IdentityGetResponse struct {
AccountId string `json:"accountId"`
State string `json:"state"`
List []Identity `json:"list,omitempty"`
NotFound []any `json:"notFound,omitempty"`
NotFound []string `json:"notFound,omitempty"`
}
type VacationResponseGetCommand struct {

View File

@@ -10,6 +10,7 @@ import (
"github.com/mitchellh/mapstructure"
"github.com/opencloud-eu/opencloud/pkg/log"
"github.com/rs/zerolog"
)
type eventListeners[T any] struct {
@@ -222,3 +223,47 @@ func (i *Invocation) UnmarshalJSON(bs []byte) error {
i.Parameters = params
return nil
}
const logMaxStrLength = 1024
// Safely caps a string to a given size to avoid log bombing.
// Use this function to wrap strings that are user input (HTTP headers, path parameters, URI parameters, HTTP body, ...).
func logstr(text string) string {
runes := []rune(text)
if len(runes) <= logMaxStrLength {
return text
} else {
return string(runes[0:logMaxStrLength-1]) + `\u2026` // hellip
}
}
type SafeLogStringArrayMarshaller struct {
array []string
}
func (m SafeLogStringArrayMarshaller) MarshalZerologArray(a *zerolog.Array) {
for _, elem := range m.array {
a.Str(logstr(elem))
}
}
var _ zerolog.LogArrayMarshaler = SafeLogStringArrayMarshaller{}
func logstrarray(array []string) SafeLogStringArrayMarshaller {
return SafeLogStringArrayMarshaller{array: array}
}
func uniq[T comparable](ary []T) []T {
m := map[T]bool{}
for _, v := range ary {
m[v] = true
}
set := make([]T, len(m))
i := 0
for v := range m {
set[i] = v
i++
}
return set
}