diff --git a/pkg/jmap/api_addressbook.go b/pkg/jmap/api_addressbook.go index 4294ebce55..71fd606263 100644 --- a/pkg/jmap/api_addressbook.go +++ b/pkg/jmap/api_addressbook.go @@ -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} diff --git a/pkg/jmap/api_blob.go b/pkg/jmap/api_blob.go index c094e254e2..7cf1037da1 100644 --- a/pkg/jmap/api_blob.go +++ b/pkg/jmap/api_blob.go @@ -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 }) - } diff --git a/pkg/jmap/api_bootstrap.go b/pkg/jmap/api_bootstrap.go index ae373703aa..cf2c69af64 100644 --- a/pkg/jmap/api_bootstrap.go +++ b/pkg/jmap/api_bootstrap.go @@ -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 { diff --git a/pkg/jmap/api_calendar.go b/pkg/jmap/api_calendar.go index 1727501ca0..774541dd46 100644 --- a/pkg/jmap/api_calendar.go +++ b/pkg/jmap/api_calendar.go @@ -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} diff --git a/pkg/jmap/api_changes.go b/pkg/jmap/api_changes.go index 7cc455b687..df54d549e3 100644 --- a/pkg/jmap/api_changes.go +++ b/pkg/jmap/api_changes.go @@ -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) diff --git a/pkg/jmap/api_contact.go b/pkg/jmap/api_contact.go index d7172eb5c0..4a5ee283b4 100644 --- a/pkg/jmap/api_contact.go +++ b/pkg/jmap/api_contact.go @@ -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} diff --git a/pkg/jmap/api_email.go b/pkg/jmap/api_email.go index 41ef7c4f24..7eca1a0cab 100644 --- a/pkg/jmap/api_email.go +++ b/pkg/jmap/api_email.go @@ -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 { diff --git a/pkg/jmap/api_event.go b/pkg/jmap/api_event.go index 8e7d8469d1..374cf5d295 100644 --- a/pkg/jmap/api_event.go +++ b/pkg/jmap/api_event.go @@ -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} diff --git a/pkg/jmap/api_identity.go b/pkg/jmap/api_identity.go index da13c549a3..d3bf5bda14 100644 --- a/pkg/jmap/api_identity.go +++ b/pkg/jmap/api_identity.go @@ -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 { diff --git a/pkg/jmap/api_mailbox.go b/pkg/jmap/api_mailbox.go index 7e5fb72393..48447b74bb 100644 --- a/pkg/jmap/api_mailbox.go +++ b/pkg/jmap/api_mailbox.go @@ -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{}, diff --git a/pkg/jmap/api_objects.go b/pkg/jmap/api_objects.go index 401523e110..14820a84a2 100644 --- a/pkg/jmap/api_objects.go +++ b/pkg/jmap/api_objects.go @@ -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, diff --git a/pkg/jmap/api_principal.go b/pkg/jmap/api_principal.go index 9f3470bcdb..6cf66fc4a6 100644 --- a/pkg/jmap/api_principal.go +++ b/pkg/jmap/api_principal.go @@ -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 { diff --git a/pkg/jmap/api_quota.go b/pkg/jmap/api_quota.go index 3950402c7d..4fbb6e34f8 100644 --- a/pkg/jmap/api_quota.go +++ b/pkg/jmap/api_quota.go @@ -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 { diff --git a/pkg/jmap/api_vacation.go b/pkg/jmap/api_vacation.go index 21eb6ad1ce..eab5d50b78 100644 --- a/pkg/jmap/api_vacation.go +++ b/pkg/jmap/api_vacation.go @@ -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) diff --git a/pkg/jmap/export_integration_test.go b/pkg/jmap/export_integration_test.go index 3d8dc02721..ae596bbfd1 100644 --- a/pkg/jmap/export_integration_test.go +++ b/pkg/jmap/export_integration_test.go @@ -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 diff --git a/pkg/jmap/integration_addressbook_test.go b/pkg/jmap/integration_addressbook_test.go index 50261d59cd..97428cc78e 100644 --- a/pkg/jmap/integration_addressbook_test.go +++ b/pkg/jmap/integration_addressbook_test.go @@ -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) diff --git a/pkg/jmap/integration_calendar_test.go b/pkg/jmap/integration_calendar_test.go index 4978097851..53aaf24976 100644 --- a/pkg/jmap/integration_calendar_test.go +++ b/pkg/jmap/integration_calendar_test.go @@ -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) diff --git a/pkg/jmap/integration_email_test.go b/pkg/jmap/integration_email_test.go index b85dfa3b0a..d7b1e1389f 100644 --- a/pkg/jmap/integration_email_test.go +++ b/pkg/jmap/integration_email_test.go @@ -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) diff --git a/pkg/jmap/integration_ws_test.go b/pkg/jmap/integration_ws_test.go index 499141038b..8bcd0b35e3 100644 --- a/pkg/jmap/integration_ws_test.go +++ b/pkg/jmap/integration_ws_test.go @@ -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) } diff --git a/pkg/jmap/model.go b/pkg/jmap/model.go index 9dfe499a6f..1ec63cc164 100644 --- a/pkg/jmap/model.go +++ b/pkg/jmap/model.go @@ -445,6 +445,10 @@ var ( } ) +type AccountId string + +type PrincipalId string + type SessionMailAccountCapabilities struct { // The maximum number of Mailboxes that can be can assigned to a single Email object. // @@ -683,16 +687,16 @@ type SessionTasksCustomTimezonesAccountCapabilities struct { type SessionPrincipalsAccountCapabilities struct { // The id of the principal in this account that corresponds to the user fetching this object, if any. - CurrentUserPrincipalId string `json:"currentUserPrincipalId,omitempty"` + CurrentUserPrincipalId PrincipalId `json:"currentUserPrincipalId,omitempty"` } type SessionPrincipalsOwnerAccountCapabilities struct { // The id of an account with the `urn:ietf:params:jmap:principals` capability that contains the // corresponding `Principal` object. - AccountIdForPrincipal string `json:"accountIdForPrincipal,omitempty"` + AccountIdForPrincipal AccountId `json:"accountIdForPrincipal,omitempty"` // The id of the `Principal` that owns this account. - PrincipalId string `json:"principalId,omitempty"` + PrincipalId PrincipalId `json:"principalId,omitempty"` } type SessionPrincipalAvailabilityAccountCapabilities struct { @@ -821,7 +825,7 @@ type SessionPrincipalCapabilities struct { // // The corresponding Account object can be found in the Principal's "accounts" property, as // per Section 2 of [RFC9670](https://www.rfc-editor.org/rfc/rfc9670.html). - AccountId string `json:"accountId,omitempty"` + AccountId AccountId `json:"accountId,omitempty"` // If true, the user may call the "Principal/getAvailability" method with this Principal. MayGetAvailability *bool `json:"mayGetAvailability,omitzero"` @@ -916,19 +920,19 @@ type SessionCapabilities struct { } type SessionPrimaryAccounts struct { - Core string `json:"urn:ietf:params:jmap:core,omitempty"` - Mail string `json:"urn:ietf:params:jmap:mail,omitempty"` - Submission string `json:"urn:ietf:params:jmap:submission,omitempty"` - VacationResponse string `json:"urn:ietf:params:jmap:vacationresponse,omitempty"` - Sieve string `json:"urn:ietf:params:jmap:sieve,omitempty"` - Blob string `json:"urn:ietf:params:jmap:blob,omitempty"` - Quota string `json:"urn:ietf:params:jmap:quota,omitempty"` - Websocket string `json:"urn:ietf:params:jmap:websocket,omitempty"` - Task string `json:"urn:ietf:params:jmap:task,omitempty"` - Calendars string `json:"urn:ietf:params:jmap:calendars,omitempty"` - CalendarsParse string `json:"urn:ietf:params:jmap:calendars:parse,omitempty"` - Contacts string `json:"urn:ietf:params:jmap:contacts,omitempty"` - ContactsParse string `json:"urn:ietf:params:jmap:contacts:parse,omitempty"` + Core AccountId `json:"urn:ietf:params:jmap:core,omitempty"` + Mail AccountId `json:"urn:ietf:params:jmap:mail,omitempty"` + Submission AccountId `json:"urn:ietf:params:jmap:submission,omitempty"` + VacationResponse AccountId `json:"urn:ietf:params:jmap:vacationresponse,omitempty"` + Sieve AccountId `json:"urn:ietf:params:jmap:sieve,omitempty"` + Blob AccountId `json:"urn:ietf:params:jmap:blob,omitempty"` + Quota AccountId `json:"urn:ietf:params:jmap:quota,omitempty"` + Websocket AccountId `json:"urn:ietf:params:jmap:websocket,omitempty"` + Task AccountId `json:"urn:ietf:params:jmap:task,omitempty"` + Calendars AccountId `json:"urn:ietf:params:jmap:calendars,omitempty"` + CalendarsParse AccountId `json:"urn:ietf:params:jmap:calendars:parse,omitempty"` + Contacts AccountId `json:"urn:ietf:params:jmap:contacts,omitempty"` + ContactsParse AccountId `json:"urn:ietf:params:jmap:contacts:parse,omitempty"` } type SessionState string @@ -946,7 +950,7 @@ const NoLanguage = Language("") type SessionResponse struct { Capabilities SessionCapabilities `json:"capabilities"` - Accounts map[string]Account `json:"accounts,omitempty"` + Accounts map[AccountId]Account `json:"accounts,omitempty"` // A map of capability URIs (as found in accountCapabilities) to the account id that is considered to be the user’s main or default // account for data pertaining to that capability. @@ -1164,6 +1168,8 @@ type SetError struct { type Command string +const NoCommand = Command("") + type Invocation struct { Command Command Parameters any @@ -1179,7 +1185,7 @@ func invocation(parameters JmapCommand, tag string) Invocation { } func skipInvocation() Invocation { - return Invocation{Command: ""} + return Invocation{Command: NoCommand} } type TypeOfRequest string @@ -1239,10 +1245,12 @@ type Response struct { RequestId string `json:"requestId,omitempty"` } +// A JMAP object. type Foo interface { GetObjectType() ObjectType } +// A JMAP object that also has an identifier. type Idable interface { GetId() string Foo @@ -1384,6 +1392,7 @@ type ChangesResponse[T Foo] interface { type QueryCommand[T Foo, SELF QueryCommand[T, SELF]] interface { JmapCommand GetResponse() QueryResponse[T] + // Wither that creates a new object of the same type, keeping all the same values except for the limit that is specified as parameter. WithLimit(limit *uint) SELF } @@ -1436,8 +1445,8 @@ type QueryParams struct { var NullQueryParams = QueryParams{Position: 0, Anchor: "", AnchorOffset: nil} -func toNullQueryParams(accountIds []string) map[string]QueryParams { - return structs.ToMap(accountIds, func(k string) (string, QueryParams) { return k, NullQueryParams }) +func toNullQueryParams(accountIds []AccountId) map[AccountId]QueryParams { + return structs.ToMap(accountIds, func(k AccountId) (AccountId, QueryParams) { return k, NullQueryParams }) } type FilterElement[T Foo] interface { @@ -1751,8 +1760,8 @@ func (m MailboxChange) AsPatch() (PatchObject, error) { } type MailboxGetCommand struct { - AccountId string `json:"accountId"` - Ids []string `json:"ids,omitempty"` + AccountId AccountId `json:"accountId"` + Ids []string `json:"ids,omitempty"` } var _ GetCommand[Mailbox] = &MailboxGetCommand{} @@ -1762,7 +1771,7 @@ func (c MailboxGetCommand) GetObjectType() ObjectType { return MailboxTy func (c MailboxGetCommand) GetResponse() GetResponse[Mailbox] { return MailboxGetResponse{} } type MailboxGetRefCommand struct { - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` IdsRef *ResultReference `json:"#ids,omitempty"` } @@ -1773,8 +1782,8 @@ func (c MailboxGetRefCommand) GetObjectType() ObjectType { return Mailbo func (c MailboxGetRefCommand) GetResponse() GetResponse[Mailbox] { return MailboxGetResponse{} } type MailboxSetCommand struct { - AccountId string `json:"accountId"` - IfInState string `json:"ifInState,omitempty"` + AccountId AccountId `json:"accountId"` + IfInState State `json:"ifInState,omitempty"` Create map[string]MailboxChange `json:"create,omitempty"` Update map[string]PatchObject `json:"update,omitempty"` Destroy []string `json:"destroy,omitempty"` @@ -1787,7 +1796,7 @@ func (c MailboxSetCommand) GetObjectType() ObjectType { return MailboxTy func (c MailboxSetCommand) GetResponse() SetResponse[Mailbox] { return MailboxSetResponse{} } type MailboxSetResponse struct { - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` OldState State `json:"oldState,omitempty"` NewState State `json:"newState,omitempty"` Created map[string]*Mailbox `json:"created,omitempty"` @@ -1853,7 +1862,7 @@ var _ Comparator[Mailbox] = &MailboxComparator{} func (c MailboxComparator) GetMarker() Mailbox { return Mailbox{} } type MailboxQueryCommand struct { - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` Filter MailboxFilterElement `json:"filter,omitempty"` Sort []MailboxComparator `json:"sort,omitempty"` SortAsTree bool `json:"sortAsTree,omitempty"` @@ -2157,7 +2166,7 @@ func (c EmailComparator) GetMarker() Email { return Email{} } // A client can use anchor instead of position to find the index of an id within a large set of results. type EmailQueryCommand struct { // The id of the account to use. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // Determines the set of Emails returned in the results. // @@ -2250,7 +2259,7 @@ type EmailGetCommand struct { Ids []string `json:"ids,omitempty"` // The id of the account to use. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // If supplied, only the properties listed in the array are returned for each Email object. // @@ -2316,7 +2325,7 @@ type EmailGetRefCommand struct { IdsRef *ResultReference `json:"#ids,omitempty"` // The id of the account to use. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // If supplied, only the properties listed in the array are returned for each Email object. // @@ -2372,7 +2381,7 @@ func (c EmailGetRefCommand) GetResponse() GetResponse[Email] { return EmailGetRe type EmailChangesCommand struct { // The id of the account to use. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // The current state of the client. // @@ -2634,7 +2643,7 @@ type Email struct { // The account ID this email belongs to. // Note that this is not part of the JMAP specification, and is only contained in all-account operations. - AccountId string `json:"accountId,omitempty"` + AccountId AccountId `json:"accountId,omitempty"` // The set of Mailbox ids this Email belongs to. // @@ -2998,7 +3007,7 @@ func (f EmailSubmission) GetId() string { return f.Id } type EmailSubmissionGetCommand struct { // The id of the account to use. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // The ids of the EmailSubmission objects to return. // @@ -3024,7 +3033,7 @@ func (c EmailSubmissionGetCommand) GetResponse() GetResponse[EmailSubmission] { type EmailSubmissionGetRefCommand struct { // The id of the account to use. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // The ids of the EmailSubmission objects to return. // @@ -3050,7 +3059,7 @@ func (c EmailSubmissionGetRefCommand) GetResponse() GetResponse[EmailSubmission] type EmailSubmissionGetResponse struct { // The id of the account used for the call. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // A (preferably short) string representing the state on the server for all the data // of this type in the account (not just the objects returned in this call). @@ -3089,7 +3098,7 @@ func (r EmailSubmissionGetResponse) GetList() []EmailSubmission { return r.List type EmailSubmissionChangesCommand struct { // The id of the account to use. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // The current state of the client. // @@ -3120,7 +3129,7 @@ func (c EmailSubmissionChangesCommand) GetResponse() ChangesResponse[EmailSubmis type EmailSubmissionChangesResponse struct { // The id of the account used for the call. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // This is the sinceState argument echoed back; it’s the state from which the server is returning changes. OldState State `json:"oldState"` @@ -3169,7 +3178,7 @@ type EmailSubmissionCreate struct { } type EmailSubmissionSetCommand struct { - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` Create map[string]EmailSubmissionCreate `json:"create,omitempty"` OldState State `json:"oldState,omitempty"` NewState State `json:"newState,omitempty"` @@ -3203,7 +3212,7 @@ type CreatedEmailSubmission struct { type EmailSubmissionSetResponse struct { // The id of the account used for the call. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // This is the sinceState argument echoed back; it’s the state from which the server is returning changes. OldState State `json:"oldState"` @@ -3239,7 +3248,7 @@ func (r EmailSubmissionSetResponse) GetMarker() EmailSubmission { retu type EmailQueryResponse struct { // The id of the account used for the call. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // A string encoding the current state of the query on the server. // @@ -3294,7 +3303,7 @@ func (r EmailQueryResponse) GetMarker() Email { return Email{} } type EmailGetResponse struct { // The id of the account used for the call. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // A (preferably short) string representing the state on the server for all the data of this type // in the account (not just the objects returned in this call). @@ -3328,7 +3337,7 @@ func (r EmailGetResponse) GetMarker() Email { return Email{} } type EmailChangesResponse struct { // The id of the account used for the call. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // This is the sinceState argument echoed back; it’s the state from which the server is returning changes. OldState State `json:"oldState"` @@ -3362,7 +3371,7 @@ func (r EmailChangesResponse) GetMarker() Email { return Email{} } type MailboxGetResponse struct { // The id of the account used for the call. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // A (preferably short) string representing the state on the server for all the data of this type in the account // (not just the objects returned in this call). @@ -3393,7 +3402,7 @@ func (r MailboxGetResponse) GetList() []Mailbox { return r.List } type MailboxChangesCommand struct { // The id of the account to use. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // The current state of the client. // @@ -3424,7 +3433,7 @@ func (c MailboxChangesCommand) GetResponse() ChangesResponse[Mailbox] { type MailboxChangesResponse struct { // The id of the account used for the call. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // This is the sinceState argument echoed back; it’s the state from which the server is returning changes. OldState State `json:"oldState"` @@ -3465,7 +3474,7 @@ func (r MailboxChangesResponse) GetMarker() Mailbox { return Mailbox{} } type MailboxQueryResponse struct { // The id of the account used for the call. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // A string encoding the current state of the query on the server. // @@ -3625,7 +3634,7 @@ func (e EmailChange) AsPatch() (PatchObject, error) { type EmailSetCommand struct { // The id of the account to use. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // This is a state string as returned by the `Email/get` method. // @@ -3633,7 +3642,7 @@ type EmailSetCommand struct { // `stateMismatch` error returned. // // If null, any changes will be applied to the current state. - IfInState string `json:"ifInState,omitempty"` + IfInState State `json:"ifInState,omitempty"` // A map of a creation id (a temporary id set by the client) to Email objects, // or null if no objects are to be created. @@ -3684,7 +3693,7 @@ func (c EmailSetCommand) GetResponse() SetResponse[Email] { return EmailSetRespo type EmailSetResponse struct { // The id of the account used for the call. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // The state string that would have been returned by Email/get before making the // requested changes, or null if the server doesn’t know what the previous state @@ -3760,7 +3769,7 @@ type EmailImport struct { } type EmailImportCommand struct { - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // This is a state string as returned by the Email/get method. // @@ -3769,7 +3778,7 @@ type EmailImportCommand struct { // error returned. // // If null, any changes will be applied to the current state. - IfInState string `json:"ifInState,omitempty"` + IfInState State `json:"ifInState,omitempty"` // A map of creation id (client specified) to EmailImport objects. Emails map[string]EmailImport `json:"emails"` @@ -3792,7 +3801,7 @@ type ImportedEmail struct { type EmailImportResponse struct { // The id of the account used for this call. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // The state string that would have been returned by Email/get on this account // before making the requested changes, or null if the server doesn’t know @@ -3834,8 +3843,8 @@ func (f Thread) GetObjectType() ObjectType { return ThreadType } func (f Thread) GetId() string { return f.Id } type ThreadGetCommand struct { - AccountId string `json:"accountId"` - Ids []string `json:"ids,omitempty"` + AccountId AccountId `json:"accountId"` + Ids []string `json:"ids,omitempty"` } var _ GetCommand[Thread] = &ThreadGetCommand{} @@ -3845,7 +3854,7 @@ func (c ThreadGetCommand) GetObjectType() ObjectType { return ThreadType func (c ThreadGetCommand) GetResponse() GetResponse[Thread] { return ThreadGetResponse{} } type ThreadGetRefCommand struct { - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` IdsRef *ResultReference `json:"#ids,omitempty"` } @@ -3856,7 +3865,7 @@ func (c ThreadGetRefCommand) GetObjectType() ObjectType { return ThreadTy func (c ThreadGetRefCommand) GetResponse() GetResponse[Thread] { return ThreadGetResponse{} } type ThreadGetResponse struct { - AccountId string + AccountId AccountId State State List []Thread NotFound []string @@ -3870,8 +3879,8 @@ func (r ThreadGetResponse) GetList() []Thread { return r.List } func (r ThreadGetResponse) GetMarker() Thread { return Thread{} } type IdentityGetCommand struct { - AccountId string `json:"accountId"` - Ids []string `json:"ids,omitempty"` + AccountId AccountId `json:"accountId"` + Ids []string `json:"ids,omitempty"` } var _ GetCommand[Identity] = &IdentityGetCommand{} @@ -3881,7 +3890,7 @@ func (c IdentityGetCommand) GetObjectType() ObjectType { return Identit func (c IdentityGetCommand) GetResponse() GetResponse[Identity] { return IdentityGetResponse{} } type IdentityGetRefCommand struct { - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` IdsRef *ResultReference `json:"#ids,omitempty"` PropertiesRef *ResultReference `json:"#properties,omitempty"` } @@ -3894,7 +3903,7 @@ func (c IdentityGetRefCommand) GetResponse() GetResponse[Identity] { return Iden type IdentityChangesCommand struct { // The id of the account to use. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // The current state of the client. // @@ -3925,7 +3934,7 @@ func (c IdentityChangesCommand) GetResponse() ChangesResponse[Identity] { type IdentityChangesResponse struct { // The id of the account used for the call. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // This is the sinceState argument echoed back; it’s the state from which the server is returning changes. OldState State `json:"oldState"` @@ -3959,8 +3968,8 @@ func (r IdentityChangesResponse) GetDestroyed() []string { return r.Destroyed } func (r IdentityChangesResponse) GetMarker() Identity { return Identity{} } type IdentitySetCommand struct { - AccountId string `json:"accountId"` - IfInState string `json:"ifInState,omitempty"` + AccountId AccountId `json:"accountId"` + IfInState State `json:"ifInState,omitempty"` Create map[string]IdentityChange `json:"create,omitempty"` Update map[string]PatchObject `json:"update,omitempty"` Destroy []string `json:"destroy,omitempty"` @@ -3973,7 +3982,7 @@ func (c IdentitySetCommand) GetObjectType() ObjectType { return Identit func (c IdentitySetCommand) GetResponse() SetResponse[Identity] { return IdentitySetResponse{} } type IdentitySetResponse struct { - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` OldState State `json:"oldState,omitempty"` NewState State `json:"newState,omitempty"` Created map[string]*Identity `json:"created,omitempty"` @@ -4081,7 +4090,7 @@ func (i IdentityChange) AsPatch() (PatchObject, error) { } type IdentityGetResponse struct { - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` State State `json:"state"` List []Identity `json:"list,omitempty"` NotFound []string `json:"notFound,omitempty"` @@ -4095,7 +4104,7 @@ func (r IdentityGetResponse) GetNotFound() []string { return r.NotFound } func (r IdentityGetResponse) GetList() []Identity { return r.List } type VacationResponseGetCommand struct { - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` } var _ GetCommand[VacationResponse] = &VacationResponseGetCommand{} @@ -4156,7 +4165,7 @@ func (f VacationResponse) GetId() string { return f.Id } type VacationResponseGetResponse struct { // The identifier of the account this response pertains to. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // A string representing the state on the server for all the data of this type in the account // (not just the objects returned in this call). @@ -4180,7 +4189,7 @@ func (r VacationResponseGetResponse) GetNotFound() []string { return r.Not func (r VacationResponseGetResponse) GetList() []VacationResponse { return r.List } type VacationResponseSetCommand struct { - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` IfInState string `json:"ifInState,omitempty"` Create map[string]VacationResponse `json:"create,omitempty"` Update map[string]PatchObject `json:"update,omitempty"` @@ -4196,7 +4205,7 @@ func (c VacationResponseSetCommand) GetResponse() SetResponse[VacationResponse] } type VacationResponseSetResponse struct { - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` OldState State `json:"oldState,omitempty"` NewState State `json:"newState,omitempty"` Created map[string]VacationResponse `json:"created,omitempty"` @@ -4228,7 +4237,7 @@ type UploadObject struct { } type BlobUploadCommand struct { - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` Create map[string]UploadObject `json:"create"` } @@ -4245,7 +4254,7 @@ type BlobUploadCreateResult struct { } type BlobUploadResponse struct { - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` Created map[string]BlobUploadCreateResult `json:"created"` } @@ -4341,11 +4350,11 @@ func (c BlobChanges) GetUpdated() []Blob { return c.Updated } func (c BlobChanges) GetDestroyed() []string { return c.Destroyed } type BlobGetCommand struct { - AccountId string `json:"accountId"` - Ids []string `json:"ids,omitempty"` - Properties []string `json:"properties,omitempty"` - Position int `json:"position,omitzero"` - Length int `json:"length,omitzero"` + AccountId AccountId `json:"accountId"` + Ids []string `json:"ids,omitempty"` + Properties []string `json:"properties,omitempty"` + Position int `json:"position,omitzero"` + Length int `json:"length,omitzero"` } var _ GetCommand[Blob] = &BlobGetCommand{} @@ -4355,7 +4364,7 @@ func (c BlobGetCommand) GetObjectType() ObjectType { return BlobType } func (c BlobGetCommand) GetResponse() GetResponse[Blob] { return BlobGetResponse{} } type BlobGetRefCommand struct { - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` IdRef *ResultReference `json:"#ids,omitempty"` Properties []string `json:"properties,omitempty"` Position int `json:"position,omitzero"` @@ -4370,7 +4379,7 @@ func (c BlobGetRefCommand) GetResponse() GetResponse[Blob] { return BlobGetRespo type BlobGetResponse struct { // The id of the account used for the call. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // A string representing the state on the server for all the data of this type in the // account (not just the objects returned in this call). @@ -4461,7 +4470,7 @@ func (f SearchSnippet) GetObjectType() ObjectType { return SearchSnippetType } type SearchSnippetGetRefCommand struct { // The id of the account to use. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // The same filter as passed to Email/query. Filter EmailFilterElement `json:"filter,omitempty"` @@ -4476,7 +4485,7 @@ func (c SearchSnippetGetRefCommand) GetCommand() Command { return CommandS func (c SearchSnippetGetRefCommand) GetObjectType() ObjectType { return SearchSnippetType } type SearchSnippetGetResponse struct { - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` List []SearchSnippet `json:"list,omitempty"` NotFound []string `json:"notFound,omitempty"` } @@ -4503,7 +4512,7 @@ type StateChange struct { // The client can compare the new state strings with its current values to see whether // it has the current data for these types. If not, the changes can then be efficiently // fetched in a single standard API request (using the /changes type methods). - Changed map[string]map[ObjectTypeName]string `json:"changed"` + Changed map[AccountId]map[ObjectTypeName]string `json:"changed"` // A (preferably short) string that encodes the entire server state visible to the user // (not just the objects returned in this call). @@ -4586,7 +4595,7 @@ type AddressBook struct { // // The account id for the principals may be found in the urn:ietf:params:jmap:principals:owner capability // of the Account to which the AddressBook belongs. - ShareWith map[string]AddressBookRights `json:"shareWith,omitempty"` + ShareWith map[PrincipalId]AddressBookRights `json:"shareWith,omitempty"` // The set of access rights the user has in relation to this AddressBook (server-set). MyRights AddressBookRights `json:"myRights"` @@ -5337,7 +5346,7 @@ type Calendar struct { // // The account id for the principals may be found in the `urn:ietf:params:jmap:principals:owner` // capability of the `Account` to which the calendar belongs. - ShareWith map[string]CalendarRights `json:"shareWith,omitempty"` + ShareWith map[PrincipalId]CalendarRights `json:"shareWith,omitempty"` // The set of access rights the user has in relation to this Calendar. // @@ -5468,7 +5477,7 @@ type CalendarChange struct { // // The account id for the principals may be found in the `urn:ietf:params:jmap:principals:owner` // capability of the `Account` to which the calendar belongs. - ShareWith map[string]CalendarRights `json:"shareWith,omitempty"` + ShareWith map[PrincipalId]CalendarRights `json:"shareWith,omitempty"` // The set of access rights the user has in relation to this Calendar. // @@ -5790,7 +5799,7 @@ type CalendarAlert struct { Type TypeOfCalendarAlert `json:"@type,omitempty"` // The account id for the calendar in which the alert triggered. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // The CalendarEvent id for the alert that triggered. // @@ -5818,7 +5827,7 @@ type Person struct { // The id of the `Principal` corresponding to the person who made the change, if any. // // This will be null if the change was due to receving an iTIP message. - PrincipalId string `json:"principalId,omitempty"` + PrincipalId PrincipalId `json:"principalId,omitempty"` // The `scheduleId` URI of the person who made the change, if any. // @@ -6052,7 +6061,7 @@ type TaskList struct { // // The account id for the principals may be found in the `urn:ietf:params:jmap:principals:owner` capability // of the `Account` to which the task list belongs. - ShareWith map[string]TaskRights `json:"shareWith,omitempty"` + ShareWith map[PrincipalId]TaskRights `json:"shareWith,omitempty"` // The set of access rights the user has in relation to this `TaskList`. // @@ -6366,7 +6375,7 @@ type Principal struct { // A map of account id to `Account` object for each JMAP Account containing data for // this principal that the user has access to, or null if none. - Accounts map[string]Account `json:"accounts,omitempty"` + Accounts map[AccountId]Account `json:"accounts,omitempty"` } var _ Idable = &Principal{} @@ -6598,7 +6607,7 @@ type MDN struct { type SendMDN struct { // The id of the account to use. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // The id of the `Identity` to associate with these MDNs. // @@ -6616,8 +6625,8 @@ type SendMDN struct { } type QuotaGetCommand struct { - AccountId string `json:"accountId"` - Ids []string `json:"ids,omitempty"` + AccountId AccountId `json:"accountId"` + Ids []string `json:"ids,omitempty"` } var _ GetCommand[Quota] = &QuotaGetCommand{} @@ -6627,7 +6636,7 @@ func (c QuotaGetCommand) GetObjectType() ObjectType { return QuotaType } func (c QuotaGetCommand) GetResponse() GetResponse[Quota] { return QuotaGetResponse{} } type QuotaGetRefCommand struct { - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` IdsRef *ResultReference `json:"#ids,omitempty"` PropertiesRef *ResultReference `json:"#properties,omitempty"` } @@ -6639,10 +6648,10 @@ func (c QuotaGetRefCommand) GetObjectType() ObjectType { return QuotaType func (c QuotaGetRefCommand) GetResponse() GetResponse[Quota] { return QuotaGetResponse{} } type QuotaGetResponse struct { - AccountId string `json:"accountId"` - State State `json:"state,omitempty"` - List []Quota `json:"list,omitempty"` - NotFound []string `json:"notFound,omitempty"` + AccountId AccountId `json:"accountId"` + State State `json:"state,omitempty"` + List []Quota `json:"list,omitempty"` + NotFound []string `json:"notFound,omitempty"` } var _ GetResponse[Quota] = &QuotaGetResponse{} @@ -6654,7 +6663,7 @@ func (r QuotaGetResponse) GetList() []Quota { return r.List } type QuotaChangesCommand struct { // The id of the account to use. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // The current state of the client. // This is the string that was returned as the "state" argument in the "Quota/get" response. @@ -6682,7 +6691,7 @@ func (c QuotaChangesCommand) GetResponse() ChangesResponse[Quota] { return Quota type QuotaChangesResponse struct { // The id of the account used for the call. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // This is the "sinceState" argument echoed back; it's the state from which the server is returning changes. OldState State `json:"oldState"` @@ -6715,8 +6724,8 @@ func (r QuotaChangesResponse) GetDestroyed() []string { return r.Destroyed } func (r QuotaChangesResponse) GetMarker() Quota { return Quota{} } type AddressBookGetCommand struct { - AccountId string `json:"accountId"` - Ids []string `json:"ids,omitempty"` + AccountId AccountId `json:"accountId"` + Ids []string `json:"ids,omitempty"` } var _ GetCommand[AddressBook] = &AddressBookGetCommand{} @@ -6728,7 +6737,7 @@ func (c AddressBookGetCommand) GetResponse() GetResponse[AddressBook] { } type AddressBookGetRefCommand struct { - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` IdsRef *ResultReference `json:"#ids,omitempty"` } @@ -6741,7 +6750,7 @@ func (c AddressBookGetRefCommand) GetResponse() GetResponse[AddressBook] { } type AddressBookGetResponse struct { - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` State State `json:"state,omitempty"` List []AddressBook `json:"list,omitempty"` NotFound []string `json:"notFound,omitempty"` @@ -6795,7 +6804,7 @@ type AddressBookChange struct { // // The account id for the principals may be found in the urn:ietf:params:jmap:principals:owner capability // of the Account to which the AddressBook belongs. - ShareWith map[string]AddressBookRights `json:"shareWith,omitempty"` + ShareWith map[PrincipalId]AddressBookRights `json:"shareWith,omitempty"` } var _ Change = AddressBookChange{} @@ -6805,8 +6814,8 @@ func (a AddressBookChange) AsPatch() (PatchObject, error) { } type AddressBookSetCommand struct { - AccountId string `json:"accountId"` - IfInState string `json:"ifInState,omitempty"` + AccountId AccountId `json:"accountId"` + IfInState State `json:"ifInState,omitempty"` Create map[string]AddressBookChange `json:"create,omitempty"` Update map[string]PatchObject `json:"update,omitempty"` Destroy []string `json:"destroy,omitempty"` @@ -6822,7 +6831,7 @@ func (c AddressBookSetCommand) GetResponse() SetResponse[AddressBook] { type AddressBookSetResponse struct { // The id of the account used for the call. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // The state string that would have been returned by AddressBook/get before making the // requested changes, or null if the server doesn’t know what the previous state @@ -6878,7 +6887,7 @@ func (r AddressBookSetResponse) GetMarker() AddressBook { return A type AddressBookChangesCommand struct { // The id of the account to use. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // The current state of the client. // @@ -6909,7 +6918,7 @@ func (c AddressBookChangesCommand) GetResponse() ChangesResponse[AddressBook] { type AddressBookChangesResponse struct { // The id of the account used for the call. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // This is the sinceState argument echoed back; it’s the state from which the server is returning changes. OldState State `json:"oldState"` @@ -7144,7 +7153,7 @@ func (o ContactCardFilterOperator) IsNotEmpty() bool { } type ContactCardQueryCommand struct { - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` Filter ContactCardFilterElement `json:"filter,omitempty"` @@ -7216,7 +7225,7 @@ func (c ContactCardQueryCommand) WithLimit(limit *uint) ContactCardQueryCommand type ContactCardQueryResponse struct { // The id of the account used for the call. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // A string encoding the current state of the query on the server. // @@ -7277,7 +7286,7 @@ type ContactCardGetCommand struct { Ids []string `json:"ids,omitempty"` // The id of the account to use. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // If supplied, only the properties listed in the array are returned for each ContactCard object. // @@ -7303,7 +7312,7 @@ type ContactCardGetRefCommand struct { IdsRef *ResultReference `json:"#ids,omitempty"` // The id of the account to use. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // If supplied, only the properties listed in the array are returned for each ContactCard object. // @@ -7323,7 +7332,7 @@ func (c ContactCardGetRefCommand) GetResponse() GetResponse[ContactCard] { type ContactCardGetResponse struct { // The id of the account used for the call. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // A (preferably short) string representing the state on the server for all the data of this type // in the account (not just the objects returned in this call). @@ -7357,7 +7366,7 @@ func (r ContactCardGetResponse) GetList() []ContactCard { return r.List } type ContactCardChangesCommand struct { // The id of the account to use. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // The current state of the client. // This is the string that was returned as the "state" argument in the "ContactCard/get" response. @@ -7382,7 +7391,7 @@ func (c ContactCardChangesCommand) GetResponse() ChangesResponse[ContactCard] { type ContactCardChangesResponse struct { // The id of the account used for the call. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // This is the "sinceState" argument echoed back; it's the state from which the server is returning changes. OldState State `json:"oldState"` @@ -7416,7 +7425,7 @@ func (r ContactCardChangesResponse) GetMarker() ContactCard { return ContactCar type ContactCardSetCommand struct { // The id of the account to use. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // This is a state string as returned by the `ContactCard/get` method. // @@ -7424,7 +7433,7 @@ type ContactCardSetCommand struct { // `stateMismatch` error returned. // // If null, any changes will be applied to the current state. - IfInState string `json:"ifInState,omitempty"` + IfInState State `json:"ifInState,omitempty"` // A map of a creation id (a temporary id set by the client) to ContactCard objects, // or null if no objects are to be created. @@ -7477,7 +7486,7 @@ func (c ContactCardSetCommand) GetResponse() SetResponse[ContactCard] { type ContactCardSetResponse struct { // The id of the account used for the call. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // The state string that would have been returned by ContactCard/get before making the // requested changes, or null if the server doesn’t know what the previous state @@ -7533,7 +7542,7 @@ func (r ContactCardSetResponse) GetMarker() ContactCard { return C type CalendarEventParseCommand struct { // The id of the account to use. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // The ids of the blobs to parse BlobIds []string `json:"blobIds,omitempty"` @@ -7554,7 +7563,7 @@ func (c CalendarEventParseCommand) GetResponse() ParseResponse[CalendarEvent] { type CalendarEventParseResponse struct { // The id of the account used for the call. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // A map of blob ids to parsed CalendarEvent objects representations for each successfully // parsed blob, or null if none. @@ -7573,8 +7582,8 @@ var _ ParseResponse[CalendarEvent] = &CalendarEventParseResponse{} func (r CalendarEventParseResponse) GetMarker() CalendarEvent { return CalendarEvent{} } type CalendarGetCommand struct { - AccountId string `json:"accountId"` - Ids []string `json:"ids,omitempty"` + AccountId AccountId `json:"accountId"` + Ids []string `json:"ids,omitempty"` } var _ GetCommand[Calendar] = &CalendarGetCommand{} @@ -7584,7 +7593,7 @@ func (c CalendarGetCommand) GetObjectType() ObjectType { return Calenda func (c CalendarGetCommand) GetResponse() GetResponse[Calendar] { return CalendarGetResponse{} } type CalendarGetRefCommand struct { - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` IdsRef *ResultReference `json:"#ids,omitempty"` } @@ -7595,7 +7604,7 @@ func (c CalendarGetRefCommand) GetObjectType() ObjectType { return Cale func (c CalendarGetRefCommand) GetResponse() GetResponse[Calendar] { return CalendarGetResponse{} } type CalendarGetResponse struct { - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` State State `json:"state,omitempty"` List []Calendar `json:"list,omitempty"` NotFound []string `json:"notFound,omitempty"` @@ -7609,8 +7618,8 @@ func (r CalendarGetResponse) GetNotFound() []string { return r.NotFound } func (r CalendarGetResponse) GetList() []Calendar { return r.List } type CalendarSetCommand struct { - AccountId string `json:"accountId"` - IfInState string `json:"ifInState,omitempty"` + AccountId AccountId `json:"accountId"` + IfInState State `json:"ifInState,omitempty"` Create map[string]CalendarChange `json:"create,omitempty"` Update map[string]PatchObject `json:"update,omitempty"` Destroy []string `json:"destroy,omitempty"` @@ -7626,7 +7635,7 @@ func (c CalendarSetCommand) GetResponse() SetResponse[Calendar] { type CalendarSetResponse struct { // The id of the account used for the call. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // The state string that would have been returned by Calendar/get before making the // requested changes, or null if the server doesn’t know what the previous state @@ -7682,7 +7691,7 @@ func (r CalendarSetResponse) GetMarker() Calendar { return Cale type CalendarChangesCommand struct { // The id of the account to use. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // The current state of the client. // @@ -7713,7 +7722,7 @@ func (c CalendarChangesCommand) GetResponse() ChangesResponse[Calendar] { type CalendarChangesResponse struct { // The id of the account used for the call. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // This is the "sinceState" argument echoed back; it's the state from which the server is returning changes. OldState State `json:"oldState"` @@ -7893,7 +7902,7 @@ func (o CalendarEventFilterOperator) IsNotEmpty() bool { var _ CalendarEventFilterElement = &CalendarEventFilterOperator{} type CalendarEventQueryCommand struct { - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` Filter CalendarEventFilterElement `json:"filter,omitempty"` @@ -7965,7 +7974,7 @@ func (c CalendarEventQueryCommand) WithLimit(limit *uint) CalendarEventQueryComm type CalendarEventQueryResponse struct { // The id of the account used for the call. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // A string encoding the current state of the query on the server. // @@ -8026,7 +8035,7 @@ type CalendarEventGetCommand struct { Ids []string `json:"ids,omitempty"` // The id of the account to use. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // If supplied, only the properties listed in the array are returned for each CalendarEvent object. // @@ -8052,7 +8061,7 @@ type CalendarEventGetRefCommand struct { IdsRef *ResultReference `json:"#ids,omitempty"` // The id of the account to use. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // If supplied, only the properties listed in the array are returned for each CalendarEvent object. // @@ -8072,7 +8081,7 @@ func (c CalendarEventGetRefCommand) GetResponse() GetResponse[CalendarEvent] { type CalendarEventGetResponse struct { // The id of the account used for the call. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // A (preferably short) string representing the state on the server for all the data of this type // in the account (not just the objects returned in this call). @@ -8106,7 +8115,7 @@ func (r CalendarEventGetResponse) GetList() []CalendarEvent { return r.List } type CalendarEventChangesCommand struct { // The id of the account to use. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // The current state of the client. // @@ -8137,7 +8146,7 @@ func (c CalendarEventChangesCommand) GetResponse() ChangesResponse[CalendarEvent type CalendarEventChangesResponse struct { // The id of the account used for the call. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // This is the "sinceState" argument echoed back; it's the state from which the server is returning changes. OldState State `json:"oldState"` @@ -8171,7 +8180,7 @@ func (r CalendarEventChangesResponse) GetMarker() CalendarEvent { return Calenda type CalendarEventSetCommand struct { // The id of the account to use. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // This is a state string as returned by the `CalendarEvent/get` method. // @@ -8179,7 +8188,7 @@ type CalendarEventSetCommand struct { // `stateMismatch` error returned. // // If null, any changes will be applied to the current state. - IfInState string `json:"ifInState,omitempty"` + IfInState State `json:"ifInState,omitempty"` // A map of a creation id (a temporary id set by the client) to CalendarEvent objects, // or null if no objects are to be created. @@ -8232,7 +8241,7 @@ func (c CalendarEventSetCommand) GetResponse() SetResponse[CalendarEvent] { type CalendarEventSetResponse struct { // The id of the account used for the call. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // The state string that would have been returned by CalendarEvent/get before making the // requested changes, or null if the server doesn’t know what the previous state @@ -8287,8 +8296,8 @@ func (r CalendarEventSetResponse) GetNotDestroyed() map[string]SetError { return func (r CalendarEventSetResponse) GetMarker() CalendarEvent { return CalendarEvent{} } type PrincipalGetCommand struct { - AccountId string `json:"accountId"` - Ids []string `json:"ids,omitempty"` + AccountId AccountId `json:"accountId"` + Ids []PrincipalId `json:"ids,omitempty"` } var _ GetCommand[Principal] = &PrincipalGetCommand{} @@ -8298,7 +8307,7 @@ func (c PrincipalGetCommand) GetObjectType() ObjectType { return Princ func (c PrincipalGetCommand) GetResponse() GetResponse[Principal] { return PrincipalGetResponse{} } type PrincipalGetRefCommand struct { - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` IdsRef *ResultReference `json:"#ids,omitempty"` } @@ -8310,7 +8319,7 @@ func (c PrincipalGetRefCommand) GetResponse() GetResponse[Principal] { return Pr type PrincipalGetResponse struct { // The id of the account used for the call. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // A (preferably short) string representing the state on the server for all the data of this type in the account // (not just the objects returned in this call). @@ -8346,7 +8355,7 @@ type PrincipalFilterElement interface { type PrincipalFilterCondition struct { // A list of Account ids. // The Principal matches if any of the ids in this list are keys in the Principal's "accounts" property (i.e., if any of the Account ids belong to the Principal). - AccountIds []string `json:"accountIds,omitempty"` + AccountIds []AccountId `json:"accountIds,omitempty"` // The email property of the Principal contains the given string. Email string `json:"email,omitempty"` // The name property of the Principal contains the given string. @@ -8394,7 +8403,7 @@ var _ Comparator[Principal] = &PrincipalComparator{} func (c PrincipalComparator) GetMarker() Principal { return Principal{} } type PrincipalQueryCommand struct { - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` Filter PrincipalFilterElement `json:"filter,omitempty"` Sort []PrincipalComparator `json:"sort,omitempty"` @@ -8464,7 +8473,7 @@ func (c PrincipalQueryCommand) WithLimit(limit *uint) PrincipalQueryCommand { type PrincipalQueryResponse struct { // The id of the account used for the call. - AccountId string `json:"accountId"` + AccountId AccountId `json:"accountId"` // A string encoding the current state of the query on the server. // diff --git a/pkg/jmap/model_examples.go b/pkg/jmap/model_examples.go index 1c763bcabd..2585ca15bc 100644 --- a/pkg/jmap/model_examples.go +++ b/pkg/jmap/model_examples.go @@ -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, diff --git a/pkg/jmap/templates.go b/pkg/jmap/templates.go index fc8ba115be..fffeda7ca1 100644 --- a/pkg/jmap/templates.go +++ b/pkg/jmap/templates.go @@ -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) diff --git a/pkg/jmap/tools.go b/pkg/jmap/tools.go index 3956aa3673..e00bef9bcc 100644 --- a/pkg/jmap/tools.go +++ b/pkg/jmap/tools.go @@ -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 { diff --git a/pkg/log/log_safely.go b/pkg/log/log_safely.go index 67c4df9dd6..686a2d67e2 100644 --- a/pkg/log/log_safely.go +++ b/pkg/log/log_safely.go @@ -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 } diff --git a/pkg/structs/structs.go b/pkg/structs/structs.go index ff7cc3cdaf..ce997ea7ce 100644 --- a/pkg/structs/structs.go +++ b/pkg/structs/structs.go @@ -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 { diff --git a/pkg/structs/structs_test.go b/pkg/structs/structs_test.go index 82ca9034a4..c4eac27285 100644 --- a/pkg/structs/structs_test.go +++ b/pkg/structs/structs_test.go @@ -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 diff --git a/services/groupware/QueryPagination.md b/services/groupware/QueryPagination.md index d65a203046..0f64bad7d9 100644 --- a/services/groupware/QueryPagination.md +++ b/services/groupware/QueryPagination.md @@ -244,4 +244,3 @@ The alternative would be to have different APIs depending on what each endpoint * endpoint with multiple backends or multiple accounts:
same as above with `?first=...` and `?next=...` * endpoint with a single backend and a single account:
`?position=...&anchor=...&offset=...&limit=...` - diff --git a/services/groupware/pkg/groupware/address_book_supplier_jmap.go b/services/groupware/pkg/groupware/address_book_supplier_jmap.go index 25e1d962f4..7dd86b3183 100644 --- a/services/groupware/pkg/groupware/address_book_supplier_jmap.go +++ b/services/groupware/pkg/groupware/address_book_supplier_jmap.go @@ -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) } diff --git a/services/groupware/pkg/groupware/address_book_supplier_mock.go b/services/groupware/pkg/groupware/address_book_supplier_mock.go index ca8f9ea441..ab10314123 100644 --- a/services/groupware/pkg/groupware/address_book_supplier_mock.go +++ b/services/groupware/pkg/groupware/address_book_supplier_mock.go @@ -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, diff --git a/services/groupware/pkg/groupware/api_account.go b/services/groupware/pkg/groupware/api_account.go index 92b6b7ef1d..dbcbeafe2a 100644 --- a/services/groupware/pkg/groupware/api_account.go +++ b/services/groupware/pkg/groupware/api_account.go @@ -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 } diff --git a/services/groupware/pkg/groupware/api_addressbooks.go b/services/groupware/pkg/groupware/api_addressbooks.go index 38f9a880d3..45621b2859 100644 --- a/services/groupware/pkg/groupware/api_addressbooks.go +++ b/services/groupware/pkg/groupware/api_addressbooks.go @@ -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} }) } diff --git a/services/groupware/pkg/groupware/api_blob.go b/services/groupware/pkg/groupware/api_blob.go index 8d33ab78ee..e612247a1c 100644 --- a/services/groupware/pkg/groupware/api_blob.go +++ b/services/groupware/pkg/groupware/api_blob.go @@ -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 } diff --git a/services/groupware/pkg/groupware/api_changes.go b/services/groupware/pkg/groupware/api_changes.go index fa7ec29068..4650eeb91a 100644 --- a/services/groupware/pkg/groupware/api_changes.go +++ b/services/groupware/pkg/groupware/api_changes.go @@ -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. diff --git a/services/groupware/pkg/groupware/api_contacts.go b/services/groupware/pkg/groupware/api_contacts.go index e5ee8f2906..cfe96db940 100644 --- a/services/groupware/pkg/groupware/api_contacts.go +++ b/services/groupware/pkg/groupware/api_contacts.go @@ -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, diff --git a/services/groupware/pkg/groupware/api_emails.go b/services/groupware/pkg/groupware/api_emails.go index 9e6f6d5eac..5582cac8c1 100644 --- a/services/groupware/pkg/groupware/api_emails.go +++ b/services/groupware/pkg/groupware/api_emails.go @@ -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 { diff --git a/services/groupware/pkg/groupware/api_index.go b/services/groupware/pkg/groupware/api_index.go index db6efe5c17..7671d1ff13 100644 --- a/services/groupware/pkg/groupware/api_index.go +++ b/services/groupware/pkg/groupware/api_index.go @@ -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 } diff --git a/services/groupware/pkg/groupware/api_mailbox.go b/services/groupware/pkg/groupware/api_mailbox.go index f7b26cb0ac..8bcbf85978 100644 --- a/services/groupware/pkg/groupware/api_mailbox.go +++ b/services/groupware/pkg/groupware/api_mailbox.go @@ -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) diff --git a/services/groupware/pkg/groupware/api_objects.go b/services/groupware/pkg/groupware/api_objects.go index be75e2b177..e377e8cf72 100644 --- a/services/groupware/pkg/groupware/api_objects.go +++ b/services/groupware/pkg/groupware/api_objects.go @@ -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{} diff --git a/services/groupware/pkg/groupware/api_quota.go b/services/groupware/pkg/groupware/api_quota.go index a751a71b87..bac9727b49 100644 --- a/services/groupware/pkg/groupware/api_quota.go +++ b/services/groupware/pkg/groupware/api_quota.go @@ -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, diff --git a/services/groupware/pkg/groupware/api_tasklists.go b/services/groupware/pkg/groupware/api_tasklists.go index fee45a857e..096318e069 100644 --- a/services/groupware/pkg/groupware/api_tasklists.go +++ b/services/groupware/pkg/groupware/api_tasklists.go @@ -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 { diff --git a/services/groupware/pkg/groupware/api_vacation.go b/services/groupware/pkg/groupware/api_vacation.go index 0f8f2c344e..04c58a3974 100644 --- a/services/groupware/pkg/groupware/api_vacation.go +++ b/services/groupware/pkg/groupware/api_vacation.go @@ -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) }) } diff --git a/services/groupware/pkg/groupware/error.go b/services/groupware/pkg/groupware/error.go index e9de913a92..037e23d738 100644 --- a/services/groupware/pkg/groupware/error.go +++ b/services/groupware/pkg/groupware/error.go @@ -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 { diff --git a/services/groupware/pkg/groupware/examples_test.go b/services/groupware/pkg/groupware/examples_test.go index 0867b6ee2c..d470faf054 100644 --- a/services/groupware/pkg/groupware/examples_test.go +++ b/services/groupware/pkg/groupware/examples_test.go @@ -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" diff --git a/services/groupware/pkg/groupware/framework.go b/services/groupware/pkg/groupware/framework.go index 27074171fc..543268f750 100644 --- a/services/groupware/pkg/groupware/framework.go +++ b/services/groupware/pkg/groupware/framework.go @@ -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 } diff --git a/services/groupware/pkg/groupware/mock_tasks.go b/services/groupware/pkg/groupware/mock_tasks.go index 5b91ce0028..d7e79f600c 100644 --- a/services/groupware/pkg/groupware/mock_tasks.go +++ b/services/groupware/pkg/groupware/mock_tasks.go @@ -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, diff --git a/services/groupware/pkg/groupware/next.go b/services/groupware/pkg/groupware/next.go index c03b4cfcce..5eb3635904 100644 --- a/services/groupware/pkg/groupware/next.go +++ b/services/groupware/pkg/groupware/next.go @@ -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 diff --git a/services/groupware/pkg/groupware/objtypes.go b/services/groupware/pkg/groupware/objtypes.go index c52a61032a..8a51ad64ed 100644 --- a/services/groupware/pkg/groupware/objtypes.go +++ b/services/groupware/pkg/groupware/objtypes.go @@ -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 } diff --git a/services/groupware/pkg/groupware/request.go b/services/groupware/pkg/groupware/request.go index 3881c12c75..950c561c0b 100644 --- a/services/groupware/pkg/groupware/request.go +++ b/services/groupware/pkg/groupware/request.go @@ -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) +} diff --git a/services/groupware/pkg/groupware/response.go b/services/groupware/pkg/groupware/response.go index 196c2d19c3..973650998a 100644 --- a/services/groupware/pkg/groupware/response.go +++ b/services/groupware/pkg/groupware/response.go @@ -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) } diff --git a/services/groupware/pkg/groupware/suppliers.go b/services/groupware/pkg/groupware/suppliers.go index 91b706a865..4bf35fa302 100644 --- a/services/groupware/pkg/groupware/suppliers.go +++ b/services/groupware/pkg/groupware/suppliers.go @@ -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 } } diff --git a/services/groupware/pkg/groupware/suppliers_test.go b/services/groupware/pkg/groupware/suppliers_test.go index 5d2fa43ce5..e0ca3defe0 100644 --- a/services/groupware/pkg/groupware/suppliers_test.go +++ b/services/groupware/pkg/groupware/suppliers_test.go @@ -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) diff --git a/services/groupware/pkg/groupware/templates.go b/services/groupware/pkg/groupware/templates.go index 7cbeddd9f7..6d2c559c76 100644 --- a/services/groupware/pkg/groupware/templates.go +++ b/services/groupware/pkg/groupware/templates.go @@ -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)