mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-04-30 20:23:26 -04:00
groupware: refactor responses to a jmap.Response object
* in the JMAP API as well as in several places in the Groupware framework, use a single jmap.Response[T] object to return the payload, the language, the session state and the etag/state instead of individual multi-valued return values
This commit is contained in:
@@ -62,3 +62,57 @@ const (
|
||||
logBlobId = "blob-id"
|
||||
logSinceState = "since-state"
|
||||
)
|
||||
|
||||
type ResultMetadata interface {
|
||||
GetSessionState() SessionState
|
||||
GetState() State
|
||||
GetLanguage() Language
|
||||
}
|
||||
|
||||
type Result[T any] struct {
|
||||
Payload T
|
||||
SessionState SessionState
|
||||
State State
|
||||
Language Language
|
||||
}
|
||||
|
||||
func RefineResult[A, B any](a Result[A], refiner func(A) B) Result[B] {
|
||||
return newResult(
|
||||
refiner(a.Payload),
|
||||
a.SessionState,
|
||||
a.State,
|
||||
a.Language,
|
||||
)
|
||||
}
|
||||
|
||||
func (r Result[T]) GetSessionState() SessionState {
|
||||
return r.SessionState
|
||||
}
|
||||
|
||||
func (r Result[T]) GetState() State {
|
||||
return r.State
|
||||
}
|
||||
|
||||
func (r Result[T]) GetLanguage() Language {
|
||||
return r.Language
|
||||
}
|
||||
|
||||
func newResult[T any](result T, sessionState SessionState, state State, language Language) Result[T] {
|
||||
return Result[T]{
|
||||
Payload: result,
|
||||
SessionState: sessionState,
|
||||
State: state,
|
||||
Language: language,
|
||||
}
|
||||
}
|
||||
|
||||
func newPartialResult[T any](sessionState SessionState, language Language) Result[T] {
|
||||
return Result[T]{
|
||||
SessionState: sessionState,
|
||||
Language: language,
|
||||
}
|
||||
}
|
||||
|
||||
func ZeroResult[T any]() Result[T] {
|
||||
return Result[T]{}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package jmap
|
||||
|
||||
var NS_ADDRESSBOOKS = ns(JmapContacts)
|
||||
|
||||
func (j *Client) GetAddressbooks(accountId string, ids []string, ctx Context) (AddressBookGetResponse, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetAddressbooks(accountId string, ids []string, ctx Context) (Result[AddressBookGetResponse], Error) {
|
||||
return get(j, "GetAddressbooks", MailboxType,
|
||||
func(accountId string, ids []string) AddressBookGetCommand {
|
||||
return AddressBookGetCommand{AccountId: accountId, Ids: ids}
|
||||
@@ -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) (AddressBookChanges, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetAddressbookChanges(accountId string, 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,7 +58,7 @@ func (j *Client) GetAddressbookChanges(accountId string, sinceState State, maxCh
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) CreateAddressBook(accountId string, addressbook AddressBookChange, ctx Context) (*AddressBook, SessionState, State, Language, Error) {
|
||||
func (j *Client) CreateAddressBook(accountId string, addressbook AddressBookChange, ctx Context) (Result[*AddressBook], Error) {
|
||||
return create(j, "CreateAddressBook", MailboxType,
|
||||
func(accountId string, create map[string]AddressBookChange) AddressBookSetCommand {
|
||||
return AddressBookSetCommand{AccountId: accountId, Create: create}
|
||||
@@ -77,7 +77,7 @@ func (j *Client) CreateAddressBook(accountId string, addressbook AddressBookChan
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) DeleteAddressBook(accountId string, destroyIds []string, ctx Context) (map[string]SetError, SessionState, State, Language, Error) {
|
||||
func (j *Client) DeleteAddressBook(accountId string, destroyIds []string, ctx Context) (Result[map[string]SetError], Error) {
|
||||
return destroy(j, "DeleteAddressBook", MailboxType,
|
||||
func(accountId string, destroy []string) AddressBookSetCommand {
|
||||
return AddressBookSetCommand{AccountId: accountId, Destroy: destroy}
|
||||
@@ -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) (AddressBook, SessionState, State, Language, Error) {
|
||||
func (j *Client) UpdateAddressBook(accountId string, 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}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
|
||||
var NS_BLOB = ns(JmapBlob)
|
||||
|
||||
func (j *Client) GetBlobMetadata(accountId string, ids []string, ctx Context) (BlobGetResponse, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetBlobMetadata(accountId string, ids []string, ctx Context) (Result[BlobGetResponse], Error) {
|
||||
get := BlobGetCommand{
|
||||
AccountId: accountId,
|
||||
Ids: ids,
|
||||
@@ -21,7 +21,7 @@ func (j *Client) GetBlobMetadata(accountId string, ids []string, ctx Context) (B
|
||||
invocation(get, "0"),
|
||||
)
|
||||
if jerr != nil {
|
||||
return bail[BlobGetResponse](jerr)
|
||||
return ZeroResult[BlobGetResponse](), jerr
|
||||
}
|
||||
|
||||
return command(j, ctx, cmd, func(body *Response) (BlobGetResponse, State, Error) {
|
||||
@@ -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) (UploadedBlobWithHash, SessionState, State, Language, Error) {
|
||||
func (j *Client) UploadBlob(accountId string, data []byte, contentType string, ctx Context) (Result[UploadedBlobWithHash], Error) {
|
||||
encoded := base64.StdEncoding.EncodeToString(data)
|
||||
|
||||
upload := BlobUploadCommand{
|
||||
@@ -92,7 +92,7 @@ func (j *Client) UploadBlob(accountId string, data []byte, contentType string, c
|
||||
invocation(getHash, "1"),
|
||||
)
|
||||
if jerr != nil {
|
||||
return UploadedBlobWithHash{}, "", "", "", jerr
|
||||
return ZeroResult[UploadedBlobWithHash](), jerr
|
||||
}
|
||||
|
||||
return command(j, ctx, cmd, func(body *Response) (UploadedBlobWithHash, State, Error) {
|
||||
|
||||
@@ -11,7 +11,7 @@ type AccountBootstrapResult struct {
|
||||
|
||||
var NS_MAIL_QUOTA = ns(JmapMail, JmapQuota)
|
||||
|
||||
func (j *Client) GetBootstrap(accountIds []string, ctx Context) (map[string]AccountBootstrapResult, SessionState, State, Language, Error) { //NOSONAR
|
||||
func (j *Client) GetBootstrap(accountIds []string, ctx Context) (Result[map[string]AccountBootstrapResult], Error) { //NOSONAR
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
|
||||
logger := j.logger("GetBootstrap", ctx)
|
||||
@@ -25,7 +25,7 @@ func (j *Client) GetBootstrap(accountIds []string, ctx Context) (map[string]Acco
|
||||
|
||||
cmd, err := j.request(ctx, NS_MAIL_QUOTA, calls...)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
return ZeroResult[map[string]AccountBootstrapResult](), err
|
||||
}
|
||||
return command(j, ctx, cmd, func(body *Response) (map[string]AccountBootstrapResult, State, Error) {
|
||||
identityPerAccount := map[string][]Identity{}
|
||||
|
||||
@@ -2,7 +2,7 @@ package jmap
|
||||
|
||||
var NS_CALENDARS = ns(JmapCalendars)
|
||||
|
||||
func (j *Client) ParseICalendarBlob(accountId string, blobIds []string, ctx Context) (CalendarEventParseResponse, SessionState, State, Language, Error) {
|
||||
func (j *Client) ParseICalendarBlob(accountId string, blobIds []string, ctx Context) (Result[CalendarEventParseResponse], Error) {
|
||||
logger := j.logger("ParseICalendarBlob", ctx)
|
||||
|
||||
parse := CalendarEventParseCommand{AccountId: accountId, BlobIds: blobIds}
|
||||
@@ -10,7 +10,7 @@ func (j *Client) ParseICalendarBlob(accountId string, blobIds []string, ctx Cont
|
||||
invocation(parse, "0"),
|
||||
)
|
||||
if err != nil {
|
||||
return CalendarEventParseResponse{}, "", "", "", err
|
||||
return ZeroResult[CalendarEventParseResponse](), err
|
||||
}
|
||||
|
||||
return command(j, ctx, cmd, func(body *Response) (CalendarEventParseResponse, State, Error) {
|
||||
@@ -23,7 +23,7 @@ func (j *Client) ParseICalendarBlob(accountId string, blobIds []string, ctx Cont
|
||||
})
|
||||
}
|
||||
|
||||
func (j *Client) GetCalendars(accountId string, ids []string, ctx Context) (CalendarGetResponse, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetCalendars(accountId string, ids []string, ctx Context) (Result[CalendarGetResponse], Error) {
|
||||
return get(j, "GetCalendars", CalendarType,
|
||||
func(accountId string, ids []string) CalendarGetCommand {
|
||||
return CalendarGetCommand{AccountId: accountId, Ids: ids}
|
||||
@@ -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) (CalendarChanges, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetCalendarChanges(accountId string, 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,7 +79,7 @@ func (j *Client) GetCalendarChanges(accountId string, sinceState State, maxChang
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) CreateCalendar(accountId string, calendar CalendarChange, ctx Context) (*Calendar, SessionState, State, Language, Error) {
|
||||
func (j *Client) CreateCalendar(accountId string, calendar CalendarChange, ctx Context) (Result[*Calendar], Error) {
|
||||
return create(j, "CreateCalendar", CalendarEventType,
|
||||
func(accountId string, create map[string]CalendarChange) CalendarSetCommand {
|
||||
return CalendarSetCommand{AccountId: accountId, Create: create}
|
||||
@@ -98,7 +98,7 @@ func (j *Client) CreateCalendar(accountId string, calendar CalendarChange, ctx C
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) DeleteCalendar(accountId string, destroyIds []string, ctx Context) (map[string]SetError, SessionState, State, Language, Error) {
|
||||
func (j *Client) DeleteCalendar(accountId string, destroyIds []string, ctx Context) (Result[map[string]SetError], Error) {
|
||||
return destroy(j, "DeleteCalendar", CalendarEventType,
|
||||
func(accountId string, destroy []string) CalendarSetCommand {
|
||||
return CalendarSetCommand{AccountId: accountId, Destroy: destroy}
|
||||
@@ -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) (Calendar, SessionState, State, Language, Error) {
|
||||
func (j *Client) UpdateCalendar(accountId string, 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}
|
||||
|
||||
@@ -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) (ObjectChanges, SessionState, State, Language, Error) { //NOSONAR
|
||||
func (j *Client) GetChanges(accountId string, 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)
|
||||
|
||||
@@ -107,7 +107,7 @@ func (j *Client) GetChanges(accountId string, stateMap StateMap, maxChanges uint
|
||||
|
||||
cmd, err := j.request(ctx, NS_CHANGES, methodCalls...)
|
||||
if err != nil {
|
||||
return ObjectChanges{}, "", "", "", err
|
||||
return ZeroResult[ObjectChanges](), err
|
||||
}
|
||||
|
||||
return command(j, ctx, cmd, func(body *Response) (ObjectChanges, State, Error) {
|
||||
|
||||
@@ -6,7 +6,7 @@ var NS_CONTACTS = ns(JmapContacts)
|
||||
|
||||
var DEFAULT_CONTACT_CARD_VERSION = jscontact.JSContactVersion_1_0
|
||||
|
||||
func (j *Client) GetContactCards(accountId string, contactIds []string, ctx Context) (ContactCardGetResponse, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetContactCards(accountId string, contactIds []string, ctx Context) (Result[ContactCardGetResponse], Error) {
|
||||
return get(j, "GetContactCards", ContactCardType,
|
||||
func(accountId string, ids []string) ContactCardGetCommand {
|
||||
return ContactCardGetCommand{AccountId: accountId, Ids: contactIds}
|
||||
@@ -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) (ContactCardChanges, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetContactCardChanges(accountId string, 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)}
|
||||
@@ -80,7 +80,7 @@ func (r *ContactCardSearchResults) SetPosition(position *uint) { r.Position = po
|
||||
func (j *Client) QueryContactCards(accountIds []string, //NOSONAR
|
||||
filter ContactCardFilterElement, sortBy []ContactCardComparator,
|
||||
position int, anchor string, anchorOffset *int, limit *uint, calculateTotal bool,
|
||||
ctx Context) (map[string]*ContactCardSearchResults, SessionState, State, Language, Error) {
|
||||
ctx Context) (Result[map[string]*ContactCardSearchResults], Error) {
|
||||
return queryN(j, "QueryContactCards", ContactCardType,
|
||||
[]ContactCardComparator{{Property: ContactCardPropertyUpdated, IsAscending: false}},
|
||||
func(accountId string, filter ContactCardFilterElement, sortBy []ContactCardComparator, position int, anchor string, anchorOffset *int, limit *uint) ContactCardQueryCommand {
|
||||
@@ -104,7 +104,7 @@ func (j *Client) QueryContactCards(accountIds []string, //NOSONAR
|
||||
}
|
||||
|
||||
// @api:example create
|
||||
func (j *Client) CreateContactCard(accountId string, contact ContactCardChange, ctx Context) (*ContactCard, SessionState, State, Language, Error) {
|
||||
func (j *Client) CreateContactCard(accountId string, contact ContactCardChange, ctx Context) (Result[*ContactCard], Error) {
|
||||
if contact.Version == nil {
|
||||
contact.Version = &DEFAULT_CONTACT_CARD_VERSION
|
||||
}
|
||||
@@ -126,7 +126,7 @@ func (j *Client) CreateContactCard(accountId string, contact ContactCardChange,
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) DeleteContactCard(accountId string, destroyIds []string, ctx Context) (map[string]SetError, SessionState, State, Language, Error) {
|
||||
func (j *Client) DeleteContactCard(accountId string, destroyIds []string, ctx Context) (Result[map[string]SetError], Error) {
|
||||
return destroy(j, "DeleteContactCard", ContactCardType,
|
||||
func(accountId string, destroy []string) ContactCardSetCommand {
|
||||
return ContactCardSetCommand{AccountId: accountId, Destroy: destroy}
|
||||
@@ -138,7 +138,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) (ContactCard, SessionState, State, Language, Error) {
|
||||
func (j *Client) UpdateContactCard(accountId string, 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}
|
||||
|
||||
@@ -13,15 +13,10 @@ import (
|
||||
var NS_MAIL = ns(JmapMail)
|
||||
var NS_MAIL_SUBMISSION = ns(JmapMail, JmapSubmission)
|
||||
|
||||
type getEmailsResult struct {
|
||||
emails []Email
|
||||
notFound []string
|
||||
}
|
||||
|
||||
// Retrieve specific Emails by their id.
|
||||
func (j *Client) GetEmails(accountId string, ids []string, //NOSONAR
|
||||
fetchBodies bool, maxBodyValueBytes uint, markAsSeen bool, withThreads bool,
|
||||
ctx Context) ([]Email, []string, SessionState, State, Language, Error) {
|
||||
ctx Context) (Result[EmailGetResponse], Error) {
|
||||
logger := j.logger("GetEmails", ctx)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
@@ -56,46 +51,45 @@ func (j *Client) GetEmails(accountId string, ids []string, //NOSONAR
|
||||
|
||||
cmd, err := j.request(ctx, NS_MAIL, methodCalls...)
|
||||
if err != nil {
|
||||
return nil, nil, "", "", "", err
|
||||
return ZeroResult[EmailGetResponse](), err
|
||||
}
|
||||
result, sessionState, state, language, gwerr := command(j, ctx, cmd, func(body *Response) (getEmailsResult, State, Error) {
|
||||
return command(j, ctx, cmd, func(body *Response) (EmailGetResponse, State, Error) {
|
||||
if markAsSeen {
|
||||
var markResponse EmailSetResponse
|
||||
err = retrieveSet(ctx, body, markEmails, "0", &markResponse)
|
||||
if err != nil {
|
||||
return getEmailsResult{}, "", err
|
||||
return EmailGetResponse{}, "", err
|
||||
}
|
||||
for _, seterr := range markResponse.NotUpdated {
|
||||
// TODO we don't have a way to compose multiple set errors yet
|
||||
return getEmailsResult{}, "", setErrorError(seterr, EmailType)
|
||||
return EmailGetResponse{}, "", setErrorError(seterr, EmailType)
|
||||
}
|
||||
}
|
||||
var response EmailGetResponse
|
||||
err = retrieveGet(ctx, body, getEmails, "1", &response)
|
||||
if err != nil {
|
||||
return getEmailsResult{}, "", err
|
||||
return EmailGetResponse{}, "", err
|
||||
}
|
||||
if withThreads {
|
||||
var threads ThreadGetResponse
|
||||
err = retrieveGet(ctx, body, getThreads, "2", &threads)
|
||||
if err != nil {
|
||||
return getEmailsResult{}, "", err
|
||||
return EmailGetResponse{}, "", err
|
||||
}
|
||||
setThreadSize(&threads, response.List)
|
||||
}
|
||||
return getEmailsResult{emails: response.List, notFound: response.NotFound}, response.State, nil
|
||||
return response, response.State, nil
|
||||
})
|
||||
return result.emails, result.notFound, sessionState, state, language, gwerr
|
||||
}
|
||||
|
||||
func (j *Client) GetEmailBlobId(accountId string, id string, ctx Context) (string, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetEmailBlobId(accountId string, id string, ctx Context) (Result[string], Error) {
|
||||
logger := j.logger("GetEmailBlobId", ctx)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
get := EmailGetCommand{AccountId: accountId, Ids: []string{id}, FetchAllBodyValues: false, Properties: []string{"blobId"}}
|
||||
cmd, err := j.request(ctx, NS_MAIL, invocation(get, "0"))
|
||||
if err != nil {
|
||||
return "", "", "", "", err
|
||||
return ZeroResult[string](), err
|
||||
}
|
||||
return command(j, ctx, cmd, func(body *Response) (string, State, Error) {
|
||||
var response EmailGetResponse
|
||||
@@ -127,7 +121,7 @@ func (r *EmailSearchResults) SetPosition(position *uint) { r.Posi
|
||||
// Retrieve all the Emails in a given Mailbox by its id.
|
||||
func (j *Client) GetAllEmailsInMailbox(accountId string, mailboxId string, //NOSONAR
|
||||
position int, anchor string, anchorOffset *int, limit *uint, collapseThreads bool, fetchBodies bool, maxBodyValueBytes uint, withThreads bool,
|
||||
ctx Context) (*EmailSearchResults, SessionState, State, Language, Error) {
|
||||
ctx Context) (Result[*EmailSearchResults], Error) {
|
||||
logger := j.loggerParams("GetAllEmailsInMailbox", ctx, func(z zerolog.Context) zerolog.Context {
|
||||
l := z.Bool(logFetchBodies, fetchBodies).Int(logPosition, position)
|
||||
if limit != nil {
|
||||
@@ -178,7 +172,7 @@ func (j *Client) GetAllEmailsInMailbox(accountId string, mailboxId string, //NOS
|
||||
|
||||
cmd, err := j.request(ctx, NS_MAIL, invocations...)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
return ZeroResult[*EmailSearchResults](), err
|
||||
}
|
||||
|
||||
return command(j, ctx, cmd, func(body *Response) (*EmailSearchResults, State, Error) {
|
||||
@@ -228,7 +222,7 @@ func (c EmailChanges) GetDestroyed() []string { return c.Destroyed }
|
||||
// @api:tags email,changes
|
||||
func (j *Client) GetEmailChanges(accountId string,
|
||||
sinceState State, fetchBodies bool, maxBodyValueBytes uint, maxChanges uint,
|
||||
ctx Context) (EmailChanges, SessionState, State, Language, Error) { //NOSONAR
|
||||
ctx Context) (Result[EmailChanges], Error) { //NOSONAR
|
||||
logger := j.loggerParams("GetEmailChanges", ctx, func(z zerolog.Context) zerolog.Context {
|
||||
return z.Bool(logFetchBodies, fetchBodies).Str(logSinceState, string(sinceState))
|
||||
})
|
||||
@@ -265,7 +259,7 @@ func (j *Client) GetEmailChanges(accountId string,
|
||||
invocation(getUpdated, "2"),
|
||||
)
|
||||
if err != nil {
|
||||
return EmailChanges{}, "", "", "", err
|
||||
return ZeroResult[EmailChanges](), err
|
||||
}
|
||||
|
||||
return command(j, ctx, cmd, func(body *Response) (EmailChanges, State, Error) {
|
||||
@@ -310,7 +304,7 @@ type EmailSnippetSearchResults SearchResultsTemplate[SearchSnippetWithMeta]
|
||||
|
||||
func (j *Client) QueryEmailSnippets(accountIds []string, //NOSONAR
|
||||
filter EmailFilterElement, position int, anchor string, anchorOffset *int, limit *uint,
|
||||
ctx Context) (map[string]EmailSnippetSearchResults, SessionState, State, Language, Error) {
|
||||
ctx Context) (Result[map[string]EmailSnippetSearchResults], Error) {
|
||||
logger := j.loggerParams("QueryEmailSnippets", ctx, func(z zerolog.Context) zerolog.Context {
|
||||
l := z.Int(logPosition, position)
|
||||
if limit != nil {
|
||||
@@ -364,7 +358,7 @@ func (j *Client) QueryEmailSnippets(accountIds []string, //NOSONAR
|
||||
|
||||
cmd, err := j.request(ctx, NS_MAIL, invocations...)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
return ZeroResult[map[string]EmailSnippetSearchResults](), err
|
||||
}
|
||||
|
||||
return command(j, ctx, cmd, func(body *Response) (map[string]EmailSnippetSearchResults, State, Error) {
|
||||
@@ -434,7 +428,7 @@ type EmailQueryResult struct {
|
||||
|
||||
func (j *Client) QueryEmails(accountIds []string,
|
||||
filter EmailFilterElement, position int, limit uint, fetchBodies bool, maxBodyValueBytes uint,
|
||||
ctx Context) (map[string]EmailQueryResult, SessionState, State, Language, Error) { //NOSONAR
|
||||
ctx Context) (Result[map[string]EmailQueryResult], Error) { //NOSONAR
|
||||
logger := j.loggerParams("QueryEmails", ctx, func(z zerolog.Context) zerolog.Context {
|
||||
return z.Bool(logFetchBodies, fetchBodies)
|
||||
})
|
||||
@@ -474,7 +468,7 @@ func (j *Client) QueryEmails(accountIds []string,
|
||||
|
||||
cmd, err := j.request(ctx, NS_MAIL, invocations...)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
return ZeroResult[map[string]EmailQueryResult](), err
|
||||
}
|
||||
|
||||
return command(j, ctx, cmd, func(body *Response) (map[string]EmailQueryResult, State, Error) {
|
||||
@@ -519,7 +513,7 @@ type EmailQueryWithSnippetsResult struct {
|
||||
|
||||
func (j *Client) QueryEmailsWithSnippets(accountIds []string, //NOSONAR
|
||||
filter EmailFilterElement, position int, anchor string, anchorOffset *int, limit *uint, collapseThreads bool, calculateTotal bool, fetchBodies bool, maxBodyValueBytes uint,
|
||||
ctx Context) (map[string]EmailQueryWithSnippetsResult, SessionState, State, Language, Error) {
|
||||
ctx Context) (Result[map[string]EmailQueryWithSnippetsResult], Error) {
|
||||
logger := j.loggerParams("QueryEmailsWithSnippets", ctx, func(z zerolog.Context) zerolog.Context {
|
||||
return z.Bool(logFetchBodies, fetchBodies)
|
||||
})
|
||||
@@ -567,7 +561,7 @@ func (j *Client) QueryEmailsWithSnippets(accountIds []string, //NOSONAR
|
||||
|
||||
cmd, err := j.request(ctx, NS_MAIL, invocations...)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
return ZeroResult[map[string]EmailQueryWithSnippetsResult](), err
|
||||
}
|
||||
|
||||
return command(j, ctx, cmd, func(body *Response) (map[string]EmailQueryWithSnippetsResult, State, Error) {
|
||||
@@ -631,7 +625,7 @@ type UploadedEmail struct {
|
||||
Sha512 string `json:"sha:512"`
|
||||
}
|
||||
|
||||
func (j *Client) ImportEmail(accountId string, data []byte, ctx Context) (UploadedEmail, SessionState, State, Language, Error) {
|
||||
func (j *Client) ImportEmail(accountId string, data []byte, ctx Context) (Result[UploadedEmail], Error) {
|
||||
encoded := base64.StdEncoding.EncodeToString(data)
|
||||
|
||||
upload := BlobUploadCommand{
|
||||
@@ -661,7 +655,7 @@ func (j *Client) ImportEmail(accountId string, data []byte, ctx Context) (Upload
|
||||
invocation(getHash, "1"),
|
||||
)
|
||||
if err != nil {
|
||||
return UploadedEmail{}, "", "", "", err
|
||||
return ZeroResult[UploadedEmail](), err
|
||||
}
|
||||
|
||||
return command(j, ctx, cmd, func(body *Response) (UploadedEmail, State, Error) {
|
||||
@@ -704,7 +698,7 @@ func (j *Client) ImportEmail(accountId string, data []byte, ctx Context) (Upload
|
||||
|
||||
}
|
||||
|
||||
func (j *Client) CreateEmail(accountId string, email EmailChange, replaceId string, ctx Context) (*Email, SessionState, State, Language, Error) {
|
||||
func (j *Client) CreateEmail(accountId string, email EmailChange, replaceId string, ctx Context) (Result[*Email], Error) {
|
||||
set := EmailSetCommand{
|
||||
AccountId: accountId,
|
||||
Create: map[string]EmailChange{
|
||||
@@ -719,7 +713,7 @@ func (j *Client) CreateEmail(accountId string, email EmailChange, replaceId stri
|
||||
invocation(set, "0"),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
return ZeroResult[*Email](), err
|
||||
}
|
||||
|
||||
return command(j, ctx, cmd, func(body *Response) (*Email, State, Error) {
|
||||
@@ -759,14 +753,14 @@ 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) (map[string]*Email, SessionState, State, Language, Error) {
|
||||
func (j *Client) UpdateEmails(accountId string, updates map[string]PatchObject, ctx Context) (Result[map[string]*Email], Error) {
|
||||
set := EmailSetCommand{
|
||||
AccountId: accountId,
|
||||
Update: updates,
|
||||
}
|
||||
cmd, err := j.request(ctx, NS_MAIL, invocation(set, "0"))
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
return ZeroResult[map[string]*Email](), err
|
||||
}
|
||||
|
||||
return command(j, ctx, cmd, func(body *Response) (map[string]*Email, State, Error) {
|
||||
@@ -785,7 +779,7 @@ func (j *Client) UpdateEmails(accountId string, updates map[string]PatchObject,
|
||||
})
|
||||
}
|
||||
|
||||
func (j *Client) UpdateEmail(accountId string, id string, changes EmailChange, ctx Context) (Email, SessionState, State, Language, Error) {
|
||||
func (j *Client) UpdateEmail(accountId string, 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}
|
||||
@@ -800,7 +794,7 @@ func (j *Client) UpdateEmail(accountId string, id string, changes EmailChange, c
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) DeleteEmails(accountId string, destroyIds []string, ctx Context) (map[string]SetError, SessionState, State, Language, Error) {
|
||||
func (j *Client) DeleteEmails(accountId string, destroyIds []string, ctx Context) (Result[map[string]SetError], Error) {
|
||||
return destroy(j, "DeleteEmails", EmailType,
|
||||
func(accountId string, destroy []string) EmailSetCommand {
|
||||
return EmailSetCommand{AccountId: accountId, Destroy: destroy}
|
||||
@@ -841,7 +835,7 @@ type MoveMail struct {
|
||||
}
|
||||
|
||||
func (j *Client) SubmitEmail(accountId string, identityId string, emailId string, move *MoveMail, //NOSONAR
|
||||
ctx Context) (EmailSubmission, SessionState, State, Language, Error) {
|
||||
ctx Context) (Result[EmailSubmission], Error) {
|
||||
logger := j.logger("SubmitEmail", ctx)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
@@ -880,7 +874,7 @@ func (j *Client) SubmitEmail(accountId string, identityId string, emailId string
|
||||
invocation(get, "1"),
|
||||
)
|
||||
if err != nil {
|
||||
return EmailSubmission{}, "", "", "", err
|
||||
return ZeroResult[EmailSubmission](), err
|
||||
}
|
||||
|
||||
return command(j, ctx, cmd, func(body *Response) (EmailSubmission, State, Error) {
|
||||
@@ -928,12 +922,7 @@ func (j *Client) SubmitEmail(accountId string, identityId string, emailId string
|
||||
})
|
||||
}
|
||||
|
||||
type emailSubmissionResult struct {
|
||||
submissions map[string]EmailSubmission
|
||||
notFound []string
|
||||
}
|
||||
|
||||
func (j *Client) GetEmailSubmissionStatus(accountId string, submissionIds []string, ctx Context) (map[string]EmailSubmission, []string, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetEmailSubmissionStatus(accountId string, submissionIds []string, ctx Context) (Result[EmailSubmissionGetResponse], Error) {
|
||||
logger := j.logger("GetEmailSubmissionStatus", ctx)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
@@ -943,28 +932,22 @@ func (j *Client) GetEmailSubmissionStatus(accountId string, submissionIds []stri
|
||||
}
|
||||
cmd, err := j.request(ctx, NS_MAIL_SUBMISSION, invocation(get, "0"))
|
||||
if err != nil {
|
||||
return nil, nil, "", "", "", err
|
||||
return ZeroResult[EmailSubmissionGetResponse](), err
|
||||
}
|
||||
|
||||
result, sessionState, state, lang, err := command(j, ctx, cmd, func(body *Response) (emailSubmissionResult, State, Error) {
|
||||
return command(j, ctx, cmd, func(body *Response) (EmailSubmissionGetResponse, State, Error) {
|
||||
var response EmailSubmissionGetResponse
|
||||
err = retrieveGet(ctx, body, get, "0", &response)
|
||||
if err != nil {
|
||||
return emailSubmissionResult{}, "", err
|
||||
return EmailSubmissionGetResponse{}, "", err
|
||||
}
|
||||
m := make(map[string]EmailSubmission, len(response.List))
|
||||
for _, s := range response.List {
|
||||
m[s.Id] = s
|
||||
}
|
||||
return emailSubmissionResult{submissions: m, notFound: response.NotFound}, response.State, nil
|
||||
return response, response.State, nil
|
||||
})
|
||||
|
||||
return result.submissions, result.notFound, sessionState, state, lang, err
|
||||
}
|
||||
|
||||
func (j *Client) EmailsInThread(accountId string, threadId string,
|
||||
fetchBodies bool, maxBodyValueBytes uint,
|
||||
ctx Context) ([]Email, SessionState, State, Language, Error) { //NOSONAR
|
||||
ctx Context) (Result[[]Email], Error) { //NOSONAR
|
||||
logger := j.loggerParams("EmailsInThread", ctx, func(z zerolog.Context) zerolog.Context {
|
||||
return z.Bool(logFetchBodies, fetchBodies).Str("threadId", log.SafeString(threadId))
|
||||
})
|
||||
@@ -991,7 +974,7 @@ func (j *Client) EmailsInThread(accountId string, threadId string,
|
||||
invocation(get, "1"),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
return ZeroResult[[]Email](), err
|
||||
}
|
||||
|
||||
return command(j, ctx, cmd, func(body *Response) ([]Email, State, Error) {
|
||||
@@ -1033,7 +1016,7 @@ var EmailSummaryProperties = []string{
|
||||
|
||||
func (j *Client) QueryEmailSummaries(accountIds []string, //NOSONAR
|
||||
filter EmailFilterElement, position int, anchor string, anchorOffset *int, limit *uint, withThreads bool, calculateTotal bool,
|
||||
ctx Context) (map[string]EmailsSummary, SessionState, State, Language, Error) {
|
||||
ctx Context) (Result[map[string]EmailsSummary], Error) {
|
||||
logger := j.logger("QueryEmailSummaries", ctx)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
@@ -1080,7 +1063,7 @@ func (j *Client) QueryEmailSummaries(accountIds []string, //NOSONAR
|
||||
}
|
||||
cmd, err := j.request(ctx, NS_MAIL, invocations...)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
return ZeroResult[map[string]EmailsSummary](), err
|
||||
}
|
||||
|
||||
return command(j, ctx, cmd, func(body *Response) (map[string]EmailsSummary, State, Error) {
|
||||
@@ -1126,7 +1109,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,
|
||||
ctx Context) (EmailSubmissionChanges, SessionState, State, Language, Error) {
|
||||
ctx Context) (Result[EmailSubmissionChanges], Error) {
|
||||
return changes(j, "GetEmailSubmissionChanges", EmailSubmissionType,
|
||||
func() EmailSubmissionChangesCommand {
|
||||
return EmailSubmissionChangesCommand{AccountId: accountId, SinceState: sinceState, MaxChanges: uintPtr(maxChanges)}
|
||||
|
||||
@@ -17,7 +17,7 @@ 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) (CalendarEventGetResponse, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetCalendarEvents(accountId string, eventIds []string, ctx Context) (Result[CalendarEventGetResponse], Error) {
|
||||
return get(j, "GetCalendarEvents", CalendarEventType,
|
||||
func(accountId string, ids []string) CalendarEventGetCommand {
|
||||
return CalendarEventGetCommand{AccountId: accountId, Ids: eventIds}
|
||||
@@ -32,7 +32,7 @@ func (j *Client) GetCalendarEvents(accountId string, eventIds []string, ctx Cont
|
||||
func (j *Client) QueryCalendarEvents(accountIds []string, //NOSONAR
|
||||
filter CalendarEventFilterElement, sortBy []CalendarEventComparator,
|
||||
position int, anchor string, anchorOffset *int, limit *uint, calculateTotal bool,
|
||||
ctx Context) (map[string]*CalendarEventSearchResults, SessionState, State, Language, Error) {
|
||||
ctx Context) (Result[map[string]*CalendarEventSearchResults], Error) {
|
||||
return queryN(j, "QueryCalendarEvents", CalendarEventType,
|
||||
[]CalendarEventComparator{{Property: CalendarEventPropertyStart, IsAscending: false}},
|
||||
func(accountId string, filter CalendarEventFilterElement, sortBy []CalendarEventComparator, position int, anchor string, anchorOffset *int, limit *uint) CalendarEventQueryCommand {
|
||||
@@ -69,7 +69,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,
|
||||
ctx Context) (CalendarEventChanges, SessionState, State, Language, Error) {
|
||||
ctx Context) (Result[CalendarEventChanges], Error) {
|
||||
return changes(j, "GetCalendarEventChanges", CalendarEventType,
|
||||
func() CalendarEventChangesCommand {
|
||||
return CalendarEventChangesCommand{AccountId: accountId, SinceState: sinceState, MaxChanges: uintPtr(maxChanges)}
|
||||
@@ -100,7 +100,7 @@ func (j *Client) GetCalendarEventChanges(accountId string, sinceState State, max
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) CreateCalendarEvent(accountId string, event CalendarEventChange, ctx Context) (*CalendarEvent, SessionState, State, Language, Error) {
|
||||
func (j *Client) CreateCalendarEvent(accountId string, event CalendarEventChange, ctx Context) (Result[*CalendarEvent], Error) {
|
||||
return create(j, "CreateCalendarEvent", CalendarEventType,
|
||||
func(accountId string, create map[string]CalendarEventChange) CalendarEventSetCommand {
|
||||
return CalendarEventSetCommand{AccountId: accountId, Create: create}
|
||||
@@ -119,7 +119,7 @@ func (j *Client) CreateCalendarEvent(accountId string, event CalendarEventChange
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) DeleteCalendarEvent(accountId string, destroyIds []string, ctx Context) (map[string]SetError, SessionState, State, Language, Error) {
|
||||
func (j *Client) DeleteCalendarEvent(accountId string, destroyIds []string, ctx Context) (Result[map[string]SetError], Error) {
|
||||
return destroy(j, "DeleteCalendarEvent", CalendarEventType,
|
||||
func(accountId string, destroy []string) CalendarEventSetCommand {
|
||||
return CalendarEventSetCommand{AccountId: accountId, Destroy: destroy}
|
||||
@@ -130,7 +130,7 @@ func (j *Client) DeleteCalendarEvent(accountId string, destroyIds []string, ctx
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) UpdateCalendarEvent(accountId string, id string, changes CalendarEventChange, ctx Context) (CalendarEvent, SessionState, State, Language, Error) {
|
||||
func (j *Client) UpdateCalendarEvent(accountId string, 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}
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
var NS_IDENTITY = ns(JmapMail)
|
||||
|
||||
func (j *Client) GetIdentities(accountId string, identityIds []string, ctx Context) (IdentityGetResponse, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetIdentities(accountId string, identityIds []string, ctx Context) (Result[IdentityGetResponse], Error) {
|
||||
return get(j, "GetIdentities", IdentityType,
|
||||
func(accountId string, ids []string) IdentityGetCommand {
|
||||
return IdentityGetCommand{AccountId: accountId, Ids: ids}
|
||||
@@ -20,7 +20,7 @@ func (j *Client) GetIdentities(accountId string, identityIds []string, ctx Conte
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) GetIdentitiesForAllAccounts(accountIds []string, ctx Context) (map[string][]Identity, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetIdentitiesForAllAccounts(accountIds []string, ctx Context) (Result[map[string][]Identity], Error) {
|
||||
return getN(j, "GetIdentitiesForAllAccounts", IdentityType,
|
||||
func(accountId string, ids []string) IdentityGetCommand {
|
||||
return IdentityGetCommand{AccountId: accountId}
|
||||
@@ -39,7 +39,7 @@ type IdentitiesAndMailboxesGetResponse struct {
|
||||
Mailboxes []Mailbox `json:"mailboxes"`
|
||||
}
|
||||
|
||||
func (j *Client) GetIdentitiesAndMailboxes(mailboxAccountId string, accountIds []string, ctx Context) (IdentitiesAndMailboxesGetResponse, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetIdentitiesAndMailboxes(mailboxAccountId string, accountIds []string, ctx Context) (Result[IdentitiesAndMailboxesGetResponse], Error) {
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
|
||||
logger := j.logger("GetIdentitiesAndMailboxes", ctx)
|
||||
@@ -53,7 +53,7 @@ func (j *Client) GetIdentitiesAndMailboxes(mailboxAccountId string, accountIds [
|
||||
|
||||
cmd, err := j.request(ctx, NS_IDENTITY, calls...)
|
||||
if err != nil {
|
||||
return IdentitiesAndMailboxesGetResponse{}, "", "", "", err
|
||||
return ZeroResult[IdentitiesAndMailboxesGetResponse](), err
|
||||
}
|
||||
return command(j, ctx, cmd, func(body *Response) (IdentitiesAndMailboxesGetResponse, State, Error) {
|
||||
identities := make(map[string][]Identity, len(uniqueAccountIds))
|
||||
@@ -85,7 +85,7 @@ func (j *Client) GetIdentitiesAndMailboxes(mailboxAccountId string, accountIds [
|
||||
})
|
||||
}
|
||||
|
||||
func (j *Client) CreateIdentity(accountId string, identity IdentityChange, ctx Context) (*Identity, SessionState, State, Language, Error) {
|
||||
func (j *Client) CreateIdentity(accountId string, identity IdentityChange, ctx Context) (Result[*Identity], Error) {
|
||||
return create(j, "CreateIdentity", IdentityType,
|
||||
func(accountId string, create map[string]IdentityChange) IdentitySetCommand {
|
||||
return IdentitySetCommand{AccountId: accountId, Create: create}
|
||||
@@ -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) (Identity, SessionState, State, Language, Error) {
|
||||
func (j *Client) UpdateIdentity(accountId string, 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,7 +119,7 @@ func (j *Client) UpdateIdentity(accountId string, id string, changes IdentityCha
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) DeleteIdentity(accountId string, destroyIds []string, ctx Context) (map[string]SetError, SessionState, State, Language, Error) {
|
||||
func (j *Client) DeleteIdentity(accountId string, destroyIds []string, ctx Context) (Result[map[string]SetError], Error) {
|
||||
return destroy(j, "DeleteIdentity", IdentityType,
|
||||
func(accountId string, destroy []string) IdentitySetCommand {
|
||||
return IdentitySetCommand{AccountId: accountId, Destroy: destroyIds}
|
||||
@@ -144,7 +144,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,
|
||||
ctx Context) (IdentityChanges, SessionState, State, Language, Error) {
|
||||
ctx Context) (Result[IdentityChanges], Error) {
|
||||
return changes(j, "GetIdentityChanges", IdentityType,
|
||||
func() IdentityChangesCommand {
|
||||
return IdentityChangesCommand{AccountId: accountId, SinceState: sinceState, MaxChanges: uintPtr(maxChanges)}
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
var NS_MAILBOX = ns(JmapMail)
|
||||
|
||||
func (j *Client) GetMailbox(accountId string, ids []string, ctx Context) (MailboxGetResponse, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetMailbox(accountId string, ids []string, ctx Context) (Result[MailboxGetResponse], Error) {
|
||||
return get(j, "GetMailbox", MailboxType,
|
||||
func(accountId string, ids []string) MailboxGetCommand {
|
||||
return MailboxGetCommand{AccountId: accountId, Ids: ids}
|
||||
@@ -20,7 +20,7 @@ func (j *Client) GetMailbox(accountId string, ids []string, ctx Context) (Mailbo
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) GetAllMailboxes(accountIds []string, ctx Context) (map[string][]Mailbox, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetAllMailboxes(accountIds []string, ctx Context) (Result[map[string][]Mailbox], Error) {
|
||||
return getAN(j, "GetAllMailboxes", MailboxType,
|
||||
func(accountId string, ids []string) MailboxGetCommand {
|
||||
return MailboxGetCommand{AccountId: accountId}
|
||||
@@ -32,7 +32,7 @@ func (j *Client) GetAllMailboxes(accountIds []string, ctx Context) (map[string][
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) SearchMailboxes(accountIds []string, filter MailboxFilterElement, ctx Context) (map[string][]Mailbox, SessionState, State, Language, Error) {
|
||||
func (j *Client) SearchMailboxes(accountIds []string, filter MailboxFilterElement, ctx Context) (Result[map[string][]Mailbox], Error) {
|
||||
logger := j.logger("SearchMailboxes", ctx)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
@@ -52,7 +52,7 @@ func (j *Client) SearchMailboxes(accountIds []string, filter MailboxFilterElemen
|
||||
}
|
||||
cmd, err := j.request(ctx, NS_MAILBOX, invocations...)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
return ZeroResult[map[string][]Mailbox](), err
|
||||
}
|
||||
|
||||
return command(j, ctx, cmd, func(body *Response) (map[string][]Mailbox, State, Error) {
|
||||
@@ -72,7 +72,7 @@ func (j *Client) SearchMailboxes(accountIds []string, filter MailboxFilterElemen
|
||||
})
|
||||
}
|
||||
|
||||
func (j *Client) SearchMailboxIdsPerRole(accountIds []string, roles []string, ctx Context) (map[string]map[string]string, SessionState, State, Language, Error) { //NOSONAR
|
||||
func (j *Client) SearchMailboxIdsPerRole(accountIds []string, roles []string, ctx Context) (Result[map[string]map[string]string], Error) { //NOSONAR
|
||||
logger := j.logger("SearchMailboxIdsPerRole", ctx)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
@@ -86,7 +86,7 @@ func (j *Client) SearchMailboxIdsPerRole(accountIds []string, roles []string, ct
|
||||
}
|
||||
cmd, err := j.request(ctx, NS_MAILBOX, invocations...)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
return ZeroResult[map[string]map[string]string](), err
|
||||
}
|
||||
|
||||
return command(j, ctx, cmd, func(body *Response) (map[string]map[string]string, State, Error) {
|
||||
@@ -138,7 +138,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) (MailboxChanges, SessionState, State, Language, Error) {
|
||||
ctx Context) (Result[MailboxChanges], Error) {
|
||||
return changesA(j, "GetMailboxChanges", MailboxType,
|
||||
func() MailboxChangesCommand {
|
||||
return MailboxChangesCommand{AccountId: accountId, SinceState: sinceState, MaxChanges: uintPtr(maxChanges)}
|
||||
@@ -164,7 +164,7 @@ func (j *Client) GetMailboxChanges(accountId string, sinceState State, maxChange
|
||||
// @api:tags email,changes
|
||||
func (j *Client) GetMailboxChangesForMultipleAccounts(accountIds []string, //NOSONAR
|
||||
sinceStateMap map[string]State, maxChanges uint,
|
||||
ctx Context) (map[string]MailboxChanges, SessionState, State, Language, Error) {
|
||||
ctx Context) (Result[map[string]MailboxChanges], Error) {
|
||||
return changesN(j, "GetMailboxChangesForMultipleAccounts", MailboxType,
|
||||
accountIds, sinceStateMap,
|
||||
func(accountId string, state State) MailboxChangesCommand {
|
||||
@@ -182,7 +182,7 @@ func (j *Client) GetMailboxChangesForMultipleAccounts(accountIds []string, //NOS
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) GetMailboxRolesForMultipleAccounts(accountIds []string, ctx Context) (map[string]*[]string, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetMailboxRolesForMultipleAccounts(accountIds []string, ctx Context) (Result[map[string]*[]string], Error) {
|
||||
return queryN(j, "GetMailboxRolesForMultipleAccounts", MailboxType,
|
||||
[]MailboxComparator{{Property: MailboxPropertySortOrder, IsAscending: true}},
|
||||
func(accountId string, filter MailboxFilterCondition, sortBy []MailboxComparator, _ int, _ string, _ *int, _ *uint) MailboxQueryCommand {
|
||||
@@ -201,14 +201,14 @@ func (j *Client) GetMailboxRolesForMultipleAccounts(accountIds []string, ctx Con
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) GetInboxNameForMultipleAccounts(accountIds []string, ctx Context) (map[string]string, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetInboxNameForMultipleAccounts(accountIds []string, ctx Context) (Result[map[string]string], Error) {
|
||||
logger := j.logger("GetInboxNameForMultipleAccounts", ctx)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
n := len(uniqueAccountIds)
|
||||
if n < 1 {
|
||||
return nil, "", "", "", nil
|
||||
return ZeroResult[map[string]string](), nil
|
||||
}
|
||||
|
||||
invocations := make([]Invocation, n*2)
|
||||
@@ -223,7 +223,7 @@ func (j *Client) GetInboxNameForMultipleAccounts(accountIds []string, ctx Contex
|
||||
|
||||
cmd, err := j.request(ctx, NS_MAILBOX, invocations...)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
return ZeroResult[map[string]string](), err
|
||||
}
|
||||
|
||||
return command(j, ctx, cmd, func(body *Response) (map[string]string, State, Error) {
|
||||
@@ -252,7 +252,7 @@ func (j *Client) GetInboxNameForMultipleAccounts(accountIds []string, ctx Contex
|
||||
}
|
||||
|
||||
func (j *Client) UpdateMailbox(accountId string, mailboxId string, change MailboxChange, //NOSONAR
|
||||
ctx Context) (Mailbox, SessionState, State, Language, Error) {
|
||||
ctx Context) (Result[Mailbox], Error) {
|
||||
return update(j, "UpdateMailbox", MailboxType,
|
||||
func(update map[string]PatchObject) MailboxSetCommand {
|
||||
return MailboxSetCommand{AccountId: accountId, Update: update}
|
||||
@@ -267,7 +267,7 @@ func (j *Client) UpdateMailbox(accountId string, mailboxId string, change Mailbo
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) CreateMailbox(accountId string, mailbox MailboxChange, ctx Context) (*Mailbox, SessionState, State, Language, Error) {
|
||||
func (j *Client) CreateMailbox(accountId string, mailbox MailboxChange, ctx Context) (Result[*Mailbox], Error) {
|
||||
return create(j, "CreateMailbox", MailboxType,
|
||||
func(accountId string, create map[string]MailboxChange) MailboxSetCommand {
|
||||
return MailboxSetCommand{AccountId: accountId, Create: create}
|
||||
@@ -286,7 +286,7 @@ func (j *Client) CreateMailbox(accountId string, mailbox MailboxChange, ctx Cont
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) DeleteMailboxes(accountId string, destroyIds []string, ctx Context) (map[string]SetError, SessionState, State, Language, Error) {
|
||||
func (j *Client) DeleteMailboxes(accountId string, destroyIds []string, ctx Context) (Result[map[string]SetError], Error) {
|
||||
return destroy(j, "DeleteMailboxes", MailboxType,
|
||||
func(accountId string, destroy []string) MailboxSetCommand {
|
||||
return MailboxSetCommand{AccountId: accountId, Destroy: destroyIds}
|
||||
|
||||
@@ -27,7 +27,7 @@ func (j *Client) GetObjects(accountId string, //NOSONAR
|
||||
quotaIds []string, identityIds []string,
|
||||
emailSubmissionIds []string,
|
||||
ctx Context,
|
||||
) (Objects, SessionState, State, Language, Error) {
|
||||
) (Result[Objects], Error) {
|
||||
l := j.logger("GetObjects", ctx).With()
|
||||
if len(mailboxIds) > 0 {
|
||||
l = l.Array("mailboxIds", log.SafeStringArray(mailboxIds))
|
||||
@@ -90,7 +90,7 @@ func (j *Client) GetObjects(accountId string, //NOSONAR
|
||||
|
||||
cmd, err := j.request(ctx, NS_OBJECTS, methodCalls...)
|
||||
if err != nil {
|
||||
return Objects{}, "", "", "", err
|
||||
return ZeroResult[Objects](), err
|
||||
}
|
||||
|
||||
return command(j, ctx, cmd, func(body *Response) (Objects, State, Error) {
|
||||
|
||||
@@ -2,7 +2,7 @@ package jmap
|
||||
|
||||
var NS_PRINCIPALS = ns(JmapPrincipals)
|
||||
|
||||
func (j *Client) GetPrincipals(accountId string, ids []string, ctx Context) (PrincipalGetResponse, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetPrincipals(accountId string, ids []string, ctx Context) (Result[PrincipalGetResponse], Error) {
|
||||
return get(j, "GetPrincipals", PrincipalType,
|
||||
func(accountId string, ids []string) PrincipalGetCommand {
|
||||
return PrincipalGetCommand{AccountId: accountId, Ids: ids}
|
||||
@@ -32,7 +32,7 @@ func (r *PrincipalSearchResults) SetPosition(position *uint) { r.Position = posi
|
||||
func (j *Client) QueryPrincipals(accountId string, //NOSONAR
|
||||
filter PrincipalFilterElement, sortBy []PrincipalComparator,
|
||||
position int, anchor string, anchorOffset *int, limit *uint, calculateTotal bool,
|
||||
ctx Context) (*PrincipalSearchResults, SessionState, State, Language, Error) {
|
||||
ctx Context) (Result[*PrincipalSearchResults], Error) {
|
||||
return query(j, "QueryPrincipals", PrincipalType,
|
||||
[]PrincipalComparator{{Property: PrincipalPropertyName, IsAscending: true}},
|
||||
func(filter PrincipalFilterElement, sortBy []PrincipalComparator, position int, anchor string, anchorOffset *int, limit *uint) PrincipalQueryCommand {
|
||||
|
||||
@@ -2,7 +2,7 @@ package jmap
|
||||
|
||||
var NS_QUOTA = ns(JmapQuota)
|
||||
|
||||
func (j *Client) GetQuotas(accountIds []string, ctx Context) (map[string]QuotaGetResponse, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetQuotas(accountIds []string, ctx Context) (Result[map[string]QuotaGetResponse], Error) {
|
||||
return getN(j, "GetQuotas", QuotaType,
|
||||
func(accountId string, ids []string) QuotaGetCommand {
|
||||
return QuotaGetCommand{AccountId: accountId}
|
||||
@@ -29,7 +29,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,
|
||||
ctx Context) (QuotaChanges, SessionState, State, Language, Error) {
|
||||
ctx Context) (Result[QuotaChanges], Error) {
|
||||
return changesA(j, "GetQuotaChanges", QuotaType,
|
||||
func() QuotaChangesCommand {
|
||||
return QuotaChangesCommand{AccountId: accountId, SinceState: sinceState, MaxChanges: uintPtr(maxChanges)}
|
||||
@@ -61,7 +61,7 @@ func (j *Client) GetQuotaChanges(accountId string, sinceState State, maxChanges
|
||||
}
|
||||
|
||||
func (j *Client) GetQuotaUsageChanges(accountId string, sinceState State, maxChanges uint,
|
||||
ctx Context) (QuotaChanges, SessionState, State, Language, Error) {
|
||||
ctx Context) (Result[QuotaChanges], Error) {
|
||||
return updates(j, "GetQuotaUsageChanges", QuotaType,
|
||||
func() QuotaChangesCommand {
|
||||
return QuotaChangesCommand{AccountId: accountId, SinceState: sinceState, MaxChanges: uintPtr(maxChanges)}
|
||||
|
||||
@@ -11,7 +11,7 @@ const (
|
||||
vacationResponseId = "singleton"
|
||||
)
|
||||
|
||||
func (j *Client) GetVacationResponse(accountId string, ctx Context) (VacationResponseGetResponse, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetVacationResponse(accountId string, ctx Context) (Result[VacationResponseGetResponse], Error) {
|
||||
return get(j, "GetVacationResponse", VacationResponseType,
|
||||
func(accountId string, ids []string) VacationResponseGetCommand {
|
||||
return VacationResponseGetCommand{AccountId: accountId}
|
||||
@@ -65,7 +65,7 @@ func (c VacationResponseChanges) GetUpdated() []VacationResponse { return c.Upda
|
||||
func (c VacationResponseChanges) GetDestroyed() []string { return c.Destroyed }
|
||||
|
||||
func (j *Client) SetVacationResponse(accountId string, vacation VacationResponseChange,
|
||||
ctx Context) (VacationResponse, SessionState, State, Language, Error) {
|
||||
ctx Context) (Result[VacationResponse], Error) {
|
||||
logger := j.logger("SetVacationResponse", ctx)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
@@ -92,7 +92,7 @@ func (j *Client) SetVacationResponse(accountId string, vacation VacationResponse
|
||||
invocation(get, "1"),
|
||||
)
|
||||
if err != nil {
|
||||
return VacationResponse{}, "", "", "", err
|
||||
return ZeroResult[VacationResponse](), err
|
||||
}
|
||||
return command(j, ctx, cmd, func(body *Response) (VacationResponse, State, Error) {
|
||||
var setResponse VacationResponseSetResponse
|
||||
|
||||
@@ -38,8 +38,9 @@ const (
|
||||
JmapErrorWssFailedToRetrieveSession
|
||||
JmapErrorSocketPushUnsupported
|
||||
JmapErrorMissingCreatedObject
|
||||
JmapInvalidObjectState
|
||||
JmapPatchObjectSerialization
|
||||
JmapErrorInvalidObjectState
|
||||
JmapErrorPatchObjectSerialization
|
||||
JmapErrorInvalidProperties
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -104,5 +105,10 @@ func setErrorError(err SetError, objectType ObjectType) Error {
|
||||
} else {
|
||||
e = fmt.Errorf("failed to modify %s due to %s error: %s", objectType, err.Type, err.Description)
|
||||
}
|
||||
return JmapError{code: JmapErrorSetError, err: e}
|
||||
code := JmapErrorSetError
|
||||
switch err.Type {
|
||||
case SetErrorTypeInvalidProperties:
|
||||
code = JmapErrorInvalidProperties
|
||||
}
|
||||
return JmapError{code: code, err: e}
|
||||
}
|
||||
|
||||
@@ -1157,9 +1157,9 @@ func containerTest[OBJ Idable, RESP GetResponse[OBJ], BOXES any, CHANGE Change](
|
||||
acc func(session *Session) string,
|
||||
obj func(RESP) []OBJ,
|
||||
id func(OBJ) string,
|
||||
get func(s *StalwartTest, accountId string, ids []string, ctx Context) (RESP, SessionState, State, Language, Error),
|
||||
update func(s *StalwartTest, accountId string, id string, change CHANGE, ctx Context) (OBJ, SessionState, State, Language, Error),
|
||||
destroy func(s *StalwartTest, accountId string, ids []string, ctx Context) (map[string]SetError, SessionState, State, Language, Error),
|
||||
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),
|
||||
change func(OBJ) CHANGE,
|
||||
checkChanged func(t *testing.T, orig OBJ, change CHANGE, changed OBJ),
|
||||
@@ -1179,10 +1179,10 @@ func containerTest[OBJ Idable, RESP GetResponse[OBJ], BOXES any, CHANGE Change](
|
||||
// we first need to retrieve the list of all the Principals in order to be able to use and test sharing
|
||||
principalIds := []string{}
|
||||
{
|
||||
principals, _, _, _, err := s.client.GetPrincipals(accountId, []string{}, ctx)
|
||||
result, err := s.client.GetPrincipals(accountId, []string{}, ctx)
|
||||
require.NoError(err)
|
||||
require.NotEmpty(principals.List)
|
||||
principalIds = structs.Map(principals.List, func(p Principal) string { return p.Id })
|
||||
require.NotEmpty(result.Payload.List)
|
||||
principalIds = structs.Map(result.Payload.List, func(p Principal) string { return p.Id })
|
||||
}
|
||||
|
||||
ss := EmptySessionState
|
||||
@@ -1192,37 +1192,43 @@ func containerTest[OBJ Idable, RESP GetResponse[OBJ], BOXES any, CHANGE Change](
|
||||
// from the tests below
|
||||
preExistingIds := []string{}
|
||||
{
|
||||
resp, sessionState, state, _, err := get(s, accountId, []string{}, ctx)
|
||||
result, err := get(s, accountId, []string{}, ctx)
|
||||
require.NoError(err)
|
||||
require.Empty(resp.GetNotFound())
|
||||
objs := obj(resp)
|
||||
require.Empty(result.Payload.GetNotFound())
|
||||
objs := obj(result.Payload)
|
||||
preExistingIds = structs.Map(objs, id)
|
||||
ss = sessionState
|
||||
as = state
|
||||
ss = result.GetSessionState()
|
||||
as = result.GetState()
|
||||
}
|
||||
|
||||
// we are going to create a random amount of objects
|
||||
num := uint(5 + rand.Intn(30))
|
||||
{
|
||||
boxes, all, sessionState, state, err := fill(s, t, accountId, num, ctx, user, principalIds)
|
||||
require.NoError(err)
|
||||
require.Len(all, int(num))
|
||||
ss = sessionState
|
||||
as = state
|
||||
var all []OBJ
|
||||
var boxes BOXES
|
||||
{
|
||||
b, a, sessionState, state, err := fill(s, t, accountId, num, ctx, user, principalIds)
|
||||
require.NoError(err)
|
||||
require.Len(a, int(num))
|
||||
ss = sessionState
|
||||
as = state
|
||||
boxes = b
|
||||
all = a
|
||||
}
|
||||
|
||||
{
|
||||
// lets retrieve all the existing objects by passing an empty ID slice
|
||||
resp, sessionState, state, _, err := get(s, accountId, []string{}, ctx)
|
||||
result, err := get(s, accountId, []string{}, ctx)
|
||||
require.NoError(err)
|
||||
require.Empty(resp.GetNotFound())
|
||||
objs := obj(resp)
|
||||
require.Empty(result.Payload.GetNotFound())
|
||||
objs := obj(result.Payload)
|
||||
// lets skip the objects that already exist since we did not create those
|
||||
found := structs.Filter(objs, func(a OBJ) bool { return !slices.Contains(preExistingIds, id(a)) })
|
||||
require.Len(found, int(num))
|
||||
m := structs.Index(found, id)
|
||||
require.Len(m, int(num))
|
||||
require.Equal(sessionState, ss)
|
||||
require.Equal(state, as)
|
||||
require.Equal(result.GetSessionState(), ss)
|
||||
require.Equal(result.GetState(), as)
|
||||
|
||||
for _, a := range all {
|
||||
i := id(a)
|
||||
@@ -1232,35 +1238,35 @@ func containerTest[OBJ Idable, RESP GetResponse[OBJ], BOXES any, CHANGE Change](
|
||||
require.Equal(a, found)
|
||||
}
|
||||
|
||||
ss = sessionState
|
||||
as = state
|
||||
ss = result.GetSessionState()
|
||||
as = result.GetState()
|
||||
}
|
||||
|
||||
// lets retrieve every object we created by its ID
|
||||
for _, a := range all {
|
||||
i := id(a)
|
||||
resp, sessionState, state, _, err := get(s, accountId, []string{i}, ctx)
|
||||
result, err := get(s, accountId, []string{i}, ctx)
|
||||
require.NoError(err)
|
||||
require.Empty(resp.GetNotFound())
|
||||
objs := obj(resp)
|
||||
require.Empty(result.Payload.GetNotFound())
|
||||
objs := obj(result.Payload)
|
||||
require.Len(objs, 1)
|
||||
require.Equal(sessionState, ss)
|
||||
require.Equal(state, as)
|
||||
require.Equal(result.GetSessionState(), ss)
|
||||
require.Equal(result.GetState(), as)
|
||||
require.Equal(objs[0], a)
|
||||
}
|
||||
|
||||
// let's retrieve them all by their IDs, but this time all at once
|
||||
{
|
||||
ids := structs.Map(all, id)
|
||||
resp, sessionState, state, _, err := get(s, accountId, ids, ctx)
|
||||
result, err := get(s, accountId, ids, ctx)
|
||||
require.NoError(err)
|
||||
require.Empty(resp.GetNotFound())
|
||||
objs := obj(resp)
|
||||
require.Empty(result.Payload.GetNotFound())
|
||||
objs := obj(result.Payload)
|
||||
require.Len(objs, len(all))
|
||||
require.Equal(sessionState, ss)
|
||||
require.Equal(state, as)
|
||||
require.Equal(result.GetSessionState(), ss)
|
||||
require.Equal(result.GetState(), as)
|
||||
allById := structs.Index(all, id)
|
||||
for _, r := range resp.GetList() {
|
||||
for _, r := range result.Payload.GetList() {
|
||||
a, ok := allById[r.GetId()]
|
||||
require.True(ok, "failed to find object that was retrieved in mass ID request in the list of objects that were created")
|
||||
require.Equal(a, r)
|
||||
@@ -1271,22 +1277,22 @@ func containerTest[OBJ Idable, RESP GetResponse[OBJ], BOXES any, CHANGE Change](
|
||||
for _, a := range all {
|
||||
i := id(a)
|
||||
ch := change(a)
|
||||
changed, sessionState, state, _, err := update(s, accountId, i, ch, ctx)
|
||||
result, err := update(s, accountId, i, ch, ctx)
|
||||
require.NoError(err)
|
||||
require.NotEqual(a, changed)
|
||||
require.Equal(sessionState, ss)
|
||||
require.NotEqual(state, as)
|
||||
checkChanged(t, a, ch, changed)
|
||||
require.NotEqual(a, result.Payload)
|
||||
require.Equal(result.GetSessionState(), ss)
|
||||
require.NotEqual(result.GetState(), as)
|
||||
checkChanged(t, a, ch, result.Payload)
|
||||
}
|
||||
|
||||
// now lets delete each object that we created, all at once
|
||||
ids := structs.Map(all, id)
|
||||
{
|
||||
errMap, sessionState, state, _, err := destroy(s, accountId, ids, ctx)
|
||||
result, err := destroy(s, accountId, ids, ctx)
|
||||
require.NoError(err)
|
||||
require.Empty(errMap)
|
||||
require.Equal(sessionState, ss)
|
||||
require.NotEqual(state, as)
|
||||
require.Empty(result.Payload)
|
||||
require.Equal(result.GetSessionState(), ss)
|
||||
require.NotEqual(result.GetState(), as)
|
||||
}
|
||||
|
||||
allBoxesAreTicked(t, boxes)
|
||||
@@ -45,13 +45,13 @@ func TestAddressBooks(t *testing.T) {
|
||||
func(session *Session) string { return session.PrimaryAccounts.Contacts },
|
||||
list,
|
||||
getid,
|
||||
func(s *StalwartTest, accountId string, ids []string, ctx Context) (AddressBookGetResponse, SessionState, State, Language, Error) {
|
||||
func(s *StalwartTest, accountId string, 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) (AddressBook, SessionState, State, Language, Error) { //NOSONAR
|
||||
func(s *StalwartTest, accountId string, 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) (map[string]SetError, SessionState, State, Language, Error) { //NOSONAR
|
||||
func(s *StalwartTest, accountId string, 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) {
|
||||
@@ -100,19 +100,29 @@ func TestContacts(t *testing.T) {
|
||||
{Property: ContactCardPropertyCreated, IsAscending: true},
|
||||
}
|
||||
|
||||
contactsByAccount, ss, os, _, err := s.client.QueryContactCards([]string{accountId}, filter, sortBy, 0, "", nil, nil, true, ctx)
|
||||
require.NoError(err)
|
||||
var results *ContactCardSearchResults
|
||||
ss := EmptySessionState
|
||||
os := EmptyState
|
||||
{
|
||||
result, err := s.client.QueryContactCards([]string{accountId}, filter, sortBy, 0, "", nil, nil, true, ctx)
|
||||
require.NoError(err)
|
||||
|
||||
require.Len(contactsByAccount, 1)
|
||||
require.Contains(contactsByAccount, accountId)
|
||||
results := contactsByAccount[accountId]
|
||||
require.Len(results.Results, int(count))
|
||||
require.Nil(results.Limit)
|
||||
require.NotNil(results.Position)
|
||||
require.Equal(uint(0), *results.Position)
|
||||
require.NotNil(results.Total)
|
||||
require.Equal(count, *results.Total)
|
||||
require.Equal(ChangeCalculation(true), results.CanCalculateChanges)
|
||||
require.Len(result.Payload, 1)
|
||||
require.Contains(result.Payload, accountId)
|
||||
results = result.Payload[accountId]
|
||||
require.Len(results.Results, int(count))
|
||||
require.Nil(results.Limit)
|
||||
require.NotNil(results.Position)
|
||||
require.Equal(uint(0), *results.Position)
|
||||
require.NotNil(results.Total)
|
||||
require.Equal(count, *results.Total)
|
||||
require.Equal(ChangeCalculation(true), results.CanCalculateChanges)
|
||||
|
||||
ss = result.GetSessionState()
|
||||
require.NotEmpty(ss)
|
||||
os = result.GetState()
|
||||
require.NotEmpty(os)
|
||||
}
|
||||
|
||||
for _, actual := range results.Results {
|
||||
expected, ok := expectedContactCardsById[actual.Id]
|
||||
@@ -123,11 +133,11 @@ func TestContacts(t *testing.T) {
|
||||
// retrieve all objects at once
|
||||
{
|
||||
ids := structs.Map(results.Results, func(c ContactCard) string { return c.Id })
|
||||
fetched, _, _, _, err := s.client.GetContactCards(accountId, ids, ctx)
|
||||
result, err := s.client.GetContactCards(accountId, ids, ctx)
|
||||
require.NoError(err)
|
||||
require.Empty(fetched.NotFound)
|
||||
require.Len(fetched.List, len(ids))
|
||||
byId := structs.Index(fetched.List, func(r ContactCard) string { return r.Id })
|
||||
require.Empty(result.Payload.NotFound)
|
||||
require.Len(result.Payload.List, len(ids))
|
||||
byId := structs.Index(result.Payload.List, func(r ContactCard) string { return r.Id })
|
||||
for _, actual := range results.Results {
|
||||
expected, ok := byId[actual.Id]
|
||||
require.True(ok, "failed to find created contact by its id")
|
||||
@@ -137,10 +147,10 @@ func TestContacts(t *testing.T) {
|
||||
|
||||
// retrieve each object one by one
|
||||
for _, actual := range results.Results {
|
||||
fetched, _, _, _, err := s.client.GetContactCards(accountId, []string{actual.Id}, ctx)
|
||||
result, err := s.client.GetContactCards(accountId, []string{actual.Id}, ctx)
|
||||
require.NoError(err)
|
||||
require.Len(fetched.List, 1)
|
||||
matchContact(t, fetched.List[0], actual)
|
||||
require.Len(result.Payload.List, 1)
|
||||
matchContact(t, result.Payload.List[0], actual)
|
||||
}
|
||||
|
||||
{
|
||||
@@ -151,11 +161,11 @@ func TestContacts(t *testing.T) {
|
||||
for i := range slices {
|
||||
position := int(i * limit)
|
||||
page := min(remainder, limit)
|
||||
m, sessionState, _, _, err := s.client.QueryContactCards([]string{accountId}, filter, sortBy, position, "", nil, &limit, true, ctx)
|
||||
result, err := s.client.QueryContactCards([]string{accountId}, filter, sortBy, position, "", nil, &limit, true, ctx)
|
||||
require.NoError(err)
|
||||
require.Len(m, 1)
|
||||
require.Contains(m, accountId)
|
||||
results := m[accountId]
|
||||
require.Len(result.Payload, 1)
|
||||
require.Contains(result.Payload, accountId)
|
||||
results := result.Payload[accountId]
|
||||
require.Equal(len(results.Results), int(page))
|
||||
require.NotNil(results.Limit)
|
||||
require.Equal(limit, *results.Limit)
|
||||
@@ -166,7 +176,7 @@ func TestContacts(t *testing.T) {
|
||||
require.Equal(count, *results.Total)
|
||||
remainder -= uint(len(results.Results))
|
||||
|
||||
require.Equal(ss, sessionState)
|
||||
require.Equal(ss, result.GetSessionState())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,12 +186,12 @@ func TestContacts(t *testing.T) {
|
||||
offset := 0
|
||||
i := 0
|
||||
for chunk := range slices.Chunk(results.Results, chunkSize) {
|
||||
m, sessionState, _, _, err := s.client.QueryContactCards([]string{accountId}, filter, sortBy, 0, anchor, &offset, uintPtr(chunkSize), true, ctx)
|
||||
require.Equal(ss, sessionState)
|
||||
result, err := s.client.QueryContactCards([]string{accountId}, filter, sortBy, 0, anchor, &offset, uintPtr(chunkSize), true, ctx)
|
||||
require.Equal(ss, result.GetSessionState())
|
||||
require.NoError(err)
|
||||
require.Len(m, 1)
|
||||
require.Contains(m, accountId)
|
||||
results := m[accountId]
|
||||
require.Len(result.Payload, 1)
|
||||
require.Contains(result.Payload, accountId)
|
||||
results := result.Payload[accountId]
|
||||
l := len(results.Results)
|
||||
require.LessOrEqual(l, chunkSize)
|
||||
require.NotZero(l)
|
||||
@@ -206,35 +216,35 @@ func TestContacts(t *testing.T) {
|
||||
Language: ptr("xyz"),
|
||||
Updated: ptr(now),
|
||||
}
|
||||
changed, sessionState, state, _, err := s.client.UpdateContactCard(accountId, event.Id, change, ctx)
|
||||
result, err := s.client.UpdateContactCard(accountId, event.Id, change, ctx)
|
||||
require.NoError(err)
|
||||
require.Equal("xyz", changed.Language)
|
||||
require.Equal(now, changed.Updated)
|
||||
require.Equal(ss, sessionState)
|
||||
require.NotEqual(os, state)
|
||||
os = state
|
||||
require.Equal("xyz", result.Payload.Language)
|
||||
require.Equal(now, result.Payload.Updated)
|
||||
require.Equal(ss, result.GetSessionState())
|
||||
require.NotEqual(os, result.GetState())
|
||||
os = result.GetState()
|
||||
}
|
||||
}
|
||||
{
|
||||
ids := structs.Map(slices.Collect(maps.Values(expectedContactCardsById)), func(e ContactCard) string { return e.Id })
|
||||
errMap, sessionState, state, _, err := s.client.DeleteContactCard(accountId, ids, ctx)
|
||||
result, err := s.client.DeleteContactCard(accountId, ids, ctx)
|
||||
require.NoError(err)
|
||||
require.Empty(errMap)
|
||||
require.Empty(result.Payload)
|
||||
|
||||
require.Equal(ss, sessionState)
|
||||
require.NotEqual(os, state)
|
||||
os = state
|
||||
require.Equal(ss, result.GetSessionState())
|
||||
require.NotEqual(os, result.GetState())
|
||||
os = result.GetState()
|
||||
}
|
||||
{
|
||||
shouldBeEmpty, sessionState, state, _, err := s.client.QueryContactCards([]string{accountId}, filter, sortBy, 0, "", nil, nil, true, ctx)
|
||||
result, err := s.client.QueryContactCards([]string{accountId}, filter, sortBy, 0, "", nil, nil, true, ctx)
|
||||
require.NoError(err)
|
||||
require.Contains(shouldBeEmpty, accountId)
|
||||
resp := shouldBeEmpty[accountId]
|
||||
require.Contains(result.Payload, accountId)
|
||||
resp := result.Payload[accountId]
|
||||
require.Empty(resp.Results)
|
||||
require.NotNil(resp.Total)
|
||||
require.Equal(uint(0), *resp.Total)
|
||||
require.Equal(ss, sessionState)
|
||||
require.Equal(os, state)
|
||||
require.Equal(ss, result.GetSessionState())
|
||||
require.Equal(os, result.GetState())
|
||||
}
|
||||
|
||||
exceptions := []string{}
|
||||
@@ -319,24 +329,24 @@ func (s *StalwartTest) fillAddressBook( //NOSONAR
|
||||
abook.ShareWith = m
|
||||
}
|
||||
|
||||
a, sessionState, state, _, err := s.client.CreateAddressBook(accountId, abook, ctx)
|
||||
result, err := s.client.CreateAddressBook(accountId, abook, ctx)
|
||||
if err != nil {
|
||||
return boxes, created, ss, as, err
|
||||
}
|
||||
require.NotEmpty(sessionState)
|
||||
require.NotEmpty(state)
|
||||
require.NotEmpty(result.GetSessionState())
|
||||
require.NotEmpty(result.GetState())
|
||||
if ss != EmptySessionState {
|
||||
require.Equal(ss, sessionState)
|
||||
require.Equal(ss, result.GetSessionState())
|
||||
}
|
||||
if as != EmptyState {
|
||||
require.NotEqual(as, state)
|
||||
require.NotEqual(as, result.GetState())
|
||||
}
|
||||
require.NotNil(a)
|
||||
created = append(created, *a)
|
||||
ss = sessionState
|
||||
as = state
|
||||
require.NotNil(result.Payload)
|
||||
created = append(created, *result.Payload)
|
||||
ss = result.GetSessionState()
|
||||
as = result.GetState()
|
||||
|
||||
printer(fmt.Sprintf("📔 created %*s/%v id=%v", int(math.Log10(float64(count))+1), strconv.Itoa(int(i+1)), count, a.Id))
|
||||
printer(fmt.Sprintf("📔 created %*s/%v id=%v", int(math.Log10(float64(count))+1), strconv.Itoa(int(i+1)), count, result.Payload.Id))
|
||||
}
|
||||
return boxes, created, ss, as, nil
|
||||
}
|
||||
@@ -644,13 +654,13 @@ func (s *StalwartTest) fillContacts( //NOSONAR
|
||||
return "", "", nil, boxes, err
|
||||
}
|
||||
|
||||
created, _, _, _, err := s.client.CreateContactCard(accountId, card, ctx)
|
||||
result, err := s.client.CreateContactCard(accountId, card, ctx)
|
||||
if err != nil {
|
||||
return accountId, addressbookId, filled, boxes, err
|
||||
}
|
||||
require.NotNil(created)
|
||||
filled[created.Id] = *created
|
||||
printer(fmt.Sprintf("🧑🏻 created %*s/%v id=%v", int(math.Log10(float64(count))+1), strconv.Itoa(int(i+1)), count, created.Id))
|
||||
require.NotNil(result.Payload)
|
||||
filled[result.Payload.Id] = *result.Payload
|
||||
printer(fmt.Sprintf("🧑🏻 created %*s/%v id=%v", int(math.Log10(float64(count))+1), strconv.Itoa(int(i+1)), count, result.Payload.Id))
|
||||
}
|
||||
return accountId, addressbookId, filled, boxes, nil
|
||||
}
|
||||
|
||||
@@ -35,13 +35,13 @@ func TestCalendars(t *testing.T) { //NOSONAR
|
||||
func(session *Session) string { 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) (CalendarGetResponse, SessionState, State, Language, Error) {
|
||||
func(s *StalwartTest, accountId string, 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) (Calendar, SessionState, State, Language, Error) { //NOSONAR
|
||||
func(s *StalwartTest, accountId string, 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) (map[string]SetError, SessionState, State, Language, Error) { //NOSONAR
|
||||
func(s *StalwartTest, accountId string, 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) {
|
||||
@@ -94,12 +94,12 @@ func TestEvents(t *testing.T) {
|
||||
os := EmptyState
|
||||
var results *CalendarEventSearchResults
|
||||
{
|
||||
resultsByAccount, sessionState, state, _, err := s.client.QueryCalendarEvents([]string{accountId}, filter, sortBy, 0, "", nil, nil, true, ctx)
|
||||
result, err := s.client.QueryCalendarEvents([]string{accountId}, filter, sortBy, 0, "", nil, nil, true, ctx)
|
||||
require.NoError(err)
|
||||
|
||||
require.Len(resultsByAccount, 1)
|
||||
require.Contains(resultsByAccount, accountId)
|
||||
results = resultsByAccount[accountId]
|
||||
require.Len(result.Payload, 1)
|
||||
require.Contains(result.Payload, accountId)
|
||||
results = result.Payload[accountId]
|
||||
require.NotNil(results)
|
||||
require.Len(results.Results, int(count))
|
||||
require.Nil(results.Limit)
|
||||
@@ -115,8 +115,8 @@ func TestEvents(t *testing.T) {
|
||||
matchEvent(t, actual, expected)
|
||||
}
|
||||
|
||||
ss = sessionState
|
||||
os = state
|
||||
ss = result.GetSessionState()
|
||||
os = result.GetState()
|
||||
}
|
||||
|
||||
{
|
||||
@@ -127,11 +127,11 @@ func TestEvents(t *testing.T) {
|
||||
for i := range slices {
|
||||
position := int(i * limit)
|
||||
page := min(remainder, limit)
|
||||
m, sessionState, _, _, err := s.client.QueryCalendarEvents([]string{accountId}, filter, sortBy, position, "", nil, &limit, true, ctx)
|
||||
result, err := s.client.QueryCalendarEvents([]string{accountId}, filter, sortBy, position, "", nil, &limit, true, ctx)
|
||||
require.NoError(err)
|
||||
require.Len(m, 1)
|
||||
require.Contains(m, accountId)
|
||||
results := m[accountId]
|
||||
require.Len(result.Payload, 1)
|
||||
require.Contains(result.Payload, accountId)
|
||||
results := result.Payload[accountId]
|
||||
require.Equal(len(results.Results), int(page))
|
||||
require.NotNil(results.Limit)
|
||||
require.Equal(limit, *results.Limit)
|
||||
@@ -142,7 +142,7 @@ func TestEvents(t *testing.T) {
|
||||
require.Equal(count, *results.Total)
|
||||
remainder -= uint(len(results.Results))
|
||||
|
||||
require.Equal(ss, sessionState)
|
||||
require.Equal(ss, result.GetSessionState())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,12 +152,12 @@ func TestEvents(t *testing.T) {
|
||||
offset := 0
|
||||
i := 0
|
||||
for chunk := range slices.Chunk(results.Results, chunkSize) {
|
||||
m, sessionState, _, _, err := s.client.QueryCalendarEvents([]string{accountId}, filter, sortBy, 0, anchor, &offset, uintPtr(chunkSize), true, ctx)
|
||||
require.Equal(ss, sessionState)
|
||||
result, err := s.client.QueryCalendarEvents([]string{accountId}, filter, sortBy, 0, anchor, &offset, uintPtr(chunkSize), true, ctx)
|
||||
require.Equal(ss, result.GetSessionState())
|
||||
require.NoError(err)
|
||||
require.Len(m, 1)
|
||||
require.Contains(m, accountId)
|
||||
results := m[accountId]
|
||||
require.Len(result.Payload, 1)
|
||||
require.Contains(result.Payload, accountId)
|
||||
results := result.Payload[accountId]
|
||||
l := len(results.Results)
|
||||
require.LessOrEqual(l, chunkSize)
|
||||
require.NotZero(l)
|
||||
@@ -185,37 +185,37 @@ func TestEvents(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
changed, sessionState, state, _, err := s.client.UpdateCalendarEvent(accountId, event.Id, change, ctx)
|
||||
result, err := s.client.UpdateCalendarEvent(accountId, event.Id, change, ctx)
|
||||
require.NoError(err)
|
||||
require.Equal(jscalendar.StatusCancelled, changed.Status)
|
||||
require.Equal(uint(99), changed.Sequence)
|
||||
require.Equal(true, changed.ShowWithoutTime)
|
||||
require.Equal(ss, sessionState)
|
||||
require.NotEqual(os, state)
|
||||
os = state
|
||||
require.Equal(jscalendar.StatusCancelled, result.Payload.Status)
|
||||
require.Equal(uint(99), result.Payload.Sequence)
|
||||
require.Equal(true, result.Payload.ShowWithoutTime)
|
||||
require.Equal(ss, result.GetSessionState())
|
||||
require.NotEqual(os, result.GetState())
|
||||
os = result.GetState()
|
||||
}
|
||||
|
||||
{
|
||||
ids := structs.Map(slices.Collect(maps.Values(expectedEventsById)), func(e CalendarEvent) string { return e.Id })
|
||||
errMap, sessionState, state, _, err := s.client.DeleteCalendarEvent(accountId, ids, ctx)
|
||||
result, err := s.client.DeleteCalendarEvent(accountId, ids, ctx)
|
||||
require.NoError(err)
|
||||
require.Empty(errMap)
|
||||
require.Empty(result.Payload)
|
||||
|
||||
require.Equal(ss, sessionState)
|
||||
require.NotEqual(os, state)
|
||||
os = state
|
||||
require.Equal(ss, result.GetSessionState())
|
||||
require.NotEqual(os, result.GetState())
|
||||
os = result.GetState()
|
||||
}
|
||||
|
||||
{
|
||||
shouldBeEmpty, sessionState, state, _, err := s.client.QueryCalendarEvents([]string{accountId}, filter, sortBy, 0, "", nil, nil, true, ctx)
|
||||
result, err := s.client.QueryCalendarEvents([]string{accountId}, filter, sortBy, 0, "", nil, nil, true, ctx)
|
||||
require.NoError(err)
|
||||
require.Contains(shouldBeEmpty, accountId)
|
||||
resp := shouldBeEmpty[accountId]
|
||||
require.Contains(result.Payload, accountId)
|
||||
resp := result.Payload[accountId]
|
||||
require.Empty(resp.Results)
|
||||
require.NotNil(resp.Total)
|
||||
require.Equal(uint(0), *resp.Total)
|
||||
require.Equal(ss, sessionState)
|
||||
require.Equal(os, state)
|
||||
require.Equal(ss, result.GetSessionState())
|
||||
require.Equal(os, result.GetState())
|
||||
}
|
||||
|
||||
exceptions := []string{}
|
||||
@@ -347,24 +347,24 @@ func (s *StalwartTest) fillCalendar( //NOSONAR
|
||||
cal.ShareWith = m
|
||||
}
|
||||
|
||||
a, sessionState, state, _, err := s.client.CreateCalendar(accountId, cal, ctx)
|
||||
result, err := s.client.CreateCalendar(accountId, cal, ctx)
|
||||
if err != nil {
|
||||
return boxes, created, ss, as, err
|
||||
}
|
||||
require.NotEmpty(sessionState)
|
||||
require.NotEmpty(state)
|
||||
require.NotEmpty(result.GetSessionState())
|
||||
require.NotEmpty(result.GetState())
|
||||
if ss != EmptySessionState {
|
||||
require.Equal(ss, sessionState)
|
||||
require.Equal(ss, result.GetSessionState())
|
||||
}
|
||||
if as != EmptyState {
|
||||
require.NotEqual(as, state)
|
||||
require.NotEqual(as, result.GetState())
|
||||
}
|
||||
require.NotNil(a)
|
||||
created = append(created, *a)
|
||||
ss = sessionState
|
||||
as = state
|
||||
require.NotNil(result.Payload)
|
||||
created = append(created, *result.Payload)
|
||||
ss = result.GetSessionState()
|
||||
as = result.GetState()
|
||||
|
||||
printer(fmt.Sprintf("📅 created %*s/%v id=%v", int(math.Log10(float64(count))+1), strconv.Itoa(int(i+1)), count, a.Id))
|
||||
printer(fmt.Sprintf("📅 created %*s/%v id=%v", int(math.Log10(float64(count))+1), strconv.Itoa(int(i+1)), count, result.Payload.Id))
|
||||
}
|
||||
return boxes, created, ss, as, nil
|
||||
}
|
||||
@@ -571,12 +571,12 @@ func (s *StalwartTest) fillEvents( //NOSONAR
|
||||
obj.RecurrenceRule = &rr
|
||||
}
|
||||
|
||||
created, _, _, _, err := s.client.CreateCalendarEvent(accountId, obj, ctx)
|
||||
result, err := s.client.CreateCalendarEvent(accountId, obj, ctx)
|
||||
if err != nil {
|
||||
return accountId, calendarId, nil, boxes, err
|
||||
}
|
||||
|
||||
filled[created.Id] = *created
|
||||
filled[result.Payload.Id] = *result.Payload
|
||||
|
||||
printer(fmt.Sprintf("📅 created %*s/%v id=%v", int(math.Log10(float64(count))+1), strconv.Itoa(int(i+1)), count, uid))
|
||||
}
|
||||
|
||||
@@ -56,21 +56,21 @@ func TestEmails(t *testing.T) {
|
||||
|
||||
{
|
||||
{
|
||||
resp, sessionState, _, _, err := s.client.GetIdentities(accountId, []string{}, ctx)
|
||||
result, err := s.client.GetIdentities(accountId, []string{}, ctx)
|
||||
require.NoError(err)
|
||||
require.Equal(session.State, sessionState)
|
||||
require.Len(resp.List, 1)
|
||||
require.Equal(user.email, resp.List[0].Email)
|
||||
require.Equal(user.description, resp.List[0].Name)
|
||||
require.Equal(session.State, result.GetSessionState())
|
||||
require.Len(result.Payload.List, 1)
|
||||
require.Equal(user.email, result.Payload.List[0].Email)
|
||||
require.Equal(user.description, result.Payload.List[0].Name)
|
||||
}
|
||||
|
||||
{
|
||||
respByAccountId, sessionState, _, _, err := s.client.GetAllMailboxes([]string{accountId}, ctx)
|
||||
result, err := s.client.GetAllMailboxes([]string{accountId}, ctx)
|
||||
require.NoError(err)
|
||||
require.Equal(session.State, sessionState)
|
||||
require.Len(respByAccountId, 1)
|
||||
require.Contains(respByAccountId, accountId)
|
||||
resp := respByAccountId[accountId]
|
||||
require.Equal(session.State, result.GetSessionState())
|
||||
require.Len(result.Payload, 1)
|
||||
require.Contains(result.Payload, accountId)
|
||||
resp := result.Payload[accountId]
|
||||
mailboxesUnreadByRole := map[string]int{}
|
||||
for _, m := range resp {
|
||||
if m.Role != "" {
|
||||
@@ -81,12 +81,12 @@ func TestEmails(t *testing.T) {
|
||||
}
|
||||
|
||||
{
|
||||
resp, sessionState, _, _, err := s.client.GetAllEmailsInMailbox(accountId, inboxId, 0, "", nil, nil, true, false, 0, true, ctx)
|
||||
result, err := s.client.GetAllEmailsInMailbox(accountId, inboxId, 0, "", nil, nil, true, false, 0, true, ctx)
|
||||
require.NoError(err)
|
||||
require.Equal(session.State, sessionState)
|
||||
require.Equal(session.State, result.GetSessionState())
|
||||
|
||||
require.Equalf(threads, len(resp.Results), "the number of collapsed emails in the inbox is expected to be %v, but is actually %v", threads, len(resp.Results))
|
||||
for _, e := range resp.Results {
|
||||
require.Equalf(threads, len(result.Payload.Results), "the number of collapsed emails in the inbox is expected to be %v, but is actually %v", threads, len(result.Payload.Results))
|
||||
for _, e := range result.Payload.Results {
|
||||
require.Len(e.MessageId, 1)
|
||||
expectation, ok := mailsByMessageId[e.MessageId[0]]
|
||||
require.True(ok)
|
||||
@@ -95,12 +95,12 @@ func TestEmails(t *testing.T) {
|
||||
}
|
||||
|
||||
{
|
||||
resp, sessionState, _, _, err := s.client.GetAllEmailsInMailbox(accountId, inboxId, 0, "", nil, nil, false, false, 0, true, ctx)
|
||||
result, err := s.client.GetAllEmailsInMailbox(accountId, inboxId, 0, "", nil, nil, false, false, 0, true, ctx)
|
||||
require.NoError(err)
|
||||
require.Equal(session.State, sessionState)
|
||||
require.Equal(session.State, result.GetSessionState())
|
||||
|
||||
require.Equalf(count, len(resp.Results), "the number of emails in the inbox is expected to be %v, but is actually %v", count, len(resp.Results))
|
||||
for _, e := range resp.Results {
|
||||
require.Equalf(count, len(result.Payload.Results), "the number of emails in the inbox is expected to be %v, but is actually %v", count, len(result.Payload.Results))
|
||||
for _, e := range result.Payload.Results {
|
||||
require.Len(e.MessageId, 1)
|
||||
expectation, ok := mailsByMessageId[e.MessageId[0]]
|
||||
require.True(ok)
|
||||
@@ -144,9 +144,9 @@ func TestSendingEmails(t *testing.T) {
|
||||
|
||||
var mailboxPerRole map[string]Mailbox
|
||||
{
|
||||
mailboxes, _, _, _, err := s.client.GetAllMailboxes([]string{accountId}, ctx)
|
||||
result, err := s.client.GetAllMailboxes([]string{accountId}, ctx)
|
||||
require.NoError(err)
|
||||
mailboxPerRole = structs.Index(mailboxes[accountId], func(m Mailbox) string { return m.Role })
|
||||
mailboxPerRole = structs.Index(result.Payload[accountId], func(m Mailbox) string { return m.Role })
|
||||
require.Contains(mailboxPerRole, JmapMailboxRoleInbox)
|
||||
require.Contains(mailboxPerRole, JmapMailboxRoleDrafts)
|
||||
require.Contains(mailboxPerRole, JmapMailboxRoleSent)
|
||||
@@ -154,10 +154,10 @@ func TestSendingEmails(t *testing.T) {
|
||||
}
|
||||
{
|
||||
roles := []string{JmapMailboxRoleDrafts, JmapMailboxRoleSent, JmapMailboxRoleInbox}
|
||||
m, _, _, _, err := s.client.SearchMailboxIdsPerRole([]string{accountId}, roles, ctx)
|
||||
result, err := s.client.SearchMailboxIdsPerRole([]string{accountId}, roles, ctx)
|
||||
require.NoError(err)
|
||||
require.Contains(m, accountId)
|
||||
a := m[accountId]
|
||||
require.Contains(result.Payload, accountId)
|
||||
a := result.Payload[accountId]
|
||||
for _, role := range roles {
|
||||
require.Contains(a, role)
|
||||
}
|
||||
@@ -174,9 +174,9 @@ func TestSendingEmails(t *testing.T) {
|
||||
Logger: ctx.Logger,
|
||||
AcceptLanguage: ctx.AcceptLanguage,
|
||||
}
|
||||
mailboxes, _, _, _, err := s.client.GetAllMailboxes([]string{u.accountId}, uctx)
|
||||
result, err := s.client.GetAllMailboxes([]string{u.accountId}, uctx)
|
||||
require.NoError(err)
|
||||
for _, mailbox := range mailboxes[u.accountId] {
|
||||
for _, mailbox := range result.Payload[u.accountId] {
|
||||
require.Equal(0, mailbox.TotalEmails)
|
||||
}
|
||||
}
|
||||
@@ -188,10 +188,10 @@ func TestSendingEmails(t *testing.T) {
|
||||
{
|
||||
var identity Identity
|
||||
{
|
||||
resp, _, _, _, err := s.client.GetIdentities(accountId, []string{}, ctx)
|
||||
result, err := s.client.GetIdentities(accountId, []string{}, ctx)
|
||||
require.NoError(err)
|
||||
require.NotEmpty(resp.List)
|
||||
identity = resp.List[0]
|
||||
require.NotEmpty(result.Payload.List)
|
||||
identity = result.Payload.List[0]
|
||||
}
|
||||
|
||||
create := EmailChange{
|
||||
@@ -199,16 +199,20 @@ func TestSendingEmails(t *testing.T) {
|
||||
Subject: subject,
|
||||
MailboxIds: toBoolMapS(mailboxPerRole[JmapMailboxRoleDrafts].Id),
|
||||
}
|
||||
created, _, _, _, err := s.client.CreateEmail(accountId, create, "", ctx)
|
||||
require.NoError(err)
|
||||
require.NotEmpty(created.Id)
|
||||
var created *Email
|
||||
{
|
||||
result, err := s.client.CreateEmail(accountId, create, "", ctx)
|
||||
require.NoError(err)
|
||||
created = result.Payload
|
||||
require.NotEmpty(created.Id)
|
||||
}
|
||||
|
||||
{
|
||||
emails, notFound, _, _, _, err := s.client.GetEmails(accountId, []string{created.Id}, true, 0, false, false, ctx)
|
||||
result, err := s.client.GetEmails(accountId, []string{created.Id}, true, 0, false, false, ctx)
|
||||
require.NoError(err)
|
||||
require.Len(emails, 1)
|
||||
require.Empty(notFound)
|
||||
email := emails[0]
|
||||
require.Len(result.Payload.List, 1)
|
||||
require.Empty(result.Payload.NotFound)
|
||||
email := result.Payload.List[0]
|
||||
require.Equal(created.Id, email.Id)
|
||||
require.Len(email.MailboxIds, 1)
|
||||
require.Contains(email.MailboxIds, mailboxPerRole[JmapMailboxRoleDrafts].Id)
|
||||
@@ -223,22 +227,27 @@ func TestSendingEmails(t *testing.T) {
|
||||
Subject: subject,
|
||||
MailboxIds: toBoolMapS(mailboxPerRole[JmapMailboxRoleDrafts].Id),
|
||||
}
|
||||
updated, _, _, _, err := s.client.CreateEmail(accountId, update, created.Id, ctx)
|
||||
require.NoError(err)
|
||||
require.NotEmpty(updated.Id)
|
||||
require.NotEqual(created.Id, updated.Id)
|
||||
var updated *Email
|
||||
{
|
||||
result, err := s.client.CreateEmail(accountId, update, created.Id, ctx)
|
||||
require.NoError(err)
|
||||
updated = result.Payload
|
||||
require.NotNil(updated)
|
||||
require.NotEmpty(updated.Id)
|
||||
require.NotEqual(created.Id, updated.Id)
|
||||
}
|
||||
|
||||
var updatedMailboxId string
|
||||
{
|
||||
emails, notFound, _, _, _, err := s.client.GetEmails(accountId, []string{created.Id, updated.Id}, true, 0, false, false, ctx)
|
||||
result, err := s.client.GetEmails(accountId, []string{created.Id, updated.Id}, true, 0, false, false, ctx)
|
||||
require.NoError(err)
|
||||
require.Len(emails, 1)
|
||||
require.Len(notFound, 1)
|
||||
email := emails[0]
|
||||
require.Len(result.Payload.List, 1)
|
||||
require.Len(result.Payload.NotFound, 1)
|
||||
email := result.Payload.List[0]
|
||||
require.Equal(updated.Id, email.Id)
|
||||
require.Len(email.MailboxIds, 1)
|
||||
require.Contains(email.MailboxIds, mailboxPerRole[JmapMailboxRoleDrafts].Id)
|
||||
require.Equal(notFound[0], created.Id)
|
||||
require.Equal(result.Payload.NotFound[0], created.Id)
|
||||
var ok bool
|
||||
updatedMailboxId, ok = firstKey(email.MailboxIds)
|
||||
require.True(ok)
|
||||
@@ -249,24 +258,28 @@ func TestSendingEmails(t *testing.T) {
|
||||
ToMailboxId: mailboxPerRole[JmapMailboxRoleSent].Id,
|
||||
}
|
||||
|
||||
sub, _, _, _, err := s.client.SubmitEmail(accountId, identity.Id, updated.Id, &move, ctx)
|
||||
require.NoError(err)
|
||||
require.NotEmpty(sub.Id)
|
||||
require.NotEmpty(sub.ThreadId)
|
||||
require.Equal(updated.Id, sub.EmailId)
|
||||
require.Equal(identity.Id, sub.IdentityId)
|
||||
require.Equal(sub.UndoStatus, UndoStatusPending) // this *might* be fragile: if the server is fast enough, would we get "final" here?
|
||||
require.Empty(sub.DsnBlobIds)
|
||||
require.Empty(sub.MdnBlobIds)
|
||||
require.Equal(from.email, sub.Envelope.MailFrom.Email)
|
||||
require.Nil(sub.Envelope.MailFrom.Parameters)
|
||||
require.Len(sub.Envelope.RcptTo, 2)
|
||||
require.Contains(sub.Envelope.RcptTo, Address{Email: to.email})
|
||||
require.Contains(sub.Envelope.RcptTo, Address{Email: cc.email})
|
||||
require.NotZero(sub.SendAt)
|
||||
require.Len(sub.DeliveryStatus, 2)
|
||||
require.Contains(sub.DeliveryStatus, to.email)
|
||||
require.Contains(sub.DeliveryStatus, cc.email)
|
||||
var sub EmailSubmission
|
||||
{
|
||||
result, err := s.client.SubmitEmail(accountId, identity.Id, updated.Id, &move, ctx)
|
||||
require.NoError(err)
|
||||
sub = result.Payload
|
||||
require.NotEmpty(sub.Id)
|
||||
require.NotEmpty(sub.ThreadId)
|
||||
require.Equal(updated.Id, sub.EmailId)
|
||||
require.Equal(identity.Id, sub.IdentityId)
|
||||
require.Equal(sub.UndoStatus, UndoStatusPending) // this *might* be fragile: if the server is fast enough, would we get "final" here?
|
||||
require.Empty(sub.DsnBlobIds)
|
||||
require.Empty(sub.MdnBlobIds)
|
||||
require.Equal(from.email, sub.Envelope.MailFrom.Email)
|
||||
require.Nil(sub.Envelope.MailFrom.Parameters)
|
||||
require.Len(sub.Envelope.RcptTo, 2)
|
||||
require.Contains(sub.Envelope.RcptTo, Address{Email: to.email})
|
||||
require.Contains(sub.Envelope.RcptTo, Address{Email: cc.email})
|
||||
require.NotZero(sub.SendAt)
|
||||
require.Len(sub.DeliveryStatus, 2)
|
||||
require.Contains(sub.DeliveryStatus, to.email)
|
||||
require.Contains(sub.DeliveryStatus, cc.email)
|
||||
}
|
||||
|
||||
a := 0
|
||||
maxAttempts := 3
|
||||
@@ -280,10 +293,12 @@ func TestSendingEmails(t *testing.T) {
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
subs, notFound, _, _, _, err := s.client.GetEmailSubmissionStatus(accountId, []string{sub.Id}, ctx)
|
||||
result, err := s.client.GetEmailSubmissionStatus(accountId, []string{sub.Id}, ctx)
|
||||
require.NoError(err)
|
||||
require.Empty(notFound)
|
||||
require.Contains(subs, sub.Id)
|
||||
require.Empty(result.Payload.NotFound)
|
||||
submittedIds := structs.Map(result.Payload.List, func(s EmailSubmission) string { return s.Id })
|
||||
require.Contains(submittedIds, sub.Id)
|
||||
subs := structs.Index(result.Payload.List, func(s EmailSubmission) string { return s.Id })
|
||||
delivery = subs[sub.Id].DeliveryStatus[to.email].Delivered
|
||||
}
|
||||
|
||||
@@ -300,22 +315,24 @@ func TestSendingEmails(t *testing.T) {
|
||||
Logger: ctx.Logger,
|
||||
AcceptLanguage: ctx.AcceptLanguage,
|
||||
}
|
||||
mailboxes, _, _, _, err := s.client.GetAllMailboxes([]string{r.accountId}, rctx)
|
||||
require.NoError(err)
|
||||
inboxId := ""
|
||||
for _, mailbox := range mailboxes[r.accountId] {
|
||||
if mailbox.Role == JmapMailboxRoleInbox {
|
||||
inboxId = mailbox.Id
|
||||
require.Equal(1, mailbox.TotalEmails)
|
||||
{
|
||||
result, err := s.client.GetAllMailboxes([]string{r.accountId}, rctx)
|
||||
require.NoError(err)
|
||||
for _, mailbox := range result.Payload[r.accountId] {
|
||||
if mailbox.Role == JmapMailboxRoleInbox {
|
||||
inboxId = mailbox.Id
|
||||
require.Equal(1, mailbox.TotalEmails)
|
||||
}
|
||||
}
|
||||
require.NotEmpty(inboxId, "failed to find the Mailbox with the 'inbox' role for %v", r.user.name)
|
||||
}
|
||||
require.NotEmpty(inboxId, "failed to find the Mailbox with the 'inbox' role for %v", r.user.name)
|
||||
|
||||
emails, _, _, _, err := s.client.QueryEmails([]string{r.accountId}, EmailFilterCondition{InMailbox: inboxId}, 0, 0, true, 0, rctx)
|
||||
result, err := s.client.QueryEmails([]string{r.accountId}, EmailFilterCondition{InMailbox: inboxId}, 0, 0, true, 0, rctx)
|
||||
require.NoError(err)
|
||||
require.Contains(emails, r.accountId)
|
||||
require.Len(emails[r.accountId].Emails, 1)
|
||||
received := emails[r.accountId].Emails[0]
|
||||
require.Contains(result.Payload, r.accountId)
|
||||
require.Len(result.Payload[r.accountId].Emails, 1)
|
||||
received := result.Payload[r.accountId].Emails[0]
|
||||
require.Len(received.From, 1)
|
||||
require.Equal(from.email, received.From[0].Email)
|
||||
require.Equal(fromName, received.From[0].Name)
|
||||
@@ -370,12 +387,12 @@ func matchEmail(t *testing.T, actual Email, expected filledMail, hasBodies bool)
|
||||
|
||||
func (s *StalwartTest) findInbox(t *testing.T, accountId string, ctx Context) (string, string) {
|
||||
require := require.New(t)
|
||||
respByAccountId, sessionState, _, _, err := s.client.GetAllMailboxes([]string{accountId}, ctx)
|
||||
result, err := s.client.GetAllMailboxes([]string{accountId}, ctx)
|
||||
require.NoError(err)
|
||||
require.Equal(ctx.Session.State, sessionState)
|
||||
require.Len(respByAccountId, 1)
|
||||
require.Contains(respByAccountId, accountId)
|
||||
resp := respByAccountId[accountId]
|
||||
require.Equal(ctx.Session.State, result.GetSessionState())
|
||||
require.Len(result.Payload, 1)
|
||||
require.Contains(result.Payload, accountId)
|
||||
resp := result.Payload[accountId]
|
||||
|
||||
mailboxesNameByRole := map[string]string{}
|
||||
mailboxesUnreadByRole := map[string]int{}
|
||||
|
||||
@@ -91,28 +91,28 @@ func TestWs(t *testing.T) {
|
||||
|
||||
var initialState State
|
||||
{
|
||||
changes, sessionState, state, _, err := s.client.GetEmailChanges(mailAccountId, EmptyState, true, 0, 0, ctx)
|
||||
result, err := s.client.GetEmailChanges(mailAccountId, EmptyState, true, 0, 0, ctx)
|
||||
require.NoError(err)
|
||||
require.Equal(session.State, sessionState)
|
||||
require.NotEmpty(state)
|
||||
require.Equal(session.State, result.GetSessionState())
|
||||
require.NotEmpty(result.GetState())
|
||||
//fmt.Printf("\x1b[45;1;4mChanges [%s]:\x1b[0m\n", state)
|
||||
//for _, c := range changes.Created { fmt.Printf("%s %s\n", c.Id, c.Subject) }
|
||||
initialState = state
|
||||
require.Empty(changes.Created)
|
||||
require.Empty(changes.Destroyed)
|
||||
require.Empty(changes.Updated)
|
||||
initialState = result.GetState()
|
||||
require.Empty(result.Payload.Created)
|
||||
require.Empty(result.Payload.Destroyed)
|
||||
require.Empty(result.Payload.Updated)
|
||||
}
|
||||
require.NotEmpty(initialState)
|
||||
|
||||
{
|
||||
changes, sessionState, state, _, err := s.client.GetEmailChanges(mailAccountId, initialState, true, 0, 0, ctx)
|
||||
result, err := s.client.GetEmailChanges(mailAccountId, initialState, true, 0, 0, ctx)
|
||||
require.NoError(err)
|
||||
require.Equal(session.State, sessionState)
|
||||
require.Equal(initialState, state)
|
||||
require.Equal(initialState, changes.NewState)
|
||||
require.Empty(changes.Created)
|
||||
require.Empty(changes.Destroyed)
|
||||
require.Empty(changes.Updated)
|
||||
require.Equal(session.State, result.GetSessionState())
|
||||
require.Equal(initialState, result.GetState())
|
||||
require.Equal(initialState, result.Payload.NewState)
|
||||
require.Empty(result.Payload.Created)
|
||||
require.Empty(result.Payload.Destroyed)
|
||||
require.Empty(result.Payload.Updated)
|
||||
}
|
||||
|
||||
wsc, err := s.client.EnablePushNotifications(cotx, initialState, func() (*Session, error) { return session, nil })
|
||||
@@ -148,18 +148,18 @@ func TestWs(t *testing.T) {
|
||||
}
|
||||
var lastState State
|
||||
{
|
||||
changes, sessionState, state, _, err := s.client.GetEmailChanges(mailAccountId, initialState, true, 0, 0, ctx)
|
||||
result, err := s.client.GetEmailChanges(mailAccountId, initialState, true, 0, 0, ctx)
|
||||
require.NoError(err)
|
||||
require.Equal(session.State, sessionState)
|
||||
require.NotEqual(initialState, state)
|
||||
require.NotEqual(initialState, changes.NewState)
|
||||
require.Equal(state, changes.NewState)
|
||||
require.Len(changes.Created, 1)
|
||||
require.Empty(changes.Destroyed)
|
||||
require.Empty(changes.Updated)
|
||||
lastState = state
|
||||
require.Equal(session.State, result.GetSessionState())
|
||||
require.NotEqual(initialState, result.GetState())
|
||||
require.NotEqual(initialState, result.Payload.NewState)
|
||||
require.Equal(result.GetState(), result.Payload.NewState)
|
||||
require.Len(result.Payload.Created, 1)
|
||||
require.Empty(result.Payload.Destroyed)
|
||||
require.Empty(result.Payload.Updated)
|
||||
lastState = result.GetState()
|
||||
|
||||
emailIds = append(emailIds, structs.Map(changes.Created, func(e Email) string { return e.Id })...)
|
||||
emailIds = append(emailIds, structs.Map(result.Payload.Created, func(e Email) string { return e.Id })...)
|
||||
}
|
||||
|
||||
{
|
||||
@@ -182,18 +182,18 @@ func TestWs(t *testing.T) {
|
||||
l.m.Unlock()
|
||||
}
|
||||
{
|
||||
changes, sessionState, state, _, err := s.client.GetEmailChanges(mailAccountId, lastState, true, 0, 0, ctx)
|
||||
result, err := s.client.GetEmailChanges(mailAccountId, lastState, true, 0, 0, ctx)
|
||||
require.NoError(err)
|
||||
require.Equal(session.State, sessionState)
|
||||
require.NotEqual(lastState, state)
|
||||
require.NotEqual(lastState, changes.NewState)
|
||||
require.Equal(state, changes.NewState)
|
||||
require.Len(changes.Created, 1)
|
||||
require.Empty(changes.Destroyed)
|
||||
require.Empty(changes.Updated)
|
||||
lastState = state
|
||||
require.Equal(session.State, result.GetSessionState())
|
||||
require.NotEqual(lastState, result.GetState())
|
||||
require.NotEqual(lastState, result.Payload.NewState)
|
||||
require.Equal(result.GetState(), result.Payload.NewState)
|
||||
require.Len(result.Payload.Created, 1)
|
||||
require.Empty(result.Payload.Destroyed)
|
||||
require.Empty(result.Payload.Updated)
|
||||
lastState = result.GetState()
|
||||
|
||||
emailIds = append(emailIds, structs.Map(changes.Created, func(e Email) string { return e.Id })...)
|
||||
emailIds = append(emailIds, structs.Map(result.Payload.Created, func(e Email) string { return e.Id })...)
|
||||
}
|
||||
|
||||
{
|
||||
@@ -216,25 +216,25 @@ func TestWs(t *testing.T) {
|
||||
l.m.Unlock()
|
||||
}
|
||||
{
|
||||
changes, sessionState, state, _, err := s.client.GetEmailChanges(mailAccountId, lastState, true, 0, 0, ctx)
|
||||
result, err := s.client.GetEmailChanges(mailAccountId, lastState, true, 0, 0, ctx)
|
||||
require.NoError(err)
|
||||
require.Equal(session.State, sessionState)
|
||||
require.NotEqual(lastState, state)
|
||||
require.NotEqual(lastState, changes.NewState)
|
||||
require.Equal(state, changes.NewState)
|
||||
require.Empty(changes.Created)
|
||||
require.Len(changes.Destroyed, 2)
|
||||
require.Equal(session.State, result.GetSessionState())
|
||||
require.NotEqual(lastState, result.GetState())
|
||||
require.NotEqual(lastState, result.Payload.NewState)
|
||||
require.Equal(result.GetState(), result.Payload.NewState)
|
||||
require.Empty(result.Payload.Created)
|
||||
require.Len(result.Payload.Destroyed, 2)
|
||||
{
|
||||
a := make([]string, len(emailIds))
|
||||
copy(a, emailIds)
|
||||
slices.Sort(emailIds)
|
||||
b := make([]string, len(changes.Destroyed))
|
||||
copy(b, changes.Destroyed)
|
||||
b := make([]string, len(result.Payload.Destroyed))
|
||||
copy(b, result.Payload.Destroyed)
|
||||
slices.Sort(b)
|
||||
require.EqualValues(a, b)
|
||||
}
|
||||
require.Empty(changes.Updated)
|
||||
lastState = state
|
||||
require.Empty(result.Payload.Updated)
|
||||
lastState = result.GetState()
|
||||
}
|
||||
|
||||
err = wsc.DisableNotifications()
|
||||
|
||||
@@ -55,6 +55,12 @@ type Session struct {
|
||||
SessionResponse
|
||||
}
|
||||
|
||||
var _ ResultMetadata = Session{}
|
||||
|
||||
func (s Session) GetSessionState() SessionState { return s.State }
|
||||
func (s Session) GetState() State { return EmptyState }
|
||||
func (s Session) GetLanguage() Language { return NoLanguage }
|
||||
|
||||
var (
|
||||
invalidSessionResponseErrorMissingUsername = jmapError(errors.New("JMAP session response does not provide a username"), JmapErrorInvalidSessionResponse)
|
||||
invalidSessionResponseErrorMissingApiUrl = jmapError(errors.New("JMAP session response does not provide an API URL"), JmapErrorInvalidSessionResponse)
|
||||
|
||||
@@ -13,21 +13,20 @@ func get[T Foo, GETREQ GetCommand[T], GETRESP GetResponse[T], RESP any]( //NOSON
|
||||
getCommandFactory func(string, []string) GETREQ,
|
||||
_ GETRESP,
|
||||
mapper func(GETRESP) RESP,
|
||||
accountId string, ids []string, ctx Context) (RESP, SessionState, State, Language, Error) {
|
||||
accountId string, ids []string, ctx Context) (Result[RESP], Error) {
|
||||
ctx = ctx.WithLogger(client.logger(name, ctx))
|
||||
|
||||
var zero RESP
|
||||
|
||||
get := getCommandFactory(accountId, ids)
|
||||
cmd, err := client.request(ctx, objType.Namespaces, invocation(get, "0"))
|
||||
if err != nil {
|
||||
return zero, "", "", "", err
|
||||
return ZeroResult[RESP](), err
|
||||
}
|
||||
|
||||
return command(client, ctx, cmd, func(body *Response) (RESP, State, Error) {
|
||||
var response GETRESP
|
||||
err = retrieveGet(ctx, body, get, "0", &response)
|
||||
if err != nil {
|
||||
var zero RESP
|
||||
return zero, "", err
|
||||
}
|
||||
|
||||
@@ -40,7 +39,7 @@ func getAN[T Foo, GETREQ GetCommand[T], GETRESP GetResponse[T], RESP any]( //NOS
|
||||
getCommandFactory func(string, []string) GETREQ,
|
||||
resp GETRESP,
|
||||
respMapper func(map[string][]T) RESP,
|
||||
accountIds []string, ids []string, ctx Context) (RESP, SessionState, State, Language, Error) {
|
||||
accountIds []string, ids []string, ctx Context) (Result[RESP], Error) {
|
||||
return getN(client, name, objType, getCommandFactory, resp,
|
||||
func(r GETRESP) []T { return r.GetList() },
|
||||
respMapper,
|
||||
@@ -55,12 +54,10 @@ func getN[T Foo, ITEM any, GETREQ GetCommand[T], GETRESP GetResponse[T], RESP an
|
||||
_ GETRESP,
|
||||
itemMapper func(GETRESP) ITEM,
|
||||
respMapper func(map[string]ITEM) RESP,
|
||||
accountIds []string, ids []string, ctx Context) (RESP, SessionState, State, Language, Error) {
|
||||
accountIds []string, ids []string, ctx Context) (Result[RESP], Error) {
|
||||
logger := client.logger(name, ctx)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
var zero RESP
|
||||
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
|
||||
invocations := make([]Invocation, len(uniqueAccountIds))
|
||||
@@ -73,7 +70,7 @@ func getN[T Foo, ITEM any, GETREQ GetCommand[T], GETRESP GetResponse[T], RESP an
|
||||
|
||||
cmd, err := client.request(ctx, objType.Namespaces, invocations...)
|
||||
if err != nil {
|
||||
return zero, "", "", "", err
|
||||
return ZeroResult[RESP](), err
|
||||
}
|
||||
|
||||
return command(client, ctx, cmd, func(body *Response) (RESP, State, Error) {
|
||||
@@ -83,6 +80,7 @@ func getN[T Foo, ITEM any, GETREQ GetCommand[T], GETRESP GetResponse[T], RESP an
|
||||
var resp GETRESP
|
||||
err = retrieveResponseMatchParameters(ctx, body, c, mcid(accountId, "0"), &resp)
|
||||
if err != nil {
|
||||
var zero RESP
|
||||
return zero, "", err
|
||||
}
|
||||
responses[accountId] = resp
|
||||
@@ -99,7 +97,7 @@ func create[T Foo, C any, SETREQ SetCommand[T], GETREQ GetCommand[T], SETRESP Se
|
||||
createdMapper func(SETRESP) map[string]*T,
|
||||
listMapper func(GETRESP) []T,
|
||||
accountId string, create C,
|
||||
ctx Context) (*T, SessionState, State, Language, Error) {
|
||||
ctx Context) (Result[*T], Error) {
|
||||
logger := client.logger(name, ctx)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
@@ -111,7 +109,7 @@ func create[T Foo, C any, SETREQ SetCommand[T], GETREQ GetCommand[T], SETRESP Se
|
||||
invocation(get, "1"),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
return ZeroResult[*T](), err
|
||||
}
|
||||
|
||||
return command(client, ctx, cmd, func(body *Response) (*T, State, Error) {
|
||||
@@ -155,7 +153,7 @@ 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) (map[string]SetError, SessionState, State, Language, Error) {
|
||||
accountId string, destroy []string, ctx Context) (Result[map[string]SetError], Error) {
|
||||
logger := client.logger(name, ctx)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
@@ -164,7 +162,7 @@ func destroy[T Foo, REQ SetCommand[T], RESP SetResponse[T]](client *Client, name
|
||||
invocation(set, "0"),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
return ZeroResult[map[string]SetError](), err
|
||||
}
|
||||
|
||||
return command(client, ctx, cmd, func(body *Response) (map[string]SetError, State, Error) {
|
||||
@@ -184,8 +182,7 @@ func changesA[T Foo, CHANGESREQ ChangesCommand[T], GETREQ GetCommand[T], CHANGES
|
||||
_ GETRESP,
|
||||
getCommandFactory func(string, string) GETREQ,
|
||||
respMapper func(State, State, bool, []T, []T, []string) RESP,
|
||||
ctx Context) (RESP, SessionState, State, Language, Error) {
|
||||
|
||||
ctx Context) (Result[RESP], Error) {
|
||||
return changes(client, name, objType, changesCommandFactory, changesResp, getCommandFactory,
|
||||
func(r GETRESP) []T { return r.GetList() },
|
||||
respMapper,
|
||||
@@ -200,9 +197,8 @@ func changes[T Foo, CHANGESREQ ChangesCommand[T], GETREQ GetCommand[T], CHANGESR
|
||||
getCommandFactory func(string, string) GETREQ,
|
||||
getMapper func(GETRESP) []ITEM,
|
||||
respMapper func(State, State, bool, []ITEM, []ITEM, []string) RESP,
|
||||
ctx Context) (RESP, SessionState, State, Language, Error) {
|
||||
ctx Context) (Result[RESP], Error) {
|
||||
logger := client.logger(name, ctx)
|
||||
var zero RESP
|
||||
|
||||
changes := changesCommandFactory()
|
||||
getCreated := getCommandFactory("/created", "0") //NOSONAR
|
||||
@@ -214,13 +210,14 @@ func changes[T Foo, CHANGESREQ ChangesCommand[T], GETREQ GetCommand[T], CHANGESR
|
||||
invocation(getUpdated, "2"),
|
||||
)
|
||||
if err != nil {
|
||||
return zero, "", "", "", err
|
||||
return ZeroResult[RESP](), err
|
||||
}
|
||||
|
||||
return command(client, ctx, cmd, func(body *Response) (RESP, State, Error) {
|
||||
var changesResponse CHANGESRESP
|
||||
err = retrieveChanges(ctx, body, changes, "0", &changesResponse)
|
||||
if err != nil {
|
||||
var zero RESP
|
||||
return zero, "", err
|
||||
}
|
||||
|
||||
@@ -228,6 +225,7 @@ func changes[T Foo, CHANGESREQ ChangesCommand[T], GETREQ GetCommand[T], CHANGESR
|
||||
err = retrieveGet(ctx, body, getCreated, "1", &createdResponse)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Send()
|
||||
var zero RESP
|
||||
return zero, "", err
|
||||
}
|
||||
|
||||
@@ -235,6 +233,7 @@ func changes[T Foo, CHANGESREQ ChangesCommand[T], GETREQ GetCommand[T], CHANGESR
|
||||
err = retrieveGet(ctx, body, getUpdated, "2", &updatedResponse)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Send()
|
||||
var zero RESP
|
||||
return zero, "", err
|
||||
}
|
||||
|
||||
@@ -257,7 +256,7 @@ func changesN[T Foo, CHANGESREQ ChangesCommand[T], GETREQ GetCommand[T], CHANGES
|
||||
changesItemMapper func(State, State, bool, []ITEM, []ITEM, []string) CHANGESITEM,
|
||||
respMapper func(map[string]CHANGESITEM) RESP,
|
||||
stateMapper func(GETRESP) State,
|
||||
ctx Context) (RESP, SessionState, State, Language, Error) {
|
||||
ctx Context) (Result[RESP], Error) {
|
||||
logger := client.loggerParams(name, ctx, func(z zerolog.Context) zerolog.Context {
|
||||
sinceStateLogDict := zerolog.Dict()
|
||||
for k, v := range sinceStateMap {
|
||||
@@ -266,12 +265,10 @@ func changesN[T Foo, CHANGESREQ ChangesCommand[T], GETREQ GetCommand[T], CHANGES
|
||||
return z.Dict(logSinceState, sinceStateLogDict)
|
||||
})
|
||||
|
||||
var zero RESP
|
||||
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
n := len(uniqueAccountIds)
|
||||
if n < 1 {
|
||||
return zero, "", "", "", nil
|
||||
return ZeroResult[RESP](), nil
|
||||
}
|
||||
|
||||
invocations := make([]Invocation, n*3)
|
||||
@@ -302,7 +299,7 @@ func changesN[T Foo, CHANGESREQ ChangesCommand[T], GETREQ GetCommand[T], CHANGES
|
||||
|
||||
cmd, err := client.request(ctx, objType.Namespaces, invocations...)
|
||||
if err != nil {
|
||||
return zero, "", "", "", err
|
||||
return ZeroResult[RESP](), err
|
||||
}
|
||||
|
||||
return command(client, ctx, cmd, func(body *Response) (RESP, State, Error) {
|
||||
@@ -312,18 +309,21 @@ func changesN[T Foo, CHANGESREQ ChangesCommand[T], GETREQ GetCommand[T], CHANGES
|
||||
var changesResponse CHANGESRESP
|
||||
err = retrieveChanges(ctx, body, ch, mcid(accountId, "0"), &changesResponse)
|
||||
if err != nil {
|
||||
var zero RESP
|
||||
return zero, "", err
|
||||
}
|
||||
|
||||
var createdResponse GETRESP
|
||||
err = retrieveGet(ctx, body, gc, mcid(accountId, "1"), &createdResponse)
|
||||
if err != nil {
|
||||
var zero RESP
|
||||
return zero, "", err
|
||||
}
|
||||
|
||||
var updatedResponse GETRESP
|
||||
err = retrieveGet(ctx, body, gu, mcid(accountId, "2"), &updatedResponse)
|
||||
if err != nil {
|
||||
var zero RESP
|
||||
return zero, "", err
|
||||
}
|
||||
|
||||
@@ -343,10 +343,9 @@ func updates[T Foo, CHANGESREQ ChangesCommand[T], GETREQ GetCommand[T], CHANGESR
|
||||
getCommandFactory func(string, string) GETREQ,
|
||||
getMapper func(GETRESP) []ITEM,
|
||||
respMapper func(State, State, bool, []ITEM) RESP,
|
||||
ctx Context) (RESP, SessionState, State, Language, Error) {
|
||||
ctx Context) (Result[RESP], Error) {
|
||||
logger := client.logger(name, ctx)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
var zero RESP
|
||||
|
||||
changes := changesCommandFactory()
|
||||
getUpdated := getCommandFactory("/updated", "0") //NOSONAR
|
||||
@@ -355,13 +354,14 @@ func updates[T Foo, CHANGESREQ ChangesCommand[T], GETREQ GetCommand[T], CHANGESR
|
||||
invocation(getUpdated, "1"),
|
||||
)
|
||||
if err != nil {
|
||||
return zero, "", "", "", err
|
||||
return ZeroResult[RESP](), err
|
||||
}
|
||||
|
||||
return command(client, ctx, cmd, func(body *Response) (RESP, State, Error) {
|
||||
var changesResponse CHANGESRESP
|
||||
err = retrieveChanges(ctx, body, changes, "0", &changesResponse)
|
||||
if err != nil {
|
||||
var zero RESP
|
||||
return zero, "", err
|
||||
}
|
||||
|
||||
@@ -369,6 +369,7 @@ func updates[T Foo, CHANGESREQ ChangesCommand[T], GETREQ GetCommand[T], CHANGESR
|
||||
err = retrieveGet(ctx, body, getUpdated, "1", &updatedResponse)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Send()
|
||||
var zero RESP
|
||||
return zero, "", err
|
||||
}
|
||||
|
||||
@@ -386,41 +387,42 @@ func update[T Foo, CHANGES Change, SET SetCommand[T], GET GetCommand[T], RESP an
|
||||
notUpdatedExtractor func(SETRESP) map[string]SetError,
|
||||
objExtractor func(GETRESP) RESP,
|
||||
id string, changes CHANGES,
|
||||
ctx Context) (RESP, SessionState, State, Language, Error) {
|
||||
ctx Context) (Result[RESP], Error) {
|
||||
logger := client.logger(name, ctx)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
var zero RESP
|
||||
|
||||
var update SET
|
||||
{
|
||||
patch, err := changes.AsPatch()
|
||||
if err != nil {
|
||||
return zero, "", "", "", jmapError(err, JmapPatchObjectSerialization)
|
||||
return ZeroResult[RESP](), jmapError(err, JmapErrorPatchObjectSerialization)
|
||||
}
|
||||
update = setCommandFactory(map[string]PatchObject{id: patch})
|
||||
}
|
||||
get := getCommandFactory(id)
|
||||
cmd, err := client.request(ctx, objType.Namespaces, invocation(update, "0"), invocation(get, "1"))
|
||||
if err != nil {
|
||||
return zero, "", "", "", err
|
||||
return ZeroResult[RESP](), err
|
||||
}
|
||||
|
||||
return command(client, ctx, cmd, func(body *Response) (RESP, State, Error) {
|
||||
var setResponse SETRESP
|
||||
err = retrieveSet(ctx, body, update, "0", &setResponse)
|
||||
if err != nil {
|
||||
var zero RESP
|
||||
return zero, setResponse.GetNewState(), err
|
||||
}
|
||||
nc := notUpdatedExtractor(setResponse)
|
||||
setErr, notok := nc[id]
|
||||
if notok {
|
||||
logger.Error().Msgf("%T.NotUpdated returned an error %v", setResponse, setErr)
|
||||
var zero RESP
|
||||
return zero, "", setErrorError(setErr, update.GetObjectType())
|
||||
}
|
||||
var getResponse GETRESP
|
||||
err = retrieveGet(ctx, body, get, "1", &getResponse)
|
||||
if err != nil {
|
||||
var zero RESP
|
||||
return zero, setResponse.GetNewState(), err
|
||||
}
|
||||
return objExtractor(getResponse), setResponse.GetNewState(), nil
|
||||
@@ -434,7 +436,7 @@ func query[T Foo, FILTER any, SORT any, QUERY QueryCommand[T], GET GetCommand[T]
|
||||
getCommandFactory func(cmd Command, path string, rof string) GET,
|
||||
respMapper func(query QUERYRESP, get GETRESP) *RESP,
|
||||
filter FILTER, sortBy []SORT, position int, anchor string, anchorOffset *int, limit *uint,
|
||||
ctx Context) (*RESP, SessionState, State, Language, Error) {
|
||||
ctx Context) (Result[*RESP], Error) {
|
||||
|
||||
logger := client.logger(name, ctx)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
@@ -448,7 +450,7 @@ func query[T Foo, FILTER any, SORT any, QUERY QueryCommand[T], GET GetCommand[T]
|
||||
|
||||
cmd, err := client.request(ctx, objType.Namespaces, invocation(query, "0"), invocation(get, "1"))
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
return ZeroResult[*RESP](), err
|
||||
}
|
||||
|
||||
return command(client, ctx, cmd, func(body *Response) (*RESP, State, Error) {
|
||||
@@ -474,7 +476,7 @@ func queryN[T Foo, FILTER any, SORT any, QUERY QueryCommand[T], GET GetCommand[T
|
||||
respMapper func(query QUERYRESP, get GETRESP) *RESP,
|
||||
accountIds []string,
|
||||
filter FILTER, sortBy []SORT, position int, anchor string, anchorOffset *int, limit *uint,
|
||||
ctx Context) (map[string]*RESP, SessionState, State, Language, Error) {
|
||||
ctx Context) (Result[map[string]*RESP], Error) {
|
||||
logger := client.logger(name, ctx)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
@@ -498,7 +500,7 @@ func queryN[T Foo, FILTER any, SORT any, QUERY QueryCommand[T], GET GetCommand[T
|
||||
|
||||
cmd, err := client.request(ctx, objType.Namespaces, invocations...)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
return ZeroResult[map[string]*RESP](), err
|
||||
}
|
||||
|
||||
return command(client, ctx, cmd, func(body *Response) (map[string]*RESP, State, Error) {
|
||||
|
||||
@@ -50,11 +50,6 @@ func mcid(accountId string, tag string) string {
|
||||
return accountId + ":" + tag
|
||||
}
|
||||
|
||||
func bail[R JmapResponse[T], T Foo](err Error) (R, SessionState, State, Language, Error) {
|
||||
var zero R
|
||||
return zero, EmptySessionState, EmptyState, NoLanguage, err
|
||||
}
|
||||
|
||||
type Cmdr interface {
|
||||
ApiSupplier
|
||||
Hooks
|
||||
@@ -63,22 +58,22 @@ type Cmdr interface {
|
||||
func command[T any](client Cmdr, //NOSONAR
|
||||
ctx Context,
|
||||
request Request,
|
||||
mapper func(body *Response) (T, State, Error)) (T, SessionState, State, Language, Error) {
|
||||
mapper func(body *Response) (T, State, Error)) (Result[T], Error) {
|
||||
|
||||
logger := ctx.Logger
|
||||
|
||||
responseBody, language, jmapErr := client.Api().Command(request, ctx)
|
||||
if jmapErr != nil {
|
||||
var zero T
|
||||
return zero, "", "", language, jmapErr
|
||||
var zero Result[T]
|
||||
return zero, jmapErr
|
||||
}
|
||||
|
||||
var response Response
|
||||
err := json.Unmarshal(responseBody, &response)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msgf("failed to deserialize body JSON payload into a %T", response)
|
||||
var zero T
|
||||
return zero, "", "", language, jmapError(err, JmapErrorDecodingResponseBody)
|
||||
var zero Result[T]
|
||||
return zero, jmapError(err, JmapErrorDecodingResponseBody)
|
||||
}
|
||||
|
||||
if response.SessionState != ctx.Session.State {
|
||||
@@ -102,7 +97,7 @@ func command[T any](client Cmdr, //NOSONAR
|
||||
case MethodLevelErrorInvalidArguments:
|
||||
code = JmapErrorInvalidArguments
|
||||
if strings.HasPrefix(errorParameters.Description, "invalid JMAP State") {
|
||||
code = JmapInvalidObjectState
|
||||
code = JmapErrorInvalidObjectState
|
||||
}
|
||||
case MethodLevelErrorInvalidResultReference:
|
||||
code = JmapErrorInvalidResultReference
|
||||
@@ -126,22 +121,20 @@ func command[T any](client Cmdr, //NOSONAR
|
||||
msg := fmt.Sprintf("found method level error in response '%v', type: '%v', description: '%v'", mr.Tag, errorParameters.Type, errorParameters.Description)
|
||||
err = errors.New(msg)
|
||||
logger.Warn().Int("code", code).Str("type", errorParameters.Type).Msg(msg)
|
||||
var zero T
|
||||
return zero, response.SessionState, "", language, jmapResponseError(code, err, errorParameters.Type, errorParameters.Description)
|
||||
return newPartialResult[T](response.SessionState, language), jmapResponseError(code, err, errorParameters.Type, errorParameters.Description)
|
||||
} else {
|
||||
code := JmapErrorUnspecifiedType
|
||||
msg := fmt.Sprintf("found method level error in response '%v'", mr.Tag)
|
||||
err := errors.New(msg)
|
||||
logger.Warn().Int("code", code).Msg(msg)
|
||||
var zero T
|
||||
return zero, response.SessionState, "", language, jmapResponseError(code, err, errorParameters.Type, errorParameters.Description)
|
||||
return newPartialResult[T](response.SessionState, language), jmapResponseError(code, err, errorParameters.Type, errorParameters.Description)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result, state, jerr := mapper(&response)
|
||||
sessionState := response.SessionState
|
||||
return result, sessionState, state, language, jerr
|
||||
return newResult(result, sessionState, state, language), jerr
|
||||
}
|
||||
|
||||
func mapstructStringToTimeHook() mapstructure.DecodeHookFunc {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@redocly/cli": "^2.30.1",
|
||||
"@redocly/cli": "^2.30.2",
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"cheerio": "^1.2.0",
|
||||
"js-yaml": "^4.1.1",
|
||||
|
||||
@@ -17,7 +17,7 @@ func (g *Groupware) GetAccountById(w http.ResponseWriter, r *http.Request) {
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
var body jmap.Account = account
|
||||
return req.respond(accountId, body, req.session.State, AccountResponseObjectType, jmap.EmptyState, jmap.NoLanguage)
|
||||
return req.respond(accountId, body, AccountResponseObjectType, req.session)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ func (g *Groupware) GetAccounts(w http.ResponseWriter, r *http.Request) {
|
||||
// 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) })
|
||||
var RBODY []AccountWithId = list
|
||||
return req.respondN(structs.Map(list, func(a AccountWithId) string { return a.AccountId }), RBODY, req.session.State, AccountResponseObjectType, jmap.EmptyState, jmap.NoLanguage)
|
||||
return req.respondN(structs.Map(list, func(a AccountWithId) string { return a.AccountId }), RBODY, AccountResponseObjectType, req.session)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -44,14 +44,14 @@ func (g *Groupware) GetAccounts(w http.ResponseWriter, r *http.Request) {
|
||||
func (g *Groupware) GetAccountsWithTheirIdentities(w http.ResponseWriter, r *http.Request) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
allAccountIds := req.AllAccountIds()
|
||||
resp, sessionState, state, lang, err := g.jmap.GetIdentitiesForAllAccounts(allAccountIds, req.ctx)
|
||||
resp, err := g.jmap.GetIdentitiesForAllAccounts(allAccountIds, req.ctx)
|
||||
if err != nil {
|
||||
return req.jmapErrorN(allAccountIds, err, sessionState, lang)
|
||||
return req.jmapErrorN(allAccountIds, err, resp)
|
||||
}
|
||||
list := make([]AccountWithIdAndIdentities, len(req.session.Accounts))
|
||||
i := 0
|
||||
for accountId, account := range req.session.Accounts {
|
||||
identities, ok := resp[accountId]
|
||||
identities, ok := resp.Payload[accountId]
|
||||
if !ok {
|
||||
identities = []jmap.Identity{}
|
||||
}
|
||||
@@ -66,7 +66,7 @@ func (g *Groupware) GetAccountsWithTheirIdentities(w http.ResponseWriter, r *htt
|
||||
// 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) })
|
||||
var RBODY []AccountWithIdAndIdentities = list
|
||||
return req.respondN(structs.Map(list, func(a AccountWithIdAndIdentities) string { return a.AccountId }), RBODY, sessionState, AccountResponseObjectType, state, lang)
|
||||
return req.respondN(structs.Map(list, func(a AccountWithIdAndIdentities) string { return a.AccountId }), RBODY, AccountResponseObjectType, resp)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -36,9 +36,9 @@ func (g *Groupware) UploadBlob(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
logger := log.From(req.logger.With().Str(logAccountId, accountId))
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
resp, lang, jerr := g.jmap.UploadBlobStream(accountId, contentType, body, ctx)
|
||||
resp, _, jerr := g.jmap.UploadBlobStream(accountId, contentType, body, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, req.session.State, lang)
|
||||
return req.jmapError(accountId, jerr, req.session)
|
||||
}
|
||||
|
||||
return req.respondWithoutStatus(accountId, resp)
|
||||
|
||||
@@ -78,12 +78,12 @@ func (g *Groupware) GetChanges(w http.ResponseWriter, r *http.Request) { //NOSON
|
||||
|
||||
logger := log.From(l)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
changes, sessionState, state, lang, jerr := g.jmap.GetChanges(accountId, sinceState, maxChanges, ctx)
|
||||
result, jerr := g.jmap.GetChanges(accountId, sinceState, maxChanges, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
return req.jmapError(accountId, jerr, result)
|
||||
}
|
||||
var body jmap.ObjectChanges = changes
|
||||
var body jmap.ObjectChanges = result.Payload
|
||||
|
||||
return req.respond(accountId, body, sessionState, "", state, lang)
|
||||
return req.respond(accountId, body, UnspecifiedResponseObjectType, result)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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.EmailChanges, jmap.SessionState, jmap.State, jmap.Language, jmap.Error) {
|
||||
changes(Email, w, r, g, func(accountId string, sinceState jmap.State, maxChanges uint, ctx jmap.Context) (jmap.Result[jmap.EmailChanges], jmap.Error) {
|
||||
return g.jmap.GetEmailChanges(accountId, sinceState, true, g.config.maxBodyValueBytes, maxChanges, ctx)
|
||||
})
|
||||
}
|
||||
@@ -42,25 +42,26 @@ 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, containerId string, position int, anchor string, anchorOffset *int, limit *uint, ctx jmap.Context) (*jmap.EmailSearchResults, jmap.SessionState, jmap.State, jmap.Language, *Error) { //NOSONAR
|
||||
emails, sessionState, state, lang, jerr := g.jmap.GetAllEmailsInMailbox(accountId, containerId, position, anchor, anchorOffset, limit, collapseThreads, fetchBodies, g.config.maxBodyValueBytes, withThreads, ctx)
|
||||
func(req Request, accountId, containerId string, position int, anchor string, anchorOffset *int, limit *uint, ctx jmap.Context) (jmap.Result[*jmap.EmailSearchResults], *Error) { //NOSONAR
|
||||
result, jerr := g.jmap.GetAllEmailsInMailbox(accountId, containerId, position, anchor, anchorOffset, limit, collapseThreads, fetchBodies, g.config.maxBodyValueBytes, withThreads, ctx)
|
||||
if jerr != nil {
|
||||
return emails, sessionState, state, lang, req.apiErrorFromJmap(req.observeJmapError(jerr))
|
||||
return jmap.ZeroResult[*jmap.EmailSearchResults](), req.apiErrorFromJmap(req.observeJmapError(jerr))
|
||||
}
|
||||
|
||||
sanitized, err := req.sanitizeEmails(emails.Results)
|
||||
sanitized, err := req.sanitizeEmails(result.Payload.Results)
|
||||
if err != nil {
|
||||
return emails, sessionState, state, lang, err
|
||||
return jmap.ZeroResult[*jmap.EmailSearchResults](), err
|
||||
}
|
||||
|
||||
safe := &jmap.EmailSearchResults{
|
||||
Results: sanitized,
|
||||
Total: emails.Total,
|
||||
Limit: emails.Limit,
|
||||
Position: emails.Position,
|
||||
CanCalculateChanges: emails.CanCalculateChanges,
|
||||
}
|
||||
return safe, sessionState, state, lang, nil
|
||||
return jmap.RefineResult(result, func(orig *jmap.EmailSearchResults) *jmap.EmailSearchResults {
|
||||
return &jmap.EmailSearchResults{
|
||||
Results: sanitized,
|
||||
Total: orig.Total,
|
||||
Limit: orig.Limit,
|
||||
Position: orig.Position,
|
||||
CanCalculateChanges: orig.CanCalculateChanges,
|
||||
}
|
||||
}), nil
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -93,20 +94,20 @@ func (g *Groupware) GetEmailsById(w http.ResponseWriter, r *http.Request) { //NO
|
||||
|
||||
logger := log.From(req.logger.With().Str(logAccountId, log.SafeString(accountId)).Str("id", log.SafeString(id)).Str("accept", log.SafeString(accept)))
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
blobId, _, _, _, jerr := g.jmap.GetEmailBlobId(accountId, id, ctx)
|
||||
result, jerr := g.jmap.GetEmailBlobId(accountId, id, ctx)
|
||||
if jerr != nil {
|
||||
return req.apiErrorFromJmap(req.observeJmapError(jerr))
|
||||
}
|
||||
if blobId == "" {
|
||||
if result.Payload == "" {
|
||||
return nil
|
||||
} else {
|
||||
name := blobId + ".eml"
|
||||
name := result.Payload + ".eml"
|
||||
typ := accept
|
||||
accountId, gwerr := req.GetAccountIdForBlob()
|
||||
if gwerr != nil {
|
||||
return gwerr
|
||||
}
|
||||
return req.serveBlob(blobId, name, typ, ctx, accountId, w)
|
||||
return req.serveBlob(result.Payload, name, typ, ctx, accountId, w)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
@@ -137,34 +138,34 @@ func (g *Groupware) GetEmailsById(w http.ResponseWriter, r *http.Request) { //NO
|
||||
if len(ids) == 1 {
|
||||
logger := log.From(l.Str(UriParamEmailId, log.SafeString(id)))
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
emails, _, sessionState, state, lang, jerr := g.jmap.GetEmails(accountId, ids, true, g.config.maxBodyValueBytes, markAsSeen, true, ctx)
|
||||
result, jerr := g.jmap.GetEmails(accountId, ids, true, g.config.maxBodyValueBytes, markAsSeen, true, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
return req.jmapError(accountId, jerr, result)
|
||||
}
|
||||
if len(emails) < 1 {
|
||||
return req.notFound(accountId, sessionState, EmailResponseObjectType, state)
|
||||
if len(result.Payload.List) < 1 {
|
||||
return req.notFound(accountId, EmailResponseObjectType, result)
|
||||
} else {
|
||||
sanitized, err := req.sanitizeEmail(emails[0])
|
||||
sanitized, err := req.sanitizeEmail(result.Payload.List[0])
|
||||
if err != nil {
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
return req.respond(accountId, sanitized, sessionState, EmailResponseObjectType, state, lang)
|
||||
return req.respond(accountId, sanitized, EmailResponseObjectType, result)
|
||||
}
|
||||
} else {
|
||||
logger := log.From(l.Array(UriParamEmailId, log.SafeStringArray(ids)))
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
emails, _, sessionState, state, lang, jerr := g.jmap.GetEmails(accountId, ids, true, g.config.maxBodyValueBytes, markAsSeen, false, ctx)
|
||||
result, jerr := g.jmap.GetEmails(accountId, ids, true, g.config.maxBodyValueBytes, markAsSeen, false, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
return req.jmapError(accountId, jerr, result)
|
||||
}
|
||||
if len(emails) < 1 {
|
||||
return req.notFound(accountId, sessionState, EmailResponseObjectType, state)
|
||||
if len(result.Payload.List) < 1 {
|
||||
return req.notFound(accountId, EmailResponseObjectType, result)
|
||||
} else {
|
||||
sanitized, err := req.sanitizeEmails(emails)
|
||||
sanitized, err := req.sanitizeEmails(result.Payload.List)
|
||||
if err != nil {
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
return req.respond(accountId, sanitized, sessionState, EmailResponseObjectType, state, lang)
|
||||
return req.respond(accountId, sanitized, EmailResponseObjectType, result)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -211,19 +212,19 @@ func (g *Groupware) GetEmailAttachments(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
logger := log.From(l)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
emails, _, sessionState, state, lang, jerr := g.jmap.GetEmails(accountId, single(id), false, 0, false, false, ctx)
|
||||
result, jerr := g.jmap.GetEmails(accountId, single(id), false, 0, false, false, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
return req.jmapError(accountId, jerr, result)
|
||||
}
|
||||
if len(emails) < 1 {
|
||||
return req.notFound(accountId, sessionState, EmailResponseObjectType, state)
|
||||
if len(result.Payload.List) < 1 {
|
||||
return req.notFound(accountId, EmailResponseObjectType, result)
|
||||
}
|
||||
email, err := req.sanitizeEmail(emails[0])
|
||||
email, err := req.sanitizeEmail(result.Payload.List[0])
|
||||
if err != nil {
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
var body []jmap.EmailBodyPart = email.Attachments
|
||||
return req.respond(accountId, body, sessionState, EmailResponseObjectType, state, lang)
|
||||
return req.respond(accountId, body, EmailResponseObjectType, result)
|
||||
})
|
||||
} else {
|
||||
g.stream(w, r, func(req Request, w http.ResponseWriter) *Error {
|
||||
@@ -248,15 +249,15 @@ func (g *Groupware) GetEmailAttachments(w http.ResponseWriter, r *http.Request)
|
||||
l = contextAppender(l)
|
||||
logger := log.From(l)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
emails, _, _, _, lang, jerr := g.jmap.GetEmails(mailAccountId, single(id), false, 0, false, false, ctx)
|
||||
result, jerr := g.jmap.GetEmails(mailAccountId, single(id), false, 0, false, false, ctx)
|
||||
if jerr != nil {
|
||||
return req.apiErrorFromJmap(req.observeJmapError(jerr))
|
||||
}
|
||||
if len(emails) < 1 {
|
||||
if len(result.Payload.List) < 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
email, err := req.sanitizeEmail(emails[0])
|
||||
email, err := req.sanitizeEmail(result.Payload.List[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -333,12 +334,12 @@ func (g *Groupware) getEmailsSince(w http.ResponseWriter, r *http.Request, since
|
||||
|
||||
logger := log.From(l)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
changes, sessionState, state, lang, jerr := g.jmap.GetEmailChanges(accountId, since, true, g.config.maxBodyValueBytes, maxChanges, ctx)
|
||||
result, jerr := g.jmap.GetEmailChanges(accountId, since, true, g.config.maxBodyValueBytes, maxChanges, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
return req.jmapError(accountId, jerr, result)
|
||||
}
|
||||
|
||||
return req.respond(accountId, changes, sessionState, EmailResponseObjectType, state, lang)
|
||||
return req.respond(accountId, result.Payload, EmailResponseObjectType, result)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -583,12 +584,12 @@ func (g *Groupware) GetEmails(w http.ResponseWriter, r *http.Request) { //NOSONA
|
||||
jmaplimit = UintPtrOne
|
||||
}
|
||||
|
||||
resultsByAccount, sessionState, state, lang, jerr := g.jmap.QueryEmailsWithSnippets(single(accountId), filter, position, anchor, anchorOffset, jmaplimit, collapseThreads, calculateTotal, fetchBodies, g.config.maxBodyValueBytes, ctx)
|
||||
result, jerr := g.jmap.QueryEmailsWithSnippets(single(accountId), filter, position, anchor, anchorOffset, jmaplimit, collapseThreads, calculateTotal, fetchBodies, g.config.maxBodyValueBytes, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
return req.jmapError(accountId, jerr, result)
|
||||
}
|
||||
|
||||
if results, ok := resultsByAccount[accountId]; ok {
|
||||
if results, ok := result.Payload[accountId]; ok {
|
||||
var flattened []EmailWithSnippets
|
||||
if limit != nil && *limit == 0 {
|
||||
flattened = nil
|
||||
@@ -628,9 +629,9 @@ func (g *Groupware) GetEmails(w http.ResponseWriter, r *http.Request) { //NOSONA
|
||||
Total: ptrIf(results.Total, calculateTotal),
|
||||
Position: results.Position,
|
||||
Limit: rlimit,
|
||||
}, sessionState, EmailResponseObjectType, state, lang)
|
||||
}, EmailResponseObjectType, result)
|
||||
} else {
|
||||
return req.notFound(accountId, sessionState, EmailResponseObjectType, state)
|
||||
return req.notFound(accountId, EmailResponseObjectType, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -657,14 +658,14 @@ func (g *Groupware) GetEmailsForAllAccounts(w http.ResponseWriter, r *http.Reque
|
||||
}
|
||||
|
||||
if makesSnippets {
|
||||
resultsByAccountId, sessionState, state, lang, jerr := g.jmap.QueryEmailSnippets(allAccountIds, filter, position, anchor, anchorOffset, jmaplimit, ctx)
|
||||
result, jerr := g.jmap.QueryEmailSnippets(allAccountIds, filter, position, anchor, anchorOffset, jmaplimit, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapErrorN(allAccountIds, jerr, sessionState, lang)
|
||||
return req.jmapErrorN(allAccountIds, jerr, result)
|
||||
}
|
||||
|
||||
var totalOverAllAccounts uint = 0
|
||||
total := 0
|
||||
for _, results := range resultsByAccountId {
|
||||
for _, results := range result.Payload {
|
||||
if results.Total != nil {
|
||||
totalOverAllAccounts += *results.Total
|
||||
}
|
||||
@@ -678,7 +679,7 @@ func (g *Groupware) GetEmailsForAllAccounts(w http.ResponseWriter, r *http.Reque
|
||||
flattened = make([]Snippet, total)
|
||||
{
|
||||
i := 0
|
||||
for accountId, results := range resultsByAccountId {
|
||||
for accountId, results := range result.Payload {
|
||||
for _, result := range results.Results {
|
||||
flattened[i] = Snippet{
|
||||
AccountId: accountId,
|
||||
@@ -699,19 +700,19 @@ func (g *Groupware) GetEmailsForAllAccounts(w http.ResponseWriter, r *http.Reque
|
||||
Limit: limit,
|
||||
}
|
||||
|
||||
return req.respondN(allAccountIds, body, sessionState, EmailResponseObjectType, state, lang)
|
||||
return req.respondN(allAccountIds, body, EmailResponseObjectType, result)
|
||||
} else {
|
||||
withThreads := true
|
||||
calculateTotal := true
|
||||
|
||||
resultsByAccountId, sessionState, state, lang, jerr := g.jmap.QueryEmailSummaries(allAccountIds, filter, position, anchor, anchorOffset, jmaplimit, withThreads, calculateTotal, ctx)
|
||||
result, jerr := g.jmap.QueryEmailSummaries(allAccountIds, filter, position, anchor, anchorOffset, jmaplimit, withThreads, calculateTotal, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapErrorN(allAccountIds, jerr, sessionState, lang)
|
||||
return req.jmapErrorN(allAccountIds, jerr, result)
|
||||
}
|
||||
|
||||
var totalAcrossAllAccounts uint = 0
|
||||
total := 0
|
||||
for _, results := range resultsByAccountId {
|
||||
for _, results := range result.Payload {
|
||||
totalAcrossAllAccounts += results.Total
|
||||
total += len(results.Emails)
|
||||
}
|
||||
@@ -723,7 +724,7 @@ func (g *Groupware) GetEmailsForAllAccounts(w http.ResponseWriter, r *http.Reque
|
||||
flattened = make([]jmap.Email, total)
|
||||
{
|
||||
i := 0
|
||||
for accountId, results := range resultsByAccountId {
|
||||
for accountId, results := range result.Payload {
|
||||
for _, result := range results.Emails {
|
||||
result.AccountId = accountId
|
||||
flattened[i] = result
|
||||
@@ -743,7 +744,7 @@ func (g *Groupware) GetEmailsForAllAccounts(w http.ResponseWriter, r *http.Reque
|
||||
Limit: limit,
|
||||
}
|
||||
|
||||
return req.respondN(allAccountIds, body, sessionState, EmailResponseObjectType, state, lang)
|
||||
return req.respondN(allAccountIds, body, EmailResponseObjectType, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -754,12 +755,12 @@ var draftEmailAutoMailboxRolePrecedence = []string{
|
||||
}
|
||||
|
||||
func findDraftsMailboxId(j *jmap.Client, accountId string, req Request, ctx jmap.Context) (string, Response) {
|
||||
mailboxIdsPerAccountIds, sessionState, _, lang, jerr := j.SearchMailboxIdsPerRole(single(accountId), draftEmailAutoMailboxRolePrecedence, ctx)
|
||||
result, jerr := j.SearchMailboxIdsPerRole(single(accountId), draftEmailAutoMailboxRolePrecedence, ctx)
|
||||
if jerr != nil {
|
||||
return "", req.jmapError(accountId, jerr, sessionState, lang)
|
||||
return "", req.jmapError(accountId, jerr, result)
|
||||
} else {
|
||||
for _, role := range draftEmailAutoMailboxRolePrecedence {
|
||||
if mailboxId, ok := mailboxIdsPerAccountIds[accountId][role]; ok {
|
||||
if mailboxId, ok := result.Payload[accountId][role]; ok {
|
||||
return mailboxId, Response{}
|
||||
}
|
||||
}
|
||||
@@ -777,13 +778,13 @@ 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
|
||||
mailboxIdsPerAccountIds, sessionState, _, lang, jerr := j.SearchMailboxIdsPerRole(single(accountId), draftAndSentMailboxRoles, ctx)
|
||||
result, jerr := j.SearchMailboxIdsPerRole(single(accountId), draftAndSentMailboxRoles, ctx)
|
||||
if jerr != nil {
|
||||
return "", "", req.jmapError(accountId, jerr, sessionState, lang)
|
||||
return "", "", req.jmapError(accountId, jerr, result)
|
||||
} else {
|
||||
sentMailboxId := ""
|
||||
for _, role := range sentEmailAutoMailboxRolePrecedence {
|
||||
if mailboxId, ok := mailboxIdsPerAccountIds[accountId][role]; ok {
|
||||
if mailboxId, ok := result.Payload[accountId][role]; ok {
|
||||
sentMailboxId = mailboxId
|
||||
break
|
||||
}
|
||||
@@ -793,7 +794,7 @@ func findSentMailboxId(j *jmap.Client, accountId string, req Request, ctx jmap.C
|
||||
}
|
||||
draftsMailboxId := ""
|
||||
for _, role := range draftEmailAutoMailboxRolePrecedence {
|
||||
if mailboxId, ok := mailboxIdsPerAccountIds[accountId][role]; ok {
|
||||
if mailboxId, ok := result.Payload[accountId][role]; ok {
|
||||
draftsMailboxId = mailboxId
|
||||
break
|
||||
}
|
||||
@@ -810,7 +811,10 @@ func (g *Groupware) CreateEmail(w http.ResponseWriter, r *http.Request) {
|
||||
func(r Request, accountId string, body *jmap.EmailChange, ctx jmap.Context) (bool, Response) {
|
||||
if len(body.MailboxIds) < 1 {
|
||||
mailboxId, resp := findDraftsMailboxId(g.jmap, accountId, r, ctx)
|
||||
if mailboxId != "" {
|
||||
if mailboxId != "" && body != nil {
|
||||
if body.MailboxIds == nil {
|
||||
body.MailboxIds = map[string]bool{}
|
||||
}
|
||||
body.MailboxIds[mailboxId] = true
|
||||
} else {
|
||||
return false, resp
|
||||
@@ -818,7 +822,7 @@ func (g *Groupware) CreateEmail(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
return true, Response{}
|
||||
},
|
||||
func(accountId string, body jmap.EmailChange, ctx jmap.Context) (*jmap.Email, jmap.SessionState, jmap.State, jmap.Language, jmap.Error) {
|
||||
func(accountId string, body jmap.EmailChange, ctx jmap.Context) (jmap.Result[*jmap.Email], jmap.Error) {
|
||||
return g.jmap.CreateEmail(accountId, body, "", ctx)
|
||||
},
|
||||
)
|
||||
@@ -844,7 +848,7 @@ func (g *Groupware) ReplaceEmail(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
return true, Response{}
|
||||
},
|
||||
func(accountId string, body jmap.EmailChange, ctx jmap.Context) (*jmap.Email, jmap.SessionState, jmap.State, jmap.Language, jmap.Error) {
|
||||
func(accountId string, body jmap.EmailChange, ctx jmap.Context) (jmap.Result[*jmap.Email], jmap.Error) {
|
||||
ctx = ctx.WithLogger(log.From(ctx.Logger.With().Str("replaceId", replaceId)))
|
||||
return g.jmap.CreateEmail(accountId, body, replaceId, ctx)
|
||||
},
|
||||
@@ -907,22 +911,22 @@ func (g *Groupware) UpdateEmailKeywords(w http.ResponseWriter, r *http.Request)
|
||||
emailId: patch,
|
||||
}
|
||||
|
||||
result, sessionState, state, lang, jerr := g.jmap.UpdateEmails(accountId, patches, ctx)
|
||||
result, jerr := g.jmap.UpdateEmails(accountId, patches, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
return req.jmapError(accountId, jerr, result)
|
||||
}
|
||||
|
||||
if result == nil {
|
||||
if result.Payload == nil {
|
||||
return req.error(accountId, apiError(req.errorId(), ErrorApiInconsistency, withTitle("API Inconsistency: Missing Email Update Response", //NOSONAR
|
||||
"An internal API behaved unexpectedly: missing Email update response from JMAP endpoint"))) //NOSONAR
|
||||
}
|
||||
updatedEmail, ok := result[emailId]
|
||||
updatedEmail, ok := result.Payload[emailId]
|
||||
if !ok {
|
||||
return req.error(accountId, apiError(req.errorId(), ErrorApiInconsistency, withTitle("API Inconsistency: Wrong Email Update Response ID", //NOSONAR
|
||||
"An internal API behaved unexpectedly: wrong Email update ID response from JMAP endpoint"))) //NOSONAR
|
||||
}
|
||||
|
||||
return req.respond(accountId, updatedEmail, sessionState, EmailResponseObjectType, state, lang)
|
||||
return req.respond(accountId, updatedEmail, EmailResponseObjectType, result)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -966,25 +970,25 @@ func (g *Groupware) AddEmailKeywords(w http.ResponseWriter, r *http.Request) { /
|
||||
emailId: patch,
|
||||
}
|
||||
|
||||
result, sessionState, state, lang, jerr := g.jmap.UpdateEmails(accountId, patches, ctx)
|
||||
result, jerr := g.jmap.UpdateEmails(accountId, patches, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
return req.jmapError(accountId, jerr, result)
|
||||
}
|
||||
|
||||
if result == nil {
|
||||
if result.Payload == nil {
|
||||
return req.error(accountId, apiError(req.errorId(), ErrorApiInconsistency, withTitle("API Inconsistency: Missing Email Update Response",
|
||||
"An internal API behaved unexpectedly: missing Email update response from JMAP endpoint")))
|
||||
}
|
||||
updatedEmail, ok := result[emailId]
|
||||
updatedEmail, ok := result.Payload[emailId]
|
||||
if !ok {
|
||||
return req.error(accountId, apiError(req.errorId(), ErrorApiInconsistency, withTitle("API Inconsistency: Wrong Email Update Response ID",
|
||||
"An internal API behaved unexpectedly: wrong Email update ID response from JMAP endpoint")))
|
||||
}
|
||||
|
||||
if updatedEmail == nil {
|
||||
return req.noContent(accountId, sessionState, EmailResponseObjectType, state)
|
||||
return req.noContent(accountId, EmailResponseObjectType, result)
|
||||
} else {
|
||||
return req.respond(accountId, updatedEmail, sessionState, EmailResponseObjectType, state, lang)
|
||||
return req.respond(accountId, updatedEmail, EmailResponseObjectType, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1029,25 +1033,25 @@ func (g *Groupware) RemoveEmailKeywords(w http.ResponseWriter, r *http.Request)
|
||||
emailId: patch,
|
||||
}
|
||||
|
||||
result, sessionState, state, lang, jerr := g.jmap.UpdateEmails(accountId, patches, ctx)
|
||||
result, jerr := g.jmap.UpdateEmails(accountId, patches, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
return req.jmapError(accountId, jerr, result)
|
||||
}
|
||||
|
||||
if result == nil {
|
||||
if result.Payload == nil {
|
||||
return req.error(accountId, apiError(req.errorId(), ErrorApiInconsistency, withTitle("API Inconsistency: Missing Email Update Response",
|
||||
"An internal API behaved unexpectedly: missing Email update response from JMAP endpoint")))
|
||||
}
|
||||
updatedEmail, ok := result[emailId]
|
||||
updatedEmail, ok := result.Payload[emailId]
|
||||
if !ok {
|
||||
return req.error(accountId, apiError(req.errorId(), ErrorApiInconsistency, withTitle("API Inconsistency: Wrong Email Update Response ID",
|
||||
"An internal API behaved unexpectedly: wrong Email update ID response from JMAP endpoint")))
|
||||
}
|
||||
|
||||
if updatedEmail == nil {
|
||||
return req.noContent(accountId, sessionState, EmailResponseObjectType, state)
|
||||
return req.noContent(accountId, EmailResponseObjectType, result)
|
||||
} else {
|
||||
return req.respond(accountId, updatedEmail, sessionState, EmailResponseObjectType, state, lang)
|
||||
return req.respond(accountId, updatedEmail, EmailResponseObjectType, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1116,12 +1120,12 @@ func (g *Groupware) SendEmail(w http.ResponseWriter, r *http.Request) { //NOSONA
|
||||
|
||||
logger := log.From(l)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
resp, sessionState, state, lang, jerr := g.jmap.SubmitEmail(accountId, identityId, emailId, move, ctx)
|
||||
result, jerr := g.jmap.SubmitEmail(accountId, identityId, emailId, move, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
return req.jmapError(accountId, jerr, result)
|
||||
}
|
||||
|
||||
return req.respond(accountId, resp, sessionState, EmailResponseObjectType, state, lang)
|
||||
return req.respond(accountId, result.Payload, EmailResponseObjectType, result)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1221,21 +1225,21 @@ func (g *Groupware) RelatedToEmail(w http.ResponseWriter, r *http.Request) { //N
|
||||
|
||||
reqId := req.GetRequestId()
|
||||
getEmailsBefore := time.Now()
|
||||
emails, _, sessionState, state, lang, jerr := g.jmap.GetEmails(accountId, single(id), true, g.config.maxBodyValueBytes, false, false, ctx)
|
||||
result, jerr := g.jmap.GetEmails(accountId, single(id), true, g.config.maxBodyValueBytes, false, false, ctx)
|
||||
getEmailsDuration := time.Since(getEmailsBefore)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
return req.jmapError(accountId, jerr, result)
|
||||
}
|
||||
|
||||
if len(emails) < 1 {
|
||||
if len(result.Payload.List) < 1 {
|
||||
req.observe(g.metrics.EmailByIdDuration.WithLabelValues(req.session.JmapEndpoint, metrics.Values.Result.NotFound), getEmailsDuration.Seconds())
|
||||
logger.Trace().Msg("failed to find any emails matching id") // the id is already in the log field
|
||||
return req.notFound(accountId, sessionState, EmailResponseObjectType, state)
|
||||
return req.notFound(accountId, EmailResponseObjectType, result)
|
||||
} else {
|
||||
req.observe(g.metrics.EmailByIdDuration.WithLabelValues(req.session.JmapEndpoint, metrics.Values.Result.Found), getEmailsDuration.Seconds())
|
||||
}
|
||||
|
||||
email := emails[0]
|
||||
email := result.Payload.List[0]
|
||||
|
||||
beacon := email.ReceivedAt // TODO configurable: either relative to when the email was received, or relative to now
|
||||
//beacon := time.Now()
|
||||
@@ -1247,8 +1251,8 @@ func (g *Groupware) RelatedToEmail(w http.ResponseWriter, r *http.Request) { //N
|
||||
g.job(logger, RelationTypeSameSender, func(jobId uint64, l *log.Logger) {
|
||||
before := time.Now()
|
||||
ctx = ctx.WithLogger(logger).WithContext(bgctx)
|
||||
resultsByAccountId, _, _, lang, jerr := g.jmap.QueryEmails(single(accountId), filter, 0, limit, false, g.config.maxBodyValueBytes, ctx)
|
||||
if results, ok := resultsByAccountId[accountId]; ok {
|
||||
results, jerr := g.jmap.QueryEmails(single(accountId), filter, 0, limit, false, g.config.maxBodyValueBytes, ctx)
|
||||
if results, ok := results.Payload[accountId]; ok {
|
||||
duration := time.Since(before)
|
||||
if jerr != nil {
|
||||
_ = req.observeJmapError(jerr)
|
||||
@@ -1259,7 +1263,7 @@ func (g *Groupware) RelatedToEmail(w http.ResponseWriter, r *http.Request) { //N
|
||||
if err == nil {
|
||||
l.Trace().Msgf("'%v' found %v other emails", RelationTypeSameSender, len(related))
|
||||
if len(related) > 0 {
|
||||
req.push(RelationEntityEmail, AboutEmailsEvent{Id: reqId, Emails: related, Source: RelationTypeSameSender, Language: lang})
|
||||
req.push(RelationEntityEmail, AboutEmailsEvent{Id: reqId, Emails: related, Source: RelationTypeSameSender, Language: result.GetLanguage()})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1269,18 +1273,18 @@ func (g *Groupware) RelatedToEmail(w http.ResponseWriter, r *http.Request) { //N
|
||||
g.job(logger, RelationTypeSameThread, func(jobId uint64, l *log.Logger) {
|
||||
before := time.Now()
|
||||
ctx = ctx.WithLogger(logger).WithContext(bgctx)
|
||||
emails, _, _, lang, jerr := g.jmap.EmailsInThread(accountId, email.ThreadId, false, g.config.maxBodyValueBytes, ctx)
|
||||
results, jerr := g.jmap.EmailsInThread(accountId, email.ThreadId, false, g.config.maxBodyValueBytes, ctx)
|
||||
duration := time.Since(before)
|
||||
if jerr != nil {
|
||||
_ = req.observeJmapError(jerr)
|
||||
l.Error().Err(jerr).Msgf("failed to list %v emails", RelationTypeSameThread)
|
||||
} else {
|
||||
req.observe(g.metrics.EmailSameThreadDuration.WithLabelValues(req.session.JmapEndpoint), duration.Seconds())
|
||||
related, err := req.sanitizeEmails(filterEmails(emails, email))
|
||||
related, err := req.sanitizeEmails(filterEmails(results.Payload, email))
|
||||
if err == nil {
|
||||
l.Trace().Msgf("'%v' found %v other emails", RelationTypeSameThread, len(related))
|
||||
if len(related) > 0 {
|
||||
req.push(RelationEntityEmail, AboutEmailsEvent{Id: reqId, Emails: related, Source: RelationTypeSameThread, Language: lang})
|
||||
req.push(RelationEntityEmail, AboutEmailsEvent{Id: reqId, Emails: related, Source: RelationTypeSameThread, Language: result.GetLanguage()})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1293,7 +1297,7 @@ func (g *Groupware) RelatedToEmail(w http.ResponseWriter, r *http.Request) { //N
|
||||
return req.respond(accountId, AboutEmailResponse{
|
||||
Email: sanitized,
|
||||
RequestId: reqId,
|
||||
}, sessionState, EmailResponseObjectType, state, lang)
|
||||
}, EmailResponseObjectType, result)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1562,19 +1566,19 @@ func (g *Groupware) GetLatestEmailsSummaryForAllAccounts(w http.ResponseWriter,
|
||||
|
||||
calculateTotal := true
|
||||
withThreads := true
|
||||
emailsSummariesByAccount, sessionState, state, lang, jerr := g.jmap.QueryEmailSummaries(allAccountIds, filter, position, anchor, anchorOffset, &limit, withThreads, calculateTotal, ctx)
|
||||
result, jerr := g.jmap.QueryEmailSummaries(allAccountIds, filter, position, anchor, anchorOffset, &limit, withThreads, calculateTotal, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapErrorN(allAccountIds, jerr, sessionState, lang)
|
||||
return req.jmapErrorN(allAccountIds, jerr, result)
|
||||
}
|
||||
|
||||
// sort in memory to respect the overall limit
|
||||
total := uint(0)
|
||||
for _, emails := range emailsSummariesByAccount {
|
||||
for _, emails := range result.Payload {
|
||||
total += uint(max(len(emails.Emails), 0))
|
||||
}
|
||||
all := make([]emailWithAccountId, total)
|
||||
i := uint(0)
|
||||
for accountId, emails := range emailsSummariesByAccount {
|
||||
for accountId, emails := range result.Payload {
|
||||
for _, email := range emails.Emails {
|
||||
all[i] = emailWithAccountId{accountId: accountId, email: email}
|
||||
i++
|
||||
@@ -1597,7 +1601,7 @@ func (g *Groupware) GetLatestEmailsSummaryForAllAccounts(w http.ResponseWriter,
|
||||
body.Total = &total
|
||||
}
|
||||
|
||||
return req.respondN(allAccountIds, body, sessionState, EmailResponseObjectType, state, lang)
|
||||
return req.respondN(allAccountIds, body, EmailResponseObjectType, result)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -72,11 +72,15 @@ func (g *Groupware) GetEventsInCalendar(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
|
||||
func curryMapQuery[SRES jmap.SearchResults[T], T jmap.Foo, FILTER any, COMP any](
|
||||
f func(accountIds []string, filter FILTER, sortBy []COMP, position int, anchor string, anchorOffset *int, limit *uint, calculateTotal bool, ctx jmap.Context) (map[string]SRES, jmap.SessionState, jmap.State, jmap.Language, jmap.Error),
|
||||
) func(req Request, accountId string, filter FILTER, sortBy []COMP, position int, anchor string, anchorOffset *int, limit *uint, ctx jmap.Context) (SRES, jmap.SessionState, jmap.State, jmap.Language, jmap.Error) {
|
||||
return func(req Request, accountId string, filter FILTER, sortBy []COMP, position int, anchor string, anchorOffset *int, limit *uint, ctx jmap.Context) (SRES, jmap.SessionState, jmap.State, jmap.Language, jmap.Error) { //NOSONAR
|
||||
m, sessionState, state, lang, err := f(single(accountId), filter, sortBy, position, anchor, anchorOffset, limit, true, ctx)
|
||||
return m[accountId], sessionState, state, lang, err
|
||||
f func(accountIds []string, filter FILTER, sortBy []COMP, position int, anchor string, anchorOffset *int, limit *uint, calculateTotal bool, ctx jmap.Context) (jmap.Result[map[string]SRES], jmap.Error),
|
||||
) func(req Request, accountId string, filter FILTER, sortBy []COMP, position int, anchor string, anchorOffset *int, limit *uint, ctx jmap.Context) (jmap.Result[SRES], jmap.Error) {
|
||||
return func(req Request, accountId string, filter FILTER, sortBy []COMP, position int, anchor string, anchorOffset *int, limit *uint, ctx jmap.Context) (jmap.Result[SRES], jmap.Error) { //NOSONAR
|
||||
result, err := f(single(accountId), filter, sortBy, position, anchor, anchorOffset, limit, true, ctx)
|
||||
if err != nil {
|
||||
return jmap.ZeroResult[SRES](), err
|
||||
} else {
|
||||
return jmap.RefineResult(result, func(m map[string]SRES) SRES { return m[accountId] }), err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,10 +134,10 @@ func (g *Groupware) ParseIcalBlob(w http.ResponseWriter, r *http.Request) {
|
||||
l := req.logger.With().Array(UriParamBlobId, log.SafeStringArray(blobIds))
|
||||
logger := log.From(l)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
resp, sessionState, state, lang, jerr := g.jmap.ParseICalendarBlob(accountId, blobIds, ctx)
|
||||
result, jerr := g.jmap.ParseICalendarBlob(accountId, blobIds, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
return req.jmapError(accountId, jerr, result)
|
||||
}
|
||||
return req.respond(accountId, resp, sessionState, EventResponseObjectType, state, lang)
|
||||
return req.respond(accountId, result.Payload, EventResponseObjectType, result)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -148,19 +148,19 @@ func (g *Groupware) Index(w http.ResponseWriter, r *http.Request) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
accountIds := req.AllAccountIds()
|
||||
|
||||
boot, sessionState, state, lang, err := g.jmap.GetBootstrap(accountIds, req.ctx)
|
||||
result, err := g.jmap.GetBootstrap(accountIds, req.ctx)
|
||||
if err != nil {
|
||||
return req.jmapErrorN(accountIds, err, sessionState, lang)
|
||||
return req.jmapErrorN(accountIds, err, result)
|
||||
}
|
||||
|
||||
var body IndexResponse = IndexResponse{
|
||||
Version: Version,
|
||||
Capabilities: Capabilities,
|
||||
Limits: buildIndexLimits(req.session),
|
||||
Accounts: buildIndexAccounts(req.session, boot),
|
||||
Accounts: buildIndexAccounts(req.session, result.Payload),
|
||||
PrimaryAccounts: buildIndexPrimaryAccounts(req.session),
|
||||
}
|
||||
return req.respondN(accountIds, body, sessionState, IndexResponseObjectType, state, lang)
|
||||
return req.respondN(accountIds, body, IndexResponseObjectType, result)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -75,25 +75,25 @@ func (g *Groupware) GetMailboxes(w http.ResponseWriter, r *http.Request) { //NOS
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
|
||||
if hasCriteria {
|
||||
mailboxesByAccountId, sessionState, state, lang, err := g.jmap.SearchMailboxes(single(accountId), filter, ctx)
|
||||
result, err := g.jmap.SearchMailboxes(single(accountId), filter, ctx)
|
||||
if err != nil {
|
||||
return req.jmapError(accountId, err, sessionState, lang)
|
||||
return req.jmapError(accountId, err, result)
|
||||
}
|
||||
|
||||
if mailboxes, ok := mailboxesByAccountId[accountId]; ok {
|
||||
return req.respond(accountId, sortMailboxSlice(mailboxes), sessionState, MailboxResponseObjectType, state, lang)
|
||||
if mailboxes, ok := result.Payload[accountId]; ok {
|
||||
return req.respond(accountId, sortMailboxSlice(mailboxes), MailboxResponseObjectType, result)
|
||||
} else {
|
||||
return req.notFound(accountId, sessionState, MailboxResponseObjectType, state)
|
||||
return req.notFound(accountId, MailboxResponseObjectType, result)
|
||||
}
|
||||
} else {
|
||||
mailboxesByAccountId, sessionState, state, lang, err := g.jmap.GetAllMailboxes(single(accountId), ctx)
|
||||
result, err := g.jmap.GetAllMailboxes(single(accountId), ctx)
|
||||
if err != nil {
|
||||
return req.jmapError(accountId, err, sessionState, lang)
|
||||
return req.jmapError(accountId, err, result)
|
||||
}
|
||||
if mailboxes, ok := mailboxesByAccountId[accountId]; ok {
|
||||
return req.respond(accountId, sortMailboxSlice(mailboxes), sessionState, MailboxResponseObjectType, state, lang)
|
||||
if mailboxes, ok := result.Payload[accountId]; ok {
|
||||
return req.respond(accountId, sortMailboxSlice(mailboxes), MailboxResponseObjectType, result)
|
||||
} else {
|
||||
return req.notFound(accountId, sessionState, MailboxResponseObjectType, state)
|
||||
return req.notFound(accountId, MailboxResponseObjectType, result)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -125,17 +125,17 @@ func (g *Groupware) GetMailboxesForAllAccounts(w http.ResponseWriter, r *http.Re
|
||||
}
|
||||
|
||||
if hasCriteria {
|
||||
mailboxesByAccountId, sessionState, state, lang, err := g.jmap.SearchMailboxes(accountIds, filter, ctx)
|
||||
result, err := g.jmap.SearchMailboxes(accountIds, filter, ctx)
|
||||
if err != nil {
|
||||
return req.jmapErrorN(accountIds, err, sessionState, lang)
|
||||
return req.jmapErrorN(accountIds, err, result)
|
||||
}
|
||||
return req.respondN(accountIds, sortMailboxesMap(mailboxesByAccountId), sessionState, MailboxResponseObjectType, state, lang)
|
||||
return req.respondN(accountIds, sortMailboxesMap(result.Payload), MailboxResponseObjectType, result)
|
||||
} else {
|
||||
mailboxesByAccountId, sessionState, state, lang, err := g.jmap.GetAllMailboxes(accountIds, ctx)
|
||||
result, err := g.jmap.GetAllMailboxes(accountIds, ctx)
|
||||
if err != nil {
|
||||
return req.jmapErrorN(accountIds, err, sessionState, lang)
|
||||
return req.jmapErrorN(accountIds, err, result)
|
||||
}
|
||||
return req.respondN(accountIds, sortMailboxesMap(mailboxesByAccountId), sessionState, MailboxResponseObjectType, state, lang)
|
||||
return req.respondN(accountIds, sortMailboxesMap(result.Payload), MailboxResponseObjectType, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -160,11 +160,11 @@ func (g *Groupware) GetMailboxByRoleForAllAccounts(w http.ResponseWriter, r *htt
|
||||
Role: role,
|
||||
}
|
||||
|
||||
mailboxesByAccountId, sessionState, state, lang, jerr := g.jmap.SearchMailboxes(accountIds, filter, ctx)
|
||||
result, jerr := g.jmap.SearchMailboxes(accountIds, filter, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapErrorN(accountIds, jerr, sessionState, lang)
|
||||
return req.jmapErrorN(accountIds, jerr, result)
|
||||
}
|
||||
return req.respondN(accountIds, sortMailboxesMap(mailboxesByAccountId), sessionState, MailboxResponseObjectType, state, lang)
|
||||
return req.respondN(accountIds, sortMailboxesMap(result.Payload), MailboxResponseObjectType, result)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -206,12 +206,12 @@ func (g *Groupware) GetMailboxChangesForAllAccounts(w http.ResponseWriter, r *ht
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
|
||||
sinceStateMap := structs.MapValues(sinceStateStrMap, toState)
|
||||
changesByAccountId, sessionState, state, lang, jerr := g.jmap.GetMailboxChangesForMultipleAccounts(allAccountIds, sinceStateMap, maxChanges, ctx)
|
||||
result, jerr := g.jmap.GetMailboxChangesForMultipleAccounts(allAccountIds, sinceStateMap, maxChanges, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapErrorN(allAccountIds, jerr, sessionState, lang)
|
||||
return req.jmapErrorN(allAccountIds, jerr, result)
|
||||
}
|
||||
|
||||
return req.respondN(allAccountIds, changesByAccountId, sessionState, MailboxResponseObjectType, state, lang)
|
||||
return req.respondN(allAccountIds, result.Payload, MailboxResponseObjectType, result)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -225,12 +225,12 @@ func (g *Groupware) GetMailboxRoles(w http.ResponseWriter, r *http.Request) {
|
||||
logger := log.From(l)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
|
||||
rolesByAccountId, sessionState, state, lang, jerr := g.jmap.GetMailboxRolesForMultipleAccounts(allAccountIds, ctx)
|
||||
result, jerr := g.jmap.GetMailboxRolesForMultipleAccounts(allAccountIds, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapErrorN(allAccountIds, jerr, sessionState, lang)
|
||||
return req.jmapErrorN(allAccountIds, jerr, result)
|
||||
}
|
||||
|
||||
return req.respondN(allAccountIds, rolesByAccountId, sessionState, MailboxResponseObjectType, state, lang)
|
||||
return req.respondN(allAccountIds, result.Payload, MailboxResponseObjectType, result)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -238,11 +238,6 @@ func (g *Groupware) CreateMailbox(w http.ResponseWriter, r *http.Request) {
|
||||
create(Mailbox, w, r, g, nil, g.jmap.CreateMailbox)
|
||||
}
|
||||
|
||||
// Delete Mailboxes by their unique identifiers.
|
||||
//
|
||||
// Returns the identifiers of the Mailboxes that have successfully been deleted.
|
||||
//
|
||||
// @api:example deletedmailboxes
|
||||
func (g *Groupware) DeleteMailbox(w http.ResponseWriter, r *http.Request) {
|
||||
delete(Mailbox, w, r, g, g.jmap.DeleteMailboxes)
|
||||
}
|
||||
|
||||
@@ -121,15 +121,15 @@ func (g *Groupware) GetObjects(w http.ResponseWriter, r *http.Request) { //NOSON
|
||||
|
||||
logger := log.From(l)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
objs, sessionState, state, lang, jerr := g.jmap.GetObjects(accountId,
|
||||
result, jerr := g.jmap.GetObjects(accountId,
|
||||
mailboxIds, emailIds, addressbookIds, contactIds, calendarIds, eventIds, quotaIds, identityIds, emailSubmissionIds,
|
||||
ctx,
|
||||
)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
return req.jmapError(accountId, jerr, result)
|
||||
}
|
||||
var body jmap.Objects = objs
|
||||
var body jmap.Objects = result.Payload
|
||||
|
||||
return req.respond(accountId, body, sessionState, "", state, lang)
|
||||
return req.respond(accountId, body, UnspecifiedResponseObjectType, result)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -13,7 +13,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) (map[string]jmap.QuotaGetResponse, jmap.SessionState, jmap.State, jmap.Language, jmap.Error) {
|
||||
getFromMap(Quota, w, r, g, func(accountIds, _ []string, ctx jmap.Context) (jmap.Result[map[string]jmap.QuotaGetResponse], jmap.Error) {
|
||||
return g.jmap.GetQuotas(accountIds, ctx)
|
||||
})
|
||||
}
|
||||
@@ -36,19 +36,19 @@ func (g *Groupware) GetQuotaForAllAccounts(w http.ResponseWriter, r *http.Reques
|
||||
logger := log.From(req.logger.With().Array(logAccountId, log.SafeStringArray(accountIds)))
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
|
||||
res, sessionState, state, lang, jerr := g.jmap.GetQuotas(accountIds, ctx)
|
||||
result, jerr := g.jmap.GetQuotas(accountIds, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapErrorN(accountIds, jerr, sessionState, lang)
|
||||
return req.jmapErrorN(accountIds, jerr, result)
|
||||
}
|
||||
|
||||
result := make(map[string]AccountQuota, len(res))
|
||||
for accountId, accountQuotas := range res {
|
||||
result[accountId] = AccountQuota{
|
||||
body := make(map[string]AccountQuota, len(result.Payload))
|
||||
for accountId, accountQuotas := range result.Payload {
|
||||
body[accountId] = AccountQuota{
|
||||
State: accountQuotas.State,
|
||||
Quotas: accountQuotas.List,
|
||||
}
|
||||
}
|
||||
return req.respondN(accountIds, result, sessionState, QuotaResponseObjectType, state, lang)
|
||||
return req.respondN(accountIds, body, QuotaResponseObjectType, result)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,8 @@ func (g *Groupware) GetTaskLists(w http.ResponseWriter, r *http.Request) {
|
||||
var _ string = accountId
|
||||
|
||||
var body []jmap.TaskList = AllTaskLists
|
||||
return req.respond(accountId, body, req.session.State, TaskListResponseObjectType, TaskListsState, jmap.NoLanguage)
|
||||
meta := TaskListsMeta{SessionState: req.session.State}
|
||||
return req.respond(accountId, body, TaskListResponseObjectType, meta)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -34,9 +35,10 @@ func (g *Groupware) GetTaskListById(w http.ResponseWriter, r *http.Request) {
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
// TODO replace with proper implementation
|
||||
meta := TaskListsMeta{SessionState: req.session.State}
|
||||
for _, tasklist := range AllTaskLists {
|
||||
if tasklist.Id == tasklistId {
|
||||
return req.respond(accountId, tasklist, req.session.State, TaskListResponseObjectType, TaskListsState, jmap.NoLanguage)
|
||||
return req.respond(accountId, tasklist, TaskListResponseObjectType, meta)
|
||||
}
|
||||
}
|
||||
return req.etaggedNotFound(accountId, req.session.State, TaskListResponseObjectType, TaskListsState)
|
||||
@@ -57,10 +59,11 @@ func (g *Groupware) GetTasksInTaskList(w http.ResponseWriter, r *http.Request) {
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
// TODO replace with proper implementation
|
||||
meta := TaskMeta{SessionState: req.session.State}
|
||||
tasks, ok := TaskMapByTaskListId[tasklistId]
|
||||
if !ok {
|
||||
return req.notFound(accountId, req.session.State, TaskResponseObjectType, TaskState)
|
||||
return req.notFound(accountId, TaskResponseObjectType, meta)
|
||||
}
|
||||
return req.respond(accountId, tasks, req.session.State, TaskResponseObjectType, TaskState, jmap.NoLanguage)
|
||||
return req.respond(accountId, tasks, TaskResponseObjectType, meta)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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.VacationResponseGetResponse, jmap.SessionState, jmap.State, jmap.Language, jmap.Error) {
|
||||
get(VacationResponse, w, r, g, func(accountId string, ids []string, ctx jmap.Context) (jmap.Result[jmap.VacationResponseGetResponse], jmap.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.VacationResponse, jmap.SessionState, jmap.State, jmap.Language, jmap.Error) {
|
||||
modify(VacationResponse, w, r, g, func(accountId string, id string, change jmap.VacationResponseChange, ctx jmap.Context) (jmap.Result[jmap.VacationResponse], jmap.Error) {
|
||||
return g.jmap.SetVacationResponse(accountId, change, ctx)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -134,11 +134,11 @@ func groupwareErrorFromJmap(j jmap.Error) *GroupwareError {
|
||||
return &ErrorSendingRequest
|
||||
case jmap.JmapErrorInvalidSessionResponse:
|
||||
return &ErrorInvalidSessionResponse
|
||||
case jmap.JmapErrorInvalidJmapRequestPayload:
|
||||
case jmap.JmapErrorInvalidJmapRequestPayload, jmap.JmapErrorInvalidProperties:
|
||||
return &ErrorInvalidRequestPayload
|
||||
case jmap.JmapErrorInvalidJmapResponsePayload:
|
||||
return &ErrorInvalidResponsePayload
|
||||
case jmap.JmapInvalidObjectState:
|
||||
case jmap.JmapErrorInvalidObjectState:
|
||||
return &ErrorInvalidObjectState
|
||||
case jmap.JmapErrorUnspecifiedType, jmap.JmapErrorUnknownMethod, jmap.JmapErrorInvalidArguments, jmap.JmapErrorInvalidResultReference:
|
||||
return &ErrorInvalidGroupwareRequest
|
||||
@@ -748,18 +748,18 @@ func (r *Request) error(accountId string, err *Error) Response {
|
||||
return errorResponse(single(accountId), err, r.session.State, jmap.NoLanguage)
|
||||
}
|
||||
|
||||
func (r *Request) errorS(accountId string, err *Error, sessionState jmap.SessionState) Response {
|
||||
return errorResponse(single(accountId), err, sessionState, jmap.NoLanguage)
|
||||
func (r *Request) errorS(accountId string, err *Error, result jmap.ResultMetadata) Response {
|
||||
return errorResponse(single(accountId), err, result.GetSessionState(), result.GetLanguage())
|
||||
}
|
||||
|
||||
func (r *Request) errorN(accountIds []string, err *Error) Response {
|
||||
return errorResponse(accountIds, err, r.session.State, jmap.NoLanguage)
|
||||
}
|
||||
|
||||
func (r *Request) jmapError(accountId string, err jmap.Error, sessionState jmap.SessionState, lang jmap.Language) Response {
|
||||
return errorResponse(single(accountId), r.apiErrorFromJmap(r.observeJmapError(err)), sessionState, lang)
|
||||
func (r *Request) jmapError(accountId string, err jmap.Error, result jmap.ResultMetadata) Response {
|
||||
return errorResponse(single(accountId), r.apiErrorFromJmap(r.observeJmapError(err)), result.GetSessionState(), result.GetLanguage())
|
||||
}
|
||||
|
||||
func (r *Request) jmapErrorN(accountIds []string, err jmap.Error, sessionState jmap.SessionState, lang jmap.Language) Response {
|
||||
return errorResponse(accountIds, r.apiErrorFromJmap(r.observeJmapError(err)), sessionState, lang)
|
||||
func (r *Request) jmapErrorN(accountIds []string, err jmap.Error, result jmap.ResultMetadata) Response {
|
||||
return errorResponse(accountIds, r.apiErrorFromJmap(r.observeJmapError(err)), result.GetSessionState(), result.GetLanguage())
|
||||
}
|
||||
|
||||
@@ -201,6 +201,16 @@ var AllTaskLists = []jmap.TaskList{TL1}
|
||||
|
||||
var TaskListsState = jmap.State("mock")
|
||||
|
||||
type TaskListsMeta struct {
|
||||
SessionState jmap.SessionState
|
||||
}
|
||||
|
||||
func (t TaskListsMeta) GetSessionState() jmap.SessionState { return t.SessionState }
|
||||
func (t TaskListsMeta) GetState() jmap.State { return TaskListsState }
|
||||
func (t TaskListsMeta) GetLanguage() jmap.Language { return jmap.NoLanguage }
|
||||
|
||||
var _ jmap.ResultMetadata = TaskListsMeta{}
|
||||
|
||||
var TaskMapByTaskListId = map[string][]jmap.Task{
|
||||
TL1.Id: {
|
||||
T1,
|
||||
@@ -209,6 +219,16 @@ var TaskMapByTaskListId = map[string][]jmap.Task{
|
||||
|
||||
var TaskState = jmap.State("mock")
|
||||
|
||||
type TaskMeta struct {
|
||||
SessionState jmap.SessionState
|
||||
}
|
||||
|
||||
func (t TaskMeta) GetSessionState() jmap.SessionState { return t.SessionState }
|
||||
func (t TaskMeta) GetState() jmap.State { return TaskState }
|
||||
func (t TaskMeta) GetLanguage() jmap.Language { return jmap.NoLanguage }
|
||||
|
||||
var _ jmap.ResultMetadata = TaskListsMeta{}
|
||||
|
||||
func mustParseTime(text string) time.Time {
|
||||
t, err := time.Parse(time.RFC3339, text)
|
||||
if err != nil {
|
||||
|
||||
@@ -413,10 +413,13 @@ func (r *Request) body(target any) *Error {
|
||||
}
|
||||
}(body)
|
||||
|
||||
err := json.NewDecoder(body).Decode(target)
|
||||
decoder := json.NewDecoder(body)
|
||||
decoder.DisallowUnknownFields()
|
||||
err := decoder.Decode(target)
|
||||
if err != nil {
|
||||
r.logger.Warn().Msgf("failed to deserialize the request body: %s", err.Error())
|
||||
return r.observedParameterError(ErrorInvalidRequestBody, withSource(&ErrorSource{Pointer: "/"})) // we don't get any details here
|
||||
// we don't get any structured details here
|
||||
return r.observedParameterError(ErrorInvalidRequestBody, withSource(&ErrorSource{Pointer: "/"}), withDetail(err.Error()))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
type ResponseObjectType string
|
||||
|
||||
const (
|
||||
UnspecifiedResponseObjectType = ResponseObjectType("")
|
||||
IndexResponseObjectType = ResponseObjectType("index")
|
||||
AccountResponseObjectType = ResponseObjectType("account")
|
||||
IdentityResponseObjectType = ResponseObjectType("identity")
|
||||
@@ -74,12 +75,12 @@ func etaggedResponse(accountIds []string, body any, sessionState jmap.SessionSta
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Request) respond(accountId string, body any, sessionState jmap.SessionState, objectType ResponseObjectType, etag jmap.State, lang jmap.Language) Response {
|
||||
return etaggedResponse(single(accountId), body, sessionState, objectType, etag, lang)
|
||||
func (r *Request) respond(accountId string, 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, sessionState jmap.SessionState, objectType ResponseObjectType, etag jmap.State, lang jmap.Language) Response {
|
||||
return etaggedResponse(accountIds, body, sessionState, objectType, etag, lang)
|
||||
func (r *Request) respondN(accountIds []string, body any, objectType ResponseObjectType, result jmap.ResultMetadata) Response {
|
||||
return etaggedResponse(accountIds, body, result.GetSessionState(), objectType, result.GetState(), result.GetLanguage())
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -126,8 +127,8 @@ func noContentResponseWithEtag(accountIds []string, sessionState jmap.SessionSta
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Request) noContent(accountId string, sessionState jmap.SessionState, objectType ResponseObjectType, etag jmap.State) Response {
|
||||
return noContentResponseWithEtag(single(accountId), sessionState, objectType, etag)
|
||||
func (r *Request) noContent(accountId string, objectType ResponseObjectType, result jmap.ResultMetadata) Response {
|
||||
return noContentResponseWithEtag(single(accountId), result.GetSessionState(), objectType, result.GetState())
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -166,8 +167,8 @@ func notFoundResponse(accountIds []string, sessionState jmap.SessionState, objec
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Request) notFound(accountId string, sessionState jmap.SessionState, objectType ResponseObjectType, etag jmap.State) Response {
|
||||
return notFoundResponse(single(accountId), sessionState, objectType, etag)
|
||||
func (r *Request) notFound(accountId string, 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 {
|
||||
|
||||
@@ -15,7 +15,7 @@ func create[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T]](
|
||||
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) (*T, jmap.SessionState, jmap.State, jmap.Language, jmap.Error),
|
||||
createFunc func(accountId string, change CHANGE, ctx jmap.Context) (jmap.Result[*T], jmap.Error),
|
||||
) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
ok, accountId, resp := o.accountFunc(&req)
|
||||
@@ -43,11 +43,11 @@ func create[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T]](
|
||||
}
|
||||
}
|
||||
|
||||
created, sessionState, state, lang, jerr := createFunc(accountId, create, ctx)
|
||||
result, jerr := createFunc(accountId, create, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
return req.jmapError(accountId, jerr, result)
|
||||
}
|
||||
return req.respond(accountId, created, sessionState, o.responseType, state, lang)
|
||||
return req.respond(accountId, result.Payload, o.responseType, result)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ 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) (RESP, jmap.SessionState, jmap.State, jmap.Language, jmap.Error),
|
||||
getFunc func(accountId string, ids []string, ctx jmap.Context) (jmap.Result[RESP], jmap.Error),
|
||||
) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
ok, accountId, resp := o.accountFunc(&req)
|
||||
@@ -72,11 +72,11 @@ func getall[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T], RESP jmap.G
|
||||
|
||||
logger := log.From(l)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
objs, sessionState, state, lang, jerr := getFunc(accountId, []string{}, ctx)
|
||||
result, jerr := getFunc(accountId, []string{}, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
return req.jmapError(accountId, jerr, result)
|
||||
}
|
||||
return req.respond(accountId, objs, sessionState, o.responseType, state, lang)
|
||||
return req.respond(accountId, result.Payload, o.responseType, result)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ 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, accountId string, filter FILTER, sortBy []COMP, position int, anchor string, anchorOffset *int, limit *uint, ctx jmap.Context) (SEARCHRESULTS, jmap.SessionState, jmap.State, jmap.Language, jmap.Error),
|
||||
queryFunc func(req Request, accountId string, filter FILTER, sortBy []COMP, position int, anchor string, anchorOffset *int, limit *uint, ctx jmap.Context) (jmap.Result[SEARCHRESULTS], jmap.Error),
|
||||
) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
ok, accountId, resp := o.accountFunc(&req)
|
||||
@@ -160,20 +160,20 @@ func getallpaged[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T], FILTER
|
||||
|
||||
logger := log.From(l)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
results, sessionState, state, lang, jerr := queryFunc(req, accountId, filter, sortBy, position, anchor, anchorOffset, jmaplimit, ctx)
|
||||
result, jerr := queryFunc(req, accountId, filter, sortBy, position, anchor, anchorOffset, jmaplimit, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
return req.jmapError(accountId, jerr, result)
|
||||
}
|
||||
|
||||
if limit != nil && *limit == 0 {
|
||||
results.RemoveResults()
|
||||
results.SetLimit(UintPtrZero)
|
||||
result.Payload.RemoveResults()
|
||||
result.Payload.SetLimit(UintPtrZero)
|
||||
}
|
||||
if anchor != "" && results.GetPosition() != nil && *results.GetPosition() == 0 {
|
||||
results.SetPosition(nil)
|
||||
if anchor != "" && result.Payload.GetPosition() != nil && *result.Payload.GetPosition() == 0 {
|
||||
result.Payload.SetPosition(nil)
|
||||
}
|
||||
|
||||
return req.respond(accountId, results, sessionState, o.responseType, state, lang)
|
||||
return req.respond(accountId, result.Payload, o.responseType, result)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@ 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, position int, anchor string, anchorOffset *int, limit *uint, ctx jmap.Context) (SEARCHRESULTS, jmap.SessionState, jmap.State, jmap.Language, *Error),
|
||||
queryFunc func(req Request, accountId string, containerId string, position int, anchor string, anchorOffset *int, limit *uint, ctx jmap.Context) (jmap.Result[SEARCHRESULTS], *Error),
|
||||
) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
ok, accountId, resp := o.accountFunc(&req)
|
||||
@@ -250,20 +250,20 @@ func query[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T], SEARCHRESULT
|
||||
jmaplimit = UintPtrOne
|
||||
}
|
||||
|
||||
results, sessionState, state, lang, err := queryFunc(req, accountId, containerId, position, anchor, anchorOffset, jmaplimit, ctx)
|
||||
result, err := queryFunc(req, accountId, containerId, position, anchor, anchorOffset, jmaplimit, ctx)
|
||||
if err != nil {
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
|
||||
if limit != nil && *limit == 0 {
|
||||
results.RemoveResults()
|
||||
results.SetLimit(UintPtrZero)
|
||||
result.Payload.RemoveResults()
|
||||
result.Payload.SetLimit(UintPtrZero)
|
||||
}
|
||||
if anchor != "" && results.GetPosition() != nil && *results.GetPosition() == 0 {
|
||||
results.SetPosition(nil)
|
||||
if anchor != "" && result.Payload.GetPosition() != nil && *result.Payload.GetPosition() == 0 {
|
||||
result.Payload.SetPosition(nil)
|
||||
}
|
||||
|
||||
return req.respond(accountId, results, sessionState, o.responseType, state, lang)
|
||||
return req.respond(accountId, result.Payload, o.responseType, result)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -274,7 +274,7 @@ 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) (RESP, jmap.SessionState, jmap.State, jmap.Language, jmap.Error),
|
||||
getFunc func(accountId string, ids []string, ctx jmap.Context) (jmap.Result[RESP], jmap.Error),
|
||||
) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
ok, accountId, resp := o.accountFunc(&req)
|
||||
@@ -298,20 +298,20 @@ func get[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T], RESP jmap.GetR
|
||||
|
||||
logger := log.From(l)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
objs, sessionState, state, lang, jerr := getFunc(accountId, ids, ctx)
|
||||
result, jerr := getFunc(accountId, ids, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
return req.jmapError(accountId, jerr, result)
|
||||
}
|
||||
|
||||
n := len(objs.GetList())
|
||||
n := len(result.Payload.GetList())
|
||||
switch n {
|
||||
case 0:
|
||||
return req.notFound(accountId, sessionState, ContactResponseObjectType, state)
|
||||
return req.notFound(accountId, ContactResponseObjectType, result)
|
||||
case 1:
|
||||
return req.respond(accountId, objs.GetList()[0], sessionState, ContactResponseObjectType, state, lang)
|
||||
return req.respond(accountId, result.Payload.GetList()[0], ContactResponseObjectType, result)
|
||||
default:
|
||||
logger.Error().Msgf("found %d %s matching '%s' instead of 1", n, o.responseType, ids)
|
||||
return req.errorS(accountId, req.apiError(&ErrorMultipleIdMatches), sessionState)
|
||||
return req.errorS(accountId, req.apiError(&ErrorMultipleIdMatches), result)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -323,7 +323,7 @@ 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) (map[string]RESP, jmap.SessionState, jmap.State, jmap.Language, jmap.Error),
|
||||
getFunc func(accountIds []string, ids []string, ctx jmap.Context) (jmap.Result[map[string]RESP], jmap.Error),
|
||||
) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
ok, accountId, resp := o.accountFunc(&req)
|
||||
@@ -343,24 +343,24 @@ func getFromMap[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T], RESP jm
|
||||
|
||||
logger := log.From(l)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
objMap, sessionState, state, lang, jerr := getFunc(single(accountId), single(id), ctx)
|
||||
result, jerr := getFunc(single(accountId), single(id), ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
return req.jmapError(accountId, jerr, result)
|
||||
}
|
||||
|
||||
if objs, ok := objMap[accountId]; ok {
|
||||
if objs, ok := result.Payload[accountId]; ok {
|
||||
n := len(objs.GetList())
|
||||
switch n {
|
||||
case 0:
|
||||
return req.notFound(accountId, sessionState, ContactResponseObjectType, state)
|
||||
return req.notFound(accountId, ContactResponseObjectType, result)
|
||||
case 1:
|
||||
return req.respond(accountId, objs.GetList()[0], sessionState, ContactResponseObjectType, state, lang)
|
||||
return req.respond(accountId, objs.GetList()[0], ContactResponseObjectType, result)
|
||||
default:
|
||||
logger.Error().Msgf("found %d %s matching '%s' instead of 1", n, o.responseType, id)
|
||||
return req.errorS(accountId, req.apiError(&ErrorMultipleIdMatches), sessionState)
|
||||
return req.errorS(accountId, req.apiError(&ErrorMultipleIdMatches), result)
|
||||
}
|
||||
} else {
|
||||
return req.notFound(accountId, sessionState, ContactResponseObjectType, state)
|
||||
return req.notFound(accountId, ContactResponseObjectType, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -374,7 +374,7 @@ func changes[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T]](
|
||||
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) (CHANGES, jmap.SessionState, jmap.State, jmap.Language, jmap.Error),
|
||||
changesFunc func(accountId string, sinceState jmap.State, maxChanges uint, ctx jmap.Context) (jmap.Result[CHANGES], jmap.Error),
|
||||
) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
ok, accountId, resp := o.accountFunc(&req)
|
||||
@@ -402,23 +402,24 @@ func changes[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T]](
|
||||
|
||||
logger := log.From(l)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
changes, sessionState, state, lang, jerr := changesFunc(accountId, sinceState, maxChanges, ctx)
|
||||
result, jerr := changesFunc(accountId, sinceState, maxChanges, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
return req.jmapError(accountId, jerr, result)
|
||||
}
|
||||
|
||||
return req.respond(accountId, changes, sessionState, o.responseType, state, lang)
|
||||
return req.respond(accountId, result.Payload, o.responseType, result)
|
||||
})
|
||||
}
|
||||
|
||||
// Delete a specific {{.Name}} referenced by its unique identifier as specified in the path parameter `{{.UriParamName}}` in the path `{{.Path}}`
|
||||
// @api:success 204
|
||||
// @api:response 204 when the referenced {{.Name}} has been deleted successfully
|
||||
// @api:response 404 when there is no {{.Name}} for the requested identifier
|
||||
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) (map[string]jmap.SetError, jmap.SessionState, jmap.State, jmap.Language, jmap.Error),
|
||||
deleteFunc func(accountId string, ids []string, ctx jmap.Context) (jmap.Result[map[string]jmap.SetError], jmap.Error),
|
||||
) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
ok, accountId, resp := o.accountFunc(&req)
|
||||
@@ -438,12 +439,12 @@ func delete[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T]]( //NOSONAR
|
||||
|
||||
logger := log.From(l)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
setErrors, sessionState, state, lang, jerr := deleteFunc(accountId, single(id), ctx)
|
||||
result, jerr := deleteFunc(accountId, single(id), ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
return req.jmapError(accountId, jerr, result)
|
||||
}
|
||||
|
||||
for _, e := range setErrors {
|
||||
for _, e := range result.Payload {
|
||||
desc := e.Description
|
||||
if desc != "" {
|
||||
return req.error(accountId, apiError(
|
||||
@@ -458,7 +459,7 @@ func delete[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T]]( //NOSONAR
|
||||
))
|
||||
}
|
||||
}
|
||||
return req.noContent(accountId, sessionState, o.responseType, state)
|
||||
return req.noContent(accountId, o.responseType, result)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -472,7 +473,7 @@ 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) (map[string]jmap.SetError, jmap.SessionState, jmap.State, jmap.Language, jmap.Error),
|
||||
deleteFunc func(accountId string, ids []string, ctx jmap.Context) (jmap.Result[map[string]jmap.SetError], jmap.Error),
|
||||
) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
ok, accountId, resp := o.accountFunc(&req)
|
||||
@@ -523,12 +524,12 @@ func deleteMany[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T]]( //NOSO
|
||||
|
||||
logger := log.From(l)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
setErrors, sessionState, state, lang, jerr := deleteFunc(accountId, ids, ctx)
|
||||
result, jerr := deleteFunc(accountId, ids, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
return req.jmapError(accountId, jerr, result)
|
||||
}
|
||||
|
||||
for _, e := range setErrors {
|
||||
for _, e := range result.Payload {
|
||||
desc := e.Description
|
||||
if desc != "" {
|
||||
return req.error(accountId, apiError(
|
||||
@@ -543,7 +544,7 @@ func deleteMany[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T]]( //NOSO
|
||||
))
|
||||
}
|
||||
}
|
||||
return req.noContent(accountId, sessionState, o.responseType, state)
|
||||
return req.noContent(accountId, o.responseType, result)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -553,7 +554,7 @@ 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) (T, jmap.SessionState, jmap.State, jmap.Language, jmap.Error),
|
||||
updateFunc func(accountId string, id string, change CHANGE, ctx jmap.Context) (jmap.Result[T], jmap.Error),
|
||||
) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
ok, accountId, resp := o.accountFunc(&req)
|
||||
@@ -579,10 +580,10 @@ func modify[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T]](
|
||||
|
||||
logger := log.From(l)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
updated, sessionState, state, lang, jerr := updateFunc(accountId, id, change, ctx)
|
||||
result, jerr := updateFunc(accountId, id, change, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
return req.jmapError(accountId, jerr, result)
|
||||
}
|
||||
return req.respond(accountId, updated, sessionState, o.responseType, state, lang)
|
||||
return req.respond(accountId, result.Payload, o.responseType, result)
|
||||
})
|
||||
}
|
||||
|
||||
28
services/groupware/pnpm-lock.yaml
generated
28
services/groupware/pnpm-lock.yaml
generated
@@ -9,8 +9,8 @@ importers:
|
||||
.:
|
||||
dependencies:
|
||||
'@redocly/cli':
|
||||
specifier: ^2.30.1
|
||||
version: 2.30.1(@opentelemetry/api@1.9.1)(core-js@3.45.1)
|
||||
specifier: ^2.30.2
|
||||
version: 2.30.2(@opentelemetry/api@1.9.1)(core-js@3.45.1)
|
||||
'@types/js-yaml':
|
||||
specifier: ^4.0.9
|
||||
version: 4.0.9
|
||||
@@ -197,8 +197,8 @@ packages:
|
||||
'@redocly/cli-otel@0.1.2':
|
||||
resolution: {integrity: sha512-Bg7BoO5t1x3lVK+KhA5aGPmeXpQmdf6WtTYHhelKJCsQ+tRMiJoFAQoKHoBHAoNxXrhlS3K9lKFLHGmtxsFQfA==}
|
||||
|
||||
'@redocly/cli@2.30.1':
|
||||
resolution: {integrity: sha512-n5lRNAuA5Sz+pFn6VKhngUlj3E6bR0NtUF3eWzsuVWc3ffu5TyLhD12xRcASyi+aW7Z1z33/leGwIvKRKeG3xg==}
|
||||
'@redocly/cli@2.30.2':
|
||||
resolution: {integrity: sha512-DWTydfVgEJkqDMcriRuy+MX+IYaEPU0AvV/nKuT1/1ajTugofkxlClHfZOK8Kwv47qAHvZ9w3oF+WCP/fVyW2g==}
|
||||
engines: {node: '>=22.12.0 || >=20.19.0 <21.0.0', npm: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
@@ -212,12 +212,12 @@ packages:
|
||||
resolution: {integrity: sha512-4Tm4ysZkexx6ZTX7knqSZTqPlNgIvXc7Ha0pd30I694/GD0KtJE2xrElycfPds0vCLFAqoKyIzBtOF1xrLo8KA==}
|
||||
engines: {node: '>=18.17.0', npm: '>=9.5.0'}
|
||||
|
||||
'@redocly/openapi-core@2.30.1':
|
||||
resolution: {integrity: sha512-ggv0nRy9Y7D1PxsmXE8MWU/x6EOVC/njZw1s7Z5TVt7OzHzLUiB2AroZzsU1dIMl2KRm4n3ygdo2VlNAAovyGQ==}
|
||||
'@redocly/openapi-core@2.30.2':
|
||||
resolution: {integrity: sha512-J1UB/I1s9eRpirIVgzH/B1Jj+hYQHYExruLk+edPOqneFIlFc38wKiTRkj/TVpwcmzRHJNu5SSI6NTrrfPa4BA==}
|
||||
engines: {node: '>=22.12.0 || >=20.19.0 <21.0.0', npm: '>=10'}
|
||||
|
||||
'@redocly/respect-core@2.30.1':
|
||||
resolution: {integrity: sha512-b3IiUa+oFcUppfUNcNubyKJ1/Gnt8brlU2+MrF0E+tpFJANMLXejQ0DcNN7t6lq2ZgCyp9DDK76tlJMmOIIcAQ==}
|
||||
'@redocly/respect-core@2.30.2':
|
||||
resolution: {integrity: sha512-4dVg57ItG19MGsLWDPmbUid81kHEbGqLcSSp1Q/8wHGJVzxmFgX9JOkqEw059/dwCYjP+txPhcMDORh0pK9ivQ==}
|
||||
engines: {node: '>=22.12.0 || >=20.19.0 <21.0.0', npm: '>=10'}
|
||||
|
||||
'@tsconfig/node10@1.0.12':
|
||||
@@ -1133,15 +1133,15 @@ snapshots:
|
||||
dependencies:
|
||||
ulid: 2.4.0
|
||||
|
||||
'@redocly/cli@2.30.1(@opentelemetry/api@1.9.1)(core-js@3.45.1)':
|
||||
'@redocly/cli@2.30.2(@opentelemetry/api@1.9.1)(core-js@3.45.1)':
|
||||
dependencies:
|
||||
'@opentelemetry/exporter-trace-otlp-http': 0.214.0(@opentelemetry/api@1.9.1)
|
||||
'@opentelemetry/resources': 2.6.1(@opentelemetry/api@1.9.1)
|
||||
'@opentelemetry/sdk-trace-node': 2.6.1(@opentelemetry/api@1.9.1)
|
||||
'@opentelemetry/semantic-conventions': 1.40.0
|
||||
'@redocly/cli-otel': 0.1.2
|
||||
'@redocly/openapi-core': 2.30.1
|
||||
'@redocly/respect-core': 2.30.1
|
||||
'@redocly/openapi-core': 2.30.2
|
||||
'@redocly/respect-core': 2.30.2
|
||||
ajv: '@redocly/ajv@8.18.0'
|
||||
ajv-formats: 3.0.1(@redocly/ajv@8.18.0)
|
||||
colorette: 1.4.0
|
||||
@@ -1192,7 +1192,7 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@redocly/openapi-core@2.30.1':
|
||||
'@redocly/openapi-core@2.30.2':
|
||||
dependencies:
|
||||
'@redocly/ajv': 8.18.0
|
||||
'@redocly/config': 0.48.1
|
||||
@@ -1205,12 +1205,12 @@ snapshots:
|
||||
pluralize: 8.0.0
|
||||
yaml-ast-parser: 0.0.43
|
||||
|
||||
'@redocly/respect-core@2.30.1':
|
||||
'@redocly/respect-core@2.30.2':
|
||||
dependencies:
|
||||
'@faker-js/faker': 7.6.0
|
||||
'@noble/hashes': 1.8.0
|
||||
'@redocly/ajv': 8.18.0
|
||||
'@redocly/openapi-core': 2.30.1
|
||||
'@redocly/openapi-core': 2.30.2
|
||||
ajv: '@redocly/ajv@8.18.0'
|
||||
better-ajv-errors: 1.2.0(@redocly/ajv@8.18.0)
|
||||
colorette: 2.0.20
|
||||
|
||||
Reference in New Issue
Block a user