groupware: add strongly typed aliases for AccountId, PrincipalId and SupplierId

Purpose is to make APIs and parameters easier to understand, since plain
strings are used all over the place for all sorts of identifiers.
This commit is contained in:
Pascal Bleser
2026-06-03 15:51:00 +02:00
parent 52d905f62d
commit 7e8caab979
52 changed files with 715 additions and 692 deletions

View File

@@ -2,9 +2,9 @@ package jmap
var NS_ADDRESSBOOKS = ns(JmapContacts)
func (j *Client) GetAddressbooks(accountId string, ids []string, ctx Context) (Result[AddressBookGetResponse], error) {
func (j *Client) GetAddressbooks(accountId AccountId, ids []string, ctx Context) (Result[AddressBookGetResponse], error) {
return get(j, "GetAddressbooks", MailboxType,
func(accountId string, ids []string) AddressBookGetCommand {
func(accountId AccountId, ids []string) AddressBookGetCommand {
return AddressBookGetCommand{AccountId: accountId, Ids: ids}
},
AddressBookGetResponse{},
@@ -27,7 +27,7 @@ func (c AddressBookChanges) GetDestroyed() []string { return c.Destroyed }
// Retrieve Address Book changes since a given state.
// @apidoc addressbook,changes
func (j *Client) GetAddressbookChanges(accountId string, sinceState State, maxChanges uint, ctx Context) (Result[AddressBookChanges], error) {
func (j *Client) GetAddressbookChanges(accountId AccountId, sinceState State, maxChanges uint, ctx Context) (Result[AddressBookChanges], error) {
return changesA(j, "GetAddressbookChanges", MailboxType,
func() AddressBookChangesCommand {
return AddressBookChangesCommand{AccountId: accountId, SinceState: sinceState, MaxChanges: uintPtr(maxChanges)}
@@ -58,12 +58,12 @@ func (j *Client) GetAddressbookChanges(accountId string, sinceState State, maxCh
)
}
func (j *Client) CreateAddressBook(accountId string, addressbook AddressBookChange, ctx Context) (Result[*AddressBook], error) {
func (j *Client) CreateAddressBook(accountId AccountId, addressbook AddressBookChange, ctx Context) (Result[*AddressBook], error) {
return create(j, "CreateAddressBook", MailboxType,
func(accountId string, create map[string]AddressBookChange) AddressBookSetCommand {
func(accountId AccountId, create map[string]AddressBookChange) AddressBookSetCommand {
return AddressBookSetCommand{AccountId: accountId, Create: create}
},
func(accountId string, ids string) AddressBookGetCommand {
func(accountId AccountId, ids string) AddressBookGetCommand {
return AddressBookGetCommand{AccountId: accountId, Ids: []string{ids}}
},
func(resp AddressBookSetResponse) map[string]*AddressBook {
@@ -77,9 +77,9 @@ func (j *Client) CreateAddressBook(accountId string, addressbook AddressBookChan
)
}
func (j *Client) DeleteAddressBook(accountId string, destroyIds []string, ctx Context) (Result[map[string]SetError], error) {
func (j *Client) DeleteAddressBook(accountId AccountId, destroyIds []string, ctx Context) (Result[map[string]SetError], error) {
return destroy(j, "DeleteAddressBook", MailboxType,
func(accountId string, destroy []string) AddressBookSetCommand {
func(accountId AccountId, destroy []string) AddressBookSetCommand {
return AddressBookSetCommand{AccountId: accountId, Destroy: destroy}
},
AddressBookSetResponse{},
@@ -88,7 +88,7 @@ func (j *Client) DeleteAddressBook(accountId string, destroyIds []string, ctx Co
)
}
func (j *Client) UpdateAddressBook(accountId string, id string, changes AddressBookChange, ctx Context) (Result[AddressBook], error) {
func (j *Client) UpdateAddressBook(accountId AccountId, id string, changes AddressBookChange, ctx Context) (Result[AddressBook], error) {
return update(j, "UpdateAddressBook", MailboxType,
func(update map[string]PatchObject) AddressBookSetCommand {
return AddressBookSetCommand{AccountId: accountId, Update: update}

View File

@@ -10,7 +10,7 @@ import (
var NS_BLOB = ns(JmapBlob)
func (j *Client) GetBlobMetadata(accountId string, ids []string, ctx Context) (Result[BlobGetResponse], error) {
func (j *Client) GetBlobMetadata(accountId AccountId, ids []string, ctx Context) (Result[BlobGetResponse], error) {
get := BlobGetCommand{
AccountId: accountId,
Ids: ids,
@@ -41,20 +41,20 @@ type UploadedBlobWithHash struct {
Sha512 string `json:"sha:512,omitempty"`
}
func (j *Client) UploadBlobStream(accountId string, contentType string, body io.Reader, ctx Context) (UploadedBlob, Language, error) {
func (j *Client) UploadBlobStream(accountId AccountId, contentType string, body io.Reader, ctx Context) (UploadedBlob, Language, error) {
logger := log.From(ctx.Logger.With().Str(logEndpoint, ctx.Session.UploadEndpoint))
ctx = ctx.WithLogger(logger)
// TODO(pbleser-oc) use a library for proper URL template parsing
uploadUrl := strings.ReplaceAll(ctx.Session.UploadUrlTemplate, "{accountId}", accountId)
uploadUrl := strings.ReplaceAll(ctx.Session.UploadUrlTemplate, "{accountId}", string(accountId))
return j.blob.UploadBinary(uploadUrl, ctx.Session.UploadEndpoint, contentType, body, ctx)
}
func (j *Client) DownloadBlobStream(accountId string, blobId string, name string, typ string, ctx Context) (*BlobDownload, Language, error) { //NOSONAR
func (j *Client) DownloadBlobStream(accountId AccountId, blobId string, name string, typ string, ctx Context) (*BlobDownload, Language, error) { //NOSONAR
logger := log.From(ctx.Logger.With().Str(logEndpoint, ctx.Session.DownloadEndpoint))
ctx = ctx.WithLogger(logger)
// TODO(pbleser-oc) use a library for proper URL template parsing
downloadUrl := ctx.Session.DownloadUrlTemplate
downloadUrl = strings.ReplaceAll(downloadUrl, "{accountId}", accountId)
downloadUrl = strings.ReplaceAll(downloadUrl, "{accountId}", string(accountId))
downloadUrl = strings.ReplaceAll(downloadUrl, "{blobId}", blobId)
downloadUrl = strings.ReplaceAll(downloadUrl, "{name}", name)
downloadUrl = strings.ReplaceAll(downloadUrl, "{type}", typ)
@@ -62,7 +62,7 @@ func (j *Client) DownloadBlobStream(accountId string, blobId string, name string
return j.blob.DownloadBinary(downloadUrl, ctx.Session.DownloadEndpoint, ctx)
}
func (j *Client) UploadBlob(accountId string, data []byte, contentType string, ctx Context) (Result[UploadedBlobWithHash], error) {
func (j *Client) UploadBlob(accountId AccountId, data []byte, contentType string, ctx Context) (Result[UploadedBlobWithHash], error) {
encoded := base64.StdEncoding.EncodeToString(data)
upload := BlobUploadCommand{
@@ -131,5 +131,4 @@ func (j *Client) UploadBlob(accountId string, data []byte, contentType string, c
Sha512: get.DigestSha512,
}, getResponse.State, nil
})
}

View File

@@ -11,7 +11,7 @@ type AccountBootstrapResult struct {
var NS_MAIL_QUOTA = ns(JmapMail, JmapQuota)
func (j *Client) GetBootstrap(accountIds []string, ctx Context) (Result[map[string]AccountBootstrapResult], error) { //NOSONAR
func (j *Client) GetBootstrap(accountIds []AccountId, ctx Context) (Result[map[AccountId]AccountBootstrapResult], error) { //NOSONAR
uniqueAccountIds := structs.Uniq(accountIds)
logger := j.logger("GetBootstrap", ctx)
@@ -25,13 +25,13 @@ func (j *Client) GetBootstrap(accountIds []string, ctx Context) (Result[map[stri
cmd, err := j.request(ctx, NS_MAIL_QUOTA, calls...)
if err != nil {
return ZeroResult[map[string]AccountBootstrapResult](), err
return ZeroResult[map[AccountId]AccountBootstrapResult](), err
}
return command(j, ctx, cmd, func(body *Response) (map[string]AccountBootstrapResult, State, Error) {
identityPerAccount := map[string][]Identity{}
quotaPerAccount := map[string][]Quota{}
identityStatesPerAccount := map[string]State{}
quotaStatesPerAccount := map[string]State{}
return command(j, ctx, cmd, func(body *Response) (map[AccountId]AccountBootstrapResult, State, Error) {
identityPerAccount := map[AccountId][]Identity{}
quotaPerAccount := map[AccountId][]Quota{}
identityStatesPerAccount := map[AccountId]State{}
quotaStatesPerAccount := map[AccountId]State{}
for _, accountId := range uniqueAccountIds {
var identityResponse IdentityGetResponse
err = retrieveResponseMatchParameters(ctx, body, CommandIdentityGet, mcid(accountId, "I"), &identityResponse)
@@ -52,7 +52,7 @@ func (j *Client) GetBootstrap(accountIds []string, ctx Context) (Result[map[stri
}
}
result := map[string]AccountBootstrapResult{}
result := map[AccountId]AccountBootstrapResult{}
for accountId, value := range identityPerAccount {
r, ok := result[accountId]
if !ok {

View File

@@ -2,7 +2,7 @@ package jmap
var NS_CALENDARS = ns(JmapCalendars)
func (j *Client) ParseICalendarBlob(accountId string, blobIds []string, ctx Context) (Result[CalendarEventParseResponse], error) {
func (j *Client) ParseICalendarBlob(accountId AccountId, blobIds []string, ctx Context) (Result[CalendarEventParseResponse], error) {
logger := j.logger("ParseICalendarBlob", ctx)
parse := CalendarEventParseCommand{AccountId: accountId, BlobIds: blobIds}
@@ -23,9 +23,9 @@ func (j *Client) ParseICalendarBlob(accountId string, blobIds []string, ctx Cont
})
}
func (j *Client) GetCalendars(accountId string, ids []string, ctx Context) (Result[CalendarGetResponse], error) {
func (j *Client) GetCalendars(accountId AccountId, ids []string, ctx Context) (Result[CalendarGetResponse], error) {
return get(j, "GetCalendars", CalendarType,
func(accountId string, ids []string) CalendarGetCommand {
func(accountId AccountId, ids []string) CalendarGetCommand {
return CalendarGetCommand{AccountId: accountId, Ids: ids}
},
CalendarGetResponse{},
@@ -48,7 +48,7 @@ func (c CalendarChanges) GetDestroyed() []string { return c.Destroyed }
// Retrieve Calendar changes since a given state.
// @apidoc calendar,changes
func (j *Client) GetCalendarChanges(accountId string, sinceState State, maxChanges uint, ctx Context) (Result[CalendarChanges], error) {
func (j *Client) GetCalendarChanges(accountId AccountId, sinceState State, maxChanges uint, ctx Context) (Result[CalendarChanges], error) {
return changes(j, "GetCalendarChanges", CalendarType,
func() CalendarChangesCommand {
return CalendarChangesCommand{AccountId: accountId, SinceState: sinceState, MaxChanges: uintPtr(maxChanges)}
@@ -79,12 +79,12 @@ func (j *Client) GetCalendarChanges(accountId string, sinceState State, maxChang
)
}
func (j *Client) CreateCalendar(accountId string, calendar CalendarChange, ctx Context) (Result[*Calendar], error) {
func (j *Client) CreateCalendar(accountId AccountId, calendar CalendarChange, ctx Context) (Result[*Calendar], error) {
return create(j, "CreateCalendar", CalendarEventType,
func(accountId string, create map[string]CalendarChange) CalendarSetCommand {
func(accountId AccountId, create map[string]CalendarChange) CalendarSetCommand {
return CalendarSetCommand{AccountId: accountId, Create: create}
},
func(accountId string, ref string) CalendarGetCommand {
func(accountId AccountId, ref string) CalendarGetCommand {
return CalendarGetCommand{AccountId: accountId, Ids: []string{ref}}
},
func(resp CalendarSetResponse) map[string]*Calendar {
@@ -98,9 +98,9 @@ func (j *Client) CreateCalendar(accountId string, calendar CalendarChange, ctx C
)
}
func (j *Client) DeleteCalendar(accountId string, destroyIds []string, ctx Context) (Result[map[string]SetError], error) {
func (j *Client) DeleteCalendar(accountId AccountId, destroyIds []string, ctx Context) (Result[map[string]SetError], error) {
return destroy(j, "DeleteCalendar", CalendarEventType,
func(accountId string, destroy []string) CalendarSetCommand {
func(accountId AccountId, destroy []string) CalendarSetCommand {
return CalendarSetCommand{AccountId: accountId, Destroy: destroy}
},
CalendarSetResponse{},
@@ -109,7 +109,7 @@ func (j *Client) DeleteCalendar(accountId string, destroyIds []string, ctx Conte
)
}
func (j *Client) UpdateCalendar(accountId string, id string, changes CalendarChange, ctx Context) (Result[Calendar], error) {
func (j *Client) UpdateCalendar(accountId AccountId, id string, changes CalendarChange, ctx Context) (Result[Calendar], error) {
return update(j, "UpdateCalendar", CalendarEventType,
func(update map[string]PatchObject) CalendarSetCommand {
return CalendarSetCommand{AccountId: accountId, Update: update}

View File

@@ -74,7 +74,7 @@ func (s StateMap) MarshalZerologObject(e *zerolog.Event) {
// Retrieve the changes in any type of objects at once since a given State.
// @api:tags changes
func (j *Client) GetChanges(accountId string, stateMap StateMap, maxChanges uint, ctx Context) (Result[ObjectChanges], error) { //NOSONAR
func (j *Client) GetChanges(accountId AccountId, stateMap StateMap, maxChanges uint, ctx Context) (Result[ObjectChanges], error) { //NOSONAR
logger := log.From(j.logger("GetChanges", ctx).With().Object("state", stateMap).Uint("maxChanges", maxChanges))
ctx = ctx.WithLogger(logger)

View File

@@ -6,9 +6,9 @@ var NS_CONTACTS = ns(JmapContacts)
var DEFAULT_CONTACT_CARD_VERSION = jscontact.JSContactVersion_1_0
func (j *Client) GetContactCards(accountId string, contactIds []string, ctx Context) (Result[ContactCardGetResponse], error) {
func (j *Client) GetContactCards(accountId AccountId, contactIds []string, ctx Context) (Result[ContactCardGetResponse], error) {
return get(j, "GetContactCards", ContactCardType,
func(accountId string, ids []string) ContactCardGetCommand {
func(accountId AccountId, ids []string) ContactCardGetCommand {
return ContactCardGetCommand{AccountId: accountId, Ids: contactIds}
},
ContactCardGetResponse{},
@@ -31,7 +31,7 @@ func (c ContactCardChanges) GetDestroyed() []string { return c.Destroyed }
// Retrieve the changes in Contact Cards since a given State.
// @api:tags contact,changes
func (j *Client) GetContactCardChanges(accountId string, sinceState State, maxChanges uint, ctx Context) (Result[ContactCardChanges], error) {
func (j *Client) GetContactCardChanges(accountId AccountId, sinceState State, maxChanges uint, ctx Context) (Result[ContactCardChanges], error) {
return changes(j, "GetContactCardChanges", ContactCardType,
func() ContactCardChangesCommand {
return ContactCardChangesCommand{AccountId: accountId, SinceState: sinceState, MaxChanges: uintPtr(maxChanges)}
@@ -77,19 +77,19 @@ func (r *ContactCardSearchResults) RemoveResults() { r.Results = nil
func (r *ContactCardSearchResults) SetLimit(limit *uint) { r.Limit = limit }
func (r *ContactCardSearchResults) SetPosition(position *uint) { r.Position = position }
func (j *Client) QueryContactCards(accountIds map[string]QueryParams, //NOSONAR
func (j *Client) QueryContactCards(accountIds map[AccountId]QueryParams, //NOSONAR
limit *uint, filter ContactCardFilterElement, sortBy []ContactCardComparator, calculateTotal bool,
ctx Context) (Result[map[string]*ContactCardSearchResults], error) {
ctx Context) (Result[map[AccountId]*ContactCardSearchResults], error) {
return queryN(j, "QueryContactCards", ContactCardType,
[]ContactCardComparator{{Property: ContactCardPropertyUpdated, IsAscending: false}},
func(accountId string, qp QueryParams, limit *uint, filter ContactCardFilterElement, sortBy []ContactCardComparator) ContactCardQueryCommand {
func(accountId AccountId, qp QueryParams, limit *uint, filter ContactCardFilterElement, sortBy []ContactCardComparator) ContactCardQueryCommand {
if qp.Anchor != "" {
return ContactCardQueryCommand{AccountId: accountId, Filter: filter, Sort: sortBy, Anchor: qp.Anchor, AnchorOffset: qp.AnchorOffset, Limit: limit, CalculateTotal: calculateTotal}
} else {
return ContactCardQueryCommand{AccountId: accountId, Filter: filter, Sort: sortBy, Position: qp.Position, Limit: limit, CalculateTotal: calculateTotal}
}
},
func(accountId string, cmd Command, path string, rof string) ContactCardGetRefCommand {
func(accountId AccountId, cmd Command, path string, rof string) ContactCardGetRefCommand {
return ContactCardGetRefCommand{AccountId: accountId, IdsRef: &ResultReference{Name: cmd, Path: path, ResultOf: rof}}
},
func(query ContactCardQueryResponse, queryParams QueryParams, limit *uint) *ContactCardSearchResults {
@@ -116,15 +116,15 @@ func (j *Client) QueryContactCards(accountIds map[string]QueryParams, //NOSONAR
}
// @api:example create
func (j *Client) CreateContactCard(accountId string, contact ContactCardChange, ctx Context) (Result[*ContactCard], error) {
func (j *Client) CreateContactCard(accountId AccountId, contact ContactCardChange, ctx Context) (Result[*ContactCard], error) {
if contact.Version == nil {
contact.Version = &DEFAULT_CONTACT_CARD_VERSION
}
return create(j, "CreateContactCard", ContactCardType,
func(accountId string, create map[string]ContactCardChange) ContactCardSetCommand {
func(accountId AccountId, create map[string]ContactCardChange) ContactCardSetCommand {
return ContactCardSetCommand{AccountId: accountId, Create: create}
},
func(accountId string, ids string) ContactCardGetCommand {
func(accountId AccountId, ids string) ContactCardGetCommand {
return ContactCardGetCommand{AccountId: accountId, Ids: []string{ids}}
},
func(resp ContactCardSetResponse) map[string]*ContactCard {
@@ -138,9 +138,9 @@ func (j *Client) CreateContactCard(accountId string, contact ContactCardChange,
)
}
func (j *Client) DeleteContactCard(accountId string, destroyIds []string, ctx Context) (Result[map[string]SetError], error) {
func (j *Client) DeleteContactCard(accountId AccountId, destroyIds []string, ctx Context) (Result[map[string]SetError], error) {
return destroy(j, "DeleteContactCard", ContactCardType,
func(accountId string, destroy []string) ContactCardSetCommand {
func(accountId AccountId, destroy []string) ContactCardSetCommand {
return ContactCardSetCommand{AccountId: accountId, Destroy: destroy}
},
ContactCardSetResponse{},
@@ -150,7 +150,7 @@ func (j *Client) DeleteContactCard(accountId string, destroyIds []string, ctx Co
}
// @api:example update
func (j *Client) UpdateContactCard(accountId string, id string, changes ContactCardChange, ctx Context) (Result[ContactCard], error) {
func (j *Client) UpdateContactCard(accountId AccountId, id string, changes ContactCardChange, ctx Context) (Result[ContactCard], error) {
return update(j, "UpdateContactCard", ContactCardType,
func(update map[string]PatchObject) ContactCardSetCommand {
return ContactCardSetCommand{AccountId: accountId, Update: update}

View File

@@ -14,7 +14,7 @@ var NS_MAIL = ns(JmapMail)
var NS_MAIL_SUBMISSION = ns(JmapMail, JmapSubmission)
// Retrieve specific Emails by their id.
func (j *Client) GetEmails(accountId string, ids []string, //NOSONAR
func (j *Client) GetEmails(accountId AccountId, ids []string, //NOSONAR
fetchBodies bool, maxBodyValueBytes uint, markAsSeen bool, withThreads bool,
ctx Context) (Result[EmailGetResponse], error) {
logger := j.logger("GetEmails", ctx)
@@ -82,7 +82,7 @@ func (j *Client) GetEmails(accountId string, ids []string, //NOSONAR
})
}
func (j *Client) GetEmailBlobId(accountId string, id string, ctx Context) (Result[string], error) {
func (j *Client) GetEmailBlobId(accountId AccountId, id string, ctx Context) (Result[string], error) {
logger := j.logger("GetEmailBlobId", ctx)
ctx = ctx.WithLogger(logger)
@@ -119,7 +119,7 @@ func (r *EmailSearchResults) SetLimit(limit *uint) { r.Limi
func (r *EmailSearchResults) SetPosition(position *uint) { r.Position = position }
// Retrieve all the Emails in a given Mailbox by its id.
func (j *Client) GetAllEmailsInMailbox(accountId string, mailboxId string, //NOSONAR
func (j *Client) GetAllEmailsInMailbox(accountId AccountId, mailboxId string, //NOSONAR
qp QueryParams, limit *uint, collapseThreads bool, fetchBodies bool, maxBodyValueBytes uint, withThreads bool,
ctx Context) (Result[*EmailSearchResults], error) {
logger := j.loggerParams("GetAllEmailsInMailbox", ctx, func(z zerolog.Context) zerolog.Context {
@@ -220,7 +220,7 @@ func (c EmailChanges) GetDestroyed() []string { return c.Destroyed }
// Retrieve the changes in Emails since a given State.
// @api:tags email,changes
func (j *Client) GetEmailChanges(accountId string,
func (j *Client) GetEmailChanges(accountId AccountId,
sinceState State, fetchBodies bool, maxBodyValueBytes uint, maxChanges uint,
ctx Context) (Result[EmailChanges], error) { //NOSONAR
logger := j.loggerParams("GetEmailChanges", ctx, func(z zerolog.Context) zerolog.Context {
@@ -302,9 +302,9 @@ type SearchSnippetWithMeta struct {
type EmailSnippetSearchResults SearchResultsTemplate[SearchSnippetWithMeta]
func (j *Client) QueryEmailSnippets(accountIds []string, //NOSONAR
func (j *Client) QueryEmailSnippets(accountIds []AccountId, //NOSONAR
filter EmailFilterElement, position int, anchor string, anchorOffset *int, limit *uint,
ctx Context) (Result[map[string]EmailSnippetSearchResults], error) {
ctx Context) (Result[map[AccountId]EmailSnippetSearchResults], error) {
logger := j.loggerParams("QueryEmailSnippets", ctx, func(z zerolog.Context) zerolog.Context {
l := z.Int(logPosition, position)
if limit != nil {
@@ -358,12 +358,12 @@ func (j *Client) QueryEmailSnippets(accountIds []string, //NOSONAR
cmd, err := j.request(ctx, NS_MAIL, invocations...)
if err != nil {
return ZeroResult[map[string]EmailSnippetSearchResults](), err
return ZeroResult[map[AccountId]EmailSnippetSearchResults](), err
}
return command(j, ctx, cmd, func(body *Response) (map[string]EmailSnippetSearchResults, State, Error) {
results := make(map[string]EmailSnippetSearchResults, len(uniqueAccountIds))
states := make(map[string]State, len(uniqueAccountIds))
return command(j, ctx, cmd, func(body *Response) (map[AccountId]EmailSnippetSearchResults, State, Error) {
results := make(map[AccountId]EmailSnippetSearchResults, len(uniqueAccountIds))
states := make(map[AccountId]State, len(uniqueAccountIds))
for _, accountId := range uniqueAccountIds {
var queryResponse EmailQueryResponse
err = retrieveResponseMatchParameters(ctx, body, CommandEmailQuery, mcid(accountId, "0"), &queryResponse)
@@ -428,9 +428,9 @@ type EmailQueryResult struct {
}
*/
func (j *Client) QueryEmails(accountIds []string,
func (j *Client) QueryEmails(accountIds []AccountId,
filter EmailFilterElement, position int, limit uint, fetchBodies bool, maxBodyValueBytes uint,
ctx Context) (Result[map[string]EmailSearchResults], error) { //NOSONAR
ctx Context) (Result[map[AccountId]EmailSearchResults], error) { //NOSONAR
logger := j.loggerParams("QueryEmails", ctx, func(z zerolog.Context) zerolog.Context {
return z.Bool(logFetchBodies, fetchBodies)
})
@@ -470,12 +470,12 @@ func (j *Client) QueryEmails(accountIds []string,
cmd, err := j.request(ctx, NS_MAIL, invocations...)
if err != nil {
return ZeroResult[map[string]EmailSearchResults](), err
return ZeroResult[map[AccountId]EmailSearchResults](), err
}
return command(j, ctx, cmd, func(body *Response) (map[string]EmailSearchResults, State, Error) {
results := make(map[string]EmailSearchResults, len(uniqueAccountIds))
queryStates := map[string]State{}
return command(j, ctx, cmd, func(body *Response) (map[AccountId]EmailSearchResults, State, Error) {
results := make(map[AccountId]EmailSearchResults, len(uniqueAccountIds))
queryStates := map[AccountId]State{}
for _, accountId := range uniqueAccountIds {
var queryResponse EmailQueryResponse
err = retrieveResponseMatchParameters(ctx, body, CommandEmailQuery, mcid(accountId, "0"), &queryResponse)
@@ -515,9 +515,9 @@ type EmailQueryWithSnippetsResult struct {
QueryState State `json:"queryState"`
}
func (j *Client) QueryEmailsWithSnippets(accountIds []string, //NOSONAR
func (j *Client) QueryEmailsWithSnippets(accountIds []AccountId, //NOSONAR
filter EmailFilterElement, position int, anchor string, anchorOffset *int, limit *uint, collapseThreads bool, calculateTotal bool, fetchBodies bool, maxBodyValueBytes uint,
ctx Context) (Result[map[string]EmailQueryWithSnippetsResult], error) {
ctx Context) (Result[map[AccountId]EmailQueryWithSnippetsResult], error) {
logger := j.loggerParams("QueryEmailsWithSnippets", ctx, func(z zerolog.Context) zerolog.Context {
return z.Bool(logFetchBodies, fetchBodies)
})
@@ -565,11 +565,11 @@ func (j *Client) QueryEmailsWithSnippets(accountIds []string, //NOSONAR
cmd, err := j.request(ctx, NS_MAIL, invocations...)
if err != nil {
return ZeroResult[map[string]EmailQueryWithSnippetsResult](), err
return ZeroResult[map[AccountId]EmailQueryWithSnippetsResult](), err
}
return command(j, ctx, cmd, func(body *Response) (map[string]EmailQueryWithSnippetsResult, State, Error) {
result := make(map[string]EmailQueryWithSnippetsResult, len(uniqueAccountIds))
return command(j, ctx, cmd, func(body *Response) (map[AccountId]EmailQueryWithSnippetsResult, State, Error) {
result := make(map[AccountId]EmailQueryWithSnippetsResult, len(uniqueAccountIds))
for _, accountId := range uniqueAccountIds {
var queryResponse EmailQueryResponse
err = retrieveResponseMatchParameters(ctx, body, CommandEmailQuery, mcid(accountId, "0"), &queryResponse)
@@ -629,7 +629,7 @@ type UploadedEmail struct {
Sha512 string `json:"sha:512"`
}
func (j *Client) ImportEmail(accountId string, data []byte, ctx Context) (Result[UploadedEmail], error) {
func (j *Client) ImportEmail(accountId AccountId, data []byte, ctx Context) (Result[UploadedEmail], error) {
encoded := base64.StdEncoding.EncodeToString(data)
upload := BlobUploadCommand{
@@ -702,7 +702,7 @@ func (j *Client) ImportEmail(accountId string, data []byte, ctx Context) (Result
}
func (j *Client) CreateEmail(accountId string, email EmailChange, replaceId string, ctx Context) (Result[*Email], error) {
func (j *Client) CreateEmail(accountId AccountId, email EmailChange, replaceId string, ctx Context) (Result[*Email], error) {
set := EmailSetCommand{
AccountId: accountId,
Create: map[string]EmailChange{
@@ -757,7 +757,7 @@ func (j *Client) CreateEmail(accountId string, email EmailChange, replaceId stri
// To create drafts, use the CreateEmail function instead.
//
// To delete mails, use the DeleteEmails function instead.
func (j *Client) UpdateEmails(accountId string, updates map[string]PatchObject, ctx Context) (Result[map[string]*Email], error) {
func (j *Client) UpdateEmails(accountId AccountId, updates map[string]PatchObject, ctx Context) (Result[map[string]*Email], error) {
set := EmailSetCommand{
AccountId: accountId,
Update: updates,
@@ -783,7 +783,7 @@ func (j *Client) UpdateEmails(accountId string, updates map[string]PatchObject,
})
}
func (j *Client) UpdateEmail(accountId string, id string, changes EmailChange, ctx Context) (Result[Email], error) {
func (j *Client) UpdateEmail(accountId AccountId, id string, changes EmailChange, ctx Context) (Result[Email], error) {
return update(j, "UpdateEmail", EmailType,
func(update map[string]PatchObject) EmailSetCommand {
return EmailSetCommand{AccountId: accountId, Update: update}
@@ -798,9 +798,9 @@ func (j *Client) UpdateEmail(accountId string, id string, changes EmailChange, c
)
}
func (j *Client) DeleteEmails(accountId string, destroyIds []string, ctx Context) (Result[map[string]SetError], error) {
func (j *Client) DeleteEmails(accountId AccountId, destroyIds []string, ctx Context) (Result[map[string]SetError], error) {
return destroy(j, "DeleteEmails", EmailType,
func(accountId string, destroy []string) EmailSetCommand {
func(accountId AccountId, destroy []string) EmailSetCommand {
return EmailSetCommand{AccountId: accountId, Destroy: destroy}
},
EmailSetResponse{},
@@ -838,7 +838,7 @@ type MoveMail struct {
ToMailboxId string
}
func (j *Client) SubmitEmail(accountId string, identityId string, emailId string, move *MoveMail, //NOSONAR
func (j *Client) SubmitEmail(accountId AccountId, identityId string, emailId string, move *MoveMail, //NOSONAR
ctx Context) (Result[EmailSubmission], error) {
logger := j.logger("SubmitEmail", ctx)
ctx = ctx.WithLogger(logger)
@@ -926,7 +926,7 @@ func (j *Client) SubmitEmail(accountId string, identityId string, emailId string
})
}
func (j *Client) GetEmailSubmissionStatus(accountId string, submissionIds []string, ctx Context) (Result[EmailSubmissionGetResponse], error) {
func (j *Client) GetEmailSubmissionStatus(accountId AccountId, submissionIds []string, ctx Context) (Result[EmailSubmissionGetResponse], error) {
logger := j.logger("GetEmailSubmissionStatus", ctx)
ctx = ctx.WithLogger(logger)
@@ -949,7 +949,7 @@ func (j *Client) GetEmailSubmissionStatus(accountId string, submissionIds []stri
})
}
func (j *Client) EmailsInThread(accountId string, threadId string,
func (j *Client) EmailsInThread(accountId AccountId, threadId string,
fetchBodies bool, maxBodyValueBytes uint,
ctx Context) (Result[[]Email], Error) { //NOSONAR
logger := j.loggerParams("EmailsInThread", ctx, func(z zerolog.Context) zerolog.Context {
@@ -1018,9 +1018,9 @@ var EmailSummaryProperties = []string{
EmailPropertyPreview,
}
func (j *Client) QueryEmailSummaries(accountIds []string, //NOSONAR
func (j *Client) QueryEmailSummaries(accountIds []AccountId, //NOSONAR
filter EmailFilterElement, position int, anchor string, anchorOffset *int, limit *uint, withThreads bool, calculateTotal bool,
ctx Context) (Result[map[string]EmailsSummary], error) {
ctx Context) (Result[map[AccountId]EmailsSummary], error) {
logger := j.logger("QueryEmailSummaries", ctx)
ctx = ctx.WithLogger(logger)
@@ -1067,11 +1067,11 @@ func (j *Client) QueryEmailSummaries(accountIds []string, //NOSONAR
}
cmd, err := j.request(ctx, NS_MAIL, invocations...)
if err != nil {
return ZeroResult[map[string]EmailsSummary](), err
return ZeroResult[map[AccountId]EmailsSummary](), err
}
return command(j, ctx, cmd, func(body *Response) (map[string]EmailsSummary, State, Error) {
resp := map[string]EmailsSummary{}
return command(j, ctx, cmd, func(body *Response) (map[AccountId]EmailsSummary, State, Error) {
resp := map[AccountId]EmailsSummary{}
for _, accountId := range uniqueAccountIds {
var queryResponse EmailQueryResponse
err = retrieveResponseMatchParameters(ctx, body, CommandEmailQuery, mcid(accountId, "0"), &queryResponse)
@@ -1112,7 +1112,7 @@ type EmailSubmissionChanges = ChangesTemplate[EmailSubmission]
// Retrieve the changes in Email Submissions since a given State.
// @api:tags email,changes
func (j *Client) GetEmailSubmissionChanges(accountId string, sinceState State, maxChanges uint,
func (j *Client) GetEmailSubmissionChanges(accountId AccountId, sinceState State, maxChanges uint,
ctx Context) (Result[EmailSubmissionChanges], error) {
return changes(j, "GetEmailSubmissionChanges", EmailSubmissionType,
func() EmailSubmissionChangesCommand {

View File

@@ -17,9 +17,9 @@ func (r *CalendarEventSearchResults) RemoveResults() { r.Results = n
func (r *CalendarEventSearchResults) SetLimit(limit *uint) { r.Limit = limit }
func (r *CalendarEventSearchResults) SetPosition(position *uint) { r.Position = position }
func (j *Client) GetCalendarEvents(accountId string, eventIds []string, ctx Context) (Result[CalendarEventGetResponse], error) {
func (j *Client) GetCalendarEvents(accountId AccountId, eventIds []string, ctx Context) (Result[CalendarEventGetResponse], error) {
return get(j, "GetCalendarEvents", CalendarEventType,
func(accountId string, ids []string) CalendarEventGetCommand {
func(accountId AccountId, ids []string) CalendarEventGetCommand {
return CalendarEventGetCommand{AccountId: accountId, Ids: eventIds}
},
CalendarEventGetResponse{},
@@ -29,15 +29,15 @@ func (j *Client) GetCalendarEvents(accountId string, eventIds []string, ctx Cont
)
}
func (j *Client) QueryCalendarEvents(accountIds map[string]QueryParams, limit *uint, //NOSONAR
func (j *Client) QueryCalendarEvents(accountIds map[AccountId]QueryParams, limit *uint, //NOSONAR
filter CalendarEventFilterElement, sortBy []CalendarEventComparator, calculateTotal bool,
ctx Context) (Result[map[string]*CalendarEventSearchResults], error) {
ctx Context) (Result[map[AccountId]*CalendarEventSearchResults], error) {
return queryN(j, "QueryCalendarEvents", CalendarEventType,
[]CalendarEventComparator{{Property: CalendarEventPropertyStart, IsAscending: false}},
func(accountId string, queryParams QueryParams, limit *uint, filter CalendarEventFilterElement, sortBy []CalendarEventComparator) CalendarEventQueryCommand {
func(accountId AccountId, queryParams QueryParams, limit *uint, filter CalendarEventFilterElement, sortBy []CalendarEventComparator) CalendarEventQueryCommand {
return CalendarEventQueryCommand{AccountId: accountId, Filter: filter, Sort: sortBy, Position: queryParams.Position, Anchor: queryParams.Anchor, AnchorOffset: queryParams.AnchorOffset, Limit: limit, CalculateTotal: calculateTotal}
},
func(accountId string, cmd Command, path string, rof string) CalendarEventGetRefCommand {
func(accountId AccountId, cmd Command, path string, rof string) CalendarEventGetRefCommand {
return CalendarEventGetRefCommand{AccountId: accountId, IdsRef: &ResultReference{Name: cmd, Path: path, ResultOf: rof}}
},
func(query CalendarEventQueryResponse, queryParams QueryParams, limit *uint) *CalendarEventSearchResults {
@@ -76,7 +76,7 @@ func (c CalendarEventChanges) GetDestroyed() []string { return c.Destroyed
// Retrieve the changes in Calendar Events since a given State.
// @api:tags event,changes
func (j *Client) GetCalendarEventChanges(accountId string, sinceState State, maxChanges uint,
func (j *Client) GetCalendarEventChanges(accountId AccountId, sinceState State, maxChanges uint,
ctx Context) (Result[CalendarEventChanges], error) {
return changes(j, "GetCalendarEventChanges", CalendarEventType,
func() CalendarEventChangesCommand {
@@ -108,12 +108,12 @@ func (j *Client) GetCalendarEventChanges(accountId string, sinceState State, max
)
}
func (j *Client) CreateCalendarEvent(accountId string, event CalendarEventChange, ctx Context) (Result[*CalendarEvent], error) {
func (j *Client) CreateCalendarEvent(accountId AccountId, event CalendarEventChange, ctx Context) (Result[*CalendarEvent], error) {
return create(j, "CreateCalendarEvent", CalendarEventType,
func(accountId string, create map[string]CalendarEventChange) CalendarEventSetCommand {
func(accountId AccountId, create map[string]CalendarEventChange) CalendarEventSetCommand {
return CalendarEventSetCommand{AccountId: accountId, Create: create}
},
func(accountId string, ref string) CalendarEventGetCommand {
func(accountId AccountId, ref string) CalendarEventGetCommand {
return CalendarEventGetCommand{AccountId: accountId, Ids: []string{ref}}
},
func(resp CalendarEventSetResponse) map[string]*CalendarEvent {
@@ -127,9 +127,9 @@ func (j *Client) CreateCalendarEvent(accountId string, event CalendarEventChange
)
}
func (j *Client) DeleteCalendarEvent(accountId string, destroyIds []string, ctx Context) (Result[map[string]SetError], error) {
func (j *Client) DeleteCalendarEvent(accountId AccountId, destroyIds []string, ctx Context) (Result[map[string]SetError], error) {
return destroy(j, "DeleteCalendarEvent", CalendarEventType,
func(accountId string, destroy []string) CalendarEventSetCommand {
func(accountId AccountId, destroy []string) CalendarEventSetCommand {
return CalendarEventSetCommand{AccountId: accountId, Destroy: destroy}
},
CalendarEventSetResponse{},
@@ -138,7 +138,7 @@ func (j *Client) DeleteCalendarEvent(accountId string, destroyIds []string, ctx
)
}
func (j *Client) UpdateCalendarEvent(accountId string, id string, changes CalendarEventChange, ctx Context) (Result[CalendarEvent], error) {
func (j *Client) UpdateCalendarEvent(accountId AccountId, id string, changes CalendarEventChange, ctx Context) (Result[CalendarEvent], error) {
return update(j, "UpdateCalendarEvent", CalendarEventType,
func(update map[string]PatchObject) CalendarEventSetCommand {
return CalendarEventSetCommand{AccountId: accountId, Update: update}

View File

@@ -8,9 +8,9 @@ import (
var NS_IDENTITY = ns(JmapMail)
func (j *Client) GetIdentities(accountId string, identityIds []string, ctx Context) (Result[IdentityGetResponse], error) {
func (j *Client) GetIdentities(accountId AccountId, identityIds []string, ctx Context) (Result[IdentityGetResponse], error) {
return get(j, "GetIdentities", IdentityType,
func(accountId string, ids []string) IdentityGetCommand {
func(accountId AccountId, ids []string) IdentityGetCommand {
return IdentityGetCommand{AccountId: accountId, Ids: ids}
},
IdentityGetResponse{},
@@ -20,9 +20,9 @@ func (j *Client) GetIdentities(accountId string, identityIds []string, ctx Conte
)
}
func (j *Client) GetIdentitiesForAllAccounts(accountIds []string, ctx Context) (Result[map[string][]Identity], error) {
func (j *Client) GetIdentitiesForAllAccounts(accountIds []AccountId, ctx Context) (Result[map[AccountId][]Identity], error) {
return getN(j, "GetIdentitiesForAllAccounts", IdentityType,
func(accountId string, ids []string) IdentityGetCommand {
func(accountId AccountId, ids []string) IdentityGetCommand {
return IdentityGetCommand{AccountId: accountId}
},
IdentityGetResponse{},
@@ -34,12 +34,12 @@ func (j *Client) GetIdentitiesForAllAccounts(accountIds []string, ctx Context) (
}
type IdentitiesAndMailboxesGetResponse struct {
Identities map[string][]Identity `json:"identities,omitempty"`
NotFound []string `json:"notFound,omitempty"`
Mailboxes []Mailbox `json:"mailboxes"`
Identities map[AccountId][]Identity `json:"identities,omitempty"`
NotFound []string `json:"notFound,omitempty"`
Mailboxes []Mailbox `json:"mailboxes"`
}
func (j *Client) GetIdentitiesAndMailboxes(mailboxAccountId string, accountIds []string, ctx Context) (Result[IdentitiesAndMailboxesGetResponse], error) {
func (j *Client) GetIdentitiesAndMailboxes(mailboxAccountId AccountId, accountIds []AccountId, ctx Context) (Result[IdentitiesAndMailboxesGetResponse], error) {
uniqueAccountIds := structs.Uniq(accountIds)
logger := j.logger("GetIdentitiesAndMailboxes", ctx)
@@ -56,8 +56,8 @@ func (j *Client) GetIdentitiesAndMailboxes(mailboxAccountId string, accountIds [
return ZeroResult[IdentitiesAndMailboxesGetResponse](), err
}
return command(j, ctx, cmd, func(body *Response) (IdentitiesAndMailboxesGetResponse, State, Error) {
identities := make(map[string][]Identity, len(uniqueAccountIds))
stateByAccountId := make(map[string]State, len(uniqueAccountIds))
identities := make(map[AccountId][]Identity, len(uniqueAccountIds))
stateByAccountId := make(map[AccountId]State, len(uniqueAccountIds))
notFound := []string{}
for i, accountId := range uniqueAccountIds {
var response IdentityGetResponse
@@ -85,12 +85,12 @@ func (j *Client) GetIdentitiesAndMailboxes(mailboxAccountId string, accountIds [
})
}
func (j *Client) CreateIdentity(accountId string, identity IdentityChange, ctx Context) (Result[*Identity], error) {
func (j *Client) CreateIdentity(accountId AccountId, identity IdentityChange, ctx Context) (Result[*Identity], error) {
return create(j, "CreateIdentity", IdentityType,
func(accountId string, create map[string]IdentityChange) IdentitySetCommand {
func(accountId AccountId, create map[string]IdentityChange) IdentitySetCommand {
return IdentitySetCommand{AccountId: accountId, Create: create}
},
func(accountId string, ids string) IdentityGetCommand {
func(accountId AccountId, ids string) IdentityGetCommand {
return IdentityGetCommand{AccountId: accountId, Ids: []string{ids}}
},
func(resp IdentitySetResponse) map[string]*Identity {
@@ -104,7 +104,7 @@ func (j *Client) CreateIdentity(accountId string, identity IdentityChange, ctx C
)
}
func (j *Client) UpdateIdentity(accountId string, id string, changes IdentityChange, ctx Context) (Result[Identity], error) {
func (j *Client) UpdateIdentity(accountId AccountId, id string, changes IdentityChange, ctx Context) (Result[Identity], error) {
return update(j, "UpdateIdentity", IdentityType,
func(update map[string]PatchObject) IdentitySetCommand {
return IdentitySetCommand{AccountId: accountId, Update: update}
@@ -119,9 +119,9 @@ func (j *Client) UpdateIdentity(accountId string, id string, changes IdentityCha
)
}
func (j *Client) DeleteIdentity(accountId string, destroyIds []string, ctx Context) (Result[map[string]SetError], error) {
func (j *Client) DeleteIdentity(accountId AccountId, destroyIds []string, ctx Context) (Result[map[string]SetError], error) {
return destroy(j, "DeleteIdentity", IdentityType,
func(accountId string, destroy []string) IdentitySetCommand {
func(accountId AccountId, destroy []string) IdentitySetCommand {
return IdentitySetCommand{AccountId: accountId, Destroy: destroyIds}
},
IdentitySetResponse{},
@@ -143,7 +143,7 @@ func (c IdentityChanges) GetDestroyed() []string { return c.Destroyed }
// Retrieve the changes in Email Identities since a given State.
// @api:tags email,changes
func (j *Client) GetIdentityChanges(accountId string, sinceState State, maxChanges uint,
func (j *Client) GetIdentityChanges(accountId AccountId, sinceState State, maxChanges uint,
ctx Context) (Result[IdentityChanges], error) {
return changes(j, "GetIdentityChanges", IdentityType,
func() IdentityChangesCommand {

View File

@@ -8,9 +8,9 @@ import (
var NS_MAILBOX = ns(JmapMail)
func (j *Client) GetMailbox(accountId string, ids []string, ctx Context) (Result[MailboxGetResponse], error) {
func (j *Client) GetMailbox(accountId AccountId, ids []string, ctx Context) (Result[MailboxGetResponse], error) {
return get(j, "GetMailbox", MailboxType,
func(accountId string, ids []string) MailboxGetCommand {
func(accountId AccountId, ids []string) MailboxGetCommand {
return MailboxGetCommand{AccountId: accountId, Ids: ids}
},
MailboxGetResponse{},
@@ -20,9 +20,9 @@ func (j *Client) GetMailbox(accountId string, ids []string, ctx Context) (Result
)
}
func (j *Client) GetAllMailboxes(accountIds []string, ctx Context) (Result[map[string][]Mailbox], error) {
func (j *Client) GetAllMailboxes(accountIds []AccountId, ctx Context) (Result[map[AccountId][]Mailbox], error) {
return getAN(j, "GetAllMailboxes", MailboxType,
func(accountId string, ids []string) MailboxGetCommand {
func(accountId AccountId, ids []string) MailboxGetCommand {
return MailboxGetCommand{AccountId: accountId}
},
MailboxGetResponse{},
@@ -32,7 +32,7 @@ func (j *Client) GetAllMailboxes(accountIds []string, ctx Context) (Result[map[s
)
}
func (j *Client) SearchMailboxes(accountIds []string, filter MailboxFilterElement, ctx Context) (Result[map[string][]Mailbox], error) {
func (j *Client) SearchMailboxes(accountIds []AccountId, filter MailboxFilterElement, ctx Context) (Result[map[AccountId][]Mailbox], error) {
logger := j.logger("SearchMailboxes", ctx)
ctx = ctx.WithLogger(logger)
@@ -52,12 +52,12 @@ func (j *Client) SearchMailboxes(accountIds []string, filter MailboxFilterElemen
}
cmd, err := j.request(ctx, NS_MAILBOX, invocations...)
if err != nil {
return ZeroResult[map[string][]Mailbox](), err
return ZeroResult[map[AccountId][]Mailbox](), err
}
return command(j, ctx, cmd, func(body *Response) (map[string][]Mailbox, State, Error) {
resp := map[string][]Mailbox{}
stateByAccountid := map[string]State{}
return command(j, ctx, cmd, func(body *Response) (map[AccountId][]Mailbox, State, Error) {
resp := map[AccountId][]Mailbox{}
stateByAccountid := map[AccountId]State{}
for _, accountId := range uniqueAccountIds {
var response MailboxGetResponse
err = retrieveResponseMatchParameters(ctx, body, CommandMailboxGet, mcid(accountId, "1"), &response)
@@ -72,7 +72,7 @@ func (j *Client) SearchMailboxes(accountIds []string, filter MailboxFilterElemen
})
}
func (j *Client) SearchMailboxIdsPerRole(accountIds []string, roles []string, ctx Context) (Result[map[string]map[string]string], error) { //NOSONAR
func (j *Client) SearchMailboxIdsPerRole(accountIds []AccountId, roles []string, ctx Context) (Result[map[AccountId]map[string]string], error) { //NOSONAR
logger := j.logger("SearchMailboxIdsPerRole", ctx)
ctx = ctx.WithLogger(logger)
@@ -86,12 +86,12 @@ func (j *Client) SearchMailboxIdsPerRole(accountIds []string, roles []string, ct
}
cmd, err := j.request(ctx, NS_MAILBOX, invocations...)
if err != nil {
return ZeroResult[map[string]map[string]string](), err
return ZeroResult[map[AccountId]map[string]string](), err
}
return command(j, ctx, cmd, func(body *Response) (map[string]map[string]string, State, Error) {
resp := map[string]map[string]string{}
stateByAccountid := map[string]State{}
return command(j, ctx, cmd, func(body *Response) (map[AccountId]map[string]string, State, Error) {
resp := map[AccountId]map[string]string{}
stateByAccountid := map[AccountId]State{}
for _, accountId := range uniqueAccountIds {
mailboxIdsByRole := map[string]string{}
for _, role := range roles {
@@ -137,7 +137,7 @@ func newMailboxChanges(oldState, newState State, hasMoreChanges bool, created, u
// Retrieve Mailbox changes since a given state.
// @apidoc mailboxes,changes
func (j *Client) GetMailboxChanges(accountId string, sinceState State, maxChanges uint, ctx Context) (Result[MailboxChanges], error) {
func (j *Client) GetMailboxChanges(accountId AccountId, sinceState State, maxChanges uint, ctx Context) (Result[MailboxChanges], error) {
return changesA(j, "GetMailboxChanges", MailboxType,
func() MailboxChangesCommand {
return MailboxChangesCommand{AccountId: accountId, SinceState: sinceState, MaxChanges: uintPtr(maxChanges)}
@@ -161,16 +161,16 @@ func (j *Client) GetMailboxChanges(accountId string, sinceState State, maxChange
// Retrieve Mailbox changes of multiple Accounts.
// @api:tags email,changes
func (j *Client) GetMailboxChangesForMultipleAccounts(accountIds []string, //NOSONAR
sinceStateMap map[string]State, maxChanges uint,
ctx Context) (Result[map[string]MailboxChanges], error) {
func (j *Client) GetMailboxChangesForMultipleAccounts(accountIds []AccountId, //NOSONAR
sinceStateMap map[AccountId]State, maxChanges uint,
ctx Context) (Result[map[AccountId]MailboxChanges], error) {
return changesN(j, "GetMailboxChangesForMultipleAccounts", MailboxType,
accountIds, sinceStateMap,
func(accountId string, state State) MailboxChangesCommand {
func(accountId AccountId, state State) MailboxChangesCommand {
return MailboxChangesCommand{AccountId: accountId, SinceState: state, MaxChanges: uintPtr(maxChanges)}
},
MailboxChangesResponse{},
func(accountId string, path string, ref string) MailboxGetRefCommand {
func(accountId AccountId, path string, ref string) MailboxGetRefCommand {
return MailboxGetRefCommand{AccountId: accountId, IdsRef: &ResultReference{Name: CommandMailboxChanges, Path: path, ResultOf: ref}}
},
func(resp MailboxGetResponse) []Mailbox { return resp.List },
@@ -181,13 +181,13 @@ func (j *Client) GetMailboxChangesForMultipleAccounts(accountIds []string, //NOS
)
}
func (j *Client) GetMailboxRolesForMultipleAccounts(accountIds []string, ctx Context) (Result[map[string]*[]string], error) {
func (j *Client) GetMailboxRolesForMultipleAccounts(accountIds []AccountId, ctx Context) (Result[map[AccountId]*[]string], error) {
return queryN(j, "GetMailboxRolesForMultipleAccounts", MailboxType,
[]MailboxComparator{{Property: MailboxPropertySortOrder, IsAscending: true}},
func(accountId string, _ QueryParams, _ *uint, filter MailboxFilterCondition, sortBy []MailboxComparator) MailboxQueryCommand {
func(accountId AccountId, _ QueryParams, _ *uint, filter MailboxFilterCondition, sortBy []MailboxComparator) MailboxQueryCommand {
return MailboxQueryCommand{AccountId: accountId, Filter: filter, Sort: sortBy, SortAsTree: false, FilterAsTree: false, Position: 0, Anchor: "", AnchorOffset: nil, Limit: nil, CalculateTotal: false}
},
func(accountId string, cmd Command, path, rof string) MailboxGetRefCommand {
func(accountId AccountId, cmd Command, path, rof string) MailboxGetRefCommand {
return MailboxGetRefCommand{AccountId: accountId, IdsRef: &ResultReference{Name: cmd, Path: path, ResultOf: rof}}
},
func(_ MailboxQueryResponse, _ QueryParams, _ *uint) *[]string {
@@ -203,14 +203,14 @@ func (j *Client) GetMailboxRolesForMultipleAccounts(accountIds []string, ctx Con
)
}
func (j *Client) GetInboxNameForMultipleAccounts(accountIds []string, ctx Context) (Result[map[string]string], error) {
func (j *Client) GetInboxNameForMultipleAccounts(accountIds []AccountId, ctx Context) (Result[map[AccountId]string], error) {
logger := j.logger("GetInboxNameForMultipleAccounts", ctx)
ctx = ctx.WithLogger(logger)
uniqueAccountIds := structs.Uniq(accountIds)
n := len(uniqueAccountIds)
if n < 1 {
return ZeroResult[map[string]string](), nil
return ZeroResult[map[AccountId]string](), nil
}
invocations := make([]Invocation, n*2)
@@ -225,12 +225,12 @@ func (j *Client) GetInboxNameForMultipleAccounts(accountIds []string, ctx Contex
cmd, err := j.request(ctx, NS_MAILBOX, invocations...)
if err != nil {
return ZeroResult[map[string]string](), err
return ZeroResult[map[AccountId]string](), err
}
return command(j, ctx, cmd, func(body *Response) (map[string]string, State, Error) {
resp := make(map[string]string, n)
stateByAccountId := make(map[string]State, n)
return command(j, ctx, cmd, func(body *Response) (map[AccountId]string, State, Error) {
resp := make(map[AccountId]string, n)
stateByAccountId := make(map[AccountId]State, n)
for _, accountId := range uniqueAccountIds {
var r MailboxQueryResponse
err = retrieveResponseMatchParameters(ctx, body, CommandMailboxGet, mcid(accountId, "0"), &r)
@@ -253,7 +253,7 @@ func (j *Client) GetInboxNameForMultipleAccounts(accountIds []string, ctx Contex
})
}
func (j *Client) UpdateMailbox(accountId string, mailboxId string, change MailboxChange, //NOSONAR
func (j *Client) UpdateMailbox(accountId AccountId, mailboxId string, change MailboxChange, //NOSONAR
ctx Context) (Result[Mailbox], error) {
return update(j, "UpdateMailbox", MailboxType,
func(update map[string]PatchObject) MailboxSetCommand {
@@ -269,12 +269,12 @@ func (j *Client) UpdateMailbox(accountId string, mailboxId string, change Mailbo
)
}
func (j *Client) CreateMailbox(accountId string, mailbox MailboxChange, ctx Context) (Result[*Mailbox], error) {
func (j *Client) CreateMailbox(accountId AccountId, mailbox MailboxChange, ctx Context) (Result[*Mailbox], error) {
return create(j, "CreateMailbox", MailboxType,
func(accountId string, create map[string]MailboxChange) MailboxSetCommand {
func(accountId AccountId, create map[string]MailboxChange) MailboxSetCommand {
return MailboxSetCommand{AccountId: accountId, Create: create}
},
func(accountId string, ids string) MailboxGetCommand {
func(accountId AccountId, ids string) MailboxGetCommand {
return MailboxGetCommand{AccountId: accountId, Ids: []string{ids}}
},
func(resp MailboxSetResponse) map[string]*Mailbox {
@@ -288,9 +288,9 @@ func (j *Client) CreateMailbox(accountId string, mailbox MailboxChange, ctx Cont
)
}
func (j *Client) DeleteMailboxes(accountId string, destroyIds []string, ctx Context) (Result[map[string]SetError], error) {
func (j *Client) DeleteMailboxes(accountId AccountId, destroyIds []string, ctx Context) (Result[map[string]SetError], error) {
return destroy(j, "DeleteMailboxes", MailboxType,
func(accountId string, destroy []string) MailboxSetCommand {
func(accountId AccountId, destroy []string) MailboxSetCommand {
return MailboxSetCommand{AccountId: accountId, Destroy: destroyIds}
},
MailboxSetResponse{},

View File

@@ -20,7 +20,7 @@ type Objects struct {
// Retrieve objects of all types by their identifiers in a single batch.
// @api:tags changes
func (j *Client) GetObjects(accountId string, //NOSONAR
func (j *Client) GetObjects(accountId AccountId, //NOSONAR
mailboxIds []string, emailIds []string,
addressbookIds []string, contactIds []string,
calendarIds []string, eventIds []string,

View File

@@ -2,9 +2,9 @@ package jmap
var NS_PRINCIPALS = ns(JmapPrincipals)
func (j *Client) GetPrincipals(accountId string, ids []string, ctx Context) (Result[PrincipalGetResponse], error) {
func (j *Client) GetPrincipals(accountId AccountId, ids []PrincipalId, ctx Context) (Result[PrincipalGetResponse], error) {
return get(j, "GetPrincipals", PrincipalType,
func(accountId string, ids []string) PrincipalGetCommand {
func(accountId AccountId, ids []PrincipalId) PrincipalGetCommand {
return PrincipalGetCommand{AccountId: accountId, Ids: ids}
},
PrincipalGetResponse{},
@@ -29,15 +29,15 @@ func (r *PrincipalSearchResults) RemoveResults() { r.Results = nil }
func (r *PrincipalSearchResults) SetLimit(limit *uint) { r.Limit = limit }
func (r *PrincipalSearchResults) SetPosition(position *uint) { r.Position = position }
func (j *Client) QueryPrincipals(accountIds map[string]QueryParams, limit *uint, //NOSONAR
func (j *Client) QueryPrincipals(accountIds map[AccountId]QueryParams, limit *uint, //NOSONAR
filter PrincipalFilterElement, sortBy []PrincipalComparator, calculateTotal bool,
ctx Context) (Result[map[string]*PrincipalSearchResults], error) {
ctx Context) (Result[map[AccountId]*PrincipalSearchResults], error) {
return queryN(j, "QueryPrincipals", PrincipalType,
[]PrincipalComparator{{Property: PrincipalPropertyName, IsAscending: true}},
func(accountId string, p QueryParams, limit *uint, filter PrincipalFilterElement, sortBy []PrincipalComparator) PrincipalQueryCommand {
func(accountId AccountId, p QueryParams, limit *uint, filter PrincipalFilterElement, sortBy []PrincipalComparator) PrincipalQueryCommand {
return PrincipalQueryCommand{AccountId: accountId, Filter: filter, Sort: sortBy, Position: p.Position, Anchor: p.Anchor, AnchorOffset: p.AnchorOffset, Limit: limit, CalculateTotal: calculateTotal}
},
func(accountId string, cmd Command, path, rof string) PrincipalGetRefCommand {
func(accountId AccountId, cmd Command, path, rof string) PrincipalGetRefCommand {
return PrincipalGetRefCommand{AccountId: accountId, IdsRef: &ResultReference{Name: cmd, Path: path, ResultOf: rof}}
},
func(query PrincipalQueryResponse, queryParams QueryParams, limit *uint) *PrincipalSearchResults {

View File

@@ -2,9 +2,9 @@ package jmap
var NS_QUOTA = ns(JmapQuota)
func (j *Client) GetQuotas(accountIds []string, ctx Context) (Result[map[string]QuotaGetResponse], error) {
func (j *Client) GetQuotas(accountIds []AccountId, ctx Context) (Result[map[AccountId]QuotaGetResponse], error) {
return getN(j, "GetQuotas", QuotaType,
func(accountId string, ids []string) QuotaGetCommand {
func(accountId AccountId, ids []string) QuotaGetCommand {
return QuotaGetCommand{AccountId: accountId}
},
QuotaGetResponse{},
@@ -28,7 +28,7 @@ func (c QuotaChanges) GetDestroyed() []string { return c.Destroyed }
// Retrieve the changes in Quotas since a given State.
// @api:tags quota,changes
func (j *Client) GetQuotaChanges(accountId string, sinceState State, maxChanges uint,
func (j *Client) GetQuotaChanges(accountId AccountId, sinceState State, maxChanges uint,
ctx Context) (Result[QuotaChanges], error) {
return changesA(j, "GetQuotaChanges", QuotaType,
func() QuotaChangesCommand {
@@ -60,7 +60,7 @@ func (j *Client) GetQuotaChanges(accountId string, sinceState State, maxChanges
)
}
func (j *Client) GetQuotaUsageChanges(accountId string, sinceState State, maxChanges uint,
func (j *Client) GetQuotaUsageChanges(accountId AccountId, sinceState State, maxChanges uint,
ctx Context) (Result[QuotaChanges], error) {
return updates(j, "GetQuotaUsageChanges", QuotaType,
func() QuotaChangesCommand {

View File

@@ -11,9 +11,9 @@ const (
vacationResponseId = "singleton"
)
func (j *Client) GetVacationResponse(accountId string, ctx Context) (Result[VacationResponseGetResponse], error) {
func (j *Client) GetVacationResponse(accountId AccountId, ctx Context) (Result[VacationResponseGetResponse], error) {
return get(j, "GetVacationResponse", VacationResponseType,
func(accountId string, ids []string) VacationResponseGetCommand {
func(accountId AccountId, ids []string) VacationResponseGetCommand {
return VacationResponseGetCommand{AccountId: accountId}
},
VacationResponseGetResponse{},
@@ -64,7 +64,7 @@ func (c VacationResponseChanges) GetCreated() []VacationResponse { return c.Crea
func (c VacationResponseChanges) GetUpdated() []VacationResponse { return c.Updated }
func (c VacationResponseChanges) GetDestroyed() []string { return c.Destroyed }
func (j *Client) SetVacationResponse(accountId string, vacation VacationResponseChange,
func (j *Client) SetVacationResponse(accountId AccountId, vacation VacationResponseChange,
ctx Context) (Result[VacationResponse], error) {
logger := j.logger("SetVacationResponse", ctx)
ctx = ctx.WithLogger(logger)

View File

@@ -584,8 +584,8 @@ type uploadedBlob struct {
Sha512 string `json:"sha:512"`
}
func (j *TestJmapClient) uploadBlob(accountId string, data []byte, mimetype string) (uploadedBlob, error) { //NOSONAR
uploadUrl := strings.ReplaceAll(j.session.UploadUrl, "{accountId}", accountId)
func (j *TestJmapClient) uploadBlob(accountId AccountId, data []byte, mimetype string) (uploadedBlob, error) { //NOSONAR
uploadUrl := strings.ReplaceAll(j.session.UploadUrl, "{accountId}", string(accountId))
req, err := http.NewRequest(http.MethodPost, uploadUrl, bytes.NewReader(data))
if err != nil {
return uploadedBlob{}, err
@@ -707,7 +707,7 @@ func (c Commander[T]) command(body map[string]any) (T, error) {
return c.closure(methodResponses)
}
func (j *TestJmapClient) objectsById(accountId string, objectType ObjectType) (map[string]map[string]any, error) {
func (j *TestJmapClient) objectsById(accountId AccountId, objectType ObjectType) (map[string]map[string]any, error) {
m := map[string]map[string]any{}
{
body := map[string]any{
@@ -1154,13 +1154,13 @@ func deepEqual[T any](t *testing.T, expected, actual T) {
}
func containerTest[OBJ Idable, RESP GetResponse[OBJ], BOXES any, CHANGE Change](t *testing.T, //NOSONAR
acc func(session *Session) string,
acc func(session *Session) AccountId,
obj func(RESP) []OBJ,
id func(OBJ) string,
get func(s *StalwartTest, accountId string, ids []string, ctx Context) (Result[RESP], error),
update func(s *StalwartTest, accountId string, id string, change CHANGE, ctx Context) (Result[OBJ], error),
destroy func(s *StalwartTest, accountId string, ids []string, ctx Context) (Result[map[string]SetError], error),
fill func(s *StalwartTest, t *testing.T, accountId string, count uint, ctx Context, _ User, principalIds []string) (BOXES, []OBJ, SessionState, State, error),
get func(s *StalwartTest, accountId AccountId, ids []string, ctx Context) (Result[RESP], error),
update func(s *StalwartTest, accountId AccountId, id string, change CHANGE, ctx Context) (Result[OBJ], error),
destroy func(s *StalwartTest, accountId AccountId, ids []string, ctx Context) (Result[map[string]SetError], error),
fill func(s *StalwartTest, t *testing.T, accountId AccountId, count uint, ctx Context, _ User, principalIds []PrincipalId) (BOXES, []OBJ, SessionState, State, error),
change func(OBJ) CHANGE,
checkChanged func(t *testing.T, orig OBJ, change CHANGE, changed OBJ),
) {
@@ -1177,12 +1177,12 @@ func containerTest[OBJ Idable, RESP GetResponse[OBJ], BOXES any, CHANGE Change](
accountId := acc(session)
// we first need to retrieve the list of all the Principals in order to be able to use and test sharing
principalIds := []string{}
principalIds := []PrincipalId{}
{
result, err := s.client.GetPrincipals(accountId, []string{}, ctx)
result, err := s.client.GetPrincipals(accountId, []PrincipalId{}, ctx)
require.NoError(err)
require.NotEmpty(result.Payload.List)
principalIds = structs.Map(result.Payload.List, func(p Principal) string { return p.Id })
principalIds = structs.Map(result.Payload.List, func(p Principal) PrincipalId { return PrincipalId(p.Id) })
}
ss := EmptySessionState

View File

@@ -42,19 +42,19 @@ func TestAddressBooks(t *testing.T) {
}
containerTest(t,
func(session *Session) string { return session.PrimaryAccounts.Contacts },
func(session *Session) AccountId { return session.PrimaryAccounts.Contacts },
list,
getid,
func(s *StalwartTest, accountId string, ids []string, ctx Context) (Result[AddressBookGetResponse], error) {
func(s *StalwartTest, accountId AccountId, ids []string, ctx Context) (Result[AddressBookGetResponse], error) {
return s.client.GetAddressbooks(accountId, ids, ctx)
},
func(s *StalwartTest, accountId string, id string, change AddressBookChange, ctx Context) (Result[AddressBook], error) { //NOSONAR
func(s *StalwartTest, accountId AccountId, id string, change AddressBookChange, ctx Context) (Result[AddressBook], error) { //NOSONAR
return s.client.UpdateAddressBook(accountId, id, change, ctx)
},
func(s *StalwartTest, accountId string, ids []string, ctx Context) (Result[map[string]SetError], error) { //NOSONAR
func(s *StalwartTest, accountId AccountId, ids []string, ctx Context) (Result[map[string]SetError], error) { //NOSONAR
return s.client.DeleteAddressBook(accountId, ids, ctx)
},
func(s *StalwartTest, t *testing.T, accountId string, count uint, ctx Context, user User, principalIds []string) (AddressBookBoxes, []AddressBook, SessionState, State, error) {
func(s *StalwartTest, t *testing.T, accountId AccountId, count uint, ctx Context, user User, principalIds []PrincipalId) (AddressBookBoxes, []AddressBook, SessionState, State, error) {
return s.fillAddressBook(t, accountId, count, ctx, user, principalIds)
},
func(orig AddressBook) AddressBookChange {
@@ -104,7 +104,7 @@ func TestContacts(t *testing.T) {
ss := EmptySessionState
os := EmptyState
{
result, err := s.client.QueryContactCards(toNullQueryParams([]string{accountId}), nil, filter, sortBy, true, ctx)
result, err := s.client.QueryContactCards(toNullQueryParams([]AccountId{accountId}), nil, filter, sortBy, true, ctx)
require.NoError(err)
require.Len(result.Payload, 1)
@@ -161,7 +161,7 @@ func TestContacts(t *testing.T) {
for i := range slices {
position := int(i * limit)
page := min(remainder, limit)
result, err := s.client.QueryContactCards(map[string]QueryParams{accountId: {Position: position}}, &limit, filter, sortBy, true, ctx)
result, err := s.client.QueryContactCards(map[AccountId]QueryParams{accountId: {Position: position}}, &limit, filter, sortBy, true, ctx)
require.NoError(err)
require.Len(result.Payload, 1)
require.Contains(result.Payload, accountId)
@@ -186,7 +186,7 @@ func TestContacts(t *testing.T) {
offset := 0
i := 0
for chunk := range slices.Chunk(results.Results, chunkSize) {
result, err := s.client.QueryContactCards(map[string]QueryParams{accountId: {Anchor: anchor, AnchorOffset: &offset}}, uintPtr(chunkSize), filter, sortBy, true, ctx)
result, err := s.client.QueryContactCards(map[AccountId]QueryParams{accountId: {Anchor: anchor, AnchorOffset: &offset}}, uintPtr(chunkSize), filter, sortBy, true, ctx)
require.Equal(ss, result.GetSessionState())
require.NoError(err)
require.Len(result.Payload, 1)
@@ -236,7 +236,7 @@ func TestContacts(t *testing.T) {
os = result.GetState()
}
{
result, err := s.client.QueryContactCards(toNullQueryParams([]string{accountId}), nil, filter, sortBy, true, ctx)
result, err := s.client.QueryContactCards(toNullQueryParams([]AccountId{accountId}), nil, filter, sortBy, true, ctx)
require.NoError(err)
require.Contains(result.Payload, accountId)
resp := result.Payload[accountId]
@@ -278,11 +278,11 @@ var streetNumberRegex = regexp.MustCompile(`^(\d+)\s+(.+)$`)
func (s *StalwartTest) fillAddressBook( //NOSONAR
t *testing.T,
accountId string,
accountId AccountId,
count uint,
ctx Context,
_ User,
principalIds []string,
principalIds []PrincipalId,
) (AddressBookBoxes, []AddressBook, SessionState, State, error) {
require := require.New(t)
@@ -322,7 +322,7 @@ func (s *StalwartTest) fillAddressBook( //NOSONAR
}
if sharing != nil {
numPrincipals := 1 + rand.Intn(len(principalIds)-1)
m := make(map[string]AddressBookRights, numPrincipals)
m := make(map[PrincipalId]AddressBookRights, numPrincipals)
for _, p := range pickRandomN(numPrincipals, principalIds...) {
m[p] = *sharing
}
@@ -357,7 +357,7 @@ func (s *StalwartTest) fillContacts( //NOSONAR
session *Session,
ctx Context,
user User,
) (string, string, map[string]ContactCard, ContactsBoxes, error) {
) (AccountId, string, map[string]ContactCard, ContactsBoxes, error) {
require := require.New(t)
c, err := NewTestJmapClient(session, user.name, user.password, true, true)
require.NoError(err)

View File

@@ -32,19 +32,19 @@ func TestCalendars(t *testing.T) { //NOSONAR
}
containerTest(t,
func(session *Session) string { return session.PrimaryAccounts.Calendars },
func(session *Session) AccountId { return session.PrimaryAccounts.Calendars },
func(resp CalendarGetResponse) []Calendar { return resp.List },
func(obj Calendar) string { return obj.Id },
func(s *StalwartTest, accountId string, ids []string, ctx Context) (Result[CalendarGetResponse], error) {
func(s *StalwartTest, accountId AccountId, ids []string, ctx Context) (Result[CalendarGetResponse], error) {
return s.client.GetCalendars(accountId, ids, ctx)
},
func(s *StalwartTest, accountId string, id string, change CalendarChange, ctx Context) (Result[Calendar], error) { //NOSONAR
func(s *StalwartTest, accountId AccountId, id string, change CalendarChange, ctx Context) (Result[Calendar], error) { //NOSONAR
return s.client.UpdateCalendar(accountId, id, change, ctx)
},
func(s *StalwartTest, accountId string, ids []string, ctx Context) (Result[map[string]SetError], error) { //NOSONAR
func(s *StalwartTest, accountId AccountId, ids []string, ctx Context) (Result[map[string]SetError], error) { //NOSONAR
return s.client.DeleteCalendar(accountId, ids, ctx)
},
func(s *StalwartTest, t *testing.T, accountId string, count uint, ctx Context, user User, principalIds []string) (CalendarBoxes, []Calendar, SessionState, State, error) {
func(s *StalwartTest, t *testing.T, accountId AccountId, count uint, ctx Context, user User, principalIds []PrincipalId) (CalendarBoxes, []Calendar, SessionState, State, error) {
return s.fillCalendar(t, accountId, count, ctx, user, principalIds)
},
func(orig Calendar) CalendarChange {
@@ -94,7 +94,7 @@ func TestEvents(t *testing.T) {
os := EmptyState
var results *CalendarEventSearchResults
{
result, err := s.client.QueryCalendarEvents(toNullQueryParams([]string{accountId}), nil, filter, sortBy, true, ctx)
result, err := s.client.QueryCalendarEvents(toNullQueryParams([]AccountId{accountId}), nil, filter, sortBy, true, ctx)
require.NoError(err)
require.Len(result.Payload, 1)
@@ -127,7 +127,7 @@ func TestEvents(t *testing.T) {
for i := range slices {
position := int(i * limit)
page := min(remainder, limit)
result, err := s.client.QueryCalendarEvents(map[string]QueryParams{accountId: {Position: position}}, &limit, filter, sortBy, true, ctx)
result, err := s.client.QueryCalendarEvents(map[AccountId]QueryParams{accountId: {Position: position}}, &limit, filter, sortBy, true, ctx)
require.NoError(err)
require.Len(result.Payload, 1)
require.Contains(result.Payload, accountId)
@@ -152,7 +152,7 @@ func TestEvents(t *testing.T) {
offset := 0
i := 0
for chunk := range slices.Chunk(results.Results, chunkSize) {
result, err := s.client.QueryCalendarEvents(map[string]QueryParams{accountId: {Anchor: anchor, AnchorOffset: &offset}}, uintPtr(chunkSize), filter, sortBy, true, ctx)
result, err := s.client.QueryCalendarEvents(map[AccountId]QueryParams{accountId: {Anchor: anchor, AnchorOffset: &offset}}, uintPtr(chunkSize), filter, sortBy, true, ctx)
require.Equal(ss, result.GetSessionState())
require.NoError(err)
require.Len(result.Payload, 1)
@@ -207,7 +207,7 @@ func TestEvents(t *testing.T) {
}
{
result, err := s.client.QueryCalendarEvents(toNullQueryParams([]string{accountId}), nil, filter, sortBy, true, ctx)
result, err := s.client.QueryCalendarEvents(toNullQueryParams([]AccountId{accountId}), nil, filter, sortBy, true, ctx)
require.NoError(err)
require.Contains(result.Payload, accountId)
resp := result.Payload[accountId]
@@ -239,11 +239,11 @@ type CalendarBoxes struct {
func (s *StalwartTest) fillCalendar( //NOSONAR
t *testing.T,
accountId string,
accountId AccountId,
count uint,
ctx Context,
_ User,
principalIds []string,
principalIds []PrincipalId,
) (CalendarBoxes, []Calendar, SessionState, State, error) {
require := require.New(t)
@@ -340,7 +340,7 @@ func (s *StalwartTest) fillCalendar( //NOSONAR
}
if sharing != nil {
numPrincipals := 1 + rand.Intn(len(principalIds)-1)
m := make(map[string]CalendarRights, numPrincipals)
m := make(map[PrincipalId]CalendarRights, numPrincipals)
for _, p := range pickRandomN(numPrincipals, principalIds...) {
m[p] = *sharing
}
@@ -380,7 +380,7 @@ func (s *StalwartTest) fillEvents( //NOSONAR
count uint,
ctx Context,
user User,
) (string, string, map[string]CalendarEvent, EventsBoxes, error) {
) (AccountId, string, map[string]CalendarEvent, EventsBoxes, error) {
require := require.New(t)
c, err := NewTestJmapClient(ctx.Session, user.name, user.password, true, true)
require.NoError(err)

View File

@@ -65,7 +65,7 @@ func TestEmails(t *testing.T) {
}
{
result, err := s.client.GetAllMailboxes([]string{accountId}, ctx)
result, err := s.client.GetAllMailboxes([]AccountId{accountId}, ctx)
require.NoError(err)
require.Equal(session.State, result.GetSessionState())
require.Len(result.Payload, 1)
@@ -144,7 +144,7 @@ func TestSendingEmails(t *testing.T) {
var mailboxPerRole map[string]Mailbox
{
result, err := s.client.GetAllMailboxes([]string{accountId}, ctx)
result, err := s.client.GetAllMailboxes([]AccountId{accountId}, ctx)
require.NoError(err)
mailboxPerRole = structs.Index(result.Payload[accountId], func(m Mailbox) string { return m.Role })
require.Contains(mailboxPerRole, JmapMailboxRoleInbox)
@@ -154,7 +154,7 @@ func TestSendingEmails(t *testing.T) {
}
{
roles := []string{JmapMailboxRoleDrafts, JmapMailboxRoleSent, JmapMailboxRoleInbox}
result, err := s.client.SearchMailboxIdsPerRole([]string{accountId}, roles, ctx)
result, err := s.client.SearchMailboxIdsPerRole([]AccountId{accountId}, roles, ctx)
require.NoError(err)
require.Contains(result.Payload, accountId)
a := result.Payload[accountId]
@@ -165,7 +165,7 @@ func TestSendingEmails(t *testing.T) {
// let's ensure that the recipients have zero emails in their mailboxes before we send them any
for _, u := range []struct {
accountId string
accountId AccountId
session *Session
}{{toAccountId, toSession}, {ccAccountId, ccSession}} {
uctx := Context{
@@ -174,7 +174,7 @@ func TestSendingEmails(t *testing.T) {
Logger: ctx.Logger,
AcceptLanguage: ctx.AcceptLanguage,
}
result, err := s.client.GetAllMailboxes([]string{u.accountId}, uctx)
result, err := s.client.GetAllMailboxes([]AccountId{u.accountId}, uctx)
require.NoError(err)
for _, mailbox := range result.Payload[u.accountId] {
require.Equal(0, mailbox.TotalEmails)
@@ -306,7 +306,7 @@ func TestSendingEmails(t *testing.T) {
for _, r := range []struct {
user User
accountId string
accountId AccountId
session *Session
}{{to, toAccountId, toSession}, {cc, ccAccountId, ccSession}} {
rctx := Context{
@@ -317,7 +317,7 @@ func TestSendingEmails(t *testing.T) {
}
inboxId := ""
{
result, err := s.client.GetAllMailboxes([]string{r.accountId}, rctx)
result, err := s.client.GetAllMailboxes([]AccountId{r.accountId}, rctx)
require.NoError(err)
for _, mailbox := range result.Payload[r.accountId] {
if mailbox.Role == JmapMailboxRoleInbox {
@@ -328,7 +328,7 @@ func TestSendingEmails(t *testing.T) {
require.NotEmpty(inboxId, "failed to find the Mailbox with the 'inbox' role for %v", r.user.name)
}
result, err := s.client.QueryEmails([]string{r.accountId}, EmailFilterCondition{InMailbox: inboxId}, 0, 0, true, 0, rctx)
result, err := s.client.QueryEmails([]AccountId{r.accountId}, EmailFilterCondition{InMailbox: inboxId}, 0, 0, true, 0, rctx)
require.NoError(err)
require.Contains(result.Payload, r.accountId)
require.Len(result.Payload[r.accountId].Results, 1)
@@ -385,9 +385,9 @@ func matchEmail(t *testing.T, actual Email, expected filledMail, hasBodies bool)
}
}
func (s *StalwartTest) findInbox(t *testing.T, accountId string, ctx Context) (string, string) {
func (s *StalwartTest) findInbox(t *testing.T, accountId AccountId, ctx Context) (string, string) {
require := require.New(t)
result, err := s.client.GetAllMailboxes([]string{accountId}, ctx)
result, err := s.client.GetAllMailboxes([]AccountId{accountId}, ctx)
require.NoError(err)
require.Equal(ctx.Session.State, result.GetSessionState())
require.Len(result.Payload, 1)

View File

@@ -17,7 +17,7 @@ type testWsPushListener struct {
t *testing.T
logger *log.Logger
username string
mailAccountId string
mailAccountId AccountId
calls atomic.Uint32
m sync.Mutex
emailStates []string
@@ -46,7 +46,7 @@ func (l *testWsPushListener) OnNotification(username string, pushState StateChan
unsupportedKeys := structs.Filter(structs.Keys(changed), func(o ObjectTypeName) bool { return o != EmailName && o != ThreadName && o != MailboxName })
assert.Empty(l.t, unsupportedKeys)
}
unsupportedAccounts := structs.Filter(structs.Keys(pushState.Changed), func(s string) bool { return s != l.mailAccountId })
unsupportedAccounts := structs.Filter(structs.Keys(pushState.Changed), func(s AccountId) bool { return s != l.mailAccountId })
assert.Empty(l.t, unsupportedAccounts)
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -124,8 +124,8 @@ func SerializeExamples(e any) { //NOSONAR
}
type Exemplar struct {
AccountId string
SharedAccountId string
AccountId AccountId
SharedAccountId AccountId
IdentityId string
IdentityName string
EmailAddress string
@@ -331,9 +331,9 @@ func (e Exemplar) SessionCalendarsParseAccountCapabilities() SessionCalendarsPar
return SessionCalendarsParseAccountCapabilities{}
}
func (e Exemplar) sessionPrincipalsAccountCapabilities(accountId string) SessionPrincipalsAccountCapabilities {
func (e Exemplar) sessionPrincipalsAccountCapabilities(accountId AccountId) SessionPrincipalsAccountCapabilities {
return SessionPrincipalsAccountCapabilities{
CurrentUserPrincipalId: accountId,
CurrentUserPrincipalId: PrincipalId(accountId),
}
}
@@ -380,7 +380,7 @@ func (e Exemplar) SessionTasksCustomTimezonesAccountCapabilities() SessionTasksC
func (e Exemplar) SessionPrincipalsOwnerAccountCapabilities() SessionPrincipalsOwnerAccountCapabilities {
return SessionPrincipalsOwnerAccountCapabilities{
AccountIdForPrincipal: e.AccountId,
PrincipalId: e.AccountId,
PrincipalId: PrincipalId(e.AccountId),
}
}
@@ -392,7 +392,7 @@ func (e Exemplar) SessionAccountCapabilities() SessionAccountCapabilities {
return e.sessionAccountCapabilities(e.AccountId)
}
func (e Exemplar) sessionAccountCapabilities(accountId string) SessionAccountCapabilities {
func (e Exemplar) sessionAccountCapabilities(accountId AccountId) SessionAccountCapabilities {
mail := e.SessionMailAccountCapabilities()
submission := e.SessionSubmissionAccountCapabilities()
vacationResponse := e.SessionVacationResponseAccountCapabilities()
@@ -446,7 +446,7 @@ func (e Exemplar) Account() (Account, string) {
func (e Exemplar) SharedAccount() (Account, string, string) {
return Account{
Name: e.SharedAccountId,
Name: string(e.SharedAccountId),
IsPersonal: false,
IsReadOnly: true,
AccountCapabilities: e.sessionAccountCapabilities(e.SharedAccountId),
@@ -489,7 +489,7 @@ func (e Exemplar) Quotas() []Quota {
Scope: "account",
Used: 29102918,
HardLimit: 50000000000,
Name: e.SharedAccountId,
Name: string(e.SharedAccountId),
Types: []ObjectTypeName{
EmailName,
SieveScriptName,

View File

@@ -8,12 +8,12 @@ import (
"github.com/rs/zerolog"
)
func get[T Foo, GETREQ GetCommand[T], GETRESP GetResponse[T], RESP any]( //NOSONAR
func get[T Foo, GETREQ GetCommand[T], GETRESP GetResponse[T], ID any, RESP any]( //NOSONAR
client *Client, name string, objType ObjectType,
getCommandFactory func(string, []string) GETREQ,
getCommandFactory func(AccountId, []ID) GETREQ,
_ GETRESP,
mapper func(GETRESP) RESP,
accountId string, ids []string, ctx Context) (Result[RESP], Error) {
accountId AccountId, ids []ID, ctx Context) (Result[RESP], Error) {
ctx = ctx.WithLogger(client.logger(name, ctx))
get := getCommandFactory(accountId, ids)
@@ -34,12 +34,12 @@ func get[T Foo, GETREQ GetCommand[T], GETRESP GetResponse[T], RESP any]( //NOSON
})
}
func getAN[T Foo, GETREQ GetCommand[T], GETRESP GetResponse[T], RESP any]( //NOSONAR
func getAN[T Foo, GETREQ GetCommand[T], GETRESP GetResponse[T], ID any, RESP any]( //NOSONAR
client *Client, name string, objType ObjectType,
getCommandFactory func(string, []string) GETREQ,
getCommandFactory func(AccountId, []ID) GETREQ,
resp GETRESP,
respMapper func(map[string][]T) RESP,
accountIds []string, ids []string, ctx Context) (Result[RESP], Error) {
respMapper func(map[AccountId][]T) RESP,
accountIds []AccountId, ids []ID, ctx Context) (Result[RESP], Error) {
return getN(client, name, objType, getCommandFactory, resp,
func(r GETRESP) []T { return r.GetList() },
respMapper,
@@ -48,13 +48,13 @@ func getAN[T Foo, GETREQ GetCommand[T], GETRESP GetResponse[T], RESP any]( //NOS
)
}
func getN[T Foo, ITEM any, GETREQ GetCommand[T], GETRESP GetResponse[T], RESP any]( //NOSONAR
func getN[T Foo, ITEM any, GETREQ GetCommand[T], GETRESP GetResponse[T], ID any, RESP any]( //NOSONAR
client *Client, name string, objType ObjectType,
getCommandFactory func(string, []string) GETREQ,
getCommandFactory func(AccountId, []ID) GETREQ,
_ GETRESP,
itemMapper func(GETRESP) ITEM,
respMapper func(map[string]ITEM) RESP,
accountIds []string, ids []string, ctx Context) (Result[RESP], Error) {
respMapper func(map[AccountId]ITEM) RESP,
accountIds []AccountId, ids []ID, ctx Context) (Result[RESP], Error) {
logger := client.logger(name, ctx)
ctx = ctx.WithLogger(logger)
@@ -74,8 +74,8 @@ func getN[T Foo, ITEM any, GETREQ GetCommand[T], GETRESP GetResponse[T], RESP an
}
return command(client, ctx, cmd, func(body *Response) (RESP, State, Error) {
result := map[string]ITEM{}
responses := map[string]GETRESP{}
result := map[AccountId]ITEM{}
responses := map[AccountId]GETRESP{}
for _, accountId := range uniqueAccountIds {
var resp GETRESP
err = retrieveResponseMatchParameters(ctx, body, c, mcid(accountId, "0"), &resp)
@@ -92,11 +92,11 @@ func getN[T Foo, ITEM any, GETREQ GetCommand[T], GETRESP GetResponse[T], RESP an
func create[T Foo, C any, SETREQ SetCommand[T], GETREQ GetCommand[T], SETRESP SetResponse[T], GETRESP GetResponse[T]]( //NOSONAR
client *Client, name string, objType ObjectType,
setCommandFactory func(string, map[string]C) SETREQ,
getCommandFactory func(string, string) GETREQ,
setCommandFactory func(AccountId, map[string]C) SETREQ,
getCommandFactory func(AccountId, string) GETREQ,
createdMapper func(SETRESP) map[string]*T,
listMapper func(GETRESP) []T,
accountId string, create C,
accountId AccountId, create C,
ctx Context) (Result[*T], Error) {
logger := client.logger(name, ctx)
ctx = ctx.WithLogger(logger)
@@ -152,8 +152,8 @@ func create[T Foo, C any, SETREQ SetCommand[T], GETREQ GetCommand[T], SETRESP Se
}
func destroy[T Foo, REQ SetCommand[T], RESP SetResponse[T]](client *Client, name string, objType ObjectType, //NOSONAR
setCommandFactory func(string, []string) REQ, _ RESP,
accountId string, destroy []string, ctx Context) (Result[map[string]SetError], Error) {
setCommandFactory func(AccountId, []string) REQ, _ RESP,
accountId AccountId, destroy []string, ctx Context) (Result[map[string]SetError], Error) {
logger := client.logger(name, ctx)
ctx = ctx.WithLogger(logger)
@@ -248,19 +248,19 @@ func changes[T Foo, CHANGESREQ ChangesCommand[T], GETREQ GetCommand[T], CHANGESR
func changesN[T Foo, CHANGESREQ ChangesCommand[T], GETREQ GetCommand[T], CHANGESRESP ChangesResponse[T], GETRESP GetResponse[T], ITEM any, CHANGESITEM any, RESP any]( //NOSONAR
client *Client, name string, objType ObjectType,
accountIds []string, sinceStateMap map[string]State,
changesCommandFactory func(string, State) CHANGESREQ,
accountIds []AccountId, sinceStateMap map[AccountId]State,
changesCommandFactory func(AccountId, State) CHANGESREQ,
_ CHANGESRESP,
getCommandFactory func(string, string, string) GETREQ,
getCommandFactory func(AccountId, string, string) GETREQ,
getMapper func(GETRESP) []ITEM,
changesItemMapper func(State, State, bool, []ITEM, []ITEM, []string) CHANGESITEM,
respMapper func(map[string]CHANGESITEM) RESP,
respMapper func(map[AccountId]CHANGESITEM) RESP,
stateMapper func(GETRESP) State,
ctx Context) (Result[RESP], Error) {
logger := client.loggerParams(name, ctx, func(z zerolog.Context) zerolog.Context {
sinceStateLogDict := zerolog.Dict()
for k, v := range sinceStateMap {
sinceStateLogDict.Str(log.SafeString(k), log.SafeString(string(v)))
sinceStateLogDict.Str(log.SafeString(string(k)), log.SafeString(string(v)))
}
return z.Dict(logSinceState, sinceStateLogDict)
})
@@ -303,8 +303,8 @@ func changesN[T Foo, CHANGESREQ ChangesCommand[T], GETREQ GetCommand[T], CHANGES
}
return command(client, ctx, cmd, func(body *Response) (RESP, State, Error) {
changesItemByAccount := make(map[string]CHANGESITEM, n)
stateByAccountId := make(map[string]State, n)
changesItemByAccount := make(map[AccountId]CHANGESITEM, n)
stateByAccountId := make(map[AccountId]State, n)
for _, accountId := range uniqueAccountIds {
var changesResponse CHANGESRESP
err = retrieveChanges(ctx, body, ch, mcid(accountId, "0"), &changesResponse)
@@ -488,13 +488,13 @@ func query[T Foo, FILTER any, SORT any, QUERY QueryCommand[T], GET GetCommand[T]
func queryN[T Foo, FILTER any, SORT any, QUERY QueryCommand[T, QUERY], GET GetCommand[T], QUERYRESP QueryResponse[T], GETRESP GetResponse[T], RESP any]( //NOSONAR
client *Client, name string, objType ObjectType,
defaultSortBy []SORT,
queryCommandFactory func(accountId string, queryParams QueryParams, limit *uint, filter FILTER, sortBy []SORT) QUERY,
getCommandFactory func(accountId string, cmd Command, path string, rof string) GET,
queryCommandFactory func(accountId AccountId, queryParams QueryParams, limit *uint, filter FILTER, sortBy []SORT) QUERY,
getCommandFactory func(accountId AccountId, cmd Command, path string, rof string) GET,
respMapper0 func(query QUERYRESP, queryParams QueryParams, limit *uint) *RESP,
respMapper func(query QUERYRESP, get GETRESP, queryParams QueryParams, limit *uint) *RESP,
accountIds map[string]QueryParams,
accountIds map[AccountId]QueryParams,
limit *uint, filter FILTER, sortBy []SORT,
ctx Context) (Result[map[string]*RESP], Error) {
ctx Context) (Result[map[AccountId]*RESP], Error) {
logger := client.logger(name, ctx)
ctx = ctx.WithLogger(logger)
@@ -525,12 +525,12 @@ func queryN[T Foo, FILTER any, SORT any, QUERY QueryCommand[T, QUERY], GET GetCo
cmd, err := client.request(ctx, objType.Namespaces, invocations...)
if err != nil {
return ZeroResult[map[string]*RESP](), err
return ZeroResult[map[AccountId]*RESP](), err
}
return command(client, ctx, cmd, func(body *Response) (map[string]*RESP, State, Error) {
resp := map[string]*RESP{}
stateByAccountId := map[string]State{}
return command(client, ctx, cmd, func(body *Response) (map[AccountId]*RESP, State, Error) {
resp := map[AccountId]*RESP{}
stateByAccountId := map[AccountId]State{}
for accountId, queryParams := range accountIds {
var queryResponse QUERYRESP
err = retrieveQuery(ctx, body, q, mcid(accountId, "0"), &queryResponse)

View File

@@ -44,13 +44,13 @@ func newEventListeners[T any]() *eventListeners[T] {
// Create an identifier to use as a method call ID, from the specified accountId and additional
// tag, to make something unique within that API request.
func mcid(accountId string, tag string) string {
func mcid(accountId AccountId, tag string) string {
// https://jmap.io/spec-core.html#the-invocation-data-type
// May be any string of data:
// An arbitrary string from the client to be echoed back with the responses emitted by that method
// call (a method may return 1 or more responses, as it may make implicit calls to other methods;
// all responses initiated by this method call get the same method call id in the response).
return accountId + ":" + tag
return string(accountId) + ":" + tag
}
type Cmdr interface {
@@ -308,7 +308,7 @@ func (i *Invocation) UnmarshalJSON(bs []byte) error {
return nil
}
func squashState(all map[string]State) State {
func squashState[K ~string](all map[K]State) State {
return squashStateFunc(all, func(s State) State { return s })
}
@@ -318,11 +318,11 @@ func squashStates(states ...State) State {
}
*/
func squashKeyedStates(m map[string]State) State {
func squashKeyedStates[K ~string](m map[K]State) State {
return squashStateFunc(m, identity1)
}
func squashStateFunc[V any](all map[string]V, mapper func(V) State) State {
func squashStateFunc[K ~string, V any](all map[K]V, mapper func(V) State) State {
n := len(all)
if n == 0 {
return State("")
@@ -334,7 +334,7 @@ func squashStateFunc[V any](all map[string]V, mapper func(V) State) State {
}
parts := make([]string, n)
sortedKeys := make([]string, n)
sortedKeys := make([]K, n)
i := 0
for k := range all {
sortedKeys[i] = k
@@ -343,15 +343,15 @@ func squashStateFunc[V any](all map[string]V, mapper func(V) State) State {
slices.Sort(sortedKeys)
for i, k := range sortedKeys {
if v, ok := all[k]; ok {
parts[i] = k + ":" + string(mapper(v))
parts[i] = string(k) + ":" + string(mapper(v))
} else {
parts[i] = k + ":"
parts[i] = string(k) + ":"
}
}
return State(strings.Join(parts, ","))
}
func squashStateMaps(first map[string]State, second map[string]State) State {
func squashStateMaps(first map[AccountId]State, second map[AccountId]State) State {
return squashStateFunc(mapPairs(first, second), func(p pair[State, State]) State {
if p.left != nil {
if p.right != nil {

View File

@@ -9,11 +9,12 @@ const (
// 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 SafeString(text string) string {
runes := []rune(text)
func SafeString[S ~string](text S) string {
t := string(text)
runes := []rune(t)
if len(runes) <= logMaxStrLength {
return text
return t
} else {
return string(runes[0:logMaxStrLength-1]) + `\u2026` // hellip
}

View File

@@ -95,6 +95,10 @@ func Set[V comparable](source []V) map[V]struct{} {
return result
}
func ToStrings[A ~string](s []A) []string {
return Map(s, func(a A) string { return string(a) })
}
// Creates a slice from a slice, putting each value from the source slice through the
// mapper function to determine the value to store into the resulting slice.
func Map[E any, R any](source []E, mapper func(E) R) []R {
@@ -156,6 +160,16 @@ func MapO[E any, R any](source []E, indexer func(E) (R, bool)) []R {
return result
}
// Created a map from a map, mapping both the key and the value using the mapper function.
func MapMap[A comparable, B any, X comparable, Y any](m map[A]B, mapper func(A, B) (X, Y)) map[X]Y {
r := make(map[X]Y, len(m))
for a, b := range m {
x, y := mapper(a, b)
r[x] = y
}
return r
}
// Creates a map from a map, keeping each key as-is, and using the mapper
// function to determine the value to store into the resulting map.
func MapValues[K comparable, S any, T any](m map[K]S, mapper func(S) T) map[K]T {

View File

@@ -122,6 +122,24 @@ func TestIndex(t *testing.T) {
}
}
func TestMapMap(t *testing.T) {
{
m := map[string]int{
"un": 1,
"deux": 2,
"trois": 3,
}
n := MapMap(m, func(a string, b int) (string, int) { return strings.ToUpper(a), b + 100 })
assert.Len(t, n, 3)
assert.Contains(t, n, "UN")
assert.Equal(t, 1001, n["UN"])
assert.Contains(t, n, "DEUX")
assert.Equal(t, 1002, n["DEUX"])
assert.Contains(t, n, "TROIS")
assert.Equal(t, 1003, n["TROIS"])
}
}
func TestMap(t *testing.T) {
tests := []struct {
input []string

View File

@@ -244,4 +244,3 @@ The alternative would be to have different APIs depending on what each endpoint
* endpoint with multiple backends or multiple accounts:<br>same as above with `?first=...` and `?next=...`
* endpoint with a single backend and a single account:<br>`?position=...&anchor=...&offset=...&limit=...`

View File

@@ -17,18 +17,20 @@ func newJmapContactCardSupplier(client *jmap.Client) *JmapContactCardSupplier {
return &JmapContactCardSupplier{client: client}
}
func (c *JmapContactCardSupplier) GetId() string {
return "jmap"
const jmapContactCardSupplierid = SupplierId("jmap")
func (c *JmapContactCardSupplier) GetId() SupplierId {
return jmapContactCardSupplierid
}
func (c *JmapContactCardSupplier) IsMine(id string) bool {
return id != "" && !strings.Contains(id, ":")
}
func (c *JmapContactCardSupplier) GetAll(accountId string, ids []string, ctx jmap.Context) (jmap.Result[jmap.AddressBookGetResponse], error) {
func (c *JmapContactCardSupplier) GetAll(accountId jmap.AccountId, ids []string, ctx jmap.Context) (jmap.Result[jmap.AddressBookGetResponse], error) {
return c.client.GetAddressbooks(accountId, ids, ctx)
}
func (c *JmapContactCardSupplier) Query(accountIds []string, qps QueryParamsSupplier, limit *uint, filter jmap.ContactCardFilterElement, sortBy []jmap.ContactCardComparator, calculateTotal bool, ctx jmap.Context) (jmap.Result[map[string]*jmap.ContactCardSearchResults], error) { //NOSONAR
func (c *JmapContactCardSupplier) Query(accountIds []jmap.AccountId, qps QueryParamsSupplier, limit *uint, filter jmap.ContactCardFilterElement, sortBy []jmap.ContactCardComparator, calculateTotal bool, ctx jmap.Context) (jmap.Result[map[jmap.AccountId]*jmap.ContactCardSearchResults], error) { //NOSONAR
if m, err := mapQueryParams(c.GetId(), accountIds, qps); err != nil {
return jmap.ZeroResult[map[string]*jmap.ContactCardSearchResults](), err
return jmap.ZeroResult[map[jmap.AccountId]*jmap.ContactCardSearchResults](), err
} else {
return c.client.QueryContactCards(m, limit, filter, sortBy, calculateTotal, ctx)
}

View File

@@ -64,13 +64,13 @@ func newMockContactCardSupplier() *MockContactCardSupplier {
return MockContactCardSupplierInstance
}
func (c *MockContactCardSupplier) GetId() string {
return "mock"
func (c *MockContactCardSupplier) GetId() SupplierId {
return SupplierId("mock")
}
func (c *MockContactCardSupplier) IsMine(id string) bool {
return strings.HasPrefix(id, "mock:")
}
func (c *MockContactCardSupplier) GetAll(accountId string, ids []string, ctx jmap.Context) (jmap.Result[jmap.AddressBookGetResponse], error) {
func (c *MockContactCardSupplier) GetAll(accountId jmap.AccountId, ids []string, ctx jmap.Context) (jmap.Result[jmap.AddressBookGetResponse], error) {
abooks := []jmap.AddressBook{c.addressBook}
if len(ids) > 0 {
abooks = structs.Filter(abooks, func(a jmap.AddressBook) bool { return slices.Contains(ids, a.Id) })
@@ -86,14 +86,14 @@ func (c *MockContactCardSupplier) GetAll(accountId string, ids []string, ctx jma
},
}, nil
}
func (c *MockContactCardSupplier) Query(accountIds []string, qps QueryParamsSupplier, limit *uint, filter jmap.ContactCardFilterElement, sortBy []jmap.ContactCardComparator, calculateTotal bool, ctx jmap.Context) (jmap.Result[map[string]*jmap.ContactCardSearchResults], error) { //NOSONAR
payload := make(map[string]*jmap.ContactCardSearchResults, len(accountIds))
func (c *MockContactCardSupplier) Query(accountIds []jmap.AccountId, qps QueryParamsSupplier, limit *uint, filter jmap.ContactCardFilterElement, sortBy []jmap.ContactCardComparator, calculateTotal bool, ctx jmap.Context) (jmap.Result[map[jmap.AccountId]*jmap.ContactCardSearchResults], error) { //NOSONAR
payload := make(map[jmap.AccountId]*jmap.ContactCardSearchResults, len(accountIds))
total := len(c.contacts)
for _, accountId := range accountIds {
all := []jmap.ContactCard{}
var qp jmap.QueryParams
if q, ok, err := qps.ForSupplier(c.GetId(), accountId); err != nil {
return jmap.ZeroResult[map[string]*jmap.ContactCardSearchResults](), err
return jmap.ZeroResult[map[jmap.AccountId]*jmap.ContactCardSearchResults](), err
} else if ok {
qp = q
} else {
@@ -141,7 +141,7 @@ func (c *MockContactCardSupplier) Query(accountIds []string, qps QueryParamsSupp
payload[accountId] = res
}
return jmap.Result[map[string]*jmap.ContactCardSearchResults]{
return jmap.Result[map[jmap.AccountId]*jmap.ContactCardSearchResults]{
Payload: payload,
SessionState: jmap.EmptySessionState,
State: jmap.EmptyState,

View File

@@ -34,9 +34,9 @@ func (g *Groupware) GetAccounts(w http.ResponseWriter, r *http.Request) {
i++
}
// sort on accountId to have a stable order that remains the same with every query
slices.SortFunc(list, func(a, b AccountWithId) int { return strings.Compare(a.AccountId, b.AccountId) })
slices.SortFunc(list, func(a, b AccountWithId) int { return strings.Compare(string(a.AccountId), string(b.AccountId)) })
var RBODY []AccountWithId = list
return req.respondN(structs.Map(list, func(a AccountWithId) string { return a.AccountId }), RBODY, AccountResponseObjectType, req.session)
return req.respondN(structs.Map(list, func(a AccountWithId) jmap.AccountId { return a.AccountId }), RBODY, AccountResponseObjectType, req.session)
})
}
@@ -64,19 +64,21 @@ func (g *Groupware) GetAccountsWithTheirIdentities(w http.ResponseWriter, r *htt
i++
}
// sort on accountId to have a stable order that remains the same with every query
slices.SortFunc(list, func(a, b AccountWithIdAndIdentities) int { return strings.Compare(a.AccountId, b.AccountId) })
slices.SortFunc(list, func(a, b AccountWithIdAndIdentities) int {
return strings.Compare(string(a.AccountId), string(b.AccountId))
})
var RBODY []AccountWithIdAndIdentities = list
return req.respondN(structs.Map(list, func(a AccountWithIdAndIdentities) string { return a.AccountId }), RBODY, AccountResponseObjectType, resp)
return req.respondN(structs.Map(list, func(a AccountWithIdAndIdentities) jmap.AccountId { return a.AccountId }), RBODY, AccountResponseObjectType, resp)
})
}
type AccountWithId struct {
AccountId string `json:"accountId,omitempty"`
AccountId jmap.AccountId `json:"accountId,omitempty"`
jmap.Account
}
type AccountWithIdAndIdentities struct {
AccountId string `json:"accountId,omitempty"`
AccountId jmap.AccountId `json:"accountId,omitempty"`
Identities []jmap.Identity `json:"identities,omitempty"`
jmap.Account
}

View File

@@ -34,8 +34,8 @@ func (g *Groupware) ModifyAddressBook(w http.ResponseWriter, r *http.Request) {
modify(AddressBook, w, r, g, g.jmap.UpdateAddressBook)
}
func (g *Groupware) addressbooks(accountId string, ids []string, ctx jmap.Context) (jmap.Result[jmap.AddressBookGetResponse], error) {
return slist(g.addressBookListSuppliers, accountId, ids, ctx, func(accountId string, state jmap.State, notFound []string, list []jmap.AddressBook) jmap.AddressBookGetResponse {
func (g *Groupware) addressbooks(accountId jmap.AccountId, ids []string, ctx jmap.Context) (jmap.Result[jmap.AddressBookGetResponse], error) {
return slist(g.addressBookListSuppliers, accountId, ids, ctx, func(accountId jmap.AccountId, state jmap.State, notFound []string, list []jmap.AddressBook) jmap.AddressBookGetResponse {
return jmap.AddressBookGetResponse{AccountId: accountId, State: state, NotFound: notFound, List: list}
})
}

View File

@@ -34,7 +34,7 @@ func (g *Groupware) UploadBlob(w http.ResponseWriter, r *http.Request) {
if err != nil {
return req.error(accountId, err)
}
logger := log.From(req.logger.With().Str(logAccountId, accountId))
logger := log.From(req.logger.With().Str(logAccountId, log.SafeString(accountId)))
ctx := req.ctx.WithLogger(logger)
resp, _, jerr := g.jmap.UploadBlobStream(accountId, contentType, body, ctx)
if jerr != nil {
@@ -63,7 +63,7 @@ func (g *Groupware) DownloadBlob(w http.ResponseWriter, r *http.Request) {
}
typ, _ := req.getStringParam(QueryParamBlobType, "") // optionally, the Content-Type of the blob, which is then used in the response
logger := log.From(req.logger.With().Str(logAccountId, accountId).Str(UriParamBlobId, blobId))
logger := log.From(req.logger.With().Str(logAccountId, log.SafeString(accountId)).Str(UriParamBlobId, blobId))
ctx := req.ctx.WithLogger(logger)
if err := req.serveBlob(blobId, name, typ, ctx, accountId, w); err != nil {
@@ -74,7 +74,7 @@ func (g *Groupware) DownloadBlob(w http.ResponseWriter, r *http.Request) {
})
}
func (r *Request) serveBlob(blobId string, name string, typ string, ctx jmap.Context, accountId string, w http.ResponseWriter) *Error { //NOSONAR
func (r *Request) serveBlob(blobId string, name string, typ string, ctx jmap.Context, accountId jmap.AccountId, w http.ResponseWriter) *Error { //NOSONAR
if typ == "" {
typ = DefaultBlobDownloadType
}

View File

@@ -34,7 +34,7 @@ func (g *Groupware) GetChanges(w http.ResponseWriter, r *http.Request) { //NOSON
if err != nil {
return req.error(accountId, err)
}
l = l.Str(logAccountId, accountId)
l = l.Str(logAccountId, log.SafeString(accountId))
var maxChanges uint = 0
if v, ok, err := req.parseUIntParam(QueryParamMaxChanges, 0); err != nil { // The maximum amount of changes to emit for each type of object.

View File

@@ -82,7 +82,7 @@ func (g *Groupware) ModifyContact(w http.ResponseWriter, r *http.Request) {
modify(Contact, w, r, g, g.jmap.UpdateContactCard)
}
func (g *Groupware) contacts(accountIds []string, qps QueryParamsSupplier, limit *uint, //NOSONAR
func (g *Groupware) contacts(accountIds []jmap.AccountId, qps QueryParamsSupplier, limit *uint, //NOSONAR
filter jmap.ContactCardFilterElement, sortBy []jmap.ContactCardComparator, calculateTotal bool,
ctx jmap.Context) (jmap.Result[*jmap.ContactCardSearchResults], NextToken, error) {
return squery(g.contactCardQuerySuppliers, accountIds, qps, limit, filter, sortBy, calculateTotal, ctx,

View File

@@ -24,7 +24,7 @@ import (
// Get the changes tp Emails since a certain State.
// @api:tags email,changes
func (g *Groupware) GetEmailChanges(w http.ResponseWriter, r *http.Request) {
changes(Email, w, r, g, func(accountId string, sinceState jmap.State, maxChanges uint, ctx jmap.Context) (jmap.Result[jmap.EmailChanges], error) {
changes(Email, w, r, g, func(accountId jmap.AccountId, sinceState jmap.State, maxChanges uint, ctx jmap.Context) (jmap.Result[jmap.EmailChanges], error) {
return g.jmap.GetEmailChanges(accountId, sinceState, true, g.config.maxBodyValueBytes, maxChanges, ctx)
})
}
@@ -42,7 +42,7 @@ func (g *Groupware) GetAllEmailsInMailbox(w http.ResponseWriter, r *http.Request
fetchBodies := false
withThreads := true
query(Email, w, r, g, g.defaults.emailLimit,
func(req Request, accountId string, containerId string, qp jmap.QueryParams, limit *uint, ctx jmap.Context) (jmap.Result[*jmap.EmailSearchResults], error) { //NOSONAR
func(req Request, accountId jmap.AccountId, containerId string, qp jmap.QueryParams, limit *uint, ctx jmap.Context) (jmap.Result[*jmap.EmailSearchResults], error) { //NOSONAR
result, jerr := g.jmap.GetAllEmailsInMailbox(accountId, containerId, qp, limit, collapseThreads, fetchBodies, g.config.maxBodyValueBytes, withThreads, ctx)
if jerr != nil {
return jmap.ZeroResult[*jmap.EmailSearchResults](), jerr
@@ -348,13 +348,13 @@ func (g *Groupware) getEmailsSince(w http.ResponseWriter, r *http.Request, since
type EmailSearchSnippetsResults jmap.SearchResultsTemplate[Snippet]
type EmailWithSnippets struct {
AccountId string `json:"accountId,omitempty"`
AccountId jmap.AccountId `json:"accountId,omitempty"`
Snippets []SnippetWithoutEmailId `json:"snippets,omitempty"`
jmap.Email
}
type Snippet struct {
AccountId string `json:"accountId,omitempty"`
AccountId jmap.AccountId `json:"accountId,omitempty"`
jmap.SearchSnippetWithMeta
}
@@ -649,7 +649,7 @@ func (g *Groupware) GetEmailsForAllAccounts(w http.ResponseWriter, r *http.Reque
if !ok {
return req.errorN(allAccountIds, err)
}
logger = log.From(req.logger.With().Array(logAccountId, log.SafeStringArray(allAccountIds)))
logger = log.From(req.logger.With().Array(logAccountId, log.SafeStringArray(structs.ToStrings(allAccountIds))))
ctx := req.ctx.WithLogger(logger)
if !filter.IsNotEmpty() {
@@ -758,7 +758,7 @@ var draftEmailAutoMailboxRolePrecedence = []string{
jmap.JmapMailboxRoleInbox, // but if there is none, we will use the Mailbox with the inbox role instead
}
func findDraftsMailboxId(j *jmap.Client, accountId string, req Request, ctx jmap.Context) (string, Response) {
func findDraftsMailboxId(j *jmap.Client, accountId jmap.AccountId, req Request, ctx jmap.Context) (string, Response) {
result, jerr := j.SearchMailboxIdsPerRole(single(accountId), draftEmailAutoMailboxRolePrecedence, ctx)
if jerr != nil {
return "", req.jmapError(accountId, jerr, result)
@@ -781,7 +781,7 @@ var sentEmailAutoMailboxRolePrecedence = []string{
var draftAndSentMailboxRoles = structs.Uniq(structs.Concat(draftEmailAutoMailboxRolePrecedence, sentEmailAutoMailboxRolePrecedence))
func findSentMailboxId(j *jmap.Client, accountId string, req Request, ctx jmap.Context) (string, string, Response) { //NOSONAR
func findSentMailboxId(j *jmap.Client, accountId jmap.AccountId, req Request, ctx jmap.Context) (string, string, Response) { //NOSONAR
result, jerr := j.SearchMailboxIdsPerRole(single(accountId), draftAndSentMailboxRoles, ctx)
if jerr != nil {
return "", "", req.jmapError(accountId, jerr, result)
@@ -812,7 +812,7 @@ func findSentMailboxId(j *jmap.Client, accountId string, req Request, ctx jmap.C
func (g *Groupware) CreateEmail(w http.ResponseWriter, r *http.Request) {
create(Email, w, r, g,
func(r Request, accountId string, body *jmap.EmailChange, ctx jmap.Context) (bool, Response) {
func(r Request, accountId jmap.AccountId, body *jmap.EmailChange, ctx jmap.Context) (bool, Response) {
if len(body.MailboxIds) < 1 {
mailboxId, resp := findDraftsMailboxId(g.jmap, accountId, r, ctx)
if mailboxId != "" && body != nil {
@@ -826,7 +826,7 @@ func (g *Groupware) CreateEmail(w http.ResponseWriter, r *http.Request) {
}
return true, Response{}
},
func(accountId string, body jmap.EmailChange, ctx jmap.Context) (jmap.Result[*jmap.Email], error) {
func(accountId jmap.AccountId, body jmap.EmailChange, ctx jmap.Context) (jmap.Result[*jmap.Email], error) {
return g.jmap.CreateEmail(accountId, body, "", ctx)
},
)
@@ -835,7 +835,7 @@ func (g *Groupware) CreateEmail(w http.ResponseWriter, r *http.Request) {
func (g *Groupware) ReplaceEmail(w http.ResponseWriter, r *http.Request) {
replaceId := ""
create(Email, w, r, g,
func(r Request, accountId string, body *jmap.EmailChange, ctx jmap.Context) (bool, Response) {
func(r Request, accountId jmap.AccountId, body *jmap.EmailChange, ctx jmap.Context) (bool, Response) {
if len(body.MailboxIds) < 1 {
mailboxId, resp := findDraftsMailboxId(g.jmap, accountId, r, ctx)
if mailboxId != "" {
@@ -852,7 +852,7 @@ func (g *Groupware) ReplaceEmail(w http.ResponseWriter, r *http.Request) {
return true, Response{}
},
func(accountId string, body jmap.EmailChange, ctx jmap.Context) (jmap.Result[*jmap.Email], error) {
func(accountId jmap.AccountId, body jmap.EmailChange, ctx jmap.Context) (jmap.Result[*jmap.Email], error) {
ctx = ctx.WithLogger(log.From(ctx.Logger.With().Str("replaceId", replaceId)))
return g.jmap.CreateEmail(accountId, body, replaceId, ctx)
},
@@ -883,7 +883,7 @@ func (g *Groupware) UpdateEmailKeywords(w http.ResponseWriter, r *http.Request)
if gwerr != nil {
return req.error(accountId, gwerr)
}
l.Str(logAccountId, accountId)
l.Str(logAccountId, log.SafeString(accountId))
emailId, err := req.PathParam(UriParamEmailId)
if err != nil {
@@ -945,7 +945,7 @@ func (g *Groupware) AddEmailKeywords(w http.ResponseWriter, r *http.Request) { /
if gwerr != nil {
return req.error(accountId, gwerr)
}
l.Str(logAccountId, accountId)
l.Str(logAccountId, log.SafeString(accountId))
emailId, err := req.PathParam(UriParamEmailId)
if err != nil {
@@ -1008,7 +1008,7 @@ func (g *Groupware) RemoveEmailKeywords(w http.ResponseWriter, r *http.Request)
if err != nil {
return req.error(accountId, err)
}
l.Str(logAccountId, accountId)
l.Str(logAccountId, log.SafeString(accountId))
emailId, err := req.PathParam(UriParamEmailId)
if err != nil {
@@ -1082,7 +1082,7 @@ func (g *Groupware) SendEmail(w http.ResponseWriter, r *http.Request) { //NOSONA
if gwerr != nil {
return req.error(accountId, gwerr)
}
l.Str(logAccountId, accountId)
l.Str(logAccountId, log.SafeString(accountId))
emailId, err := req.PathParam(UriParamEmailId)
if err != nil {
@@ -1309,7 +1309,7 @@ func (g *Groupware) RelatedToEmail(w http.ResponseWriter, r *http.Request) { //N
type EmailSummary struct {
// The id of the account this Email summary pertains to.
AccountId string `json:"accountId,omitempty"`
AccountId jmap.AccountId `json:"accountId,omitempty"`
// The id of the Email object.
//
@@ -1450,7 +1450,7 @@ var _ jmap.Foo = EmailSummary{}
func (e EmailSummary) GetObjectType() jmap.ObjectType { return jmap.EmailType }
func summarizeEmail(accountId string, email jmap.Email) EmailSummary {
func summarizeEmail(accountId jmap.AccountId, email jmap.Email) EmailSummary {
return EmailSummary{
AccountId: accountId,
Id: email.Id,
@@ -1474,7 +1474,7 @@ func summarizeEmail(accountId string, email jmap.Email) EmailSummary {
}
type emailWithAccountId struct {
accountId string
accountId jmap.AccountId
email jmap.Email
}
@@ -1495,7 +1495,7 @@ func (g *Groupware) GetLatestEmailsSummaryForAllAccounts(w http.ResponseWriter,
l := req.logger.With()
allAccountIds := req.AllAccountIds()
l.Array(logAccountId, log.SafeStringArray(allAccountIds))
l.Array(logAccountId, log.SafeStringArray(structs.ToStrings(allAccountIds)))
limit, ok, err := req.parseUIntParam(QueryParamLimit, 10) // TODO from configuration
if err != nil {

View File

@@ -90,7 +90,7 @@ type IndexAccountCapabilities struct {
}
type IndexAccount struct {
AccountId string `json:"accountId"`
AccountId jmap.AccountId `json:"accountId"`
// A user-friendly string to show when presenting content from this Account,
// e.g., the email address representing the owner of the account.
@@ -116,11 +116,11 @@ type IndexAccount struct {
// Primary account identifiers per API usage type.
type IndexPrimaryAccounts struct {
Mail string `json:"mail"`
Submission string `json:"submission"`
Blob string `json:"blob"`
VacationResponse string `json:"vacationResponse"`
Sieve string `json:"sieve"`
Mail jmap.AccountId `json:"mail"`
Submission jmap.AccountId `json:"submission"`
Blob jmap.AccountId `json:"blob"`
VacationResponse jmap.AccountId `json:"vacationResponse"`
Sieve jmap.AccountId `json:"sieve"`
}
type IndexResponse struct {
@@ -185,7 +185,7 @@ func buildIndexPrimaryAccounts(session *jmap.Session) IndexPrimaryAccounts {
}
}
func buildIndexAccounts(session *jmap.Session, boot map[string]jmap.AccountBootstrapResult) []IndexAccount {
func buildIndexAccounts(session *jmap.Session, boot map[jmap.AccountId]jmap.AccountBootstrapResult) []IndexAccount {
accounts := make([]IndexAccount, len(session.Accounts))
i := 0
for accountId, account := range session.Accounts {
@@ -206,7 +206,7 @@ func buildIndexAccounts(session *jmap.Session, boot map[string]jmap.AccountBoots
accounts[i] = indexAccount
i++
}
slices.SortFunc(accounts, func(a, b IndexAccount) int { return strings.Compare(a.AccountId, b.AccountId) })
slices.SortFunc(accounts, func(a, b IndexAccount) int { return strings.Compare(string(a.AccountId), string(b.AccountId)) })
return accounts
}

View File

@@ -71,7 +71,7 @@ func (g *Groupware) GetMailboxes(w http.ResponseWriter, r *http.Request) { //NOS
return resp
}
logger := log.From(req.logger.With().Str(logAccountId, accountId))
logger := log.From(req.logger.With().Str(logAccountId, log.SafeString(accountId)))
ctx := req.ctx.WithLogger(logger)
if hasCriteria {
@@ -106,7 +106,7 @@ func (g *Groupware) GetMailboxesForAllAccounts(w http.ResponseWriter, r *http.Re
if len(accountIds) < 1 {
return req.noopN(nil) // when the user has no accounts
}
logger := log.From(req.logger.With().Array(logAccountId, log.SafeStringArray(accountIds)))
logger := log.From(req.logger.With().Array(logAccountId, log.SafeStringArray(structs.ToStrings(accountIds))))
ctx := req.ctx.WithLogger(logger)
var filter jmap.MailboxFilterCondition
@@ -153,7 +153,7 @@ func (g *Groupware) GetMailboxByRoleForAllAccounts(w http.ResponseWriter, r *htt
return req.errorN(accountIds, err)
}
logger := log.From(req.logger.With().Array(logAccountId, log.SafeStringArray(accountIds)).Str("role", role))
logger := log.From(req.logger.With().Array(logAccountId, log.SafeStringArray(structs.ToStrings(accountIds))).Str("role", role))
ctx := req.ctx.WithLogger(logger)
filter := jmap.MailboxFilterCondition{
@@ -180,7 +180,7 @@ func (g *Groupware) GetMailboxChangesForAllAccounts(w http.ResponseWriter, r *ht
l := req.logger.With()
allAccountIds := req.AllAccountIds()
l.Array(logAccountId, log.SafeStringArray(allAccountIds))
l.Array(logAccountId, log.SafeStringArray(structs.ToStrings(allAccountIds)))
sinceStateStrMap, ok, err := req.parseMapParam(QueryParamSince)
if err != nil {
@@ -205,7 +205,7 @@ func (g *Groupware) GetMailboxChangesForAllAccounts(w http.ResponseWriter, r *ht
logger := log.From(l)
ctx := req.ctx.WithLogger(logger)
sinceStateMap := structs.MapValues(sinceStateStrMap, toState)
sinceStateMap := structs.MapMap(sinceStateStrMap, toAccountIdState)
result, jerr := g.jmap.GetMailboxChangesForMultipleAccounts(allAccountIds, sinceStateMap, maxChanges, ctx)
if jerr != nil {
return req.jmapErrorN(allAccountIds, jerr, result)
@@ -221,7 +221,7 @@ func (g *Groupware) GetMailboxRoles(w http.ResponseWriter, r *http.Request) {
g.respond(w, r, func(req Request) Response {
l := req.logger.With()
allAccountIds := req.AllAccountIds()
l.Array(logAccountId, log.SafeStringArray(allAccountIds))
l.Array(logAccountId, log.SafeStringArray(structs.ToStrings(allAccountIds)))
logger := log.From(l)
ctx := req.ctx.WithLogger(logger)
@@ -257,8 +257,8 @@ func scoreMailbox(m jmap.Mailbox) int {
return 1000
}
func sortMailboxesMap(mailboxesByAccountId map[string][]jmap.Mailbox) map[string][]jmap.Mailbox {
sortedByAccountId := make(map[string][]jmap.Mailbox, len(mailboxesByAccountId))
func sortMailboxesMap(mailboxesByAccountId map[jmap.AccountId][]jmap.Mailbox) map[jmap.AccountId][]jmap.Mailbox {
sortedByAccountId := make(map[jmap.AccountId][]jmap.Mailbox, len(mailboxesByAccountId))
for accountId, unsorted := range mailboxesByAccountId {
mailboxes := make([]jmap.Mailbox, len(unsorted))
copy(mailboxes, unsorted)

View File

@@ -45,7 +45,7 @@ func (g *Groupware) GetObjects(w http.ResponseWriter, r *http.Request) { //NOSON
if err != nil {
return req.error(accountId, err)
}
l = l.Str(logAccountId, accountId)
l = l.Str(logAccountId, log.SafeString(accountId))
mailboxIds := []string{}
emailIds := []string{}

View File

@@ -5,6 +5,7 @@ import (
"github.com/opencloud-eu/opencloud/pkg/jmap"
"github.com/opencloud-eu/opencloud/pkg/log"
"github.com/opencloud-eu/opencloud/pkg/structs"
)
// Get quota limits.
@@ -13,7 +14,7 @@ import (
//
// Note that there may be multiple Quota objects for different resource types.
func (g *Groupware) GetQuota(w http.ResponseWriter, r *http.Request) {
getFromMap(Quota, w, r, g, func(accountIds, _ []string, ctx jmap.Context) (jmap.Result[map[string]jmap.QuotaGetResponse], error) {
getFromMap(Quota, w, r, g, func(accountIds []jmap.AccountId, _ []string, ctx jmap.Context) (jmap.Result[map[jmap.AccountId]jmap.QuotaGetResponse], error) {
return g.jmap.GetQuotas(accountIds, ctx)
})
}
@@ -33,7 +34,7 @@ func (g *Groupware) GetQuotaForAllAccounts(w http.ResponseWriter, r *http.Reques
if len(accountIds) < 1 {
return req.noopN(accountIds) // user has no accounts
}
logger := log.From(req.logger.With().Array(logAccountId, log.SafeStringArray(accountIds)))
logger := log.From(req.logger.With().Array(logAccountId, log.SafeStringArray(structs.ToStrings(accountIds))))
ctx := req.ctx.WithLogger(logger)
result, jerr := g.jmap.GetQuotas(accountIds, ctx)
@@ -41,7 +42,7 @@ func (g *Groupware) GetQuotaForAllAccounts(w http.ResponseWriter, r *http.Reques
return req.jmapErrorN(accountIds, jerr, result)
}
body := make(map[string]AccountQuota, len(result.Payload))
body := make(map[jmap.AccountId]AccountQuota, len(result.Payload))
for accountId, accountQuotas := range result.Payload {
body[accountId] = AccountQuota{
State: accountQuotas.State,

View File

@@ -13,7 +13,7 @@ func (g *Groupware) GetTaskLists(w http.ResponseWriter, r *http.Request) {
if !ok {
return resp
}
var _ string = accountId
var _ jmap.AccountId = accountId
var body []jmap.TaskList = AllTaskLists
meta := TaskListsMeta{SessionState: req.session.State}
@@ -28,7 +28,7 @@ func (g *Groupware) GetTaskListById(w http.ResponseWriter, r *http.Request) {
if !ok {
return resp
}
var _ string = accountId
var _ jmap.AccountId = accountId
tasklistId, err := req.PathParam(UriParamTaskListId)
if err != nil {
@@ -52,7 +52,7 @@ func (g *Groupware) GetTasksInTaskList(w http.ResponseWriter, r *http.Request) {
if !ok {
return resp
}
var _ string = accountId
var _ jmap.AccountId = accountId
tasklistId, err := req.PathParam(UriParamTaskListId)
if err != nil {

View File

@@ -13,7 +13,7 @@ import (
//
// The VacationResponse object represents the state of vacation-response-related settings for an account.
func (g *Groupware) GetVacation(w http.ResponseWriter, r *http.Request) {
get(VacationResponse, w, r, g, func(accountId string, ids []string, ctx jmap.Context) (jmap.Result[jmap.VacationResponseGetResponse], error) {
get(VacationResponse, w, r, g, func(accountId jmap.AccountId, ids []string, ctx jmap.Context) (jmap.Result[jmap.VacationResponseGetResponse], error) {
return g.jmap.GetVacationResponse(accountId, ctx)
})
}
@@ -23,7 +23,7 @@ func (g *Groupware) GetVacation(w http.ResponseWriter, r *http.Request) {
// A vacation response sends an automatic reply when a message is delivered to the mail store, informing the original
// sender that their message may not be read for some time.
func (g *Groupware) SetVacation(w http.ResponseWriter, r *http.Request) {
modify(VacationResponse, w, r, g, func(accountId string, id string, change jmap.VacationResponseChange, ctx jmap.Context) (jmap.Result[jmap.VacationResponse], error) {
modify(VacationResponse, w, r, g, func(accountId jmap.AccountId, id string, change jmap.VacationResponseChange, ctx jmap.Context) (jmap.Result[jmap.VacationResponse], error) {
return g.jmap.SetVacationResponse(accountId, change, ctx)
})
}

View File

@@ -750,19 +750,19 @@ func errorResponses(errors ...Error) ErrorResponse {
return ErrorResponse{Errors: errors}
}
func (r *Request) error(accountId string, err *Error) Response {
func (r *Request) error(accountId jmap.AccountId, err *Error) Response {
return errorResponse(single(accountId), err, r.session.State, jmap.NoLanguage)
}
func (r *Request) errorS(accountId string, err *Error, result jmap.ResultMetadata) Response {
func (r *Request) errorS(accountId jmap.AccountId, err *Error, result jmap.ResultMetadata) Response {
return errorResponse(single(accountId), err, result.GetSessionState(), result.GetLanguage())
}
func (r *Request) errorN(accountIds []string, err *Error) Response {
func (r *Request) errorN(accountIds []jmap.AccountId, err *Error) Response {
return errorResponse(accountIds, err, r.session.State, jmap.NoLanguage)
}
func (r *Request) jmapError(accountId string, err error, result jmap.ResultMetadata) Response {
func (r *Request) jmapError(accountId jmap.AccountId, err error, result jmap.ResultMetadata) Response {
switch e := err.(type) {
case jmap.Error:
if result != nil {
@@ -779,7 +779,7 @@ func (r *Request) jmapError(accountId string, err error, result jmap.ResultMetad
}
}
func (r *Request) jmapErrorN(accountIds []string, err error, result jmap.ResultMetadata) Response {
func (r *Request) jmapErrorN(accountIds []jmap.AccountId, err error, result jmap.ResultMetadata) Response {
switch e := err.(type) {
case jmap.Error:
if result != nil {

View File

@@ -27,8 +27,8 @@ func (e Exemplar) AccountQuota() AccountQuota {
}
}
func (e Exemplar) AccountQuotaMap() map[string]AccountQuota {
return map[string]AccountQuota{
func (e Exemplar) AccountQuotaMap() map[jmap.AccountId]AccountQuota {
return map[jmap.AccountId]AccountQuota{
j.AccountId: e.AccountQuota(),
}
}
@@ -148,23 +148,23 @@ func (e Exemplar) ErrorResponse() ErrorResponse {
}
}
func (e Exemplar) MailboxesByAccountId() (map[string][]jmap.Mailbox, string) {
func (e Exemplar) MailboxesByAccountId() (map[jmap.AccountId][]jmap.Mailbox, string) {
j := jmap.ExemplarInstance
return map[string][]jmap.Mailbox{
return map[jmap.AccountId][]jmap.Mailbox{
j.AccountId: j.Mailboxes(),
}, "All mailboxes for all accounts, without a role filter"
}
func (e Exemplar) MailboxesByAccountIdFilteredOnInboxRole() (map[string][]jmap.Mailbox, string, string) {
func (e Exemplar) MailboxesByAccountIdFilteredOnInboxRole() (map[jmap.AccountId][]jmap.Mailbox, string, string) {
j := jmap.ExemplarInstance
return map[string][]jmap.Mailbox{
return map[jmap.AccountId][]jmap.Mailbox{
j.AccountId: structs.Filter(j.Mailboxes(), func(m jmap.Mailbox) bool { return m.Role == jmap.JmapMailboxRoleInbox }),
}, "All mailboxes for all accounts, filtered on the 'inbox' role", "inboxrole"
}
func (e Exemplar) MailboxRolesByAccounts() (map[string][]string, string, string, string) {
func (e Exemplar) MailboxRolesByAccounts() (map[jmap.AccountId][]string, string, string, string) {
j := jmap.ExemplarInstance
return map[string][]string{
return map[jmap.AccountId][]string{
j.AccountId: jmap.JmapMailboxRoles,
j.SharedAccountId: jmap.JmapMailboxRoles,
}, "Roles of the Mailboxes of each Account", "", "mailboxrolesbyaccount"

View File

@@ -25,6 +25,7 @@ import (
"github.com/opencloud-eu/opencloud/pkg/jmap"
"github.com/opencloud-eu/opencloud/pkg/log"
"github.com/opencloud-eu/opencloud/pkg/structs"
"github.com/opencloud-eu/opencloud/services/groupware/pkg/config"
"github.com/opencloud-eu/opencloud/services/groupware/pkg/metrics"
@@ -778,10 +779,9 @@ func (g *Groupware) sendResponse(w http.ResponseWriter, r *http.Request, respons
case 0:
break
case 1:
w.Header().Add(AccountIdResponseHeader, response.accountIds[0])
w.Header().Add(AccountIdResponseHeader, string(response.accountIds[0]))
default:
c := make([]string, len(response.accountIds))
copy(c, response.accountIds)
c := structs.Map(response.accountIds, func(a jmap.AccountId) string { return string(a) })
slices.Sort(c)
value := strings.Join(c, ",")
w.Header().Add(AccountIdsResponseHeader, value)
@@ -890,12 +890,12 @@ func single[S any](s S) []S {
}
type QueryParamsSupplier interface {
ForSupplier(supplierId string, accountId string) (jmap.QueryParams, bool, error)
ForAccountId(accountId string) (jmap.QueryParams, bool, error)
ForSupplier(supplierId SupplierId, accountId jmap.AccountId) (jmap.QueryParams, bool, error)
ForAccountId(accountId jmap.AccountId) (jmap.QueryParams, bool, error)
}
func mapQueryParams(supplierId string, accountIds []string, qps QueryParamsSupplier) (map[string]jmap.QueryParams, error) {
m := map[string]jmap.QueryParams{}
func mapQueryParams(supplierId SupplierId, accountIds []jmap.AccountId, qps QueryParamsSupplier) (map[jmap.AccountId]jmap.QueryParams, error) {
m := map[jmap.AccountId]jmap.QueryParams{}
if supplierId == "" {
for _, accountId := range accountIds {
if q, ok, err := qps.ForAccountId(accountId); err != nil {
@@ -920,11 +920,11 @@ type ErrorQueryParamsSupplier struct {
err error
}
func (s ErrorQueryParamsSupplier) ForSupplier(supplierId string, accountId string) (jmap.QueryParams, bool, error) {
func (s ErrorQueryParamsSupplier) ForSupplier(supplierId SupplierId, accountId jmap.AccountId) (jmap.QueryParams, bool, error) {
return jmap.NullQueryParams, false, s.err
}
func (s ErrorQueryParamsSupplier) ForAccountId(accountId string) (jmap.QueryParams, bool, error) {
func (s ErrorQueryParamsSupplier) ForAccountId(accountId jmap.AccountId) (jmap.QueryParams, bool, error) {
return jmap.NullQueryParams, false, s.err
}
@@ -933,11 +933,11 @@ var _ QueryParamsSupplier = ErrorQueryParamsSupplier{}
type FirstQueryParamsSupplier struct {
}
func (s FirstQueryParamsSupplier) ForSupplier(supplierId string, accountId string) (jmap.QueryParams, bool, error) {
func (s FirstQueryParamsSupplier) ForSupplier(supplierId SupplierId, accountId jmap.AccountId) (jmap.QueryParams, bool, error) {
return jmap.NullQueryParams, true, nil
}
func (s FirstQueryParamsSupplier) ForAccountId(accountId string) (jmap.QueryParams, bool, error) {
func (s FirstQueryParamsSupplier) ForAccountId(accountId jmap.AccountId) (jmap.QueryParams, bool, error) {
return jmap.NullQueryParams, true, nil
}
@@ -947,21 +947,21 @@ type StaticQueryParamsSupplier struct {
qp jmap.QueryParams
}
func (s StaticQueryParamsSupplier) ForSupplier(supplierId string, accountId string) (jmap.QueryParams, bool, error) {
func (s StaticQueryParamsSupplier) ForSupplier(supplierId SupplierId, accountId jmap.AccountId) (jmap.QueryParams, bool, error) {
return s.qp, true, nil
}
func (s StaticQueryParamsSupplier) ForAccountId(accountId string) (jmap.QueryParams, bool, error) {
func (s StaticQueryParamsSupplier) ForAccountId(accountId jmap.AccountId) (jmap.QueryParams, bool, error) {
return s.qp, true, nil
}
var _ QueryParamsSupplier = StaticQueryParamsSupplier{}
type MultiSupplierQueryParamsSupplier struct {
m map[string]map[string]jmap.QueryParams
m map[SupplierId]map[jmap.AccountId]jmap.QueryParams
}
func (s MultiSupplierQueryParamsSupplier) ForSupplier(supplierId string, accountId string) (jmap.QueryParams, bool, error) {
func (s MultiSupplierQueryParamsSupplier) ForSupplier(supplierId SupplierId, accountId jmap.AccountId) (jmap.QueryParams, bool, error) {
if a, ok := s.m[supplierId]; ok {
if b, ok := a[accountId]; ok {
return b, true, nil
@@ -970,7 +970,7 @@ func (s MultiSupplierQueryParamsSupplier) ForSupplier(supplierId string, account
return jmap.NullQueryParams, false, nil
}
func (s MultiSupplierQueryParamsSupplier) ForAccountId(accountId string) (jmap.QueryParams, bool, error) {
func (s MultiSupplierQueryParamsSupplier) ForAccountId(accountId jmap.AccountId) (jmap.QueryParams, bool, error) {
switch len(s.m) {
case 1:
for _, v := range s.m {
@@ -989,14 +989,14 @@ func (s MultiSupplierQueryParamsSupplier) ForAccountId(accountId string) (jmap.Q
var _ QueryParamsSupplier = MultiSupplierQueryParamsSupplier{}
type SingleSupplierQueryParamsSupplier struct {
m map[string]jmap.QueryParams
m map[jmap.AccountId]jmap.QueryParams
}
func (s SingleSupplierQueryParamsSupplier) ForSupplier(supplierId string, accountId string) (jmap.QueryParams, bool, error) {
func (s SingleSupplierQueryParamsSupplier) ForSupplier(supplierId SupplierId, accountId jmap.AccountId) (jmap.QueryParams, bool, error) {
return jmap.NullQueryParams, false, fmt.Errorf("unable to provide for supplier with single supplier token")
}
func (s SingleSupplierQueryParamsSupplier) ForAccountId(accountId string) (jmap.QueryParams, bool, error) {
func (s SingleSupplierQueryParamsSupplier) ForAccountId(accountId jmap.AccountId) (jmap.QueryParams, bool, error) {
if b, ok := s.m[accountId]; ok {
return b, true, nil
}

View File

@@ -26,8 +26,8 @@ var TL1 = jmap.TaskList{
WorkflowStatuses: []string{
"new", "todo", "in-progress", "done",
},
ShareWith: map[string]jmap.TaskRights{
"eefeeb4p": {
ShareWith: map[jmap.PrincipalId]jmap.TaskRights{
jmap.PrincipalId("eefeeb4p"): {
MayReadItems: true,
MayWriteAll: false,
MayWriteOwn: true,

View File

@@ -13,7 +13,7 @@ type NextToken string
const NoNextToken = NextToken("")
func nextSingle(m map[string]jmap.QueryParams) (NextToken, error) {
func nextSingle(m map[jmap.AccountId]jmap.QueryParams) (NextToken, error) {
if b, err := json.Marshal(m); err != nil {
return NoNextToken, err
} else {
@@ -21,7 +21,7 @@ func nextSingle(m map[string]jmap.QueryParams) (NextToken, error) {
}
}
func nextMulti(m map[string]map[string]jmap.QueryParams) (NextToken, error) {
func nextMulti(m map[SupplierId]map[jmap.AccountId]jmap.QueryParams) (NextToken, error) {
if b, err := json.Marshal(m); err != nil {
return NoNextToken, err
} else {
@@ -42,7 +42,7 @@ func unnext(n NextToken) (QueryParamsSupplier, error) {
if b, err := DecodeBytesFromBase62(payload); err != nil {
return ErrorQueryParamsSupplier{err: err}, err
} else {
var m map[string]jmap.QueryParams
var m map[jmap.AccountId]jmap.QueryParams
if err := json.Unmarshal(b, &m); err != nil {
return ErrorQueryParamsSupplier{err: err}, err
} else {
@@ -54,7 +54,7 @@ func unnext(n NextToken) (QueryParamsSupplier, error) {
if b, err := DecodeBytesFromBase62(payload); err != nil {
return ErrorQueryParamsSupplier{err: err}, err
} else {
var m map[string]map[string]jmap.QueryParams
var m map[SupplierId]map[jmap.AccountId]jmap.QueryParams
if err := json.Unmarshal(b, &m); err != nil {
return ErrorQueryParamsSupplier{err: err}, err
} else {
@@ -68,11 +68,11 @@ func unnext(n NextToken) (QueryParamsSupplier, error) {
}
func curryNoNextMapQuery[SRES jmap.SearchResults[T], T jmap.Idable, FILTER any, COMP any](
f func(accountIds map[string]jmap.QueryParams, limit *uint, filter FILTER, sortBy []COMP, calculateTotal bool, ctx jmap.Context) (jmap.Result[map[string]SRES], error),
f func(accountIds map[jmap.AccountId]jmap.QueryParams, limit *uint, filter FILTER, sortBy []COMP, calculateTotal bool, ctx jmap.Context) (jmap.Result[map[jmap.AccountId]SRES], error),
sorter func(a, b T) int,
searchResultCtor func(canCalculateChanges jmap.ChangeCalculation, position *uint, limit *uint, total *uint, results []T) SRES,
) func(req Request, accountIds []string, qps QueryParamsSupplier, limit *uint, filter FILTER, sortBy []COMP, ctx jmap.Context) (jmap.Result[SRES], NextToken, error) {
return func(_ Request, accountIds []string, qps QueryParamsSupplier, limit *uint, filter FILTER, sortBy []COMP, ctx jmap.Context) (jmap.Result[SRES], NextToken, error) { //NOSONAR
) func(req Request, accountIds []jmap.AccountId, qps QueryParamsSupplier, limit *uint, filter FILTER, sortBy []COMP, ctx jmap.Context) (jmap.Result[SRES], NextToken, error) {
return func(_ Request, accountIds []jmap.AccountId, qps QueryParamsSupplier, limit *uint, filter FILTER, sortBy []COMP, ctx jmap.Context) (jmap.Result[SRES], NextToken, error) { //NOSONAR
if m, err := mapQueryParams("", accountIds, qps); err != nil {
return jmap.ZeroResult[SRES](), NoNextToken, err
} else {
@@ -80,7 +80,7 @@ func curryNoNextMapQuery[SRES jmap.SearchResults[T], T jmap.Idable, FILTER any,
if err != nil {
return jmap.ZeroResult[SRES](), NoNextToken, err
} else {
singleAccountId := ""
var singleAccountId jmap.AccountId = ""
// TODO what about requests with zero accountIds, can these even happen at all?
if len(accountIds) == 1 {
// optimization: no need to combine the results of several accounts if the query was
@@ -91,14 +91,14 @@ func curryNoNextMapQuery[SRES jmap.SearchResults[T], T jmap.Idable, FILTER any,
// all accounts: let's first calculate the number of results we have for each account
totalByAccount := structs.MapValues(result.Payload, func(a SRES) int { return len(a.GetResults()) })
// and let's now pick out the accounts that do have results
accountsWithResults := structs.FilterKeys(totalByAccount, func(_ string, total int) bool { return total > 0 })
accountsWithResults := structs.FilterKeys(totalByAccount, func(_ jmap.AccountId, total int) bool { return total > 0 })
if len(accountsWithResults) == 1 {
singleAccountId = accountsWithResults[0]
}
// TODO what if we don't have any results at all? (accountsWithResults == 0)
}
if singleAccountId != "" {
r, err := jmap.RefineResultPayload(result, func(a map[string]SRES) (SRES, bool, error) {
r, err := jmap.RefineResultPayload(result, func(a map[jmap.AccountId]SRES) (SRES, bool, error) {
r, ok := a[accountIds[0]]
return r, ok, nil
})
@@ -113,10 +113,10 @@ func curryNoNextMapQuery[SRES jmap.SearchResults[T], T jmap.Idable, FILTER any,
}
func flattenMultipleAccounts[SRES jmap.SearchResults[T], T jmap.Idable](
accountIds []string,
accountIds []jmap.AccountId,
qps QueryParamsSupplier,
limit *uint,
result jmap.Result[map[string]SRES],
result jmap.Result[map[jmap.AccountId]SRES],
sorter func(a, b T) int,
searchResultCtor func(canCalculateChanges jmap.ChangeCalculation, position *uint, limit *uint, total *uint, results []T) SRES,
) (jmap.Result[SRES], NextToken, error) {
@@ -133,7 +133,7 @@ func flattenMultipleAccounts[SRES jmap.SearchResults[T], T jmap.Idable](
cc := true
total := uint(0)
lastByAccountId := map[string]string{}
lastByAccountId := map[jmap.AccountId]string{}
for accountId, searchResult := range result.Payload {
if !searchResult.GetCanCalculateChanges() {
cc = false
@@ -150,7 +150,7 @@ func flattenMultipleAccounts[SRES jmap.SearchResults[T], T jmap.Idable](
// 4. we need to build the NextToken by taking the ID of the last item
// we kept after shrinking, but separately for each accountId
n := map[string]jmap.QueryParams{}
n := map[jmap.AccountId]jmap.QueryParams{}
for accountId, lastId := range lastByAccountId {
n[accountId] = jmap.QueryParams{Anchor: lastId, AnchorOffset: ptr(1)}
}
@@ -160,7 +160,7 @@ func flattenMultipleAccounts[SRES jmap.SearchResults[T], T jmap.Idable](
if t, err := nextSingle(n); err != nil {
return jmap.ZeroResult[SRES](), NoNextToken, err
} else {
if r, err := jmap.RefineResultPayload(result, func(a map[string]SRES) (SRES, bool, error) {
if r, err := jmap.RefineResultPayload(result, func(a map[jmap.AccountId]SRES) (SRES, bool, error) {
return searchResultCtor(jmap.ChangeCalculation(cc), nil, limit, &total, all), true, nil
}); err != nil {
return jmap.ZeroResult[SRES](), NoNextToken, err
@@ -184,7 +184,7 @@ func flattenMultipleAccounts[SRES jmap.SearchResults[T], T jmap.Idable](
// no need to compute a NextToken since there was no limit,
// which means that this Result contains all the elements,
// and thus there is no "next" to query for
if r, err := jmap.RefineResultPayload(result, func(a map[string]SRES) (SRES, bool, error) {
if r, err := jmap.RefineResultPayload(result, func(a map[jmap.AccountId]SRES) (SRES, bool, error) {
return searchResultCtor(jmap.ChangeCalculation(cc), nil, limit, &total, all), true, nil
}); err != nil {
return jmap.ZeroResult[SRES](), NoNextToken, err

View File

@@ -10,7 +10,7 @@ type ObjectType[T jmap.Foo, CH jmap.Change, CHS jmap.Changes[T]] struct {
responseType ResponseObjectType
uriParamName string
containerUriParamName string
accountFunc func(r *Request) (bool, string, Response)
accountFunc func(r *Request) (bool, jmap.AccountId, Response)
failedToDeleteError GroupwareError
}

View File

@@ -45,8 +45,8 @@ type Request struct {
ctx jmap.Context
}
func isDefaultAccountId(accountId string) bool {
return slices.Contains(defaultAccountIds, accountId)
func isDefaultAccountId(accountId jmap.AccountId) bool {
return slices.Contains(defaultAccountIds, string(accountId))
}
func (r *Request) push(typ string, event any) {
@@ -129,13 +129,13 @@ func (r *Request) PathListParamDoc(name string, _ string) ([]string, *Error) {
return strings.Split(value, ","), nil
}
func (r *Request) AllAccountIds() []string {
func (r *Request) AllAccountIds() []jmap.AccountId {
// TODO potentially filter on "subscribed" accounts?
return structs.Uniq(structs.Keys(r.session.Accounts))
}
func (r *Request) GetAccountIdWithoutFallback() (string, *Error) {
accountId := chi.URLParam(r.r, UriParamAccountId)
func (r *Request) GetAccountIdWithoutFallback() (jmap.AccountId, *Error) {
accountId := jmap.AccountId(chi.URLParam(r.r, UriParamAccountId))
if accountId == "" || isDefaultAccountId(accountId) {
r.logger.Error().Err(errNoPrimaryAccountFallback).Msg("failed to determine the accountId")
return "", apiError(r.errorId(), ErrorNonExistingAccount,
@@ -146,8 +146,8 @@ func (r *Request) GetAccountIdWithoutFallback() (string, *Error) {
return accountId, nil
}
func (r *Request) getAccountId(fallback string, err error) (string, *Error) {
accountId := chi.URLParam(r.r, UriParamAccountId)
func (r *Request) getAccountId(fallback jmap.AccountId, err error) (jmap.AccountId, *Error) {
accountId := jmap.AccountId(chi.URLParam(r.r, UriParamAccountId))
if accountId == "" || isDefaultAccountId(accountId) {
accountId = fallback
}
@@ -161,45 +161,45 @@ func (r *Request) getAccountId(fallback string, err error) (string, *Error) {
return accountId, nil
}
func (r *Request) GetAccountIdForMail() (string, *Error) {
func (r *Request) GetAccountIdForMail() (jmap.AccountId, *Error) {
return r.getAccountId(r.session.PrimaryAccounts.Mail, errNoPrimaryAccountForMail)
}
func (r *Request) GetAccountIdForBlob() (string, *Error) {
func (r *Request) GetAccountIdForBlob() (jmap.AccountId, *Error) {
return r.getAccountId(r.session.PrimaryAccounts.Blob, errNoPrimaryAccountForBlob)
}
func (r *Request) GetAccountIdForVacationResponse() (string, *Error) {
func (r *Request) GetAccountIdForVacationResponse() (jmap.AccountId, *Error) {
return r.getAccountId(r.session.PrimaryAccounts.VacationResponse, errNoPrimaryAccountForVacationResponse)
}
func (r *Request) GetAccountIdForQuota() (string, *Error) {
func (r *Request) GetAccountIdForQuota() (jmap.AccountId, *Error) {
return r.getAccountId(r.session.PrimaryAccounts.Quota, errNoPrimaryAccountForQuota)
}
func (r *Request) GetAccountIdForSubmission() (string, *Error) {
func (r *Request) GetAccountIdForSubmission() (jmap.AccountId, *Error) {
return r.getAccountId(r.session.PrimaryAccounts.Blob, errNoPrimaryAccountForSubmission)
}
func (r *Request) GetAccountIdForTask() (string, *Error) {
func (r *Request) GetAccountIdForTask() (jmap.AccountId, *Error) {
// TODO we don't have these yet, not implemented in Stalwart
// return r.getAccountId(r.session.PrimaryAccounts.Task, errNoPrimaryAccountForTask)
return r.GetAccountIdForMail()
}
func (r *Request) GetAccountIdForCalendar() (string, *Error) {
func (r *Request) GetAccountIdForCalendar() (jmap.AccountId, *Error) {
// TODO we don't have these yet, not implemented in Stalwart
// return r.getAccountId(r.session.PrimaryAccounts.Calendar, errNoPrimaryAccountForCalendar)
return r.GetAccountIdForMail()
}
func (r *Request) GetAccountIdForContact() (string, *Error) {
func (r *Request) GetAccountIdForContact() (jmap.AccountId, *Error) {
// TODO we don't have these yet, not implemented in Stalwart
// return r.getAccountId(r.session.PrimaryAccounts.Contact, errNoPrimaryAccountForContact)
return r.GetAccountIdForMail()
}
func (r *Request) GetAccountForMail() (string, jmap.Account, *Error) {
func (r *Request) GetAccountForMail() (jmap.AccountId, jmap.Account, *Error) {
accountId, err := r.GetAccountIdForMail()
if err != nil {
return "", jmap.Account{}, err
@@ -210,7 +210,7 @@ func (r *Request) GetAccountForMail() (string, jmap.Account, *Error) {
r.logger.Debug().Msgf("failed to find account '%v'", accountId)
// TODO metric for inexistent accounts
return accountId, jmap.Account{}, apiError(r.errorId(), ErrorNonExistingAccount,
withDetail(fmt.Sprintf("The account '%v' does not exist", log.SafeString(accountId))),
withDetail(fmt.Sprintf("The account '%v' does not exist", log.SafeString(string(accountId)))),
withSource(&ErrorSource{Parameter: UriParamAccountId}),
)
}
@@ -223,11 +223,11 @@ func (r *Request) parameterError(param string, detail string) *Error {
withSource(&ErrorSource{Parameter: param}))
}
func (r *Request) parameterErrorResponse(accountId string, param string, detail string) Response {
func (r *Request) parameterErrorResponse(accountId jmap.AccountId, param string, detail string) Response {
return r.error(accountId, r.parameterError(param, detail))
}
func (r *Request) parameterErrorResponseN(accountIds []string, param string, detail string) Response {
func (r *Request) parameterErrorResponseN(accountIds []jmap.AccountId, param string, detail string) Response {
return r.errorN(accountIds, r.parameterError(param, detail))
}
@@ -239,7 +239,7 @@ func toSupportedQueryParams(params ...string) supportedQueryParams {
var noSupportedQueryParams supportedQueryParams = toSupportedQueryParams()
func (r *Request) unsupportedQueryParams(accountIds []string, allowed supportedQueryParams) (bool, Response) {
func (r *Request) unsupportedQueryParams(accountIds []jmap.AccountId, allowed supportedQueryParams) (bool, Response) {
q := r.r.URL.Query()
for n := range q {
if _, ok := allowed[n]; !ok {
@@ -470,14 +470,14 @@ func (r *Request) observeJmapError(jerr jmap.Error) jmap.Error {
return jerr
}
func (r *Request) needBlob(accountId string) (bool, Response) {
func (r *Request) needBlob(accountId jmap.AccountId) (bool, Response) {
if r.session.Capabilities.Blob == nil {
return false, errorResponse(single(accountId), r.apiError(&ErrorMissingBlobSessionCapability), r.session.State, jmap.NoLanguage)
}
return true, Response{}
}
func (r *Request) needBlobForAccount(accountId string) (bool, Response) {
func (r *Request) needBlobForAccount(accountId jmap.AccountId) (bool, Response) {
if ok, resp := r.needBlob(accountId); !ok {
return ok, resp
}
@@ -491,7 +491,7 @@ func (r *Request) needBlobForAccount(accountId string) (bool, Response) {
return true, Response{}
}
func (r *Request) needBloblWithAccount() (bool, string, Response) {
func (r *Request) needBloblWithAccount() (bool, jmap.AccountId, Response) {
accountId, err := r.GetAccountIdForBlob()
if err != nil {
return false, "", r.error(accountId, err)
@@ -502,14 +502,14 @@ func (r *Request) needBloblWithAccount() (bool, string, Response) {
return true, accountId, Response{}
}
func (r *Request) needMail(accountId string) (bool, Response) {
func (r *Request) needMail(accountId jmap.AccountId) (bool, Response) {
if r.session.Capabilities.Mail == nil {
return false, errorResponse(single(accountId), r.apiError(&ErrorMissingMailsSessionCapability), r.session.State, jmap.NoLanguage)
}
return true, Response{}
}
func (r *Request) needMailForAccount(accountId string) (bool, Response) {
func (r *Request) needMailForAccount(accountId jmap.AccountId) (bool, Response) {
if ok, resp := r.needMail(accountId); !ok {
return ok, resp
}
@@ -523,7 +523,7 @@ func (r *Request) needMailForAccount(accountId string) (bool, Response) {
return true, Response{}
}
func (r *Request) needMailWithAccount() (bool, string, Response) {
func (r *Request) needMailWithAccount() (bool, jmap.AccountId, Response) {
accountId, err := r.GetAccountIdForMail()
if err != nil {
return false, "", r.error(accountId, err)
@@ -534,7 +534,7 @@ func (r *Request) needMailWithAccount() (bool, string, Response) {
return true, accountId, Response{}
}
func (r *Request) needTask(accountId string) (bool, Response) {
func (r *Request) needTask(accountId jmap.AccountId) (bool, Response) {
if !IgnoreSessionCapabilityChecksForTasks {
if r.session.Capabilities.Tasks == nil {
return false, errorResponse(single(accountId), r.apiError(&ErrorMissingTasksSessionCapability), r.session.State, jmap.Language(r.language()))
@@ -543,7 +543,7 @@ func (r *Request) needTask(accountId string) (bool, Response) {
return true, Response{}
}
func (r *Request) needTaskForAccount(accountId string) (bool, Response) {
func (r *Request) needTaskForAccount(accountId jmap.AccountId) (bool, Response) {
if ok, resp := r.needTask(accountId); !ok {
return ok, resp
}
@@ -557,7 +557,7 @@ func (r *Request) needTaskForAccount(accountId string) (bool, Response) {
return true, Response{}
}
func (r *Request) needTaskWithAccount() (bool, string, Response) {
func (r *Request) needTaskWithAccount() (bool, jmap.AccountId, Response) {
accountId, err := r.GetAccountIdForTask()
if err != nil {
return false, "", r.error(accountId, err)
@@ -568,14 +568,14 @@ func (r *Request) needTaskWithAccount() (bool, string, Response) {
return true, accountId, Response{}
}
func (r *Request) needCalendar(accountId string) (bool, Response) {
func (r *Request) needCalendar(accountId jmap.AccountId) (bool, Response) {
if r.session.Capabilities.Calendars == nil {
return false, errorResponse(single(accountId), r.apiError(&ErrorMissingCalendarsSessionCapability), r.session.State, jmap.NoLanguage)
}
return true, Response{}
}
func (r *Request) needCalendarForAccount(accountId string) (bool, Response) {
func (r *Request) needCalendarForAccount(accountId jmap.AccountId) (bool, Response) {
if ok, resp := r.needCalendar(accountId); !ok {
return ok, resp
}
@@ -589,7 +589,7 @@ func (r *Request) needCalendarForAccount(accountId string) (bool, Response) {
return true, Response{}
}
func (r *Request) needCalendarWithAccount() (bool, string, Response) {
func (r *Request) needCalendarWithAccount() (bool, jmap.AccountId, Response) {
accountId, err := r.GetAccountIdForCalendar()
if err != nil {
return false, "", r.error(accountId, err)
@@ -600,14 +600,14 @@ func (r *Request) needCalendarWithAccount() (bool, string, Response) {
return true, accountId, Response{}
}
func (r *Request) needContact(accountId string) (bool, Response) {
func (r *Request) needContact(accountId jmap.AccountId) (bool, Response) {
if r.session.Capabilities.Contacts == nil {
return false, errorResponse(single(accountId), r.apiError(&ErrorMissingContactsSessionCapability), r.session.State, jmap.NoLanguage)
}
return true, Response{}
}
func (r *Request) needContactForAccount(accountId string) (bool, Response) {
func (r *Request) needContactForAccount(accountId jmap.AccountId) (bool, Response) {
if ok, resp := r.needContact(accountId); !ok {
return ok, resp
}
@@ -621,7 +621,7 @@ func (r *Request) needContactForAccount(accountId string) (bool, Response) {
return true, Response{}
}
func (r *Request) needContactWithAccount() (bool, string, Response) {
func (r *Request) needContactWithAccount() (bool, jmap.AccountId, Response) {
accountId, err := r.GetAccountIdForContact()
if err != nil {
return false, "", r.error(accountId, err)
@@ -632,14 +632,14 @@ func (r *Request) needContactWithAccount() (bool, string, Response) {
return true, accountId, Response{}
}
func (r *Request) needQuota(accountId string) (bool, Response) {
func (r *Request) needQuota(accountId jmap.AccountId) (bool, Response) {
if r.session.Capabilities.Quota == nil {
return false, errorResponse(single(accountId), r.apiError(&ErrorMissingQuotaSessionCapability), r.session.State, jmap.NoLanguage)
}
return true, Response{}
}
func (r *Request) needQuotaForAccount(accountId string) (bool, Response) {
func (r *Request) needQuotaForAccount(accountId jmap.AccountId) (bool, Response) {
if ok, resp := r.needQuota(accountId); !ok {
return ok, resp
}
@@ -653,7 +653,7 @@ func (r *Request) needQuotaForAccount(accountId string) (bool, Response) {
return true, Response{}
}
func (r *Request) needQuotaWithAccount() (bool, string, Response) {
func (r *Request) needQuotaWithAccount() (bool, jmap.AccountId, Response) {
accountId, err := r.GetAccountIdForQuota()
if err != nil {
return false, "", r.error(accountId, err)
@@ -707,3 +707,7 @@ func (r *Request) parseSort(s string, props []string) ([]SortCrit, *Error) {
func toState(s string) jmap.State {
return jmap.State(s)
}
func toAccountIdState(accountId string, state string) (jmap.AccountId, jmap.State) {
return jmap.AccountId(accountId), jmap.State(state)
}

View File

@@ -32,13 +32,13 @@ type Response struct {
err *Error
etag jmap.State
objectType ResponseObjectType
accountIds []string
accountIds []jmap.AccountId
sessionState jmap.SessionState
contentLanguage jmap.Language
next NextToken
}
func errorResponse(accountIds []string, err *Error, sessionState jmap.SessionState, contentLanguage jmap.Language) Response {
func errorResponse(accountIds []jmap.AccountId, err *Error, sessionState jmap.SessionState, contentLanguage jmap.Language) Response {
return Response{
accountIds: accountIds,
body: nil,
@@ -50,7 +50,7 @@ func errorResponse(accountIds []string, err *Error, sessionState jmap.SessionSta
}
}
func response(accountIds []string, body any, sessionState jmap.SessionState, contentLanguage jmap.Language) Response {
func response(accountIds []jmap.AccountId, body any, sessionState jmap.SessionState, contentLanguage jmap.Language) Response {
return Response{
accountIds: accountIds,
body: body,
@@ -62,11 +62,11 @@ func response(accountIds []string, body any, sessionState jmap.SessionState, con
}
}
func (r *Request) respondWithoutStatus(accountId string, body any) Response {
func (r *Request) respondWithoutStatus(accountId jmap.AccountId, body any) Response {
return response(single(accountId), body, r.session.State, jmap.Language(r.language()))
}
func etaggedResponse(accountIds []string, body any, sessionState jmap.SessionState, objectType ResponseObjectType, etag jmap.State, contentLanguage jmap.Language) Response {
func etaggedResponse(accountIds []jmap.AccountId, body any, sessionState jmap.SessionState, objectType ResponseObjectType, etag jmap.State, contentLanguage jmap.Language) Response {
return Response{
accountIds: accountIds,
body: body,
@@ -79,15 +79,15 @@ func etaggedResponse(accountIds []string, body any, sessionState jmap.SessionSta
}
}
func (r *Request) respond(accountId string, body any, objectType ResponseObjectType, result jmap.ResultMetadata) Response {
func (r *Request) respond(accountId jmap.AccountId, body any, objectType ResponseObjectType, result jmap.ResultMetadata) Response {
return etaggedResponse(single(accountId), body, result.GetSessionState(), objectType, result.GetState(), result.GetLanguage())
}
func (r *Request) respondN(accountIds []string, body any, objectType ResponseObjectType, result jmap.ResultMetadata) Response {
func (r *Request) respondN(accountIds []jmap.AccountId, body any, objectType ResponseObjectType, result jmap.ResultMetadata) Response {
return etaggedResponse(accountIds, body, result.GetSessionState(), objectType, result.GetState(), result.GetLanguage())
}
func etaggedNextResponse(accountIds []string, body any, sessionState jmap.SessionState, objectType ResponseObjectType, etag jmap.State, contentLanguage jmap.Language, next NextToken) Response {
func etaggedNextResponse(accountIds []jmap.AccountId, body any, sessionState jmap.SessionState, objectType ResponseObjectType, etag jmap.State, contentLanguage jmap.Language, next NextToken) Response {
return Response{
accountIds: accountIds,
body: body,
@@ -100,7 +100,7 @@ func etaggedNextResponse(accountIds []string, body any, sessionState jmap.Sessio
}
}
func (r *Request) respondNext(accountId string, body any, objectType ResponseObjectType, result jmap.ResultMetadata, next NextToken) Response {
func (r *Request) respondNext(accountId jmap.AccountId, body any, objectType ResponseObjectType, result jmap.ResultMetadata, next NextToken) Response {
return etaggedNextResponse(single(accountId), body, result.GetSessionState(), objectType, result.GetState(), result.GetLanguage(), next)
}
@@ -117,7 +117,7 @@ func etagOnlyResponse(body any, etag jmap.State, objectType ResponseObjectType,
}
*/
func noContentResponse(accountIds []string, sessionState jmap.SessionState) Response {
func noContentResponse(accountIds []jmap.AccountId, sessionState jmap.SessionState) Response {
return Response{
accountIds: accountIds,
body: nil,
@@ -129,15 +129,15 @@ func noContentResponse(accountIds []string, sessionState jmap.SessionState) Resp
}
}
func (r *Request) noop(accountId string) Response {
func (r *Request) noop(accountId jmap.AccountId) Response {
return noContentResponse(single(accountId), r.session.State)
}
func (r *Request) noopN(accountIds []string) Response {
func (r *Request) noopN(accountIds []jmap.AccountId) Response {
return noContentResponse(accountIds, r.session.State)
}
func noContentResponseWithEtag(accountIds []string, sessionState jmap.SessionState, objectType ResponseObjectType, etag jmap.State) Response {
func noContentResponseWithEtag(accountIds []jmap.AccountId, sessionState jmap.SessionState, objectType ResponseObjectType, etag jmap.State) Response {
return Response{
accountIds: accountIds,
body: nil,
@@ -150,7 +150,7 @@ func noContentResponseWithEtag(accountIds []string, sessionState jmap.SessionSta
}
}
func (r *Request) noContent(accountId string, objectType ResponseObjectType, result jmap.ResultMetadata) Response {
func (r *Request) noContent(accountId jmap.AccountId, objectType ResponseObjectType, result jmap.ResultMetadata) Response {
return noContentResponseWithEtag(single(accountId), result.GetSessionState(), objectType, result.GetState())
}
@@ -178,7 +178,7 @@ func timeoutResponse(sessionState jmap.SessionState) Response {
}
*/
func notFoundResponse(accountIds []string, sessionState jmap.SessionState, objectType ResponseObjectType, etag jmap.State) Response {
func notFoundResponse(accountIds []jmap.AccountId, sessionState jmap.SessionState, objectType ResponseObjectType, etag jmap.State) Response {
return Response{
accountIds: accountIds,
body: nil,
@@ -191,11 +191,11 @@ func notFoundResponse(accountIds []string, sessionState jmap.SessionState, objec
}
}
func (r *Request) notFound(accountId string, objectType ResponseObjectType, result jmap.ResultMetadata) Response {
func (r *Request) notFound(accountId jmap.AccountId, objectType ResponseObjectType, result jmap.ResultMetadata) Response {
return notFoundResponse(single(accountId), result.GetSessionState(), objectType, result.GetState())
}
func etaggedNotFoundResponse(accountIds []string, sessionState jmap.SessionState, objectType ResponseObjectType, etag jmap.State, contentLanguage jmap.Language) Response {
func etaggedNotFoundResponse(accountIds []jmap.AccountId, sessionState jmap.SessionState, objectType ResponseObjectType, etag jmap.State, contentLanguage jmap.Language) Response {
return Response{
accountIds: accountIds,
body: nil,
@@ -209,11 +209,11 @@ func etaggedNotFoundResponse(accountIds []string, sessionState jmap.SessionState
}
}
func (r *Request) etaggedNotFound(accountId string, sessionState jmap.SessionState, objectType ResponseObjectType, etag jmap.State) Response {
func (r *Request) etaggedNotFound(accountId jmap.AccountId, sessionState jmap.SessionState, objectType ResponseObjectType, etag jmap.State) Response {
return etaggedNotFoundResponse(single(accountId), sessionState, objectType, etag, jmap.Language(r.language()))
}
func notImplementedResponse(accountIds []string, sessionState jmap.SessionState, objectType ResponseObjectType) Response {
func notImplementedResponse(accountIds []jmap.AccountId, sessionState jmap.SessionState, objectType ResponseObjectType) Response {
return Response{
accountIds: accountIds,
body: nil,
@@ -225,6 +225,6 @@ func notImplementedResponse(accountIds []string, sessionState jmap.SessionState,
}
}
func (r *Request) notImplementedN(accountIds []string, objectType ResponseObjectType) Response {
func (r *Request) notImplementedN(accountIds []jmap.AccountId, objectType ResponseObjectType) Response {
return notImplementedResponse(accountIds, r.session.State, objectType)
}

View File

@@ -11,26 +11,28 @@ import (
"github.com/opencloud-eu/opencloud/pkg/structs"
)
type SupplierId string
type Supplier[T jmap.Foo] interface {
GetId() string
GetId() SupplierId
IsMine(id string) bool
}
type ListSupplier[T jmap.Foo, G jmap.GetResponse[T]] interface {
GetAll(accountId string, ids []string, ctx jmap.Context) (jmap.Result[G], error)
GetAll(accountId jmap.AccountId, ids []string, ctx jmap.Context) (jmap.Result[G], error)
Supplier[T]
}
type QuerySupplier[T jmap.Foo, R jmap.SearchResults[T], F jmap.FilterElement[T], C jmap.Comparator[T]] interface {
Query(accountIds []string, qps QueryParamsSupplier, limit *uint, filter F, sortBy []C, calculateTotal bool, ctx jmap.Context) (jmap.Result[map[string]R], error)
Query(accountIds []jmap.AccountId, qps QueryParamsSupplier, limit *uint, filter F, sortBy []C, calculateTotal bool, ctx jmap.Context) (jmap.Result[map[jmap.AccountId]R], error)
Supplier[T]
}
// queryFunc func(req Request, accountIds []string, qps QueryParamsSupplier, limit *uint, filter FILTER, sortBy []COMP, ctx jmap.Context) (jmap.Result[SEARCHRESULTS], NextToken, error),
func curryQueryFunc[SRES jmap.SearchResults[T], T jmap.Foo, FILTER any, COMP any](
f func(accountIds []string, qps QueryParamsSupplier, limit *uint, filter FILTER, sortBy []COMP, calculateTotal bool, ctx jmap.Context) (jmap.Result[SRES], NextToken, error),
) func(req Request, accountIds []string, qps QueryParamsSupplier, limit *uint, filter FILTER, sortBy []COMP, ctx jmap.Context) (jmap.Result[SRES], NextToken, error) {
return func(_ Request, accountIds []string, qps QueryParamsSupplier, limit *uint, filter FILTER, sortBy []COMP, ctx jmap.Context) (jmap.Result[SRES], NextToken, error) { //NOSONAR
f func(accountIds []jmap.AccountId, qps QueryParamsSupplier, limit *uint, filter FILTER, sortBy []COMP, calculateTotal bool, ctx jmap.Context) (jmap.Result[SRES], NextToken, error),
) func(req Request, accountIds []jmap.AccountId, qps QueryParamsSupplier, limit *uint, filter FILTER, sortBy []COMP, ctx jmap.Context) (jmap.Result[SRES], NextToken, error) {
return func(_ Request, accountIds []jmap.AccountId, qps QueryParamsSupplier, limit *uint, filter FILTER, sortBy []COMP, ctx jmap.Context) (jmap.Result[SRES], NextToken, error) { //NOSONAR
result, next, err := f(accountIds, qps, limit, filter, sortBy, true, ctx)
if err != nil {
return jmap.ZeroResult[SRES](), next, err
@@ -40,8 +42,8 @@ func curryQueryFunc[SRES jmap.SearchResults[T], T jmap.Foo, FILTER any, COMP any
}
}
func agg[T jmap.Idable, R jmap.GetResponse[T]](accountId string, supplierIds []string, responses []*R, //NOSONAR
ctor func(accountId string, state jmap.State, notFound []string, list []T) R) (R, error) {
func agg[T jmap.Idable, R jmap.GetResponse[T]](accountId jmap.AccountId, supplierIds []SupplierId, responses []*R, //NOSONAR
ctor func(accountId jmap.AccountId, state jmap.State, notFound []string, list []T) R) (R, error) {
if len(responses) < 1 {
var zero R
return zero, fmt.Errorf("requires at least one response")
@@ -54,7 +56,7 @@ func agg[T jmap.Idable, R jmap.GetResponse[T]](accountId string, supplierIds []s
return zero
}
})...)
states, err := structs.MeshMap(supplierIds, responses, func(id string, e *R) (string, jmap.State, bool) {
states, err := structs.MeshMap(supplierIds, responses, func(id SupplierId, e *R) (SupplierId, jmap.State, bool) {
if e != nil {
state := (*e).GetState()
if state != jmap.EmptyState {
@@ -85,8 +87,8 @@ func agg[T jmap.Idable, R jmap.GetResponse[T]](accountId string, supplierIds []s
return ctor(accountId, state, notFounds, lists), nil
}
func slist[T jmap.Idable, G jmap.GetResponse[T], S ListSupplier[T, G]](suppliers []S, accountId string, ids []string, ctx jmap.Context, //NOSONAR
ctor func(accountId string, state jmap.State, notFound []string, list []T) G) (jmap.Result[G], error) {
func slist[T jmap.Idable, G jmap.GetResponse[T], S ListSupplier[T, G]](suppliers []S, accountId jmap.AccountId, ids []string, ctx jmap.Context, //NOSONAR
ctor func(accountId jmap.AccountId, state jmap.State, notFound []string, list []T) G) (jmap.Result[G], error) {
switch len(suppliers) {
case 0:
return jmap.ZeroResult[G](), nil
@@ -94,7 +96,7 @@ func slist[T jmap.Idable, G jmap.GetResponse[T], S ListSupplier[T, G]](suppliers
return suppliers[0].GetAll(accountId, ids, ctx)
default:
results := make([]*jmap.Result[G], len(suppliers))
supplierIds := make([]string, len(suppliers))
supplierIds := make([]SupplierId, len(suppliers))
for i, supplier := range suppliers {
supplierIds[i] = supplier.GetId()
localIds := []string{}
@@ -118,7 +120,7 @@ func slist[T jmap.Idable, G jmap.GetResponse[T], S ListSupplier[T, G]](suppliers
if err != nil {
return resp, jmap.EmptySessionState, jmap.EmptyState, jmap.NoLanguage, err
}
m, err := structs.MeshMap(supplierIds, sessionStates, func(id string, state *jmap.SessionState) (string, jmap.SessionState, bool) {
m, err := structs.MeshMap(supplierIds, sessionStates, func(id SupplierId, state *jmap.SessionState) (SupplierId, jmap.SessionState, bool) {
if state != nil && *state != jmap.EmptySessionState {
return id, *state, true
} else {
@@ -141,7 +143,7 @@ func slist[T jmap.Idable, G jmap.GetResponse[T], S ListSupplier[T, G]](suppliers
}
}
func fillMissingAccounts(qps QueryParamsSupplier, supplierId string, accountIds []string, n map[string]jmap.QueryParams) error {
func fillMissingAccounts(qps QueryParamsSupplier, supplierId SupplierId, accountIds []jmap.AccountId, n map[jmap.AccountId]jmap.QueryParams) error {
for _, accountId := range accountIds {
if _, ok := n[accountId]; !ok {
// no result item was kept for this accountId
@@ -167,7 +169,7 @@ func fillMissingAccounts(qps QueryParamsSupplier, supplierId string, accountIds
}
func squery[T jmap.Idable, R jmap.SearchResults[T], S QuerySupplier[T, R, F, C], F jmap.FilterElement[T], C jmap.Comparator[T]]( //NOSONAR
suppliers []S, accountIds []string, qps QueryParamsSupplier, limit *uint, filter F, sortBy []C,
suppliers []S, accountIds []jmap.AccountId, qps QueryParamsSupplier, limit *uint, filter F, sortBy []C,
calculateTotal bool, ctx jmap.Context,
sorter func(T, T) int,
searchResultCtor func(canCalculateChanges jmap.ChangeCalculation, position *uint, limit *uint, total *uint, results []T) R) (
@@ -190,7 +192,7 @@ func squery[T jmap.Idable, R jmap.SearchResults[T], S QuerySupplier[T, R, F, C],
// use anchor and anchorOffset and limit:
// the anchor for the next query is the ID of the last element in the results for this query
// using an anchor offset of +1
n := map[string]jmap.QueryParams{}
n := map[jmap.AccountId]jmap.QueryParams{}
for accountId, payload := range result.Payload {
items := payload.GetResults()
last := items[len(items)-1]
@@ -199,7 +201,7 @@ func squery[T jmap.Idable, R jmap.SearchResults[T], S QuerySupplier[T, R, F, C],
if nextToken, err := nextSingle(n); err != nil {
return jmap.ZeroResult[R](), NoNextToken, err
} else {
single, err := jmap.RefineResultPayload(result, func(m map[string]R) (R, bool, error) {
single, err := jmap.RefineResultPayload(result, func(m map[jmap.AccountId]R) (R, bool, error) {
if r, ok := m[accountId]; ok {
return r, true, nil
} else {
@@ -211,7 +213,7 @@ func squery[T jmap.Idable, R jmap.SearchResults[T], S QuerySupplier[T, R, F, C],
} else {
// multiple accountIds => we need to merge/flatten the results, and we must use anchor and offset for the next page
payloads := []T{}
originals := map[string][]T{}
originals := map[jmap.AccountId][]T{}
cc := true
total := uint(0)
for accountId, searchResult := range result.Payload {
@@ -249,7 +251,7 @@ func squery[T jmap.Idable, R jmap.SearchResults[T], S QuerySupplier[T, R, F, C],
r = searchResultCtor(jmap.ChangeCalculation(cc), nil, limit, &total, payloads) // TODO can we determine the position here, instead of nil?
}
lastIdByAccountId := map[string]string{}
lastIdByAccountId := map[jmap.AccountId]string{}
// not amazing, but since the accountId information is not attached to every single
// search result element (e.g. a ContactCard), we have to iterate over the original results that we
// have by accountId to find them again, in order to determine the "last ID"
@@ -263,7 +265,7 @@ func squery[T jmap.Idable, R jmap.SearchResults[T], S QuerySupplier[T, R, F, C],
}
}
n := map[string]jmap.QueryParams{}
n := map[jmap.AccountId]jmap.QueryParams{}
for accountId, lastId := range lastIdByAccountId {
// the anchor for the next query is the ID of the last element in the results for this query
// using an anchor offset of +1
@@ -273,7 +275,7 @@ func squery[T jmap.Idable, R jmap.SearchResults[T], S QuerySupplier[T, R, F, C],
return jmap.ZeroResult[R](), NoNextToken, err
}
nextBySupplier := map[string]map[string]jmap.QueryParams{supplier.GetId(): n}
nextBySupplier := map[SupplierId]map[jmap.AccountId]jmap.QueryParams{supplier.GetId(): n}
if nextToken, err := nextMulti(nextBySupplier); err != nil {
return jmap.ZeroResult[R](), NoNextToken, err
} else {
@@ -287,11 +289,11 @@ func squery[T jmap.Idable, R jmap.SearchResults[T], S QuerySupplier[T, R, F, C],
}
default:
payloads := []T{}
originals := map[string]map[string][]T{}
originals := map[SupplierId]map[jmap.AccountId][]T{}
cc := true
total := uint(0)
sessionState := jmap.EmptySessionState
states := map[string]jmap.State{}
states := map[SupplierId]jmap.State{}
lang := jmap.NoLanguage
for _, supplier := range suppliers {
// we are not injecting id prefixes here for all the objects, as each supplier is responsible for doing that if necessary
@@ -306,7 +308,7 @@ func squery[T jmap.Idable, R jmap.SearchResults[T], S QuerySupplier[T, R, F, C],
lang = result.GetLanguage()
}
// iterate over results by accountId and flatten everything into the 'payloads' array
o := map[string][]T{}
o := map[jmap.AccountId][]T{}
for accountId, searchResult := range result.Payload {
o[accountId] = searchResult.GetResults()
if !searchResult.GetCanCalculateChanges() {
@@ -345,7 +347,7 @@ func squery[T jmap.Idable, R jmap.SearchResults[T], S QuerySupplier[T, R, F, C],
r = searchResultCtor(jmap.ChangeCalculation(cc), nil, limit, &total, payloads) // TODO cen we provide the position here instead of nil?
}
lastIdBySupplierByAccountId := map[string]map[string]string{}
lastIdBySupplierByAccountId := map[SupplierId]map[jmap.AccountId]string{}
// not amazing, but since the accountId and supplier information is not attached to every single
// search result element (e.g. a ContactCard), we have to iterate over the original results that we
// kept by supplier and by accountId to find them again, in order to determine the "last ID"
@@ -356,7 +358,7 @@ func squery[T jmap.Idable, R jmap.SearchResults[T], S QuerySupplier[T, R, F, C],
for accountId, items := range o {
if slices.IndexFunc(items, func(t T) bool { return t.GetId() == item.GetId() }) >= 0 {
if _, ok := lastIdBySupplierByAccountId[supplierId]; !ok {
lastIdBySupplierByAccountId[supplierId] = map[string]string{}
lastIdBySupplierByAccountId[supplierId] = map[jmap.AccountId]string{}
}
lastIdBySupplierByAccountId[supplierId][accountId] = item.GetId()
}
@@ -364,9 +366,9 @@ func squery[T jmap.Idable, R jmap.SearchResults[T], S QuerySupplier[T, R, F, C],
}
}
nextBySupplier := map[string]map[string]jmap.QueryParams{}
nextBySupplier := map[SupplierId]map[jmap.AccountId]jmap.QueryParams{}
for supplierId, m := range lastIdBySupplierByAccountId {
n := map[string]jmap.QueryParams{}
n := map[jmap.AccountId]jmap.QueryParams{}
for accountId, lastId := range m {
// the anchor for the next query is the ID of the last element in the results for this query
// using an anchor offset of +1
@@ -397,7 +399,7 @@ func squery[T jmap.Idable, R jmap.SearchResults[T], S QuerySupplier[T, R, F, C],
const combinedStateEncodingPrefix = "="
func combineState[S jmap.State | jmap.SessionState](m map[string]S) (S, error) {
func combineState[K ~string, S jmap.State | jmap.SessionState](m map[K]S) (S, error) {
if b, err := json.Marshal(m); err != nil {
return "", err
} else {
@@ -406,13 +408,13 @@ func combineState[S jmap.State | jmap.SessionState](m map[string]S) (S, error) {
}
}
func splitState[S jmap.State | jmap.SessionState](state S) (map[string]S, error) {
func splitState[K ~string, S jmap.State | jmap.SessionState](state S) (map[K]S, error) {
s := string(state)
if strings.HasPrefix(s, combinedStateEncodingPrefix) {
if b, err := base64.RawURLEncoding.DecodeString(s[len(combinedStateEncodingPrefix):]); err != nil {
return nil, err
} else {
m := map[string]S{}
m := map[K]S{}
if err := json.Unmarshal(b, &m); err != nil {
return nil, err
} else {
@@ -420,6 +422,6 @@ func splitState[S jmap.State | jmap.SessionState](state S) (map[string]S, error)
}
}
} else {
return map[string]S{"jmap": state}, nil
return map[K]S{K("jmap"): state}, nil
}
}

View File

@@ -10,20 +10,20 @@ import (
)
type PetSupplier struct {
id string
petsByAccountId map[string][]Pet
id SupplierId
petsByAccountId map[jmap.AccountId][]Pet
}
// var _ ListSupplier[Pet, PetGetResponse] = &PetSupplier{}
var _ QuerySupplier[Pet, *PetSearchResults, PetFilterElement, PetComparator] = &PetSupplier{}
func (s *PetSupplier) GetId() string {
func (s *PetSupplier) GetId() SupplierId {
return s.id
}
func (s *PetSupplier) IsMine(id string) bool {
return strings.HasPrefix(id, s.id+":")
return strings.HasPrefix(id, string(s.id)+":")
}
func (s *PetSupplier) Query(accountIds []string, qps QueryParamsSupplier, limit *uint, filter PetFilterElement, sortBy []PetComparator, calculateTotal bool, ctx jmap.Context) (jmap.Result[map[string]*PetSearchResults], error) {
func (s *PetSupplier) Query(accountIds []jmap.AccountId, qps QueryParamsSupplier, limit *uint, filter PetFilterElement, sortBy []PetComparator, calculateTotal bool, ctx jmap.Context) (jmap.Result[map[jmap.AccountId]*PetSearchResults], error) {
return inmemquery(s.id, s.petsByAccountId, accountIds, qps, limit, calculateTotal,
func(results []Pet, canCalculateChanges jmap.ChangeCalculation, position *uint, limit *uint, total *uint) *PetSearchResults {
return &PetSearchResults{Results: results, CanCalculateChanges: canCalculateChanges, Position: position, Limit: limit, Total: total}
@@ -32,18 +32,18 @@ func (s *PetSupplier) Query(accountIds []string, qps QueryParamsSupplier, limit
}
func inmemquery[T jmap.Idable, R jmap.SearchResults[T]](
supplierId string,
store map[string][]T,
accountIds []string,
supplierId SupplierId,
store map[jmap.AccountId][]T,
accountIds []jmap.AccountId,
qps QueryParamsSupplier, limit *uint,
calculateTotal bool,
searchResultCtor func(results []T, canCalculateChanges jmap.ChangeCalculation, position *uint, limit *uint, total *uint) R,
) (jmap.Result[map[string]R], error) {
payload := make(map[string]R, len(accountIds))
) (jmap.Result[map[jmap.AccountId]R], error) {
payload := make(map[jmap.AccountId]R, len(accountIds))
for _, accountId := range accountIds {
qp := jmap.NullQueryParams
if q, ok, err := qps.ForSupplier(supplierId, accountId); err != nil {
return jmap.ZeroResult[map[string]R](), err
return jmap.ZeroResult[map[jmap.AccountId]R](), err
} else if ok {
qp = q
}
@@ -91,7 +91,7 @@ func inmemquery[T jmap.Idable, R jmap.SearchResults[T]](
payload[accountId] = res
}
return jmap.Result[map[string]R]{
return jmap.Result[map[jmap.AccountId]R]{
Payload: payload,
SessionState: jmap.EmptySessionState,
State: jmap.EmptyState,
@@ -101,7 +101,7 @@ func inmemquery[T jmap.Idable, R jmap.SearchResults[T]](
func pets(
suppliers []QuerySupplier[Pet, *PetSearchResults, PetFilterElement, PetComparator],
accountIds []string, qps QueryParamsSupplier, limit *uint,
accountIds []jmap.AccountId, qps QueryParamsSupplier, limit *uint,
filter PetFilterElement, sortBy []PetComparator,
calculateTotal bool,
ctx jmap.Context) (jmap.Result[*PetSearchResults], NextToken, error) {
@@ -125,7 +125,7 @@ func TestSquery(t *testing.T) {
suppliers := []QuerySupplier[Pet, *PetSearchResults, PetFilterElement, PetComparator]{
&PetSupplier{
id: "X",
petsByAccountId: map[string][]Pet{
petsByAccountId: map[jmap.AccountId][]Pet{
"a": {
{id: "X:1", name: "ace"},
{id: "X:2", name: "bella"},
@@ -137,7 +137,7 @@ func TestSquery(t *testing.T) {
},
&PetSupplier{
id: "Y",
petsByAccountId: map[string][]Pet{
petsByAccountId: map[jmap.AccountId][]Pet{
"a": {
{id: "Y:1", name: "cupcake"},
{id: "Y:2", name: "elvis"},
@@ -149,14 +149,14 @@ func TestSquery(t *testing.T) {
},
},
}
f := func(accountIds []string, position int, anchor string, anchorOffset *int, limit *uint) (jmap.Result[*PetSearchResults], NextToken, error) {
f := func(accountIds []jmap.AccountId, position int, anchor string, anchorOffset *int, limit *uint) (jmap.Result[*PetSearchResults], NextToken, error) {
return pets(suppliers, accountIds,
StaticQueryParamsSupplier{qp: jmap.QueryParams{Position: position, Anchor: anchor, AnchorOffset: anchorOffset}}, limit,
PetFilterCondition{}, []PetComparator{{Property: "id", IsAscending: true}},
true, jmap.Context{},
)
}
n := func(accountIds []string, nextToken NextToken, limit *uint) (jmap.Result[*PetSearchResults], NextToken, error) {
n := func(accountIds []jmap.AccountId, nextToken NextToken, limit *uint) (jmap.Result[*PetSearchResults], NextToken, error) {
if qps, err := unnext(nextToken); err != nil {
return jmap.ZeroResult[*PetSearchResults](), NoNextToken, err
} else {
@@ -165,7 +165,7 @@ func TestSquery(t *testing.T) {
}
{
res, n, err := f([]string{"a", "b", "c"}, 0, "", nil, nil)
res, n, err := f([]jmap.AccountId{"a", "b", "c"}, 0, "", nil, nil)
require.NoError(err)
require.Len(res.Payload.Results, 7)
require.Equal(uint(len(res.Payload.Results)), *res.Payload.Total)
@@ -189,7 +189,7 @@ func TestSquery(t *testing.T) {
}
var nextToken NextToken
{
res, n, err := f([]string{"a", "b", "c"}, 0, "", nil, uintPtr(4))
res, n, err := f([]jmap.AccountId{"a", "b", "c"}, 0, "", nil, uintPtr(4))
nextToken = n
require.NoError(err)
require.Len(res.Payload.Results, 4)
@@ -210,7 +210,7 @@ func TestSquery(t *testing.T) {
}
}
{
res, _, err := n([]string{"a", "b", "c"}, nextToken, uintPtr(4))
res, _, err := n([]jmap.AccountId{"a", "b", "c"}, nextToken, uintPtr(4))
require.NoError(err)
require.Equal(uint(7), *res.Payload.Total)
require.Len(res.Payload.Results, 3)

View File

@@ -14,15 +14,15 @@ func create[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T]]( //NOSONAR
o ObjectType[T, CHANGE, CHANGES],
w http.ResponseWriter, r *http.Request,
g *Groupware,
bodyFunc func(r Request, accountId string, body *CHANGE, ctx jmap.Context) (bool, Response),
createFunc func(accountId string, change CHANGE, ctx jmap.Context) (jmap.Result[*T], error),
bodyFunc func(r Request, accountId jmap.AccountId, body *CHANGE, ctx jmap.Context) (bool, Response),
createFunc func(accountId jmap.AccountId, change CHANGE, ctx jmap.Context) (jmap.Result[*T], error),
) {
g.respond(w, r, func(req Request) Response {
ok, accountId, resp := o.accountFunc(&req)
if !ok {
return resp
}
l := req.logger.With().Str(accountId, log.SafeString(accountId))
l := req.logger.With().Str(logAccountId, log.SafeString(accountId))
if notok, resp := req.unsupportedQueryParams(single(accountId), noSupportedQueryParams); notok {
return resp
@@ -66,14 +66,14 @@ func getall[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T], RESP jmap.G
o ObjectType[T, CHANGE, CHANGES],
w http.ResponseWriter, r *http.Request,
g *Groupware,
getFunc func(accountId string, ids []string, ctx jmap.Context) (jmap.Result[RESP], error),
getFunc func(accountId jmap.AccountId, ids []string, ctx jmap.Context) (jmap.Result[RESP], error),
) {
g.respond(w, r, func(req Request) Response {
ok, accountId, resp := o.accountFunc(&req)
if !ok {
return resp
}
l := req.logger.With().Str(accountId, log.SafeString(accountId))
l := req.logger.With().Str(logAccountId, log.SafeString(accountId))
if notok, resp := req.unsupportedQueryParams(single(accountId), noSupportedQueryParams); notok {
return resp
@@ -112,14 +112,14 @@ func getallpaged[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T], FILTER
withContainerId bool,
filterFunc func(containerId string) FILTER,
sortBy []COMP,
queryFunc func(req Request, accountIds []string, qps QueryParamsSupplier, limit *uint, filter FILTER, sortBy []COMP, ctx jmap.Context) (jmap.Result[SEARCHRESULTS], NextToken, error),
queryFunc func(req Request, accountIds []jmap.AccountId, qps QueryParamsSupplier, limit *uint, filter FILTER, sortBy []COMP, ctx jmap.Context) (jmap.Result[SEARCHRESULTS], NextToken, error),
) {
g.respond(w, r, func(req Request) Response {
ok, accountId, resp := o.accountFunc(&req)
if !ok {
return resp
}
l := req.logger.With().Str(accountId, log.SafeString(accountId))
l := req.logger.With().Str(logAccountId, log.SafeString(accountId))
var limit *uint = nil
{
@@ -147,34 +147,6 @@ func getallpaged[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T], FILTER
} else {
supportedQueryParams = firstQueryParams
qps = FirstQueryParamsSupplier{}
/*
position, ok, err := req.parseIntParam(QueryParamPosition, 0)
if err != nil {
return req.error(accountId, err)
}
if ok {
l = l.Int(QueryParamPosition, position)
}
anchor, ok := req.getStringParam(QueryParamAnchor, "")
if ok {
l = l.Str(QueryParamAnchor, log.SafeString(anchor))
}
var anchorOffset *int = nil
{
v, ok, err := req.parseIntParam(QueryParamAnchorOffset, 0)
if err != nil {
return req.error(accountId, err)
}
if ok {
l = l.Int(QueryParamAnchorOffset, v)
anchorOffset = &v
}
}
*/
}
}
@@ -220,14 +192,14 @@ func query[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T], SEARCHRESULT
w http.ResponseWriter, r *http.Request,
g *Groupware,
defaultLimit *uint,
queryFunc func(req Request, accountId string, containerId string, qp jmap.QueryParams, limit *uint, ctx jmap.Context) (jmap.Result[SEARCHRESULTS], error),
queryFunc func(req Request, accountId jmap.AccountId, containerId string, qp jmap.QueryParams, limit *uint, ctx jmap.Context) (jmap.Result[SEARCHRESULTS], error),
) {
g.respond(w, r, func(req Request) Response {
ok, accountId, resp := o.accountFunc(&req)
if !ok {
return resp
}
l := req.logger.With().Str(accountId, log.SafeString(accountId))
l := req.logger.With().Str(logAccountId, log.SafeString(accountId))
containerId := ""
if o.containerUriParamName != "" {
@@ -366,14 +338,14 @@ func get[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T], RESP jmap.GetR
o ObjectType[T, CHANGE, CHANGES],
w http.ResponseWriter, r *http.Request,
g *Groupware,
getFunc func(accountId string, ids []string, ctx jmap.Context) (jmap.Result[RESP], error),
getFunc func(accountId jmap.AccountId, ids []string, ctx jmap.Context) (jmap.Result[RESP], error),
) {
g.respond(w, r, func(req Request) Response {
ok, accountId, resp := o.accountFunc(&req)
if !ok {
return resp
}
l := req.logger.With().Str(accountId, log.SafeString(accountId))
l := req.logger.With().Str(logAccountId, log.SafeString(accountId))
ids := []string{}
if o.uriParamName != "" {
id, err := req.PathParamDoc(o.uriParamName, "The unique identifier of the object to retrieve")
@@ -423,14 +395,14 @@ func getFromMap[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T], RESP jm
o ObjectType[T, CHANGE, CHANGES],
w http.ResponseWriter, r *http.Request,
g *Groupware,
getFunc func(accountIds []string, ids []string, ctx jmap.Context) (jmap.Result[map[string]RESP], error),
getFunc func(accountIds []jmap.AccountId, ids []string, ctx jmap.Context) (jmap.Result[map[jmap.AccountId]RESP], error),
) {
g.respond(w, r, func(req Request) Response {
ok, accountId, resp := o.accountFunc(&req)
if !ok {
return resp
}
l := req.logger.With().Str(accountId, log.SafeString(accountId))
l := req.logger.With().Str(logAccountId, log.SafeString(accountId))
id, err := req.PathParamDoc(o.uriParamName, "The unique identifier of the object to retrieve")
if err != nil {
return req.error(accountId, err)
@@ -482,14 +454,14 @@ func changes[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T]]( //NOSONAR
o ObjectType[T, CHANGE, CHANGES],
w http.ResponseWriter, r *http.Request,
g *Groupware,
changesFunc func(accountId string, sinceState jmap.State, maxChanges uint, ctx jmap.Context) (jmap.Result[CHANGES], error),
changesFunc func(accountId jmap.AccountId, sinceState jmap.State, maxChanges uint, ctx jmap.Context) (jmap.Result[CHANGES], error),
) {
g.respond(w, r, func(req Request) Response {
ok, accountId, resp := o.accountFunc(&req)
if !ok {
return resp
}
l := req.logger.With().Str(accountId, log.SafeString(accountId))
l := req.logger.With().Str(logAccountId, log.SafeString(accountId))
maxChanges, ok, err := req.parseUIntParam(QueryParamMaxChanges, 0)
if err != nil {
@@ -535,14 +507,14 @@ func delete[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T]]( //NOSONAR
o ObjectType[T, CHANGE, CHANGES],
w http.ResponseWriter, r *http.Request,
g *Groupware,
deleteFunc func(accountId string, ids []string, ctx jmap.Context) (jmap.Result[map[string]jmap.SetError], error),
deleteFunc func(accountId jmap.AccountId, ids []string, ctx jmap.Context) (jmap.Result[map[string]jmap.SetError], error),
) {
g.respond(w, r, func(req Request) Response {
ok, accountId, resp := o.accountFunc(&req)
if !ok {
return resp
}
l := req.logger.With().Str(accountId, log.SafeString(accountId))
l := req.logger.With().Str(logAccountId, log.SafeString(accountId))
id, err := req.PathParamDoc(o.uriParamName, "The unique identifier of the object to delete")
if err != nil {
return req.error(accountId, err)
@@ -597,14 +569,14 @@ func deleteMany[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T]]( //NOSO
o ObjectType[T, CHANGE, CHANGES],
w http.ResponseWriter, r *http.Request,
g *Groupware,
deleteFunc func(accountId string, ids []string, ctx jmap.Context) (jmap.Result[map[string]jmap.SetError], error),
deleteFunc func(accountId jmap.AccountId, ids []string, ctx jmap.Context) (jmap.Result[map[string]jmap.SetError], error),
) {
g.respond(w, r, func(req Request) Response {
ok, accountId, resp := o.accountFunc(&req)
if !ok {
return resp
}
l := req.logger.With().Str(accountId, log.SafeString(accountId))
l := req.logger.With().Str(logAccountId, log.SafeString(accountId))
ids := []string{}
if o.uriParamName != "" {
@@ -686,14 +658,14 @@ func modify[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T]](
o ObjectType[T, CHANGE, CHANGES],
w http.ResponseWriter, r *http.Request,
g *Groupware,
updateFunc func(accountId string, id string, change CHANGE, ctx jmap.Context) (jmap.Result[T], error),
updateFunc func(accountId jmap.AccountId, id string, change CHANGE, ctx jmap.Context) (jmap.Result[T], error),
) {
g.respond(w, r, func(req Request) Response {
ok, accountId, resp := o.accountFunc(&req)
if !ok {
return resp
}
l := req.logger.With().Str(accountId, log.SafeString(accountId))
l := req.logger.With().Str(logAccountId, log.SafeString(accountId))
id, err := req.PathParamDoc(o.uriParamName, "The unique identifier of the object to modify")
if err != nil {
return req.error(accountId, err)