mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-04-13 20:07:41 -04:00
groupware: refactor for conciseness
* introduce jmap.Context to hold multiple parameters and shorten function calls * introduce SearchResultsTemplate
This commit is contained in:
@@ -8,8 +8,23 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
)
|
||||
|
||||
type Context struct {
|
||||
Session *Session
|
||||
Context context.Context
|
||||
Logger *log.Logger
|
||||
AcceptLanguage string
|
||||
}
|
||||
|
||||
func (c Context) WithLogger(newLogger *log.Logger) Context {
|
||||
return Context{Session: c.Session, Context: c.Context, AcceptLanguage: c.AcceptLanguage, Logger: newLogger}
|
||||
}
|
||||
|
||||
func (c Context) WithContext(newContext context.Context) Context {
|
||||
return Context{Session: c.Session, Context: newContext, AcceptLanguage: c.AcceptLanguage, Logger: c.Logger}
|
||||
}
|
||||
|
||||
type ApiClient interface {
|
||||
Command(ctx context.Context, logger *log.Logger, session *Session, request Request, acceptLanguage string) ([]byte, Language, Error)
|
||||
Command(request Request, ctx Context) ([]byte, Language, Error)
|
||||
io.Closer
|
||||
}
|
||||
|
||||
@@ -33,8 +48,8 @@ type SessionClient interface {
|
||||
}
|
||||
|
||||
type BlobClient interface {
|
||||
UploadBinary(ctx context.Context, logger *log.Logger, session *Session, uploadUrl string, endpoint string, contentType string, acceptLanguage string, content io.Reader) (UploadedBlob, Language, Error)
|
||||
DownloadBinary(ctx context.Context, logger *log.Logger, session *Session, downloadUrl string, endpoint string, acceptLanguage string) (*BlobDownload, Language, Error)
|
||||
UploadBinary(uploadUrl string, endpoint string, contentType string, content io.Reader, ctx Context) (UploadedBlob, Language, Error)
|
||||
DownloadBinary(downloadUrl string, endpoint string, ctx Context) (*BlobDownload, Language, Error)
|
||||
io.Closer
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +1,16 @@
|
||||
package jmap
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
)
|
||||
|
||||
var NS_ADDRESSBOOKS = ns(JmapContacts)
|
||||
|
||||
func (j *Client) GetAddressbooks(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, ids []string) (AddressBookGetResponse, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetAddressbooks(accountId string, ids []string, ctx Context) (AddressBookGetResponse, SessionState, State, Language, Error) {
|
||||
return get(j, "GetAddressbooks", NS_ADDRESSBOOKS,
|
||||
func(accountId string, ids []string) AddressBookGetCommand {
|
||||
return AddressBookGetCommand{AccountId: accountId, Ids: ids}
|
||||
},
|
||||
AddressBookGetResponse{},
|
||||
identity1,
|
||||
accountId, session, ctx, logger, acceptLanguage, ids,
|
||||
accountId, ids,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -23,10 +18,10 @@ type AddressBookChanges = ChangesTemplate[AddressBook]
|
||||
|
||||
// Retrieve Address Book changes since a given state.
|
||||
// @apidoc addressbook,changes
|
||||
func (j *Client) GetAddressbookChanges(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, sinceState State, maxChanges uint) (AddressBookChanges, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetAddressbookChanges(accountId string, sinceState State, maxChanges uint, ctx Context) (AddressBookChanges, SessionState, State, Language, Error) {
|
||||
return changesA(j, "GetAddressbookChanges", NS_ADDRESSBOOKS,
|
||||
func() AddressBookChangesCommand {
|
||||
return AddressBookChangesCommand{AccountId: accountId, SinceState: sinceState, MaxChanges: posUIntPtr(maxChanges)}
|
||||
return AddressBookChangesCommand{AccountId: accountId, SinceState: sinceState, MaxChanges: uintPtr(maxChanges)}
|
||||
},
|
||||
AddressBookChangesResponse{},
|
||||
AddressBookGetResponse{},
|
||||
@@ -50,11 +45,11 @@ func (j *Client) GetAddressbookChanges(accountId string, session *Session, ctx c
|
||||
Destroyed: destroyed,
|
||||
}
|
||||
},
|
||||
session, ctx, logger, acceptLanguage,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) CreateAddressBook(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, addressbook AddressBookChange) (*AddressBook, SessionState, State, Language, Error) {
|
||||
func (j *Client) CreateAddressBook(accountId string, addressbook AddressBookChange, ctx Context) (*AddressBook, SessionState, State, Language, Error) {
|
||||
return create(j, "CreateAddressBook", NS_ADDRESSBOOKS,
|
||||
func(accountId string, create map[string]AddressBookChange) AddressBookSetCommand {
|
||||
return AddressBookSetCommand{AccountId: accountId, Create: create}
|
||||
@@ -68,21 +63,23 @@ func (j *Client) CreateAddressBook(accountId string, session *Session, ctx conte
|
||||
func(resp AddressBookGetResponse) []AddressBook {
|
||||
return resp.List
|
||||
},
|
||||
accountId, session, ctx, logger, acceptLanguage, addressbook,
|
||||
accountId, addressbook,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) DeleteAddressBook(accountId string, destroyIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (map[string]SetError, SessionState, State, Language, Error) {
|
||||
func (j *Client) DeleteAddressBook(accountId string, destroyIds []string, ctx Context) (map[string]SetError, SessionState, State, Language, Error) {
|
||||
return destroy(j, "DeleteAddressBook", NS_ADDRESSBOOKS,
|
||||
func(accountId string, destroy []string) AddressBookSetCommand {
|
||||
return AddressBookSetCommand{AccountId: accountId, Destroy: destroy}
|
||||
},
|
||||
AddressBookSetResponse{},
|
||||
accountId, destroyIds, session, ctx, logger, acceptLanguage,
|
||||
accountId, destroyIds,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) UpdateAddressBook(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, id string, changes AddressBookChange) (AddressBook, SessionState, State, Language, Error) {
|
||||
func (j *Client) UpdateAddressBook(accountId string, id string, changes AddressBookChange, ctx Context) (AddressBook, SessionState, State, Language, Error) {
|
||||
return update(j, "UpdateAddressBook", NS_ADDRESSBOOKS,
|
||||
func(update map[string]PatchObject) AddressBookSetCommand {
|
||||
return AddressBookSetCommand{AccountId: accountId, Update: update}
|
||||
@@ -92,6 +89,7 @@ func (j *Client) UpdateAddressBook(accountId string, session *Session, ctx conte
|
||||
},
|
||||
func(resp AddressBookSetResponse) map[string]SetError { return resp.NotUpdated },
|
||||
func(resp AddressBookGetResponse) AddressBook { return resp.List[0] },
|
||||
id, changes, session, ctx, logger, acceptLanguage,
|
||||
id, changes,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package jmap
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"io"
|
||||
"strings"
|
||||
@@ -9,28 +8,31 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
)
|
||||
|
||||
func (j *Client) GetBlobMetadata(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, id string) (*Blob, SessionState, State, Language, Error) {
|
||||
cmd, jerr := j.request(session, logger, ns(JmapBlob),
|
||||
invocation(BlobGetCommand{
|
||||
AccountId: accountId,
|
||||
Ids: []string{id},
|
||||
// add BlobPropertyData to retrieve the data
|
||||
Properties: []string{BlobPropertyDigestSha256, BlobPropertyDigestSha512, BlobPropertySize},
|
||||
}, "0"),
|
||||
var NS_BLOB = ns(JmapBlob)
|
||||
|
||||
func (j *Client) GetBlobMetadata(accountId string, id string, ctx Context) (*Blob, SessionState, State, Language, Error) {
|
||||
get := BlobGetCommand{
|
||||
AccountId: accountId,
|
||||
Ids: []string{id},
|
||||
// add BlobPropertyData to retrieve the data
|
||||
Properties: []string{BlobPropertyDigestSha256, BlobPropertyDigestSha512, BlobPropertySize},
|
||||
}
|
||||
cmd, jerr := j.request(ctx, NS_BLOB,
|
||||
invocation(get, "0"),
|
||||
)
|
||||
if jerr != nil {
|
||||
return nil, "", "", "", jerr
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (*Blob, State, Error) {
|
||||
return command(j, ctx, cmd, func(body *Response) (*Blob, State, Error) {
|
||||
var response BlobGetResponse
|
||||
err := retrieveResponseMatchParameters(logger, body, CommandBlobGet, "0", &response)
|
||||
err := retrieveGet(ctx, body, get, "0", &response)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
if len(response.List) != 1 {
|
||||
logger.Error().Msgf("%T.List has %v entries instead of 1", response, len(response.List))
|
||||
ctx.Logger.Error().Msgf("%T.List has %v entries instead of 1", response, len(response.List))
|
||||
return nil, "", jmapError(err, JmapErrorInvalidJmapResponsePayload)
|
||||
}
|
||||
get := response.List[0]
|
||||
@@ -45,26 +47,28 @@ type UploadedBlobWithHash struct {
|
||||
Sha512 string `json:"sha:512,omitempty"`
|
||||
}
|
||||
|
||||
func (j *Client) UploadBlobStream(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, contentType string, body io.Reader) (UploadedBlob, Language, Error) {
|
||||
logger = log.From(logger.With().Str(logEndpoint, session.UploadEndpoint))
|
||||
func (j *Client) UploadBlobStream(accountId string, contentType string, body io.Reader, ctx Context) (UploadedBlob, Language, Error) {
|
||||
logger := log.From(ctx.Logger.With().Str(logEndpoint, ctx.Session.UploadEndpoint))
|
||||
ctx = ctx.WithLogger(logger)
|
||||
// TODO(pbleser-oc) use a library for proper URL template parsing
|
||||
uploadUrl := strings.ReplaceAll(session.UploadUrlTemplate, "{accountId}", accountId)
|
||||
return j.blob.UploadBinary(ctx, logger, session, uploadUrl, session.UploadEndpoint, contentType, acceptLanguage, body)
|
||||
uploadUrl := strings.ReplaceAll(ctx.Session.UploadUrlTemplate, "{accountId}", accountId)
|
||||
return j.blob.UploadBinary(uploadUrl, ctx.Session.UploadEndpoint, contentType, body, ctx)
|
||||
}
|
||||
|
||||
func (j *Client) DownloadBlobStream(accountId string, blobId string, name string, typ string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (*BlobDownload, Language, Error) { //NOSONAR
|
||||
logger = log.From(logger.With().Str(logEndpoint, session.DownloadEndpoint))
|
||||
func (j *Client) DownloadBlobStream(accountId string, blobId string, name string, typ string, ctx Context) (*BlobDownload, Language, Error) { //NOSONAR
|
||||
logger := log.From(ctx.Logger.With().Str(logEndpoint, ctx.Session.DownloadEndpoint))
|
||||
ctx = ctx.WithLogger(logger)
|
||||
// TODO(pbleser-oc) use a library for proper URL template parsing
|
||||
downloadUrl := session.DownloadUrlTemplate
|
||||
downloadUrl := ctx.Session.DownloadUrlTemplate
|
||||
downloadUrl = strings.ReplaceAll(downloadUrl, "{accountId}", accountId)
|
||||
downloadUrl = strings.ReplaceAll(downloadUrl, "{blobId}", blobId)
|
||||
downloadUrl = strings.ReplaceAll(downloadUrl, "{name}", name)
|
||||
downloadUrl = strings.ReplaceAll(downloadUrl, "{type}", typ)
|
||||
logger = log.From(logger.With().Str(logDownloadUrl, downloadUrl).Str(logBlobId, blobId))
|
||||
return j.blob.DownloadBinary(ctx, logger, session, downloadUrl, session.DownloadEndpoint, acceptLanguage)
|
||||
return j.blob.DownloadBinary(downloadUrl, ctx.Session.DownloadEndpoint, ctx)
|
||||
}
|
||||
|
||||
func (j *Client) UploadBlob(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, data []byte, contentType string) (UploadedBlobWithHash, SessionState, State, Language, Error) {
|
||||
func (j *Client) UploadBlob(accountId string, data []byte, contentType string, ctx Context) (UploadedBlobWithHash, SessionState, State, Language, Error) {
|
||||
encoded := base64.StdEncoding.EncodeToString(data)
|
||||
|
||||
upload := BlobUploadCommand{
|
||||
@@ -89,7 +93,7 @@ func (j *Client) UploadBlob(accountId string, session *Session, ctx context.Cont
|
||||
Properties: []string{BlobPropertyDigestSha512},
|
||||
}
|
||||
|
||||
cmd, jerr := j.request(session, logger, ns(JmapBlob),
|
||||
cmd, jerr := j.request(ctx, ns(JmapBlob),
|
||||
invocation(upload, "0"),
|
||||
invocation(getHash, "1"),
|
||||
)
|
||||
@@ -97,31 +101,31 @@ func (j *Client) UploadBlob(accountId string, session *Session, ctx context.Cont
|
||||
return UploadedBlobWithHash{}, "", "", "", jerr
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (UploadedBlobWithHash, State, Error) {
|
||||
return command(j, ctx, cmd, func(body *Response) (UploadedBlobWithHash, State, Error) {
|
||||
var uploadResponse BlobUploadResponse
|
||||
err := retrieveResponseMatchParameters(logger, body, upload.GetCommand(), "0", &uploadResponse)
|
||||
err := retrieveUpload(ctx, body, upload, "0", &uploadResponse)
|
||||
if err != nil {
|
||||
return UploadedBlobWithHash{}, "", err
|
||||
}
|
||||
|
||||
var getResponse BlobGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, getHash.GetCommand(), "1", &getResponse)
|
||||
err = retrieveGet(ctx, body, getHash, "1", &getResponse)
|
||||
if err != nil {
|
||||
return UploadedBlobWithHash{}, "", err
|
||||
}
|
||||
|
||||
if len(uploadResponse.Created) != 1 {
|
||||
logger.Error().Msgf("%T.Created has %v entries instead of 1", uploadResponse, len(uploadResponse.Created))
|
||||
ctx.Logger.Error().Msgf("%T.Created has %v entries instead of 1", uploadResponse, len(uploadResponse.Created))
|
||||
return UploadedBlobWithHash{}, "", jmapError(err, JmapErrorInvalidJmapResponsePayload)
|
||||
}
|
||||
upload, ok := uploadResponse.Created["0"]
|
||||
if !ok {
|
||||
logger.Error().Msgf("%T.Created has no item '0'", uploadResponse)
|
||||
ctx.Logger.Error().Msgf("%T.Created has no item '0'", uploadResponse)
|
||||
return UploadedBlobWithHash{}, "", jmapError(err, JmapErrorInvalidJmapResponsePayload)
|
||||
}
|
||||
|
||||
if len(getResponse.List) != 1 {
|
||||
logger.Error().Msgf("%T.List has %v entries instead of 1", getResponse, len(getResponse.List))
|
||||
ctx.Logger.Error().Msgf("%T.List has %v entries instead of 1", getResponse, len(getResponse.List))
|
||||
return UploadedBlobWithHash{}, "", jmapError(err, JmapErrorInvalidJmapResponsePayload)
|
||||
}
|
||||
get := getResponse.List[0]
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
package jmap
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
"github.com/opencloud-eu/opencloud/pkg/structs"
|
||||
)
|
||||
|
||||
@@ -14,10 +11,11 @@ type AccountBootstrapResult struct {
|
||||
|
||||
var NS_MAIL_QUOTA = ns(JmapMail, JmapQuota)
|
||||
|
||||
func (j *Client) GetBootstrap(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (map[string]AccountBootstrapResult, SessionState, State, Language, Error) { //NOSONAR
|
||||
func (j *Client) GetBootstrap(accountIds []string, ctx Context) (map[string]AccountBootstrapResult, SessionState, State, Language, Error) { //NOSONAR
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
|
||||
logger = j.logger("GetBootstrap", session, logger)
|
||||
logger := j.logger("GetBootstrap", ctx)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
calls := make([]Invocation, len(uniqueAccountIds)*2)
|
||||
for i, accountId := range uniqueAccountIds {
|
||||
@@ -25,18 +23,18 @@ func (j *Client) GetBootstrap(accountIds []string, session *Session, ctx context
|
||||
calls[i*2+1] = invocation(QuotaGetCommand{AccountId: accountId}, mcid(accountId, "Q"))
|
||||
}
|
||||
|
||||
cmd, err := j.request(session, logger, NS_MAIL_QUOTA, calls...)
|
||||
cmd, err := j.request(ctx, NS_MAIL_QUOTA, calls...)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
}
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (map[string]AccountBootstrapResult, State, Error) {
|
||||
return command(j, ctx, cmd, func(body *Response) (map[string]AccountBootstrapResult, State, Error) {
|
||||
identityPerAccount := map[string][]Identity{}
|
||||
quotaPerAccount := map[string][]Quota{}
|
||||
identityStatesPerAccount := map[string]State{}
|
||||
quotaStatesPerAccount := map[string]State{}
|
||||
for _, accountId := range uniqueAccountIds {
|
||||
var identityResponse IdentityGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandIdentityGet, mcid(accountId, "I"), &identityResponse)
|
||||
err = retrieveResponseMatchParameters(ctx, body, CommandIdentityGet, mcid(accountId, "I"), &identityResponse)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
} else {
|
||||
@@ -45,7 +43,7 @@ func (j *Client) GetBootstrap(accountIds []string, session *Session, ctx context
|
||||
}
|
||||
|
||||
var quotaResponse QuotaGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandQuotaGet, mcid(accountId, "Q"), "aResponse)
|
||||
err = retrieveResponseMatchParameters(ctx, body, CommandQuotaGet, mcid(accountId, "Q"), "aResponse)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
} else {
|
||||
|
||||
@@ -1,27 +1,21 @@
|
||||
package jmap
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
"github.com/opencloud-eu/opencloud/pkg/structs"
|
||||
)
|
||||
|
||||
var NS_CALENDARS = ns(JmapCalendars)
|
||||
|
||||
func (j *Client) ParseICalendarBlob(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, blobIds []string) (CalendarEventParseResponse, SessionState, State, Language, Error) {
|
||||
logger = j.logger("ParseICalendarBlob", session, logger)
|
||||
func (j *Client) ParseICalendarBlob(accountId string, blobIds []string, ctx Context) (CalendarEventParseResponse, SessionState, State, Language, Error) {
|
||||
logger := j.logger("ParseICalendarBlob", ctx)
|
||||
|
||||
cmd, err := j.request(session, logger, NS_CALENDARS,
|
||||
invocation(CalendarEventParseCommand{AccountId: accountId, BlobIds: blobIds}, "0"),
|
||||
parse := CalendarEventParseCommand{AccountId: accountId, BlobIds: blobIds}
|
||||
cmd, err := j.request(ctx.WithLogger(logger), NS_CALENDARS,
|
||||
invocation(parse, "0"),
|
||||
)
|
||||
if err != nil {
|
||||
return CalendarEventParseResponse{}, "", "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (CalendarEventParseResponse, State, Error) {
|
||||
return command(j, ctx, cmd, func(body *Response) (CalendarEventParseResponse, State, Error) {
|
||||
var response CalendarEventParseResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandCalendarEventParse, "0", &response)
|
||||
err = retrieveParse(ctx, body, parse, "0", &response)
|
||||
if err != nil {
|
||||
return CalendarEventParseResponse{}, "", err
|
||||
}
|
||||
@@ -29,14 +23,15 @@ func (j *Client) ParseICalendarBlob(accountId string, session *Session, ctx cont
|
||||
})
|
||||
}
|
||||
|
||||
func (j *Client) GetCalendars(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, ids []string) (CalendarGetResponse, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetCalendars(accountId string, ids []string, ctx Context) (CalendarGetResponse, SessionState, State, Language, Error) {
|
||||
return get(j, "GetCalendars", NS_CALENDARS,
|
||||
func(accountId string, ids []string) CalendarGetCommand {
|
||||
return CalendarGetCommand{AccountId: accountId, Ids: ids}
|
||||
},
|
||||
CalendarGetResponse{},
|
||||
identity1,
|
||||
accountId, session, ctx, logger, acceptLanguage, ids,
|
||||
accountId, ids,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -44,10 +39,10 @@ type CalendarChanges = ChangesTemplate[Calendar]
|
||||
|
||||
// Retrieve Calendar changes since a given state.
|
||||
// @apidoc calendar,changes
|
||||
func (j *Client) GetCalendarChanges(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, sinceState State, maxChanges uint) (CalendarChanges, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetCalendarChanges(accountId string, sinceState State, maxChanges uint, ctx Context) (CalendarChanges, SessionState, State, Language, Error) {
|
||||
return changes(j, "GetCalendarChanges", NS_CALENDARS,
|
||||
func() CalendarChangesCommand {
|
||||
return CalendarChangesCommand{AccountId: accountId, SinceState: sinceState, MaxChanges: posUIntPtr(maxChanges)}
|
||||
return CalendarChangesCommand{AccountId: accountId, SinceState: sinceState, MaxChanges: uintPtr(maxChanges)}
|
||||
},
|
||||
CalendarChangesResponse{},
|
||||
func(path string, rof string) CalendarGetRefCommand {
|
||||
@@ -71,78 +66,55 @@ func (j *Client) GetCalendarChanges(accountId string, session *Session, ctx cont
|
||||
Destroyed: destroyed,
|
||||
}
|
||||
},
|
||||
session, ctx, logger, acceptLanguage,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) QueryCalendarEvents(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, //NOSONAR
|
||||
type CalendarEventSearchResults SearchResultsTemplate[CalendarEvent]
|
||||
|
||||
var _ SearchResults[CalendarEvent] = CalendarEventSearchResults{}
|
||||
|
||||
func (r CalendarEventSearchResults) GetResults() []CalendarEvent { return r.Results }
|
||||
func (r CalendarEventSearchResults) GetCanCalculateChanges() bool { return r.CanCalculateChanges }
|
||||
func (r CalendarEventSearchResults) GetPosition() uint { return r.Position }
|
||||
func (r CalendarEventSearchResults) GetLimit() uint { return r.Limit }
|
||||
func (r CalendarEventSearchResults) GetTotal() *uint { return r.Total }
|
||||
|
||||
func (j *Client) QueryCalendarEvents(accountIds []string, //NOSONAR
|
||||
filter CalendarEventFilterElement, sortBy []CalendarEventComparator,
|
||||
position uint, limit uint) (map[string][]CalendarEvent, SessionState, State, Language, Error) {
|
||||
logger = j.logger("QueryCalendarEvents", session, logger)
|
||||
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
|
||||
if sortBy == nil {
|
||||
sortBy = []CalendarEventComparator{{Property: CalendarEventPropertyStart, IsAscending: false}}
|
||||
}
|
||||
|
||||
invocations := make([]Invocation, len(uniqueAccountIds)*2)
|
||||
for i, accountId := range uniqueAccountIds {
|
||||
query := CalendarEventQueryCommand{
|
||||
AccountId: accountId,
|
||||
Filter: filter,
|
||||
Sort: sortBy,
|
||||
}
|
||||
if limit > 0 {
|
||||
query.Limit = limit
|
||||
}
|
||||
if position > 0 {
|
||||
query.Position = position
|
||||
}
|
||||
invocations[i*2+0] = invocation(query, mcid(accountId, "0"))
|
||||
invocations[i*2+1] = invocation(CalendarEventGetRefCommand{
|
||||
AccountId: accountId,
|
||||
IdsRef: &ResultReference{
|
||||
Name: CommandCalendarEventQuery,
|
||||
Path: "/ids/*",
|
||||
ResultOf: mcid(accountId, "0"),
|
||||
},
|
||||
// Properties: CalendarEventProperties, // to also retrieve UTCStart and UTCEnd
|
||||
}, mcid(accountId, "1"))
|
||||
}
|
||||
cmd, err := j.request(session, logger, NS_CALENDARS, invocations...)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (map[string][]CalendarEvent, State, Error) {
|
||||
resp := map[string][]CalendarEvent{}
|
||||
stateByAccountId := map[string]State{}
|
||||
for _, accountId := range uniqueAccountIds {
|
||||
var response CalendarEventGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandCalendarEventGet, mcid(accountId, "1"), &response)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
position int, limit uint, calculateTotal bool,
|
||||
ctx Context) (map[string]CalendarEventSearchResults, SessionState, State, Language, Error) {
|
||||
return queryN(j, "QueryCalendarEvents", NS_CALENDARS,
|
||||
[]CalendarEventComparator{{Property: CalendarEventPropertyStart, IsAscending: false}},
|
||||
func(accountId string, filter CalendarEventFilterElement, sortBy []CalendarEventComparator, position int, limit uint) CalendarEventQueryCommand {
|
||||
return CalendarEventQueryCommand{AccountId: accountId, Filter: filter, Sort: sortBy, Position: position, Limit: uintPtr(limit), CalculateTotal: calculateTotal}
|
||||
},
|
||||
func(accountId string, cmd Command, path string, rof string) CalendarEventGetRefCommand {
|
||||
return CalendarEventGetRefCommand{AccountId: accountId, IdsRef: &ResultReference{Name: cmd, Path: path, ResultOf: rof}}
|
||||
},
|
||||
func(query CalendarEventQueryResponse, get CalendarEventGetResponse) CalendarEventSearchResults {
|
||||
return CalendarEventSearchResults{
|
||||
Results: get.List,
|
||||
CanCalculateChanges: query.CanCalculateChanges,
|
||||
Position: query.Position,
|
||||
Total: uintPtrIf(query.Total, calculateTotal),
|
||||
Limit: query.Limit,
|
||||
}
|
||||
if len(response.NotFound) > 0 {
|
||||
// TODO what to do when there are not-found calendarevents here? potentially nothing, they could have been deleted between query and get?
|
||||
}
|
||||
resp[accountId] = response.List
|
||||
stateByAccountId[accountId] = response.State
|
||||
}
|
||||
return resp, squashState(stateByAccountId), nil
|
||||
})
|
||||
},
|
||||
accountIds,
|
||||
filter, sortBy, limit, position, ctx,
|
||||
)
|
||||
}
|
||||
|
||||
type CalendarEventChanges = ChangesTemplate[CalendarEvent]
|
||||
|
||||
// Retrieve the changes in Calendar Events since a given State.
|
||||
// @api:tags event,changes
|
||||
func (j *Client) GetCalendarEventChanges(accountId string, session *Session, ctx context.Context, logger *log.Logger,
|
||||
acceptLanguage string, sinceState State, maxChanges uint) (CalendarEventChanges, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetCalendarEventChanges(accountId string, sinceState State, maxChanges uint,
|
||||
ctx Context) (CalendarEventChanges, SessionState, State, Language, Error) {
|
||||
return changes(j, "GetCalendarEventChanges", NS_CALENDARS,
|
||||
func() CalendarEventChangesCommand {
|
||||
return CalendarEventChangesCommand{AccountId: accountId, SinceState: sinceState, MaxChanges: posUIntPtr(maxChanges)}
|
||||
return CalendarEventChangesCommand{AccountId: accountId, SinceState: sinceState, MaxChanges: uintPtr(maxChanges)}
|
||||
},
|
||||
CalendarEventChangesResponse{},
|
||||
func(path string, rof string) CalendarEventGetRefCommand {
|
||||
@@ -166,11 +138,11 @@ func (j *Client) GetCalendarEventChanges(accountId string, session *Session, ctx
|
||||
Destroyed: destroyed,
|
||||
}
|
||||
},
|
||||
session, ctx, logger, acceptLanguage,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) CreateCalendarEvent(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, event CalendarEvent) (*CalendarEvent, SessionState, State, Language, Error) {
|
||||
func (j *Client) CreateCalendarEvent(accountId string, event CalendarEvent, ctx Context) (*CalendarEvent, SessionState, State, Language, Error) {
|
||||
return create(j, "CreateCalendarEvent", NS_CALENDARS,
|
||||
func(accountId string, create map[string]CalendarEvent) CalendarEventSetCommand {
|
||||
return CalendarEventSetCommand{AccountId: accountId, Create: create}
|
||||
@@ -184,19 +156,23 @@ func (j *Client) CreateCalendarEvent(accountId string, session *Session, ctx con
|
||||
func(resp CalendarEventGetResponse) []CalendarEvent {
|
||||
return resp.List
|
||||
},
|
||||
accountId, session, ctx, logger, acceptLanguage, event)
|
||||
accountId, event,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) DeleteCalendarEvent(accountId string, destroyIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (map[string]SetError, SessionState, State, Language, Error) {
|
||||
func (j *Client) DeleteCalendarEvent(accountId string, destroyIds []string, ctx Context) (map[string]SetError, SessionState, State, Language, Error) {
|
||||
return destroy(j, "DeleteCalendarEvent", NS_CALENDARS,
|
||||
func(accountId string, destroy []string) CalendarEventSetCommand {
|
||||
return CalendarEventSetCommand{AccountId: accountId, Destroy: destroy}
|
||||
},
|
||||
CalendarEventSetResponse{},
|
||||
accountId, destroyIds, session, ctx, logger, acceptLanguage)
|
||||
accountId, destroyIds,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) CreateCalendar(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, calendar CalendarChange) (*Calendar, SessionState, State, Language, Error) {
|
||||
func (j *Client) CreateCalendar(accountId string, calendar CalendarChange, ctx Context) (*Calendar, SessionState, State, Language, Error) {
|
||||
return create(j, "CreateCalendar", NS_CALENDARS,
|
||||
func(accountId string, create map[string]CalendarChange) CalendarSetCommand {
|
||||
return CalendarSetCommand{AccountId: accountId, Create: create}
|
||||
@@ -210,21 +186,23 @@ func (j *Client) CreateCalendar(accountId string, session *Session, ctx context.
|
||||
func(resp CalendarGetResponse) []Calendar {
|
||||
return resp.List
|
||||
},
|
||||
accountId, session, ctx, logger, acceptLanguage, calendar,
|
||||
accountId, calendar,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) DeleteCalendar(accountId string, destroyIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (map[string]SetError, SessionState, State, Language, Error) {
|
||||
func (j *Client) DeleteCalendar(accountId string, destroyIds []string, ctx Context) (map[string]SetError, SessionState, State, Language, Error) {
|
||||
return destroy(j, "DeleteCalendar", NS_CALENDARS,
|
||||
func(accountId string, destroy []string) CalendarSetCommand {
|
||||
return CalendarSetCommand{AccountId: accountId, Destroy: destroy}
|
||||
},
|
||||
CalendarSetResponse{},
|
||||
accountId, destroyIds, session, ctx, logger, acceptLanguage,
|
||||
accountId, destroyIds,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) UpdateCalendar(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, id string, changes CalendarChange) (Calendar, SessionState, State, Language, Error) {
|
||||
func (j *Client) UpdateCalendar(accountId string, id string, changes CalendarChange, ctx Context) (Calendar, SessionState, State, Language, Error) {
|
||||
return update(j, "UpdateCalendar", NS_CALENDARS,
|
||||
func(update map[string]PatchObject) CalendarSetCommand {
|
||||
return CalendarSetCommand{AccountId: accountId, Update: update}
|
||||
@@ -234,6 +212,7 @@ func (j *Client) UpdateCalendar(accountId string, session *Session, ctx context.
|
||||
},
|
||||
func(resp CalendarSetResponse) map[string]SetError { return resp.NotUpdated },
|
||||
func(resp CalendarGetResponse) Calendar { return resp.List[0] },
|
||||
id, changes, session, ctx, logger, acceptLanguage,
|
||||
id, changes,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package jmap
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
@@ -76,49 +74,50 @@ 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, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, stateMap StateMap, maxChanges uint) (Changes, SessionState, State, Language, Error) { //NOSONAR
|
||||
logger = log.From(j.logger("GetChanges", session, logger).With().Object("state", stateMap).Uint("maxChanges", maxChanges))
|
||||
func (j *Client) GetChanges(accountId string, stateMap StateMap, maxChanges uint, ctx Context) (Changes, SessionState, State, Language, Error) { //NOSONAR
|
||||
logger := log.From(j.logger("GetChanges", ctx).With().Object("state", stateMap).Uint("maxChanges", maxChanges))
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
methodCalls := []Invocation{}
|
||||
if stateMap.Mailboxes != nil {
|
||||
methodCalls = append(methodCalls, invocation(MailboxChangesCommand{AccountId: accountId, SinceState: *stateMap.Mailboxes, MaxChanges: posUIntPtr(maxChanges)}, "mailboxes"))
|
||||
methodCalls = append(methodCalls, invocation(MailboxChangesCommand{AccountId: accountId, SinceState: *stateMap.Mailboxes, MaxChanges: uintPtr(maxChanges)}, "mailboxes"))
|
||||
}
|
||||
if stateMap.Emails != nil {
|
||||
methodCalls = append(methodCalls, invocation(EmailChangesCommand{AccountId: accountId, SinceState: *stateMap.Emails, MaxChanges: posUIntPtr(maxChanges)}, "emails"))
|
||||
methodCalls = append(methodCalls, invocation(EmailChangesCommand{AccountId: accountId, SinceState: *stateMap.Emails, MaxChanges: uintPtr(maxChanges)}, "emails"))
|
||||
}
|
||||
if stateMap.Calendars != nil {
|
||||
methodCalls = append(methodCalls, invocation(CalendarChangesCommand{AccountId: accountId, SinceState: *stateMap.Calendars, MaxChanges: posUIntPtr(maxChanges)}, "calendars"))
|
||||
methodCalls = append(methodCalls, invocation(CalendarChangesCommand{AccountId: accountId, SinceState: *stateMap.Calendars, MaxChanges: uintPtr(maxChanges)}, "calendars"))
|
||||
}
|
||||
if stateMap.Events != nil {
|
||||
methodCalls = append(methodCalls, invocation(CalendarEventChangesCommand{AccountId: accountId, SinceState: *stateMap.Events, MaxChanges: posUIntPtr(maxChanges)}, "events"))
|
||||
methodCalls = append(methodCalls, invocation(CalendarEventChangesCommand{AccountId: accountId, SinceState: *stateMap.Events, MaxChanges: uintPtr(maxChanges)}, "events"))
|
||||
}
|
||||
if stateMap.Addressbooks != nil {
|
||||
methodCalls = append(methodCalls, invocation(AddressBookChangesCommand{AccountId: accountId, SinceState: *stateMap.Addressbooks, MaxChanges: posUIntPtr(maxChanges)}, "addressbooks"))
|
||||
methodCalls = append(methodCalls, invocation(AddressBookChangesCommand{AccountId: accountId, SinceState: *stateMap.Addressbooks, MaxChanges: uintPtr(maxChanges)}, "addressbooks"))
|
||||
}
|
||||
if stateMap.Contacts != nil {
|
||||
methodCalls = append(methodCalls, invocation(ContactCardChangesCommand{AccountId: accountId, SinceState: *stateMap.Contacts, MaxChanges: posUIntPtr(maxChanges)}, "contacts"))
|
||||
methodCalls = append(methodCalls, invocation(ContactCardChangesCommand{AccountId: accountId, SinceState: *stateMap.Contacts, MaxChanges: uintPtr(maxChanges)}, "contacts"))
|
||||
}
|
||||
if stateMap.Identities != nil {
|
||||
methodCalls = append(methodCalls, invocation(IdentityChangesCommand{AccountId: accountId, SinceState: *stateMap.Identities, MaxChanges: posUIntPtr(maxChanges)}, "identities"))
|
||||
methodCalls = append(methodCalls, invocation(IdentityChangesCommand{AccountId: accountId, SinceState: *stateMap.Identities, MaxChanges: uintPtr(maxChanges)}, "identities"))
|
||||
}
|
||||
if stateMap.EmailSubmissions != nil {
|
||||
methodCalls = append(methodCalls, invocation(EmailSubmissionChangesCommand{AccountId: accountId, SinceState: *stateMap.EmailSubmissions, MaxChanges: posUIntPtr(maxChanges)}, "submissions"))
|
||||
methodCalls = append(methodCalls, invocation(EmailSubmissionChangesCommand{AccountId: accountId, SinceState: *stateMap.EmailSubmissions, MaxChanges: uintPtr(maxChanges)}, "submissions"))
|
||||
}
|
||||
// if stateMap.Quotas != nil { methodCalls = append(methodCalls, invocation(CommandQuotaChanges, QuotaChangesCommand{AccountId: accountId, SinceState: *stateMap.Quotas, MaxChanges: posUIntPtr(maxChanges)}, "quotas")) }
|
||||
|
||||
cmd, err := j.request(session, logger, NS_CHANGES, methodCalls...)
|
||||
cmd, err := j.request(ctx, NS_CHANGES, methodCalls...)
|
||||
if err != nil {
|
||||
return Changes{}, "", "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (Changes, State, Error) {
|
||||
return command(j, ctx, cmd, func(body *Response) (Changes, State, Error) {
|
||||
changes := Changes{
|
||||
MaxChanges: maxChanges,
|
||||
}
|
||||
states := map[string]State{}
|
||||
|
||||
var mailboxes MailboxChangesResponse
|
||||
if ok, err := tryRetrieveResponseMatchParameters(logger, body, CommandMailboxChanges, "mailboxes", &mailboxes); err != nil {
|
||||
if ok, err := tryRetrieveResponseMatchParameters(ctx, body, CommandMailboxChanges, "mailboxes", &mailboxes); err != nil {
|
||||
return Changes{}, "", err
|
||||
} else if ok {
|
||||
changes.Mailboxes = &mailboxes
|
||||
@@ -126,7 +125,7 @@ func (j *Client) GetChanges(accountId string, session *Session, ctx context.Cont
|
||||
}
|
||||
|
||||
var emails EmailChangesResponse
|
||||
if ok, err := tryRetrieveResponseMatchParameters(logger, body, CommandEmailChanges, "emails", &emails); err != nil {
|
||||
if ok, err := tryRetrieveResponseMatchParameters(ctx, body, CommandEmailChanges, "emails", &emails); err != nil {
|
||||
return Changes{}, "", err
|
||||
} else if ok {
|
||||
changes.Emails = &emails
|
||||
@@ -134,7 +133,7 @@ func (j *Client) GetChanges(accountId string, session *Session, ctx context.Cont
|
||||
}
|
||||
|
||||
var calendars CalendarChangesResponse
|
||||
if ok, err := tryRetrieveResponseMatchParameters(logger, body, CommandCalendarChanges, "calendars", &calendars); err != nil {
|
||||
if ok, err := tryRetrieveResponseMatchParameters(ctx, body, CommandCalendarChanges, "calendars", &calendars); err != nil {
|
||||
return Changes{}, "", err
|
||||
} else if ok {
|
||||
changes.Calendars = &calendars
|
||||
@@ -142,7 +141,7 @@ func (j *Client) GetChanges(accountId string, session *Session, ctx context.Cont
|
||||
}
|
||||
|
||||
var events CalendarEventChangesResponse
|
||||
if ok, err := tryRetrieveResponseMatchParameters(logger, body, CommandCalendarEventChanges, "events", &events); err != nil {
|
||||
if ok, err := tryRetrieveResponseMatchParameters(ctx, body, CommandCalendarEventChanges, "events", &events); err != nil {
|
||||
return Changes{}, "", err
|
||||
} else if ok {
|
||||
changes.Events = &events
|
||||
@@ -150,7 +149,7 @@ func (j *Client) GetChanges(accountId string, session *Session, ctx context.Cont
|
||||
}
|
||||
|
||||
var addressbooks AddressBookChangesResponse
|
||||
if ok, err := tryRetrieveResponseMatchParameters(logger, body, CommandAddressBookChanges, "addressbooks", &addressbooks); err != nil {
|
||||
if ok, err := tryRetrieveResponseMatchParameters(ctx, body, CommandAddressBookChanges, "addressbooks", &addressbooks); err != nil {
|
||||
return Changes{}, "", err
|
||||
} else if ok {
|
||||
changes.Addressbooks = &addressbooks
|
||||
@@ -158,7 +157,7 @@ func (j *Client) GetChanges(accountId string, session *Session, ctx context.Cont
|
||||
}
|
||||
|
||||
var contacts ContactCardChangesResponse
|
||||
if ok, err := tryRetrieveResponseMatchParameters(logger, body, CommandContactCardChanges, "contacts", &contacts); err != nil {
|
||||
if ok, err := tryRetrieveResponseMatchParameters(ctx, body, CommandContactCardChanges, "contacts", &contacts); err != nil {
|
||||
return Changes{}, "", err
|
||||
} else if ok {
|
||||
changes.Contacts = &contacts
|
||||
@@ -166,7 +165,7 @@ func (j *Client) GetChanges(accountId string, session *Session, ctx context.Cont
|
||||
}
|
||||
|
||||
var identities IdentityChangesResponse
|
||||
if ok, err := tryRetrieveResponseMatchParameters(logger, body, CommandIdentityChanges, "identities", &identities); err != nil {
|
||||
if ok, err := tryRetrieveResponseMatchParameters(ctx, body, CommandIdentityChanges, "identities", &identities); err != nil {
|
||||
return Changes{}, "", err
|
||||
} else if ok {
|
||||
changes.Identities = &identities
|
||||
@@ -174,7 +173,7 @@ func (j *Client) GetChanges(accountId string, session *Session, ctx context.Cont
|
||||
}
|
||||
|
||||
var submissions EmailSubmissionChangesResponse
|
||||
if ok, err := tryRetrieveResponseMatchParameters(logger, body, CommandEmailSubmissionChanges, "submissions", &submissions); err != nil {
|
||||
if ok, err := tryRetrieveResponseMatchParameters(ctx, body, CommandEmailSubmissionChanges, "submissions", &submissions); err != nil {
|
||||
return Changes{}, "", err
|
||||
} else if ok {
|
||||
changes.EmailSubmissions = &submissions
|
||||
|
||||
@@ -1,24 +1,16 @@
|
||||
package jmap
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
"github.com/opencloud-eu/opencloud/pkg/structs"
|
||||
)
|
||||
|
||||
var NS_CONTACTS = ns(JmapContacts)
|
||||
|
||||
func (j *Client) GetContactCards(accountId string, session *Session, ctx context.Context, logger *log.Logger,
|
||||
acceptLanguage string, contactIds []string) (ContactCardGetResponse, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetContactCards(accountId string, contactIds []string, ctx Context) (ContactCardGetResponse, SessionState, State, Language, Error) {
|
||||
return get(j, "GetContactCards", NS_CONTACTS,
|
||||
func(accountId string, ids []string) ContactCardGetCommand {
|
||||
return ContactCardGetCommand{AccountId: accountId, Ids: contactIds}
|
||||
},
|
||||
ContactCardGetResponse{},
|
||||
identity1,
|
||||
accountId, session, ctx, logger, acceptLanguage, contactIds,
|
||||
accountId, contactIds,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -26,11 +18,10 @@ type ContactCardChanges = ChangesTemplate[ContactCard]
|
||||
|
||||
// Retrieve the changes in Contact Cards since a given State.
|
||||
// @api:tags contact,changes
|
||||
func (j *Client) GetContactCardChanges(accountId string, session *Session, ctx context.Context, logger *log.Logger,
|
||||
acceptLanguage string, sinceState State, maxChanges uint) (ContactCardChanges, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetContactCardChanges(accountId string, sinceState State, maxChanges uint, ctx Context) (ContactCardChanges, SessionState, State, Language, Error) {
|
||||
return changes(j, "GetContactCardChanges", NS_CONTACTS,
|
||||
func() ContactCardChangesCommand {
|
||||
return ContactCardChangesCommand{AccountId: accountId, SinceState: sinceState, MaxChanges: posUIntPtr(maxChanges)}
|
||||
return ContactCardChangesCommand{AccountId: accountId, SinceState: sinceState, MaxChanges: uintPtr(maxChanges)}
|
||||
},
|
||||
ContactCardChangesResponse{},
|
||||
func(path string, rof string) ContactCardGetRefCommand {
|
||||
@@ -54,128 +45,72 @@ func (j *Client) GetContactCardChanges(accountId string, session *Session, ctx c
|
||||
Destroyed: destroyed,
|
||||
}
|
||||
},
|
||||
session, ctx, logger, acceptLanguage,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) QueryContactCards(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, //NOSONAR
|
||||
type ContactCardSearchResults SearchResultsTemplate[ContactCard]
|
||||
|
||||
var _ SearchResults[ContactCard] = ContactCardSearchResults{}
|
||||
|
||||
func (r ContactCardSearchResults) GetResults() []ContactCard { return r.Results }
|
||||
func (r ContactCardSearchResults) GetCanCalculateChanges() bool { return r.CanCalculateChanges }
|
||||
func (r ContactCardSearchResults) GetPosition() uint { return r.Position }
|
||||
func (r ContactCardSearchResults) GetLimit() uint { return r.Limit }
|
||||
func (r ContactCardSearchResults) GetTotal() *uint { return r.Total }
|
||||
|
||||
func (j *Client) QueryContactCards(accountIds []string,
|
||||
filter ContactCardFilterElement, sortBy []ContactCardComparator,
|
||||
position uint, limit uint) (map[string][]ContactCard, SessionState, State, Language, Error) {
|
||||
logger = j.logger("QueryContactCards", session, logger)
|
||||
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
|
||||
if sortBy == nil {
|
||||
sortBy = []ContactCardComparator{{Property: ContactCardPropertyUpdated, IsAscending: false}}
|
||||
}
|
||||
|
||||
invocations := make([]Invocation, len(uniqueAccountIds)*2)
|
||||
for i, accountId := range uniqueAccountIds {
|
||||
query := ContactCardQueryCommand{
|
||||
AccountId: accountId,
|
||||
Filter: filter,
|
||||
Sort: sortBy,
|
||||
}
|
||||
if limit > 0 {
|
||||
query.Limit = limit
|
||||
}
|
||||
if position > 0 {
|
||||
query.Position = position
|
||||
}
|
||||
invocations[i*2+0] = invocation(query, mcid(accountId, "0"))
|
||||
invocations[i*2+1] = invocation(ContactCardGetRefCommand{
|
||||
AccountId: accountId,
|
||||
IdsRef: &ResultReference{
|
||||
Name: CommandContactCardQuery,
|
||||
Path: "/ids/*",
|
||||
ResultOf: mcid(accountId, "0"),
|
||||
},
|
||||
}, mcid(accountId, "1"))
|
||||
}
|
||||
cmd, err := j.request(session, logger, NS_CONTACTS, invocations...)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (map[string][]ContactCard, State, Error) {
|
||||
resp := map[string][]ContactCard{}
|
||||
stateByAccountId := map[string]State{}
|
||||
for _, accountId := range uniqueAccountIds {
|
||||
var response ContactCardGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandContactCardGet, mcid(accountId, "1"), &response)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
position int, limit uint, calculateTotal bool,
|
||||
ctx Context) (map[string]ContactCardSearchResults, SessionState, State, Language, Error) {
|
||||
return queryN(j, "QueryContactCards", NS_CONTACTS,
|
||||
[]ContactCardComparator{{Property: ContactCardPropertyUpdated, IsAscending: false}},
|
||||
func(accountId string, filter ContactCardFilterElement, sortBy []ContactCardComparator, position int, limit uint) ContactCardQueryCommand {
|
||||
return ContactCardQueryCommand{AccountId: accountId, Filter: filter, Sort: sortBy, Position: position, Limit: uintPtr(limit), CalculateTotal: calculateTotal}
|
||||
},
|
||||
func(accountId string, cmd Command, path string, rof string) ContactCardGetRefCommand {
|
||||
return ContactCardGetRefCommand{AccountId: accountId, IdsRef: &ResultReference{Name: cmd, Path: path, ResultOf: rof}}
|
||||
},
|
||||
func(query ContactCardQueryResponse, get ContactCardGetResponse) ContactCardSearchResults {
|
||||
return ContactCardSearchResults{
|
||||
Results: get.List,
|
||||
CanCalculateChanges: query.CanCalculateChanges,
|
||||
Position: query.Position,
|
||||
Total: uintPtrIf(query.Total, calculateTotal),
|
||||
Limit: query.Limit,
|
||||
}
|
||||
if len(response.NotFound) > 0 {
|
||||
// TODO what to do when there are not-found emails here? potentially nothing, they could have been deleted between query and get?
|
||||
}
|
||||
resp[accountId] = response.List
|
||||
stateByAccountId[accountId] = response.State
|
||||
}
|
||||
return resp, squashState(stateByAccountId), nil
|
||||
})
|
||||
}
|
||||
|
||||
func (j *Client) CreateContactCard(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, create ContactCard) (*ContactCard, SessionState, State, Language, Error) {
|
||||
logger = j.logger("CreateContactCard", session, logger)
|
||||
|
||||
cmd, err := j.request(session, logger, NS_CONTACTS,
|
||||
invocation(ContactCardSetCommand{
|
||||
AccountId: accountId,
|
||||
Create: map[string]ContactCard{
|
||||
"c": create,
|
||||
},
|
||||
}, "0"),
|
||||
invocation(ContactCardGetCommand{
|
||||
AccountId: accountId,
|
||||
Ids: []string{"#c"},
|
||||
}, "1"),
|
||||
},
|
||||
accountIds,
|
||||
filter, sortBy, limit, position, ctx,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (*ContactCard, State, Error) {
|
||||
var setResponse ContactCardSetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandContactCardSet, "0", &setResponse)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
setErr, notok := setResponse.NotCreated["c"]
|
||||
if notok {
|
||||
logger.Error().Msgf("%T.NotCreated returned an error %v", setResponse, setErr)
|
||||
return nil, "", setErrorError(setErr, EmailType)
|
||||
}
|
||||
|
||||
if created, ok := setResponse.Created["c"]; !ok || created == nil {
|
||||
berr := fmt.Errorf("failed to find %s in %s response", ContactCardType, string(CommandContactCardSet))
|
||||
logger.Error().Err(berr)
|
||||
return nil, "", jmapError(berr, JmapErrorInvalidJmapResponsePayload)
|
||||
}
|
||||
|
||||
var getResponse ContactCardGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandContactCardGet, "1", &getResponse)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
if len(getResponse.List) < 1 {
|
||||
berr := fmt.Errorf("failed to find %s in %s response", ContactCardType, string(CommandContactCardSet))
|
||||
logger.Error().Err(berr)
|
||||
return nil, "", jmapError(berr, JmapErrorInvalidJmapResponsePayload)
|
||||
}
|
||||
|
||||
return &getResponse.List[0], setResponse.NewState, nil
|
||||
})
|
||||
}
|
||||
|
||||
func (j *Client) DeleteContactCard(accountId string, destroyIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (map[string]SetError, SessionState, State, Language, Error) {
|
||||
func (j *Client) CreateContactCard(accountId string, contact ContactCard, ctx Context) (*ContactCard, SessionState, State, Language, Error) {
|
||||
return create(j, "CreateContactCard", NS_CONTACTS,
|
||||
func(accountId string, create map[string]ContactCard) ContactCardSetCommand {
|
||||
return ContactCardSetCommand{AccountId: accountId, Create: create}
|
||||
},
|
||||
func(accountId string, ids string) ContactCardGetCommand {
|
||||
return ContactCardGetCommand{AccountId: accountId, Ids: []string{ids}}
|
||||
},
|
||||
func(resp ContactCardSetResponse) map[string]*ContactCard {
|
||||
return resp.Created
|
||||
},
|
||||
func(resp ContactCardGetResponse) []ContactCard {
|
||||
return resp.List
|
||||
},
|
||||
accountId, contact,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) DeleteContactCard(accountId string, destroyIds []string, ctx Context) (map[string]SetError, SessionState, State, Language, Error) {
|
||||
return destroy(j, "DeleteContactCard", NS_CONTACTS,
|
||||
func(accountId string, destroy []string) ContactCardSetCommand {
|
||||
return ContactCardSetCommand{AccountId: accountId, Destroy: destroy}
|
||||
},
|
||||
ContactCardSetResponse{},
|
||||
accountId, destroyIds, session, ctx, logger, acceptLanguage,
|
||||
accountId, destroyIds,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package jmap
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"time"
|
||||
@@ -27,8 +26,11 @@ type getEmailsResult struct {
|
||||
}
|
||||
|
||||
// Retrieve specific Emails by their id.
|
||||
func (j *Client) GetEmails(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, ids []string, fetchBodies bool, maxBodyValueBytes uint, markAsSeen bool, withThreads bool) ([]Email, []string, SessionState, State, Language, Error) { //NOSONAR
|
||||
logger = j.logger("GetEmails", session, logger)
|
||||
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) {
|
||||
logger := j.logger("GetEmails", ctx)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
get := EmailGetCommand{AccountId: accountId, Ids: ids, FetchAllBodyValues: fetchBodies}
|
||||
if maxBodyValueBytes > 0 {
|
||||
@@ -57,14 +59,14 @@ func (j *Client) GetEmails(accountId string, session *Session, ctx context.Conte
|
||||
methodCalls = append(methodCalls, invocation(threads, "2"))
|
||||
}
|
||||
|
||||
cmd, err := j.request(session, logger, NS_MAIL, methodCalls...)
|
||||
cmd, err := j.request(ctx, NS_MAIL, methodCalls...)
|
||||
if err != nil {
|
||||
return nil, nil, "", "", "", err
|
||||
}
|
||||
result, sessionState, state, language, gwerr := command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (getEmailsResult, State, Error) {
|
||||
result, sessionState, state, language, gwerr := command(j, ctx, cmd, func(body *Response) (getEmailsResult, State, Error) {
|
||||
if markAsSeen {
|
||||
var markResponse EmailSetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailSet, "0", &markResponse)
|
||||
err = retrieveResponseMatchParameters(ctx, body, CommandEmailSet, "0", &markResponse)
|
||||
if err != nil {
|
||||
return getEmailsResult{}, "", err
|
||||
}
|
||||
@@ -74,13 +76,13 @@ func (j *Client) GetEmails(accountId string, session *Session, ctx context.Conte
|
||||
}
|
||||
}
|
||||
var response EmailGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailGet, "1", &response)
|
||||
err = retrieveResponseMatchParameters(ctx, body, CommandEmailGet, "1", &response)
|
||||
if err != nil {
|
||||
return getEmailsResult{}, "", err
|
||||
}
|
||||
if withThreads {
|
||||
var threads ThreadGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandThreadGet, "2", &threads)
|
||||
err = retrieveResponseMatchParameters(ctx, body, CommandThreadGet, "2", &threads)
|
||||
if err != nil {
|
||||
return getEmailsResult{}, "", err
|
||||
}
|
||||
@@ -91,17 +93,18 @@ func (j *Client) GetEmails(accountId string, session *Session, ctx context.Conte
|
||||
return result.emails, result.notFound, sessionState, state, language, gwerr
|
||||
}
|
||||
|
||||
func (j *Client) GetEmailBlobId(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, id string) (string, SessionState, State, Language, Error) {
|
||||
logger = j.logger("GetEmailBlobId", session, logger)
|
||||
func (j *Client) GetEmailBlobId(accountId string, id string, ctx Context) (string, SessionState, State, Language, 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(session, logger, NS_MAIL, invocation(get, "0"))
|
||||
cmd, err := j.request(ctx, NS_MAIL, invocation(get, "0"))
|
||||
if err != nil {
|
||||
return "", "", "", "", err
|
||||
}
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (string, State, Error) {
|
||||
return command(j, ctx, cmd, func(body *Response) (string, State, Error) {
|
||||
var response EmailGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailGet, "0", &response)
|
||||
err = retrieveGet(ctx, body, get, "0", &response)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
@@ -114,10 +117,13 @@ func (j *Client) GetEmailBlobId(accountId string, session *Session, ctx context.
|
||||
}
|
||||
|
||||
// Retrieve all the Emails in a given Mailbox by its id.
|
||||
func (j *Client) GetAllEmailsInMailbox(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, mailboxId string, offset int, limit uint, collapseThreads bool, fetchBodies bool, maxBodyValueBytes uint, withThreads bool) (Emails, SessionState, State, Language, Error) { //NOSONAR
|
||||
logger = j.loggerParams("GetAllEmailsInMailbox", session, logger, func(z zerolog.Context) zerolog.Context {
|
||||
func (j *Client) GetAllEmailsInMailbox(accountId string, mailboxId string, //NOSONAR
|
||||
offset int, limit uint, collapseThreads bool, fetchBodies bool, maxBodyValueBytes uint, withThreads bool,
|
||||
ctx Context) (Emails, SessionState, State, Language, Error) {
|
||||
logger := j.loggerParams("GetAllEmailsInMailbox", ctx, func(z zerolog.Context) zerolog.Context {
|
||||
return z.Bool(logFetchBodies, fetchBodies).Int(logOffset, offset).Uint(logLimit, limit)
|
||||
})
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
query := EmailQueryCommand{
|
||||
AccountId: accountId,
|
||||
@@ -147,8 +153,9 @@ func (j *Client) GetAllEmailsInMailbox(accountId string, session *Session, ctx c
|
||||
invocation(get, "1"),
|
||||
}
|
||||
|
||||
threads := ThreadGetRefCommand{}
|
||||
if withThreads {
|
||||
threads := ThreadGetRefCommand{
|
||||
threads = ThreadGetRefCommand{
|
||||
AccountId: accountId,
|
||||
IdsRef: &ResultReference{
|
||||
ResultOf: "1",
|
||||
@@ -159,19 +166,19 @@ func (j *Client) GetAllEmailsInMailbox(accountId string, session *Session, ctx c
|
||||
invocations = append(invocations, invocation(threads, "2"))
|
||||
}
|
||||
|
||||
cmd, err := j.request(session, logger, NS_MAIL, invocations...)
|
||||
cmd, err := j.request(ctx, NS_MAIL, invocations...)
|
||||
if err != nil {
|
||||
return Emails{}, "", "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (Emails, State, Error) {
|
||||
return command(j, ctx, cmd, func(body *Response) (Emails, State, Error) {
|
||||
var queryResponse EmailQueryResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailQuery, "0", &queryResponse)
|
||||
err = retrieveQuery(ctx, body, query, "0", &queryResponse)
|
||||
if err != nil {
|
||||
return Emails{}, "", err
|
||||
}
|
||||
var getResponse EmailGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailGet, "1", &getResponse)
|
||||
err = retrieveGet(ctx, body, get, "1", &getResponse)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Send()
|
||||
return Emails{}, "", err
|
||||
@@ -179,7 +186,7 @@ func (j *Client) GetAllEmailsInMailbox(accountId string, session *Session, ctx c
|
||||
|
||||
if withThreads {
|
||||
var thread ThreadGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandThreadGet, "2", &thread)
|
||||
err = retrieveGet(ctx, body, threads, "2", &thread)
|
||||
if err != nil {
|
||||
return Emails{}, "", err
|
||||
}
|
||||
@@ -206,10 +213,13 @@ type EmailChanges struct {
|
||||
|
||||
// Retrieve the changes in Emails since a given State.
|
||||
// @api:tags email,changes
|
||||
func (j *Client) GetEmailChanges(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, sinceState State, fetchBodies bool, maxBodyValueBytes uint, maxChanges uint) (EmailChanges, SessionState, State, Language, Error) { //NOSONAR
|
||||
logger = j.loggerParams("GetEmailChanges", session, logger, func(z zerolog.Context) zerolog.Context {
|
||||
func (j *Client) GetEmailChanges(accountId string,
|
||||
sinceState State, fetchBodies bool, maxBodyValueBytes uint, maxChanges uint,
|
||||
ctx Context) (EmailChanges, SessionState, State, Language, Error) { //NOSONAR
|
||||
logger := j.loggerParams("GetEmailChanges", ctx, func(z zerolog.Context) zerolog.Context {
|
||||
return z.Bool(logFetchBodies, fetchBodies).Str(logSinceState, string(sinceState))
|
||||
})
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
changes := EmailChangesCommand{
|
||||
AccountId: accountId,
|
||||
@@ -236,7 +246,7 @@ func (j *Client) GetEmailChanges(accountId string, session *Session, ctx context
|
||||
getUpdated.MaxBodyValueBytes = maxBodyValueBytes
|
||||
}
|
||||
|
||||
cmd, err := j.request(session, logger, NS_MAIL,
|
||||
cmd, err := j.request(ctx, NS_MAIL,
|
||||
invocation(changes, "0"),
|
||||
invocation(getCreated, "1"),
|
||||
invocation(getUpdated, "2"),
|
||||
@@ -245,22 +255,22 @@ func (j *Client) GetEmailChanges(accountId string, session *Session, ctx context
|
||||
return EmailChanges{}, "", "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (EmailChanges, State, Error) {
|
||||
return command(j, ctx, cmd, func(body *Response) (EmailChanges, State, Error) {
|
||||
var changesResponse EmailChangesResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailChanges, "0", &changesResponse)
|
||||
err = retrieveChanges(ctx, body, changes, "0", &changesResponse)
|
||||
if err != nil {
|
||||
return EmailChanges{}, "", err
|
||||
}
|
||||
|
||||
var createdResponse EmailGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailGet, "1", &createdResponse)
|
||||
err = retrieveGet(ctx, body, getCreated, "1", &createdResponse)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Send()
|
||||
return EmailChanges{}, "", err
|
||||
}
|
||||
|
||||
var updatedResponse EmailGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailGet, "2", &updatedResponse)
|
||||
err = retrieveGet(ctx, body, getUpdated, "2", &updatedResponse)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Send()
|
||||
return EmailChanges{}, "", err
|
||||
@@ -291,10 +301,13 @@ type EmailSnippetQueryResult struct {
|
||||
QueryState State `json:"queryState"`
|
||||
}
|
||||
|
||||
func (j *Client) QueryEmailSnippets(accountIds []string, filter EmailFilterElement, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, offset int, limit uint) (map[string]EmailSnippetQueryResult, SessionState, State, Language, Error) { //NOSONAR
|
||||
logger = j.loggerParams("QueryEmailSnippets", session, logger, func(z zerolog.Context) zerolog.Context {
|
||||
func (j *Client) QueryEmailSnippets(accountIds []string, //NOSONAR
|
||||
filter EmailFilterElement, offset int, limit uint,
|
||||
ctx Context) (map[string]EmailSnippetQueryResult, SessionState, State, Language, Error) {
|
||||
logger := j.loggerParams("QueryEmailSnippets", ctx, func(z zerolog.Context) zerolog.Context {
|
||||
return z.Uint(logLimit, limit).Int(logOffset, offset)
|
||||
})
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
invocations := make([]Invocation, len(uniqueAccountIds)*3)
|
||||
@@ -340,28 +353,28 @@ func (j *Client) QueryEmailSnippets(accountIds []string, filter EmailFilterEleme
|
||||
invocations[i*3+2] = invocation(snippet, mcid(accountId, "2"))
|
||||
}
|
||||
|
||||
cmd, err := j.request(session, logger, NS_MAIL, invocations...)
|
||||
cmd, err := j.request(ctx, NS_MAIL, invocations...)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (map[string]EmailSnippetQueryResult, State, Error) {
|
||||
return command(j, ctx, cmd, func(body *Response) (map[string]EmailSnippetQueryResult, State, Error) {
|
||||
results := make(map[string]EmailSnippetQueryResult, len(uniqueAccountIds))
|
||||
for _, accountId := range uniqueAccountIds {
|
||||
var queryResponse EmailQueryResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailQuery, mcid(accountId, "0"), &queryResponse)
|
||||
err = retrieveResponseMatchParameters(ctx, body, CommandEmailQuery, mcid(accountId, "0"), &queryResponse)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
var mailResponse EmailGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailGet, mcid(accountId, "1"), &mailResponse)
|
||||
err = retrieveResponseMatchParameters(ctx, body, CommandEmailGet, mcid(accountId, "1"), &mailResponse)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
var snippetResponse SearchSnippetGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandSearchSnippetGet, mcid(accountId, "2"), &snippetResponse)
|
||||
err = retrieveResponseMatchParameters(ctx, body, CommandSearchSnippetGet, mcid(accountId, "2"), &snippetResponse)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
@@ -407,10 +420,13 @@ type EmailQueryResult struct {
|
||||
QueryState State `json:"queryState"`
|
||||
}
|
||||
|
||||
func (j *Client) QueryEmails(accountIds []string, filter EmailFilterElement, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, offset int, limit uint, fetchBodies bool, maxBodyValueBytes uint) (map[string]EmailQueryResult, SessionState, State, Language, Error) { //NOSONAR
|
||||
logger = j.loggerParams("QueryEmails", session, logger, func(z zerolog.Context) zerolog.Context {
|
||||
func (j *Client) QueryEmails(accountIds []string,
|
||||
filter EmailFilterElement, offset int, limit uint, fetchBodies bool, maxBodyValueBytes uint,
|
||||
ctx Context) (map[string]EmailQueryResult, SessionState, State, Language, Error) { //NOSONAR
|
||||
logger := j.loggerParams("QueryEmails", ctx, func(z zerolog.Context) zerolog.Context {
|
||||
return z.Bool(logFetchBodies, fetchBodies)
|
||||
})
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
invocations := make([]Invocation, len(uniqueAccountIds)*2)
|
||||
@@ -444,22 +460,22 @@ func (j *Client) QueryEmails(accountIds []string, filter EmailFilterElement, ses
|
||||
invocations[i*2+1] = invocation(mails, mcid(accountId, "1"))
|
||||
}
|
||||
|
||||
cmd, err := j.request(session, logger, NS_MAIL, invocations...)
|
||||
cmd, err := j.request(ctx, NS_MAIL, invocations...)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (map[string]EmailQueryResult, State, Error) {
|
||||
return command(j, ctx, cmd, func(body *Response) (map[string]EmailQueryResult, State, Error) {
|
||||
results := make(map[string]EmailQueryResult, len(uniqueAccountIds))
|
||||
for _, accountId := range uniqueAccountIds {
|
||||
var queryResponse EmailQueryResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailQuery, mcid(accountId, "0"), &queryResponse)
|
||||
err = retrieveResponseMatchParameters(ctx, body, CommandEmailQuery, mcid(accountId, "0"), &queryResponse)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
var emailsResponse EmailGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailGet, mcid(accountId, "1"), &emailsResponse)
|
||||
err = retrieveResponseMatchParameters(ctx, body, CommandEmailGet, mcid(accountId, "1"), &emailsResponse)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
@@ -489,10 +505,13 @@ type EmailQueryWithSnippetsResult struct {
|
||||
QueryState State `json:"queryState"`
|
||||
}
|
||||
|
||||
func (j *Client) QueryEmailsWithSnippets(accountIds []string, filter EmailFilterElement, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, offset int, limit uint, fetchBodies bool, maxBodyValueBytes uint) (map[string]EmailQueryWithSnippetsResult, SessionState, State, Language, Error) { //NOSONAR
|
||||
logger = j.loggerParams("QueryEmailsWithSnippets", session, logger, func(z zerolog.Context) zerolog.Context {
|
||||
func (j *Client) QueryEmailsWithSnippets(accountIds []string, //NOSONAR
|
||||
filter EmailFilterElement, offset int, limit uint, fetchBodies bool, maxBodyValueBytes uint,
|
||||
ctx Context) (map[string]EmailQueryWithSnippetsResult, SessionState, State, Language, Error) {
|
||||
logger := j.loggerParams("QueryEmailsWithSnippets", ctx, func(z zerolog.Context) zerolog.Context {
|
||||
return z.Bool(logFetchBodies, fetchBodies)
|
||||
})
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
invocations := make([]Invocation, len(uniqueAccountIds)*3)
|
||||
@@ -536,28 +555,28 @@ func (j *Client) QueryEmailsWithSnippets(accountIds []string, filter EmailFilter
|
||||
invocations[i*3+2] = invocation(mails, mcid(accountId, "2"))
|
||||
}
|
||||
|
||||
cmd, err := j.request(session, logger, NS_MAIL, invocations...)
|
||||
cmd, err := j.request(ctx, NS_MAIL, invocations...)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (map[string]EmailQueryWithSnippetsResult, State, Error) {
|
||||
return command(j, ctx, cmd, func(body *Response) (map[string]EmailQueryWithSnippetsResult, State, Error) {
|
||||
result := make(map[string]EmailQueryWithSnippetsResult, len(uniqueAccountIds))
|
||||
for _, accountId := range uniqueAccountIds {
|
||||
var queryResponse EmailQueryResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailQuery, mcid(accountId, "0"), &queryResponse)
|
||||
err = retrieveResponseMatchParameters(ctx, body, CommandEmailQuery, mcid(accountId, "0"), &queryResponse)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
var snippetResponse SearchSnippetGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandSearchSnippetGet, mcid(accountId, "1"), &snippetResponse)
|
||||
err = retrieveResponseMatchParameters(ctx, body, CommandSearchSnippetGet, mcid(accountId, "1"), &snippetResponse)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
var emailsResponse EmailGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailGet, mcid(accountId, "2"), &emailsResponse)
|
||||
err = retrieveResponseMatchParameters(ctx, body, CommandEmailGet, mcid(accountId, "2"), &emailsResponse)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
@@ -602,7 +621,7 @@ type UploadedEmail struct {
|
||||
Sha512 string `json:"sha:512"`
|
||||
}
|
||||
|
||||
func (j *Client) ImportEmail(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, data []byte) (UploadedEmail, SessionState, State, Language, Error) {
|
||||
func (j *Client) ImportEmail(accountId string, data []byte, ctx Context) (UploadedEmail, SessionState, State, Language, Error) {
|
||||
encoded := base64.StdEncoding.EncodeToString(data)
|
||||
|
||||
upload := BlobUploadCommand{
|
||||
@@ -627,7 +646,7 @@ func (j *Client) ImportEmail(accountId string, session *Session, ctx context.Con
|
||||
Properties: []string{BlobPropertyDigestSha512},
|
||||
}
|
||||
|
||||
cmd, err := j.request(session, logger, NS_MAIL,
|
||||
cmd, err := j.request(ctx, NS_MAIL,
|
||||
invocation(upload, "0"),
|
||||
invocation(getHash, "1"),
|
||||
)
|
||||
@@ -635,32 +654,32 @@ func (j *Client) ImportEmail(accountId string, session *Session, ctx context.Con
|
||||
return UploadedEmail{}, "", "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (UploadedEmail, State, Error) {
|
||||
return command(j, ctx, cmd, func(body *Response) (UploadedEmail, State, Error) {
|
||||
var uploadResponse BlobUploadResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandBlobUpload, "0", &uploadResponse)
|
||||
err = retrieveResponseMatchParameters(ctx, body, CommandBlobUpload, "0", &uploadResponse)
|
||||
if err != nil {
|
||||
return UploadedEmail{}, "", err
|
||||
}
|
||||
|
||||
var getResponse BlobGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandBlobGet, "1", &getResponse)
|
||||
err = retrieveResponseMatchParameters(ctx, body, CommandBlobGet, "1", &getResponse)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Send()
|
||||
ctx.Logger.Error().Err(err).Send()
|
||||
return UploadedEmail{}, "", err
|
||||
}
|
||||
|
||||
if len(uploadResponse.Created) != 1 {
|
||||
logger.Error().Msgf("%T.Created has %v elements instead of 1", uploadResponse, len(uploadResponse.Created))
|
||||
ctx.Logger.Error().Msgf("%T.Created has %v elements instead of 1", uploadResponse, len(uploadResponse.Created))
|
||||
return UploadedEmail{}, "", jmapError(err, JmapErrorInvalidJmapResponsePayload)
|
||||
}
|
||||
upload, ok := uploadResponse.Created["0"]
|
||||
if !ok {
|
||||
logger.Error().Msgf("%T.Created has no element '0'", uploadResponse)
|
||||
ctx.Logger.Error().Msgf("%T.Created has no element '0'", uploadResponse)
|
||||
return UploadedEmail{}, "", jmapError(err, JmapErrorInvalidJmapResponsePayload)
|
||||
}
|
||||
|
||||
if len(getResponse.List) != 1 {
|
||||
logger.Error().Msgf("%T.List has %v elements instead of 1", getResponse, len(getResponse.List))
|
||||
ctx.Logger.Error().Msgf("%T.List has %v elements instead of 1", getResponse, len(getResponse.List))
|
||||
return UploadedEmail{}, "", jmapError(err, JmapErrorInvalidJmapResponsePayload)
|
||||
}
|
||||
get := getResponse.List[0]
|
||||
@@ -675,7 +694,7 @@ func (j *Client) ImportEmail(accountId string, session *Session, ctx context.Con
|
||||
|
||||
}
|
||||
|
||||
func (j *Client) CreateEmail(accountId string, email EmailCreate, replaceId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (*Email, SessionState, State, Language, Error) {
|
||||
func (j *Client) CreateEmail(accountId string, email EmailCreate, replaceId string, ctx Context) (*Email, SessionState, State, Language, Error) {
|
||||
set := EmailSetCommand{
|
||||
AccountId: accountId,
|
||||
Create: map[string]EmailCreate{
|
||||
@@ -686,16 +705,16 @@ func (j *Client) CreateEmail(accountId string, email EmailCreate, replaceId stri
|
||||
set.Destroy = []string{replaceId}
|
||||
}
|
||||
|
||||
cmd, err := j.request(session, logger, NS_MAIL,
|
||||
cmd, err := j.request(ctx, NS_MAIL,
|
||||
invocation(set, "0"),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (*Email, State, Error) {
|
||||
return command(j, ctx, cmd, func(body *Response) (*Email, State, Error) {
|
||||
var setResponse EmailSetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailSet, "0", &setResponse)
|
||||
err = retrieveResponseMatchParameters(ctx, body, CommandEmailSet, "0", &setResponse)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
@@ -707,14 +726,14 @@ func (j *Client) CreateEmail(accountId string, email EmailCreate, replaceId stri
|
||||
|
||||
setErr, notok := setResponse.NotCreated["c"]
|
||||
if notok {
|
||||
logger.Error().Msgf("%T.NotCreated returned an error %v", setResponse, setErr)
|
||||
ctx.Logger.Error().Msgf("%T.NotCreated returned an error %v", setResponse, setErr)
|
||||
return nil, "", setErrorError(setErr, EmailType)
|
||||
}
|
||||
|
||||
created, ok := setResponse.Created["c"]
|
||||
if !ok {
|
||||
berr := fmt.Errorf("failed to find %s in %s response", EmailType, string(CommandEmailSet))
|
||||
logger.Error().Err(berr)
|
||||
ctx.Logger.Error().Err(berr)
|
||||
return nil, "", jmapError(berr, JmapErrorInvalidJmapResponsePayload)
|
||||
}
|
||||
|
||||
@@ -730,20 +749,19 @@ func (j *Client) CreateEmail(accountId string, email EmailCreate, 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]EmailUpdate, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (map[string]*Email, SessionState, State, Language, Error) {
|
||||
cmd, err := j.request(session, logger, NS_MAIL,
|
||||
invocation(EmailSetCommand{
|
||||
AccountId: accountId,
|
||||
Update: updates,
|
||||
}, "0"),
|
||||
)
|
||||
func (j *Client) UpdateEmails(accountId string, updates map[string]EmailUpdate, ctx Context) (map[string]*Email, SessionState, State, Language, Error) {
|
||||
set := EmailSetCommand{
|
||||
AccountId: accountId,
|
||||
Update: updates,
|
||||
}
|
||||
cmd, err := j.request(ctx, NS_MAIL, invocation(set, "0"))
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (map[string]*Email, State, Error) {
|
||||
return command(j, ctx, cmd, func(body *Response) (map[string]*Email, State, Error) {
|
||||
var setResponse EmailSetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailSet, "0", &setResponse)
|
||||
err = retrieveSet(ctx, body, set, "0", &setResponse)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
@@ -757,20 +775,19 @@ func (j *Client) UpdateEmails(accountId string, updates map[string]EmailUpdate,
|
||||
})
|
||||
}
|
||||
|
||||
func (j *Client) DeleteEmails(accountId string, destroy []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (map[string]SetError, SessionState, State, Language, Error) {
|
||||
cmd, err := j.request(session, logger, NS_MAIL,
|
||||
invocation(EmailSetCommand{
|
||||
AccountId: accountId,
|
||||
Destroy: destroy,
|
||||
}, "0"),
|
||||
)
|
||||
func (j *Client) DeleteEmails(accountId string, destroy []string, ctx Context) (map[string]SetError, SessionState, State, Language, Error) {
|
||||
set := EmailSetCommand{
|
||||
AccountId: accountId,
|
||||
Destroy: destroy,
|
||||
}
|
||||
cmd, err := j.request(ctx, NS_MAIL, invocation(set, "0"))
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (map[string]SetError, State, Error) {
|
||||
return command(j, ctx, cmd, func(body *Response) (map[string]SetError, State, Error) {
|
||||
var setResponse EmailSetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailSet, "0", &setResponse)
|
||||
err = retrieveSet(ctx, body, set, "0", &setResponse)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
@@ -807,8 +824,10 @@ type MoveMail struct {
|
||||
ToMailboxId string
|
||||
}
|
||||
|
||||
func (j *Client) SubmitEmail(accountId string, identityId string, emailId string, move *MoveMail, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (EmailSubmission, SessionState, State, Language, Error) { //NOSONAR
|
||||
logger = j.logger("SubmitEmail", session, logger)
|
||||
func (j *Client) SubmitEmail(accountId string, identityId string, emailId string, move *MoveMail, //NOSONAR
|
||||
ctx Context) (EmailSubmission, SessionState, State, Language, Error) {
|
||||
logger := j.logger("SubmitEmail", ctx)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
update := map[string]any{
|
||||
EmailPropertyKeywords + "/" + JmapKeywordDraft: nil, // unmark as draft
|
||||
@@ -821,7 +840,7 @@ func (j *Client) SubmitEmail(accountId string, identityId string, emailId string
|
||||
|
||||
id := "s0"
|
||||
|
||||
set := EmailSubmissionSetCommand{
|
||||
submit := EmailSubmissionSetCommand{
|
||||
AccountId: accountId,
|
||||
Create: map[string]EmailSubmissionCreate{
|
||||
id: {
|
||||
@@ -840,17 +859,17 @@ func (j *Client) SubmitEmail(accountId string, identityId string, emailId string
|
||||
Ids: []string{"#" + id},
|
||||
}
|
||||
|
||||
cmd, err := j.request(session, logger, NS_MAIL_SUBMISSION,
|
||||
invocation(set, "0"),
|
||||
cmd, err := j.request(ctx, NS_MAIL_SUBMISSION,
|
||||
invocation(submit, "0"),
|
||||
invocation(get, "1"),
|
||||
)
|
||||
if err != nil {
|
||||
return EmailSubmission{}, "", "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (EmailSubmission, State, Error) {
|
||||
return command(j, ctx, cmd, func(body *Response) (EmailSubmission, State, Error) {
|
||||
var submissionResponse EmailSubmissionSetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailSubmissionSet, "0", &submissionResponse)
|
||||
err = retrieveSet(ctx, body, submit, "0", &submissionResponse)
|
||||
if err != nil {
|
||||
return EmailSubmission{}, "", err
|
||||
}
|
||||
@@ -866,14 +885,14 @@ func (j *Client) SubmitEmail(accountId string, identityId string, emailId string
|
||||
// The response to this MUST be returned after the EmailSubmission/set response."
|
||||
// from an example in the spec, it has the same tag as the EmailSubmission/set command ("0" in this case)
|
||||
var setResponse EmailSetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailSet, "0", &setResponse)
|
||||
err = retrieveResponseMatchParameters(ctx, body, CommandEmailSet, "0", &setResponse)
|
||||
if err != nil {
|
||||
return EmailSubmission{}, "", err
|
||||
}
|
||||
|
||||
if len(setResponse.Updated) == 1 {
|
||||
var getResponse EmailSubmissionGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailSubmissionGet, "1", &getResponse)
|
||||
err = retrieveGet(ctx, body, get, "1", &getResponse)
|
||||
if err != nil {
|
||||
return EmailSubmission{}, "", err
|
||||
}
|
||||
@@ -898,20 +917,22 @@ type emailSubmissionResult struct {
|
||||
notFound []string
|
||||
}
|
||||
|
||||
func (j *Client) GetEmailSubmissionStatus(accountId string, submissionIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (map[string]EmailSubmission, []string, SessionState, State, Language, Error) {
|
||||
logger = j.logger("GetEmailSubmissionStatus", session, logger)
|
||||
func (j *Client) GetEmailSubmissionStatus(accountId string, submissionIds []string, ctx Context) (map[string]EmailSubmission, []string, SessionState, State, Language, Error) {
|
||||
logger := j.logger("GetEmailSubmissionStatus", ctx)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
cmd, err := j.request(session, logger, NS_MAIL_SUBMISSION, invocation(EmailSubmissionGetCommand{
|
||||
get := EmailSubmissionGetCommand{
|
||||
AccountId: accountId,
|
||||
Ids: submissionIds,
|
||||
}, "0"))
|
||||
}
|
||||
cmd, err := j.request(ctx, NS_MAIL_SUBMISSION, invocation(get, "0"))
|
||||
if err != nil {
|
||||
return nil, nil, "", "", "", err
|
||||
}
|
||||
|
||||
result, sessionState, state, lang, err := command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (emailSubmissionResult, State, Error) {
|
||||
result, sessionState, state, lang, err := command(j, ctx, cmd, func(body *Response) (emailSubmissionResult, State, Error) {
|
||||
var response EmailSubmissionGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailSubmissionGet, "0", &response)
|
||||
err = retrieveGet(ctx, body, get, "0", &response)
|
||||
if err != nil {
|
||||
return emailSubmissionResult{}, "", err
|
||||
}
|
||||
@@ -925,34 +946,41 @@ func (j *Client) GetEmailSubmissionStatus(accountId string, submissionIds []stri
|
||||
return result.submissions, result.notFound, sessionState, state, lang, err
|
||||
}
|
||||
|
||||
func (j *Client) EmailsInThread(accountId string, threadId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, fetchBodies bool, maxBodyValueBytes uint) ([]Email, SessionState, State, Language, Error) { //NOSONAR
|
||||
logger = j.loggerParams("EmailsInThread", session, logger, func(z zerolog.Context) zerolog.Context {
|
||||
func (j *Client) EmailsInThread(accountId string, threadId string,
|
||||
fetchBodies bool, maxBodyValueBytes uint,
|
||||
ctx Context) ([]Email, SessionState, State, Language, Error) { //NOSONAR
|
||||
logger := j.loggerParams("EmailsInThread", ctx, func(z zerolog.Context) zerolog.Context {
|
||||
return z.Bool(logFetchBodies, fetchBodies).Str("threadId", log.SafeString(threadId))
|
||||
})
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
cmd, err := j.request(session, logger, NS_MAIL,
|
||||
invocation(ThreadGetCommand{
|
||||
AccountId: accountId,
|
||||
Ids: []string{threadId},
|
||||
}, "0"),
|
||||
invocation(EmailGetRefCommand{
|
||||
AccountId: accountId,
|
||||
IdsRef: &ResultReference{
|
||||
ResultOf: "0",
|
||||
Name: CommandThreadGet,
|
||||
Path: "/list/*/emailIds",
|
||||
},
|
||||
FetchAllBodyValues: fetchBodies,
|
||||
MaxBodyValueBytes: maxBodyValueBytes,
|
||||
}, "1"),
|
||||
thread := ThreadGetCommand{
|
||||
AccountId: accountId,
|
||||
Ids: []string{threadId},
|
||||
}
|
||||
|
||||
get := EmailGetRefCommand{
|
||||
AccountId: accountId,
|
||||
IdsRef: &ResultReference{
|
||||
ResultOf: "0",
|
||||
Name: CommandThreadGet,
|
||||
Path: "/list/*/emailIds",
|
||||
},
|
||||
FetchAllBodyValues: fetchBodies,
|
||||
MaxBodyValueBytes: maxBodyValueBytes,
|
||||
}
|
||||
|
||||
cmd, err := j.request(ctx, NS_MAIL,
|
||||
invocation(thread, "0"),
|
||||
invocation(get, "1"),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) ([]Email, State, Error) {
|
||||
return command(j, ctx, cmd, func(body *Response) ([]Email, State, Error) {
|
||||
var emailsResponse EmailGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailGet, "1", &emailsResponse)
|
||||
err = retrieveGet(ctx, body, get, "1", &emailsResponse)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
@@ -987,8 +1015,11 @@ var EmailSummaryProperties = []string{
|
||||
EmailPropertyPreview,
|
||||
}
|
||||
|
||||
func (j *Client) QueryEmailSummaries(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, filter EmailFilterElement, limit uint, withThreads bool) (map[string]EmailsSummary, SessionState, State, Language, Error) { //NOSONAR
|
||||
logger = j.logger("QueryEmailSummaries", session, logger)
|
||||
func (j *Client) QueryEmailSummaries(accountIds []string, //NOSONAR
|
||||
filter EmailFilterElement, limit uint, withThreads bool,
|
||||
ctx Context) (map[string]EmailsSummary, SessionState, State, Language, Error) {
|
||||
logger := j.logger("QueryEmailSummaries", ctx)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
|
||||
@@ -1029,22 +1060,22 @@ func (j *Client) QueryEmailSummaries(accountIds []string, session *Session, ctx
|
||||
}, mcid(accountId, "2"))
|
||||
}
|
||||
}
|
||||
cmd, err := j.request(session, logger, NS_MAIL, invocations...)
|
||||
cmd, err := j.request(ctx, NS_MAIL, invocations...)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (map[string]EmailsSummary, State, Error) {
|
||||
return command(j, ctx, cmd, func(body *Response) (map[string]EmailsSummary, State, Error) {
|
||||
resp := map[string]EmailsSummary{}
|
||||
for _, accountId := range uniqueAccountIds {
|
||||
var queryResponse EmailQueryResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailQuery, mcid(accountId, "0"), &queryResponse)
|
||||
err = retrieveResponseMatchParameters(ctx, body, CommandEmailQuery, mcid(accountId, "0"), &queryResponse)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
var response EmailGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailGet, mcid(accountId, "1"), &response)
|
||||
err = retrieveResponseMatchParameters(ctx, body, CommandEmailGet, mcid(accountId, "1"), &response)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
@@ -1053,7 +1084,7 @@ func (j *Client) QueryEmailSummaries(accountIds []string, session *Session, ctx
|
||||
}
|
||||
if withThreads {
|
||||
var thread ThreadGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandThreadGet, mcid(accountId, "2"), &thread)
|
||||
err = retrieveResponseMatchParameters(ctx, body, CommandThreadGet, mcid(accountId, "2"), &thread)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
@@ -1076,11 +1107,11 @@ type EmailSubmissionChanges = ChangesTemplate[EmailSubmission]
|
||||
|
||||
// Retrieve the changes in Email Submissions since a given State.
|
||||
// @api:tags email,changes
|
||||
func (j *Client) GetEmailSubmissionChanges(accountId string, session *Session, ctx context.Context, logger *log.Logger,
|
||||
acceptLanguage string, sinceState State, maxChanges uint) (EmailSubmissionChanges, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetEmailSubmissionChanges(accountId string, sinceState State, maxChanges uint,
|
||||
ctx Context) (EmailSubmissionChanges, SessionState, State, Language, Error) {
|
||||
return changes(j, "GetEmailSubmissionChanges", NS_MAIL_SUBMISSION,
|
||||
func() EmailSubmissionChangesCommand {
|
||||
return EmailSubmissionChangesCommand{AccountId: accountId, SinceState: sinceState, MaxChanges: posUIntPtr(maxChanges)}
|
||||
return EmailSubmissionChangesCommand{AccountId: accountId, SinceState: sinceState, MaxChanges: uintPtr(maxChanges)}
|
||||
},
|
||||
EmailSubmissionChangesResponse{},
|
||||
func(path string, rof string) EmailSubmissionGetRefCommand {
|
||||
@@ -1104,7 +1135,7 @@ func (j *Client) GetEmailSubmissionChanges(accountId string, session *Session, c
|
||||
Destroyed: destroyed,
|
||||
}
|
||||
},
|
||||
session, ctx, logger, acceptLanguage,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,36 +1,36 @@
|
||||
package jmap
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
"github.com/opencloud-eu/opencloud/pkg/structs"
|
||||
)
|
||||
|
||||
var NS_IDENTITY = ns(JmapMail)
|
||||
|
||||
func (j *Client) GetAllIdentities(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) ([]Identity, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetAllIdentities(accountId string, ctx Context) ([]Identity, SessionState, State, Language, Error) {
|
||||
return getA(j, "GetAllIdentities", NS_IDENTITY,
|
||||
func(accountId string, ids []string) IdentityGetCommand {
|
||||
return IdentityGetCommand{AccountId: accountId}
|
||||
},
|
||||
IdentityGetResponse{},
|
||||
accountId, session, ctx, logger, acceptLanguage, []string{},
|
||||
accountId, []string{},
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) GetIdentities(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, identityIds []string) ([]Identity, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetIdentities(accountId string, identityIds []string, ctx Context) ([]Identity, SessionState, State, Language, Error) {
|
||||
return getA(j, "GetIdentities", NS_IDENTITY,
|
||||
func(accountId string, ids []string) IdentityGetCommand {
|
||||
return IdentityGetCommand{AccountId: accountId, Ids: ids}
|
||||
},
|
||||
IdentityGetResponse{},
|
||||
accountId, session, ctx, logger, acceptLanguage, identityIds,
|
||||
accountId, identityIds,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) GetIdentitiesForAllAccounts(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (map[string][]Identity, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetIdentitiesForAllAccounts(accountIds []string, ctx Context) (map[string][]Identity, SessionState, State, Language, Error) {
|
||||
return getN(j, "GetIdentitiesForAllAccounts", NS_IDENTITY,
|
||||
func(accountId string, ids []string) IdentityGetCommand {
|
||||
return IdentityGetCommand{AccountId: accountId}
|
||||
@@ -38,7 +38,8 @@ func (j *Client) GetIdentitiesForAllAccounts(accountIds []string, session *Sessi
|
||||
IdentityGetResponse{},
|
||||
func(resp IdentityGetResponse) []Identity { return resp.List },
|
||||
identity1,
|
||||
accountIds, session, ctx, logger, acceptLanguage, []string{},
|
||||
accountIds, []string{},
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -48,10 +49,11 @@ type IdentitiesAndMailboxesGetResponse struct {
|
||||
Mailboxes []Mailbox `json:"mailboxes"`
|
||||
}
|
||||
|
||||
func (j *Client) GetIdentitiesAndMailboxes(mailboxAccountId string, accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (IdentitiesAndMailboxesGetResponse, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetIdentitiesAndMailboxes(mailboxAccountId string, accountIds []string, ctx Context) (IdentitiesAndMailboxesGetResponse, SessionState, State, Language, Error) {
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
|
||||
logger = j.logger("GetIdentitiesAndMailboxes", session, logger)
|
||||
logger := j.logger("GetIdentitiesAndMailboxes", ctx)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
calls := make([]Invocation, len(uniqueAccountIds)+1)
|
||||
calls[0] = invocation(MailboxGetCommand{AccountId: mailboxAccountId}, "0")
|
||||
@@ -59,17 +61,17 @@ func (j *Client) GetIdentitiesAndMailboxes(mailboxAccountId string, accountIds [
|
||||
calls[i+1] = invocation(IdentityGetCommand{AccountId: accountId}, strconv.Itoa(i+1))
|
||||
}
|
||||
|
||||
cmd, err := j.request(session, logger, NS_IDENTITY, calls...)
|
||||
cmd, err := j.request(ctx, NS_IDENTITY, calls...)
|
||||
if err != nil {
|
||||
return IdentitiesAndMailboxesGetResponse{}, "", "", "", err
|
||||
}
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (IdentitiesAndMailboxesGetResponse, State, Error) {
|
||||
return command(j, ctx, cmd, func(body *Response) (IdentitiesAndMailboxesGetResponse, State, Error) {
|
||||
identities := make(map[string][]Identity, len(uniqueAccountIds))
|
||||
stateByAccountId := make(map[string]State, len(uniqueAccountIds))
|
||||
notFound := []string{}
|
||||
for i, accountId := range uniqueAccountIds {
|
||||
var response IdentityGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandIdentityGet, strconv.Itoa(i+1), &response)
|
||||
err = retrieveResponseMatchParameters(ctx, body, CommandIdentityGet, strconv.Itoa(i+1), &response)
|
||||
if err != nil {
|
||||
return IdentitiesAndMailboxesGetResponse{}, "", err
|
||||
} else {
|
||||
@@ -80,7 +82,7 @@ func (j *Client) GetIdentitiesAndMailboxes(mailboxAccountId string, accountIds [
|
||||
}
|
||||
|
||||
var mailboxResponse MailboxGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandMailboxGet, "0", &mailboxResponse)
|
||||
err = retrieveResponseMatchParameters(ctx, body, CommandMailboxGet, "0", &mailboxResponse)
|
||||
if err != nil {
|
||||
return IdentitiesAndMailboxesGetResponse{}, "", err
|
||||
}
|
||||
@@ -93,91 +95,60 @@ func (j *Client) GetIdentitiesAndMailboxes(mailboxAccountId string, accountIds [
|
||||
})
|
||||
}
|
||||
|
||||
func (j *Client) CreateIdentity(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, identity Identity) (Identity, SessionState, State, Language, Error) {
|
||||
logger = j.logger("CreateIdentity", session, logger)
|
||||
cmd, err := j.request(session, logger, NS_IDENTITY, invocation(IdentitySetCommand{
|
||||
AccountId: accountId,
|
||||
Create: map[string]Identity{
|
||||
"c": identity,
|
||||
func (j *Client) CreateIdentity(accountId string, identity IdentityChange, ctx Context) (*Identity, SessionState, State, Language, Error) {
|
||||
return create(j, "CreateIdentity", NS_IDENTITY,
|
||||
func(accountId string, create map[string]IdentityChange) IdentitySetCommand {
|
||||
return IdentitySetCommand{AccountId: accountId, Create: create}
|
||||
},
|
||||
}, "0"))
|
||||
if err != nil {
|
||||
return Identity{}, "", "", "", err
|
||||
}
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (Identity, State, Error) {
|
||||
var response IdentitySetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandIdentitySet, "0", &response)
|
||||
if err != nil {
|
||||
return Identity{}, response.NewState, err
|
||||
}
|
||||
setErr, notok := response.NotCreated["c"]
|
||||
if notok {
|
||||
logger.Error().Msgf("%T.NotCreated returned an error %v", response, setErr) //NOSONAR
|
||||
return Identity{}, "", setErrorError(setErr, IdentityType)
|
||||
}
|
||||
return response.Created["c"], response.NewState, nil
|
||||
})
|
||||
func(accountId string, ids string) IdentityGetCommand {
|
||||
return IdentityGetCommand{AccountId: accountId, Ids: []string{ids}}
|
||||
},
|
||||
func(resp IdentitySetResponse) map[string]*Identity {
|
||||
return resp.Created
|
||||
},
|
||||
func(resp IdentityGetResponse) []Identity {
|
||||
return resp.List
|
||||
},
|
||||
accountId, identity,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) UpdateIdentity(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, identity Identity) (Identity, SessionState, State, Language, Error) {
|
||||
logger = j.logger("UpdateIdentity", session, logger)
|
||||
cmd, err := j.request(session, logger, NS_IDENTITY, invocation(IdentitySetCommand{
|
||||
AccountId: accountId,
|
||||
Update: map[string]PatchObject{
|
||||
"c": identity.AsPatch(),
|
||||
func (j *Client) UpdateIdentity(accountId string, id string, changes IdentityChange, ctx Context) (Identity, SessionState, State, Language, Error) {
|
||||
return update(j, "UpdateIdentity", NS_IDENTITY,
|
||||
func(update map[string]PatchObject) IdentitySetCommand {
|
||||
return IdentitySetCommand{AccountId: accountId, Update: update}
|
||||
},
|
||||
}, "0"))
|
||||
if err != nil {
|
||||
return Identity{}, "", "", "", err
|
||||
}
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (Identity, State, Error) {
|
||||
var response IdentitySetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandIdentitySet, "0", &response)
|
||||
if err != nil {
|
||||
return Identity{}, response.NewState, err
|
||||
}
|
||||
setErr, notok := response.NotCreated["c"]
|
||||
if notok {
|
||||
logger.Error().Msgf("%T.NotCreated returned an error %v", response, setErr)
|
||||
return Identity{}, "", setErrorError(setErr, IdentityType)
|
||||
}
|
||||
return response.Created["c"], response.NewState, nil
|
||||
})
|
||||
func(id string) IdentityGetCommand {
|
||||
return IdentityGetCommand{AccountId: accountId, Ids: []string{id}}
|
||||
},
|
||||
func(resp IdentitySetResponse) map[string]SetError { return resp.NotUpdated },
|
||||
func(resp IdentityGetResponse) Identity { return resp.List[0] },
|
||||
id, changes,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) DeleteIdentity(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, ids []string) ([]string, SessionState, State, Language, Error) {
|
||||
logger = j.logger("DeleteIdentity", session, logger)
|
||||
cmd, err := j.request(session, logger, NS_IDENTITY, invocation(IdentitySetCommand{
|
||||
AccountId: accountId,
|
||||
Destroy: ids,
|
||||
}, "0"))
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
}
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) ([]string, State, Error) {
|
||||
var response IdentitySetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandIdentitySet, "0", &response)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
for _, setErr := range response.NotDestroyed {
|
||||
// TODO only returning the first error here, we should probably aggregate them instead
|
||||
logger.Error().Msgf("%T.NotCreated returned an error %v", response, setErr)
|
||||
return nil, "", setErrorError(setErr, IdentityType)
|
||||
}
|
||||
return response.Destroyed, response.NewState, nil
|
||||
})
|
||||
func (j *Client) DeleteIdentity(accountId string, destroyIds []string, ctx Context) (map[string]SetError, SessionState, State, Language, Error) {
|
||||
return destroy(j, "DeleteIdentity", NS_IDENTITY,
|
||||
func(accountId string, destroy []string) IdentitySetCommand {
|
||||
return IdentitySetCommand{AccountId: accountId, Destroy: destroyIds}
|
||||
},
|
||||
IdentitySetResponse{},
|
||||
accountId, destroyIds,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
type IdentityChanges = ChangesTemplate[Identity]
|
||||
|
||||
// Retrieve the changes in Email Identities since a given State.
|
||||
// @api:tags email,changes
|
||||
func (j *Client) GetIdentityChanges(accountId string, session *Session, ctx context.Context, logger *log.Logger,
|
||||
acceptLanguage string, sinceState State, maxChanges uint) (IdentityChanges, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetIdentityChanges(accountId string, sinceState State, maxChanges uint,
|
||||
ctx Context) (IdentityChanges, SessionState, State, Language, Error) {
|
||||
return changes(j, "GetIdentityChanges", NS_IDENTITY,
|
||||
func() IdentityChangesCommand {
|
||||
return IdentityChangesCommand{AccountId: accountId, SinceState: sinceState, MaxChanges: posUIntPtr(maxChanges)}
|
||||
return IdentityChangesCommand{AccountId: accountId, SinceState: sinceState, MaxChanges: uintPtr(maxChanges)}
|
||||
},
|
||||
IdentityChangesResponse{},
|
||||
func(path string, rof string) IdentityGetRefCommand {
|
||||
@@ -201,6 +172,6 @@ func (j *Client) GetIdentityChanges(accountId string, session *Session, ctx cont
|
||||
Destroyed: destroyed,
|
||||
}
|
||||
},
|
||||
session, ctx, logger, acceptLanguage,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
package jmap
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"slices"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
"github.com/opencloud-eu/opencloud/pkg/structs"
|
||||
)
|
||||
|
||||
var NS_MAILBOX = ns(JmapMail)
|
||||
|
||||
func (j *Client) GetMailbox(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, ids []string) (MailboxGetResponse, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetMailbox(accountId string, ids []string, ctx Context) (MailboxGetResponse, SessionState, State, Language, Error) {
|
||||
/*
|
||||
return get(j, "GetMailbox", NS_MAILBOX,
|
||||
func(accountId string, ids []string) MailboxGetCommand {
|
||||
@@ -23,10 +20,10 @@ func (j *Client) GetMailbox(accountId string, session *Session, ctx context.Cont
|
||||
)
|
||||
*/
|
||||
|
||||
return fget[Mailboxes](MAILBOX, j, "GetMailbox", accountId, ids, session, ctx, logger, acceptLanguage)
|
||||
return fget[Mailboxes](MAILBOX, j, "GetMailbox", accountId, ids, ctx)
|
||||
}
|
||||
|
||||
func (j *Client) GetAllMailboxes(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (map[string][]Mailbox, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetAllMailboxes(accountIds []string, ctx Context) (map[string][]Mailbox, SessionState, State, Language, Error) {
|
||||
/*
|
||||
return getAN(j, "GetAllMailboxes", NS_MAILBOX,
|
||||
func(accountId string, ids []string) MailboxGetCommand {
|
||||
@@ -37,11 +34,12 @@ func (j *Client) GetAllMailboxes(accountIds []string, session *Session, ctx cont
|
||||
accountIds, session, ctx, logger, acceptLanguage, []string{},
|
||||
)
|
||||
*/
|
||||
return fgetAN[Mailboxes](MAILBOX, j, "GetAllMailboxes", identity1, accountIds, []string{}, session, ctx, logger, acceptLanguage)
|
||||
return fgetAN[Mailboxes](MAILBOX, j, "GetAllMailboxes", identity1, accountIds, []string{}, ctx)
|
||||
}
|
||||
|
||||
func (j *Client) SearchMailboxes(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, filter MailboxFilterElement) (map[string][]Mailbox, SessionState, State, Language, Error) {
|
||||
logger = j.logger("SearchMailboxes", session, logger)
|
||||
func (j *Client) SearchMailboxes(accountIds []string, filter MailboxFilterElement, ctx Context) (map[string][]Mailbox, SessionState, State, Language, Error) {
|
||||
logger := j.logger("SearchMailboxes", ctx)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
|
||||
@@ -57,17 +55,17 @@ func (j *Client) SearchMailboxes(accountIds []string, session *Session, ctx cont
|
||||
},
|
||||
}, mcid(accountId, "1"))
|
||||
}
|
||||
cmd, err := j.request(session, logger, NS_MAILBOX, invocations...)
|
||||
cmd, err := j.request(ctx, NS_MAILBOX, invocations...)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (map[string][]Mailbox, State, Error) {
|
||||
return command(j, ctx, cmd, func(body *Response) (map[string][]Mailbox, State, Error) {
|
||||
resp := map[string][]Mailbox{}
|
||||
stateByAccountid := map[string]State{}
|
||||
for _, accountId := range uniqueAccountIds {
|
||||
var response MailboxGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandMailboxGet, mcid(accountId, "1"), &response)
|
||||
err = retrieveResponseMatchParameters(ctx, body, CommandMailboxGet, mcid(accountId, "1"), &response)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
@@ -79,8 +77,9 @@ func (j *Client) SearchMailboxes(accountIds []string, session *Session, ctx cont
|
||||
})
|
||||
}
|
||||
|
||||
func (j *Client) SearchMailboxIdsPerRole(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, roles []string) (map[string]map[string]string, SessionState, State, Language, Error) { //NOSONAR
|
||||
logger = j.logger("SearchMailboxIdsPerRole", session, logger)
|
||||
func (j *Client) SearchMailboxIdsPerRole(accountIds []string, roles []string, ctx Context) (map[string]map[string]string, SessionState, State, Language, Error) { //NOSONAR
|
||||
logger := j.logger("SearchMailboxIdsPerRole", ctx)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
|
||||
@@ -90,19 +89,19 @@ func (j *Client) SearchMailboxIdsPerRole(accountIds []string, session *Session,
|
||||
invocations[i*len(roles)+j] = invocation(MailboxQueryCommand{AccountId: accountId, Filter: MailboxFilterCondition{Role: role}}, mcid(accountId, role))
|
||||
}
|
||||
}
|
||||
cmd, err := j.request(session, logger, NS_MAILBOX, invocations...)
|
||||
cmd, err := j.request(ctx, NS_MAILBOX, invocations...)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (map[string]map[string]string, State, Error) {
|
||||
return command(j, ctx, cmd, func(body *Response) (map[string]map[string]string, State, Error) {
|
||||
resp := map[string]map[string]string{}
|
||||
stateByAccountid := map[string]State{}
|
||||
for _, accountId := range uniqueAccountIds {
|
||||
mailboxIdsByRole := map[string]string{}
|
||||
for _, role := range roles {
|
||||
var response MailboxQueryResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandMailboxQuery, mcid(accountId, role), &response)
|
||||
err = retrieveResponseMatchParameters(ctx, body, CommandMailboxQuery, mcid(accountId, role), &response)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
@@ -134,10 +133,11 @@ 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, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, sinceState State, maxChanges uint) (MailboxChanges, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetMailboxChanges(accountId string, sinceState State, maxChanges uint,
|
||||
ctx Context) (MailboxChanges, SessionState, State, Language, Error) {
|
||||
return changesA(j, "GetMailboxChanges", NS_MAILBOX,
|
||||
func() MailboxChangesCommand {
|
||||
return MailboxChangesCommand{AccountId: accountId, SinceState: sinceState, MaxChanges: posUIntPtr(maxChanges)}
|
||||
return MailboxChangesCommand{AccountId: accountId, SinceState: sinceState, MaxChanges: uintPtr(maxChanges)}
|
||||
},
|
||||
MailboxChangesResponse{},
|
||||
MailboxGetResponse{},
|
||||
@@ -152,17 +152,19 @@ func (j *Client) GetMailboxChanges(accountId string, session *Session, ctx conte
|
||||
}
|
||||
},
|
||||
newMailboxChanges,
|
||||
session, ctx, logger, acceptLanguage,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
// Retrieve Mailbox changes of multiple Accounts.
|
||||
// @api:tags email,changes
|
||||
func (j *Client) GetMailboxChangesForMultipleAccounts(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, sinceStateMap map[string]State, maxChanges uint) (map[string]MailboxChanges, SessionState, State, Language, Error) { //NOSONAR
|
||||
func (j *Client) GetMailboxChangesForMultipleAccounts(accountIds []string, //NOSONAR
|
||||
sinceStateMap map[string]State, maxChanges uint,
|
||||
ctx Context) (map[string]MailboxChanges, SessionState, State, Language, Error) {
|
||||
return changesN(j, "GetMailboxChangesForMultipleAccounts", NS_MAILBOX,
|
||||
accountIds, sinceStateMap,
|
||||
func(accountId string, state State) MailboxChangesCommand {
|
||||
return MailboxChangesCommand{AccountId: accountId, SinceState: state, MaxChanges: posUIntPtr(maxChanges)}
|
||||
return MailboxChangesCommand{AccountId: accountId, SinceState: state, MaxChanges: uintPtr(maxChanges)}
|
||||
},
|
||||
MailboxChangesResponse{},
|
||||
func(accountId string, path string, ref string) MailboxGetRefCommand {
|
||||
@@ -172,12 +174,13 @@ func (j *Client) GetMailboxChangesForMultipleAccounts(accountIds []string, sessi
|
||||
newMailboxChanges,
|
||||
identity1,
|
||||
func(resp MailboxGetResponse) State { return resp.State },
|
||||
session, ctx, logger, acceptLanguage,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) GetMailboxRolesForMultipleAccounts(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (map[string][]string, SessionState, State, Language, Error) {
|
||||
logger = j.logger("GetMailboxRolesForMultipleAccounts", session, logger)
|
||||
func (j *Client) GetMailboxRolesForMultipleAccounts(accountIds []string, ctx Context) (map[string][]string, SessionState, State, Language, Error) {
|
||||
logger := j.logger("GetMailboxRolesForMultipleAccounts", ctx)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
n := len(uniqueAccountIds)
|
||||
@@ -205,17 +208,17 @@ func (j *Client) GetMailboxRolesForMultipleAccounts(accountIds []string, session
|
||||
}, mcid(accountId, "1"))
|
||||
}
|
||||
|
||||
cmd, err := j.request(session, logger, NS_MAILBOX, invocations...)
|
||||
cmd, err := j.request(ctx, NS_MAILBOX, invocations...)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (map[string][]string, State, Error) {
|
||||
return command(j, ctx, cmd, func(body *Response) (map[string][]string, State, Error) {
|
||||
resp := make(map[string][]string, n)
|
||||
stateByAccountId := make(map[string]State, n)
|
||||
for _, accountId := range uniqueAccountIds {
|
||||
var getResponse MailboxGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandMailboxGet, mcid(accountId, "1"), &getResponse)
|
||||
err = retrieveResponseMatchParameters(ctx, body, CommandMailboxGet, mcid(accountId, "1"), &getResponse)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
@@ -231,8 +234,9 @@ func (j *Client) GetMailboxRolesForMultipleAccounts(accountIds []string, session
|
||||
})
|
||||
}
|
||||
|
||||
func (j *Client) GetInboxNameForMultipleAccounts(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (map[string]string, SessionState, State, Language, Error) {
|
||||
logger = j.logger("GetInboxNameForMultipleAccounts", session, logger)
|
||||
func (j *Client) GetInboxNameForMultipleAccounts(accountIds []string, ctx Context) (map[string]string, SessionState, State, Language, Error) {
|
||||
logger := j.logger("GetInboxNameForMultipleAccounts", ctx)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
n := len(uniqueAccountIds)
|
||||
@@ -250,17 +254,17 @@ func (j *Client) GetInboxNameForMultipleAccounts(accountIds []string, session *S
|
||||
}, mcid(accountId, "0"))
|
||||
}
|
||||
|
||||
cmd, err := j.request(session, logger, NS_MAILBOX, invocations...)
|
||||
cmd, err := j.request(ctx, NS_MAILBOX, invocations...)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (map[string]string, State, Error) {
|
||||
return command(j, ctx, cmd, func(body *Response) (map[string]string, State, Error) {
|
||||
resp := make(map[string]string, n)
|
||||
stateByAccountId := make(map[string]State, n)
|
||||
for _, accountId := range uniqueAccountIds {
|
||||
var r MailboxQueryResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandMailboxGet, mcid(accountId, "0"), &r)
|
||||
err = retrieveResponseMatchParameters(ctx, body, CommandMailboxGet, mcid(accountId, "0"), &r)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
@@ -280,89 +284,48 @@ func (j *Client) GetInboxNameForMultipleAccounts(accountIds []string, session *S
|
||||
})
|
||||
}
|
||||
|
||||
func (j *Client) UpdateMailbox(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, mailboxId string, ifInState string, update MailboxChange) (Mailbox, SessionState, State, Language, Error) { //NOSONAR
|
||||
logger = j.logger("UpdateMailbox", session, logger)
|
||||
cmd, err := j.request(session, logger, NS_MAILBOX, invocation(MailboxSetCommand{
|
||||
AccountId: accountId,
|
||||
IfInState: ifInState,
|
||||
Update: map[string]PatchObject{
|
||||
mailboxId: update.AsPatch(),
|
||||
func (j *Client) UpdateMailbox(accountId string, mailboxId string, change MailboxChange, //NOSONAR
|
||||
ctx Context) (Mailbox, SessionState, State, Language, Error) {
|
||||
return update(j, "UpdateMailbox", NS_MAILBOX,
|
||||
func(update map[string]PatchObject) MailboxSetCommand {
|
||||
return MailboxSetCommand{AccountId: accountId, Update: update}
|
||||
},
|
||||
}, "0"))
|
||||
if err != nil {
|
||||
return Mailbox{}, "", "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (Mailbox, State, Error) {
|
||||
var setResp MailboxSetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandMailboxSet, "0", &setResp)
|
||||
if err != nil {
|
||||
return Mailbox{}, "", err
|
||||
}
|
||||
setErr, notok := setResp.NotUpdated["u"]
|
||||
if notok {
|
||||
logger.Error().Msgf("%T.NotUpdated returned an error %v", setResp, setErr)
|
||||
return Mailbox{}, "", setErrorError(setErr, MailboxType)
|
||||
}
|
||||
return setResp.Updated["c"], setResp.NewState, nil
|
||||
})
|
||||
}
|
||||
|
||||
func (j *Client) CreateMailbox(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, ifInState string, create MailboxChange) (Mailbox, SessionState, State, Language, Error) {
|
||||
logger = j.logger("CreateMailbox", session, logger)
|
||||
cmd, err := j.request(session, logger, NS_MAILBOX, invocation(MailboxSetCommand{
|
||||
AccountId: accountId,
|
||||
IfInState: ifInState,
|
||||
Create: map[string]MailboxChange{
|
||||
"c": create,
|
||||
func(id string) MailboxGetCommand {
|
||||
return MailboxGetCommand{AccountId: accountId, Ids: []string{id}}
|
||||
},
|
||||
}, "0"))
|
||||
if err != nil {
|
||||
return Mailbox{}, "", "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (Mailbox, State, Error) {
|
||||
var setResp MailboxSetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandMailboxSet, "0", &setResp)
|
||||
if err != nil {
|
||||
return Mailbox{}, "", err
|
||||
}
|
||||
setErr, notok := setResp.NotCreated["c"]
|
||||
if notok {
|
||||
logger.Error().Msgf("%T.NotCreated returned an error %v", setResp, setErr)
|
||||
return Mailbox{}, "", setErrorError(setErr, MailboxType)
|
||||
}
|
||||
if mailbox, ok := setResp.Created["c"]; ok {
|
||||
return mailbox, setResp.NewState, nil
|
||||
} else {
|
||||
return Mailbox{}, "", jmapError(fmt.Errorf("failed to find created %T in response", Mailbox{}), JmapErrorMissingCreatedObject)
|
||||
}
|
||||
})
|
||||
func(resp MailboxSetResponse) map[string]SetError { return resp.NotUpdated },
|
||||
func(resp MailboxGetResponse) Mailbox { return resp.List[0] },
|
||||
mailboxId, change,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) DeleteMailboxes(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, ifInState string, mailboxIds []string) ([]string, SessionState, State, Language, Error) {
|
||||
logger = j.logger("DeleteMailbox", session, logger)
|
||||
set := MailboxSetCommand{
|
||||
AccountId: accountId,
|
||||
IfInState: ifInState,
|
||||
Destroy: mailboxIds,
|
||||
}
|
||||
cmd, err := j.request(session, logger, NS_MAILBOX, invocation(set, "0"))
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) ([]string, State, Error) {
|
||||
var setResp MailboxSetResponse
|
||||
err = retrieveSet(logger, body, set, "0", &setResp)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
setErr, notok := setResp.NotDestroyed["u"]
|
||||
if notok {
|
||||
logger.Error().Msgf("%T.NotDestroyed returned an error %v", setResp, setErr)
|
||||
return nil, "", setErrorError(setErr, MailboxType)
|
||||
}
|
||||
return setResp.Destroyed, setResp.NewState, nil
|
||||
})
|
||||
func (j *Client) CreateMailbox(accountId string, mailbox MailboxChange, ctx Context) (*Mailbox, SessionState, State, Language, Error) {
|
||||
return create(j, "CreateMailbox", NS_MAILBOX,
|
||||
func(accountId string, create map[string]MailboxChange) MailboxSetCommand {
|
||||
return MailboxSetCommand{AccountId: accountId, Create: create}
|
||||
},
|
||||
func(accountId string, ids string) MailboxGetCommand {
|
||||
return MailboxGetCommand{AccountId: accountId, Ids: []string{ids}}
|
||||
},
|
||||
func(resp MailboxSetResponse) map[string]*Mailbox {
|
||||
return resp.Created
|
||||
},
|
||||
func(resp MailboxGetResponse) []Mailbox {
|
||||
return resp.List
|
||||
},
|
||||
accountId, mailbox,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) DeleteMailboxes(accountId string, destroyIds []string, ctx Context) (map[string]SetError, SessionState, State, Language, Error) {
|
||||
return destroy(j, "DeleteMailboxes", NS_MAILBOX,
|
||||
func(accountId string, destroy []string) MailboxSetCommand {
|
||||
return MailboxSetCommand{AccountId: accountId, Destroy: destroyIds}
|
||||
},
|
||||
MailboxSetResponse{},
|
||||
accountId, destroyIds,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package jmap
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
)
|
||||
|
||||
@@ -22,14 +20,15 @@ type Objects struct {
|
||||
|
||||
// Retrieve objects of all types by their identifiers in a single batch.
|
||||
// @api:tags changes
|
||||
func (j *Client) GetObjects(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, //NOSONAR
|
||||
func (j *Client) GetObjects(accountId string, //NOSONAR
|
||||
mailboxIds []string, emailIds []string,
|
||||
addressbookIds []string, contactIds []string,
|
||||
calendarIds []string, eventIds []string,
|
||||
quotaIds []string, identityIds []string,
|
||||
emailSubmissionIds []string,
|
||||
ctx Context,
|
||||
) (Objects, SessionState, State, Language, Error) {
|
||||
l := j.logger("GetObjects", session, logger).With()
|
||||
l := j.logger("GetObjects", ctx).With()
|
||||
if len(mailboxIds) > 0 {
|
||||
l = l.Array("mailboxIds", log.SafeStringArray(mailboxIds))
|
||||
}
|
||||
@@ -57,7 +56,8 @@ func (j *Client) GetObjects(accountId string, session *Session, ctx context.Cont
|
||||
if len(emailSubmissionIds) > 0 {
|
||||
l = l.Array("emailSubmissionIds", log.SafeStringArray(emailSubmissionIds))
|
||||
}
|
||||
logger = log.From(l)
|
||||
logger := log.From(l)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
methodCalls := []Invocation{}
|
||||
if len(mailboxIds) > 0 {
|
||||
@@ -88,17 +88,17 @@ func (j *Client) GetObjects(accountId string, session *Session, ctx context.Cont
|
||||
methodCalls = append(methodCalls, invocation(EmailSubmissionGetCommand{AccountId: accountId, Ids: emailSubmissionIds}, "emailSubmissionIds"))
|
||||
}
|
||||
|
||||
cmd, err := j.request(session, logger, NS_OBJECTS, methodCalls...)
|
||||
cmd, err := j.request(ctx, NS_OBJECTS, methodCalls...)
|
||||
if err != nil {
|
||||
return Objects{}, "", "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (Objects, State, Error) {
|
||||
return command(j, ctx, cmd, func(body *Response) (Objects, State, Error) {
|
||||
objs := Objects{}
|
||||
states := map[string]State{}
|
||||
|
||||
var mailboxes MailboxGetResponse
|
||||
if ok, err := tryRetrieveResponseMatchParameters(logger, body, CommandMailboxGet, "mailboxes", &mailboxes); err != nil {
|
||||
if ok, err := tryRetrieveResponseMatchParameters(ctx, body, CommandMailboxGet, "mailboxes", &mailboxes); err != nil {
|
||||
return Objects{}, "", err
|
||||
} else if ok {
|
||||
objs.Mailboxes = &mailboxes
|
||||
@@ -106,7 +106,7 @@ func (j *Client) GetObjects(accountId string, session *Session, ctx context.Cont
|
||||
}
|
||||
|
||||
var emails EmailGetResponse
|
||||
if ok, err := tryRetrieveResponseMatchParameters(logger, body, CommandEmailGet, "emails", &emails); err != nil {
|
||||
if ok, err := tryRetrieveResponseMatchParameters(ctx, body, CommandEmailGet, "emails", &emails); err != nil {
|
||||
return Objects{}, "", err
|
||||
} else if ok {
|
||||
objs.Emails = &emails
|
||||
@@ -114,7 +114,7 @@ func (j *Client) GetObjects(accountId string, session *Session, ctx context.Cont
|
||||
}
|
||||
|
||||
var calendars CalendarGetResponse
|
||||
if ok, err := tryRetrieveResponseMatchParameters(logger, body, CommandCalendarGet, "calendars", &calendars); err != nil {
|
||||
if ok, err := tryRetrieveResponseMatchParameters(ctx, body, CommandCalendarGet, "calendars", &calendars); err != nil {
|
||||
return Objects{}, "", err
|
||||
} else if ok {
|
||||
objs.Calendars = &calendars
|
||||
@@ -122,7 +122,7 @@ func (j *Client) GetObjects(accountId string, session *Session, ctx context.Cont
|
||||
}
|
||||
|
||||
var events CalendarEventGetResponse
|
||||
if ok, err := tryRetrieveResponseMatchParameters(logger, body, CommandCalendarEventGet, "events", &events); err != nil {
|
||||
if ok, err := tryRetrieveResponseMatchParameters(ctx, body, CommandCalendarEventGet, "events", &events); err != nil {
|
||||
return Objects{}, "", err
|
||||
} else if ok {
|
||||
objs.Events = &events
|
||||
@@ -130,7 +130,7 @@ func (j *Client) GetObjects(accountId string, session *Session, ctx context.Cont
|
||||
}
|
||||
|
||||
var addressbooks AddressBookGetResponse
|
||||
if ok, err := tryRetrieveResponseMatchParameters(logger, body, CommandAddressBookGet, "addressbooks", &addressbooks); err != nil {
|
||||
if ok, err := tryRetrieveResponseMatchParameters(ctx, body, CommandAddressBookGet, "addressbooks", &addressbooks); err != nil {
|
||||
return Objects{}, "", err
|
||||
} else if ok {
|
||||
objs.Addressbooks = &addressbooks
|
||||
@@ -138,7 +138,7 @@ func (j *Client) GetObjects(accountId string, session *Session, ctx context.Cont
|
||||
}
|
||||
|
||||
var contacts ContactCardGetResponse
|
||||
if ok, err := tryRetrieveResponseMatchParameters(logger, body, CommandContactCardGet, "contacts", &contacts); err != nil {
|
||||
if ok, err := tryRetrieveResponseMatchParameters(ctx, body, CommandContactCardGet, "contacts", &contacts); err != nil {
|
||||
return Objects{}, "", err
|
||||
} else if ok {
|
||||
objs.Contacts = &contacts
|
||||
@@ -146,7 +146,7 @@ func (j *Client) GetObjects(accountId string, session *Session, ctx context.Cont
|
||||
}
|
||||
|
||||
var quotas QuotaGetResponse
|
||||
if ok, err := tryRetrieveResponseMatchParameters(logger, body, CommandQuotaGet, "quotas", "as); err != nil {
|
||||
if ok, err := tryRetrieveResponseMatchParameters(ctx, body, CommandQuotaGet, "quotas", "as); err != nil {
|
||||
return Objects{}, "", err
|
||||
} else if ok {
|
||||
objs.Quotas = "as
|
||||
@@ -154,7 +154,7 @@ func (j *Client) GetObjects(accountId string, session *Session, ctx context.Cont
|
||||
}
|
||||
|
||||
var identities IdentityGetResponse
|
||||
if ok, err := tryRetrieveResponseMatchParameters(logger, body, CommandIdentityGet, "identities", &identities); err != nil {
|
||||
if ok, err := tryRetrieveResponseMatchParameters(ctx, body, CommandIdentityGet, "identities", &identities); err != nil {
|
||||
return Objects{}, "", err
|
||||
} else if ok {
|
||||
objs.Identities = &identities
|
||||
@@ -162,7 +162,7 @@ func (j *Client) GetObjects(accountId string, session *Session, ctx context.Cont
|
||||
}
|
||||
|
||||
var submissions EmailSubmissionGetResponse
|
||||
if ok, err := tryRetrieveResponseMatchParameters(logger, body, CommandEmailSubmissionGet, "submissions", &submissions); err != nil {
|
||||
if ok, err := tryRetrieveResponseMatchParameters(ctx, body, CommandEmailSubmissionGet, "submissions", &submissions); err != nil {
|
||||
return Objects{}, "", err
|
||||
} else if ok {
|
||||
objs.EmailSubmissions = &submissions
|
||||
|
||||
@@ -1,37 +1,50 @@
|
||||
package jmap
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
)
|
||||
|
||||
var NS_PRINCIPALS = ns(JmapPrincipals)
|
||||
|
||||
type PrincipalsResponse struct {
|
||||
Principals []Principal `json:"principals"`
|
||||
NotFound []string `json:"notFound,omitempty"`
|
||||
}
|
||||
|
||||
func (j *Client) GetPrincipals(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, ids []string) (PrincipalsResponse, SessionState, State, Language, Error) {
|
||||
logger = j.logger("GetPrincipals", session, logger)
|
||||
|
||||
cmd, err := j.request(session, logger, NS_PRINCIPALS,
|
||||
invocation(PrincipalGetCommand{AccountId: accountId, Ids: ids}, "0"),
|
||||
func (j *Client) GetPrincipals(accountId string, ids []string, ctx Context) (PrincipalGetResponse, SessionState, State, Language, Error) {
|
||||
return get(j, "GetPrincipals", NS_PRINCIPALS,
|
||||
func(accountId string, ids []string) PrincipalGetCommand {
|
||||
return PrincipalGetCommand{AccountId: accountId, Ids: ids}
|
||||
},
|
||||
PrincipalGetResponse{},
|
||||
identity1,
|
||||
accountId, ids,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
type PrincipalSearchResults SearchResultsTemplate[Principal]
|
||||
|
||||
var _ SearchResults[Principal] = PrincipalSearchResults{}
|
||||
|
||||
func (r PrincipalSearchResults) GetResults() []Principal { return r.Results }
|
||||
func (r PrincipalSearchResults) GetCanCalculateChanges() bool { return r.CanCalculateChanges }
|
||||
func (r PrincipalSearchResults) GetPosition() uint { return r.Position }
|
||||
func (r PrincipalSearchResults) GetLimit() uint { return r.Limit }
|
||||
func (r PrincipalSearchResults) GetTotal() *uint { return r.Total }
|
||||
|
||||
func (j *Client) QueryPrincipals(accountId string,
|
||||
filter PrincipalFilterElement, sortBy []PrincipalComparator,
|
||||
position uint, limit uint, calculateTotal bool,
|
||||
ctx Context) (PrincipalSearchResults, SessionState, State, Language, Error) {
|
||||
return query(j, "QueryPrincipals", NS_PRINCIPALS,
|
||||
[]PrincipalComparator{{Property: PrincipalPropertyName, IsAscending: true}},
|
||||
func(filter PrincipalFilterElement, sortBy []PrincipalComparator, position uint, limit uint) PrincipalQueryCommand {
|
||||
return PrincipalQueryCommand{AccountId: accountId, Filter: filter, Sort: sortBy, Position: position, Limit: limit, CalculateTotal: calculateTotal}
|
||||
},
|
||||
func(cmd Command, path string, rof string) PrincipalGetRefCommand {
|
||||
return PrincipalGetRefCommand{AccountId: accountId, IdsRef: &ResultReference{Name: cmd, Path: path, ResultOf: rof}}
|
||||
},
|
||||
func(query PrincipalQueryResponse, get PrincipalGetResponse) PrincipalSearchResults {
|
||||
return PrincipalSearchResults{
|
||||
Results: get.List,
|
||||
CanCalculateChanges: query.CanCalculateChanges,
|
||||
Position: query.Position,
|
||||
Total: uintPtrIf(query.Total, calculateTotal),
|
||||
Limit: query.Limit,
|
||||
}
|
||||
},
|
||||
filter, sortBy, limit, position, ctx,
|
||||
)
|
||||
if err != nil {
|
||||
return PrincipalsResponse{}, "", "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (PrincipalsResponse, State, Error) {
|
||||
var response PrincipalGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandPrincipalGet, "0", &response)
|
||||
if err != nil {
|
||||
return PrincipalsResponse{}, response.State, err
|
||||
}
|
||||
return PrincipalsResponse{
|
||||
Principals: response.List,
|
||||
NotFound: response.NotFound,
|
||||
}, response.State, nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
package jmap
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
)
|
||||
|
||||
var NS_QUOTA = ns(JmapQuota)
|
||||
|
||||
func (j *Client) GetQuotas(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (map[string]QuotaGetResponse, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetQuotas(accountIds []string, ctx Context) (map[string]QuotaGetResponse, SessionState, State, Language, Error) {
|
||||
return getN(j, "GetQuotas", NS_QUOTA,
|
||||
func(accountId string, ids []string) QuotaGetCommand {
|
||||
return QuotaGetCommand{AccountId: accountId}
|
||||
@@ -16,7 +10,8 @@ func (j *Client) GetQuotas(accountIds []string, session *Session, ctx context.Co
|
||||
QuotaGetResponse{},
|
||||
identity1,
|
||||
identity1,
|
||||
accountIds, session, ctx, logger, acceptLanguage, []string{},
|
||||
accountIds, []string{},
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -24,11 +19,11 @@ type QuotaChanges = ChangesTemplate[Quota]
|
||||
|
||||
// Retrieve the changes in Quotas since a given State.
|
||||
// @api:tags quota,changes
|
||||
func (j *Client) GetQuotaChanges(accountId string, session *Session, ctx context.Context, logger *log.Logger,
|
||||
acceptLanguage string, sinceState State, maxChanges uint) (QuotaChanges, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetQuotaChanges(accountId string, sinceState State, maxChanges uint,
|
||||
ctx Context) (QuotaChanges, SessionState, State, Language, Error) {
|
||||
return changesA(j, "GetQuotaChanges", NS_QUOTA,
|
||||
func() QuotaChangesCommand {
|
||||
return QuotaChangesCommand{AccountId: accountId, SinceState: sinceState, MaxChanges: posUIntPtr(maxChanges)}
|
||||
return QuotaChangesCommand{AccountId: accountId, SinceState: sinceState, MaxChanges: uintPtr(maxChanges)}
|
||||
},
|
||||
QuotaChangesResponse{},
|
||||
QuotaGetResponse{},
|
||||
@@ -52,15 +47,15 @@ func (j *Client) GetQuotaChanges(accountId string, session *Session, ctx context
|
||||
Destroyed: destroyed,
|
||||
}
|
||||
},
|
||||
session, ctx, logger, acceptLanguage,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) GetQuotaUsageChanges(accountId string, session *Session, ctx context.Context, logger *log.Logger,
|
||||
acceptLanguage string, sinceState State, maxChanges uint) (QuotaChanges, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetQuotaUsageChanges(accountId string, sinceState State, maxChanges uint,
|
||||
ctx Context) (QuotaChanges, SessionState, State, Language, Error) {
|
||||
return updates(j, "GetQuotaUsageChanges", NS_QUOTA,
|
||||
func() QuotaChangesCommand {
|
||||
return QuotaChangesCommand{AccountId: accountId, SinceState: sinceState, MaxChanges: posUIntPtr(maxChanges)}
|
||||
return QuotaChangesCommand{AccountId: accountId, SinceState: sinceState, MaxChanges: uintPtr(maxChanges)}
|
||||
},
|
||||
QuotaChangesResponse{},
|
||||
func(path string, rof string) QuotaGetRefCommand {
|
||||
@@ -87,6 +82,6 @@ func (j *Client) GetQuotaUsageChanges(accountId string, session *Session, ctx co
|
||||
Updated: updated,
|
||||
}
|
||||
},
|
||||
session, ctx, logger, acceptLanguage,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
package jmap
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
)
|
||||
|
||||
var NS_VACATION = ns(JmapVacationResponse)
|
||||
@@ -14,19 +11,20 @@ const (
|
||||
vacationResponseId = "singleton"
|
||||
)
|
||||
|
||||
func (j *Client) GetVacationResponse(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (VacationResponseGetResponse, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetVacationResponse(accountId string, ctx Context) (VacationResponseGetResponse, SessionState, State, Language, Error) {
|
||||
return get(j, "GetVacationResponse", NS_VACATION,
|
||||
func(accountId string, ids []string) VacationResponseGetCommand {
|
||||
return VacationResponseGetCommand{AccountId: accountId}
|
||||
},
|
||||
VacationResponseGetResponse{},
|
||||
identity1,
|
||||
accountId, session, ctx, logger, acceptLanguage, []string{},
|
||||
accountId, []string{},
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
// Same as VacationResponse but without the id.
|
||||
type VacationResponsePayload struct {
|
||||
type VacationResponseChange struct {
|
||||
// Should a vacation response be sent if a message arrives between the "fromDate" and "toDate"?
|
||||
IsEnabled bool `json:"isEnabled"`
|
||||
// If "isEnabled" is true, messages that arrive on or after this date-time (but before the "toDate" if defined) should receive the
|
||||
@@ -49,33 +47,39 @@ type VacationResponsePayload struct {
|
||||
HtmlBody string `json:"htmlBody,omitempty"`
|
||||
}
|
||||
|
||||
func (j *Client) SetVacationResponse(accountId string, vacation VacationResponsePayload, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (VacationResponse, SessionState, State, Language, Error) {
|
||||
logger = j.logger("SetVacationResponse", session, logger)
|
||||
func (j *Client) SetVacationResponse(accountId string, vacation VacationResponseChange,
|
||||
ctx Context) (VacationResponse, SessionState, State, Language, Error) {
|
||||
logger := j.logger("SetVacationResponse", ctx)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
cmd, err := j.request(session, logger, NS_VACATION,
|
||||
invocation(VacationResponseSetCommand{
|
||||
AccountId: accountId,
|
||||
Create: map[string]VacationResponse{
|
||||
vacationResponseId: {
|
||||
IsEnabled: vacation.IsEnabled,
|
||||
FromDate: vacation.FromDate,
|
||||
ToDate: vacation.ToDate,
|
||||
Subject: vacation.Subject,
|
||||
TextBody: vacation.TextBody,
|
||||
HtmlBody: vacation.HtmlBody,
|
||||
},
|
||||
set := VacationResponseSetCommand{
|
||||
AccountId: accountId,
|
||||
Create: map[string]VacationResponse{
|
||||
vacationResponseId: {
|
||||
IsEnabled: vacation.IsEnabled,
|
||||
FromDate: vacation.FromDate,
|
||||
ToDate: vacation.ToDate,
|
||||
Subject: vacation.Subject,
|
||||
TextBody: vacation.TextBody,
|
||||
HtmlBody: vacation.HtmlBody,
|
||||
},
|
||||
}, "0"),
|
||||
},
|
||||
}
|
||||
|
||||
get := VacationResponseGetCommand{AccountId: accountId}
|
||||
|
||||
cmd, err := j.request(ctx, NS_VACATION,
|
||||
invocation(set, "0"),
|
||||
// chain a second request to get the current complete VacationResponse object
|
||||
// after performing the changes, as that makes for a better API
|
||||
invocation(VacationResponseGetCommand{AccountId: accountId}, "1"),
|
||||
invocation(get, "1"),
|
||||
)
|
||||
if err != nil {
|
||||
return VacationResponse{}, "", "", "", err
|
||||
}
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (VacationResponse, State, Error) {
|
||||
return command(j, ctx, cmd, func(body *Response) (VacationResponse, State, Error) {
|
||||
var setResponse VacationResponseSetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandVacationResponseSet, "0", &setResponse)
|
||||
err = retrieveSet(ctx, body, set, "0", &setResponse)
|
||||
if err != nil {
|
||||
return VacationResponse{}, "", err
|
||||
}
|
||||
@@ -88,7 +92,7 @@ func (j *Client) SetVacationResponse(accountId string, vacation VacationResponse
|
||||
}
|
||||
|
||||
var getResponse VacationResponseGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandVacationResponseGet, "1", &getResponse)
|
||||
err = retrieveGet(ctx, body, get, "1", &getResponse)
|
||||
if err != nil {
|
||||
return VacationResponse{}, "", err
|
||||
}
|
||||
|
||||
@@ -22,13 +22,27 @@ type Client struct {
|
||||
WsPushListener
|
||||
}
|
||||
|
||||
type ApiSupplier interface {
|
||||
Api() ApiClient
|
||||
}
|
||||
|
||||
type Hooks interface {
|
||||
OnSessionOutdated(session *Session, newState SessionState)
|
||||
}
|
||||
|
||||
var _ io.Closer = &Client{}
|
||||
var _ WsPushListener = &Client{}
|
||||
var _ ApiSupplier = &Client{}
|
||||
var _ Hooks = &Client{}
|
||||
|
||||
func (j *Client) Close() error {
|
||||
return errors.Join(j.api.Close(), j.session.Close(), j.blob.Close(), j.ws.Close())
|
||||
}
|
||||
|
||||
func (j *Client) Api() ApiClient {
|
||||
return j.api
|
||||
}
|
||||
|
||||
func NewClient(session SessionClient, api ApiClient, blob BlobClient, ws WsClientFactory) Client {
|
||||
return Client{
|
||||
session: session,
|
||||
@@ -44,7 +58,7 @@ func (j *Client) AddSessionEventListener(listener SessionEventListener) {
|
||||
j.sessionEventListeners.add(listener)
|
||||
}
|
||||
|
||||
func (j *Client) onSessionOutdated(session *Session, newSessionState SessionState) {
|
||||
func (j *Client) OnSessionOutdated(session *Session, newSessionState SessionState) {
|
||||
j.sessionEventListeners.signal(func(listener SessionEventListener) {
|
||||
listener.OnSessionOutdated(session, newSessionState)
|
||||
})
|
||||
@@ -65,25 +79,25 @@ func (j *Client) FetchSession(ctx context.Context, sessionUrl *url.URL, username
|
||||
return newSession(wk)
|
||||
}
|
||||
|
||||
func (j *Client) logger(operation string, _ *Session, logger *log.Logger) *log.Logger {
|
||||
l := logger.With().Str(logOperation, operation)
|
||||
func (j *Client) logger(operation string, ctx Context) *log.Logger {
|
||||
l := ctx.Logger.With().Str(logOperation, operation)
|
||||
return log.From(l)
|
||||
}
|
||||
|
||||
func (j *Client) loggerParams(operation string, _ *Session, logger *log.Logger, params func(zerolog.Context) zerolog.Context) *log.Logger {
|
||||
l := logger.With().Str(logOperation, operation)
|
||||
func (j *Client) loggerParams(operation string, ctx Context, params func(zerolog.Context) zerolog.Context) *log.Logger {
|
||||
l := ctx.Logger.With().Str(logOperation, operation)
|
||||
if params != nil {
|
||||
l = params(l)
|
||||
}
|
||||
return log.From(l)
|
||||
}
|
||||
|
||||
func (j *Client) maxCallsCheck(calls int, session *Session, logger *log.Logger) Error {
|
||||
if calls > session.Capabilities.Core.MaxCallsInRequest {
|
||||
logger.Error().
|
||||
Int("max-calls-in-request", session.Capabilities.Core.MaxCallsInRequest).
|
||||
func (j *Client) maxCallsCheck(calls int, ctx Context) Error {
|
||||
if calls > ctx.Session.Capabilities.Core.MaxCallsInRequest {
|
||||
ctx.Logger.Error().
|
||||
Int("max-calls-in-request", ctx.Session.Capabilities.Core.MaxCallsInRequest).
|
||||
Int("calls-in-request", calls).
|
||||
Msgf("number of calls in request payload (%d) exceeds the allowed maximum (%d)", session.Capabilities.Core.MaxCallsInRequest, calls)
|
||||
Msgf("number of calls in request payload (%d) exceeds the allowed maximum (%d)", ctx.Session.Capabilities.Core.MaxCallsInRequest, calls)
|
||||
return jmapError(errTooManyMethodCalls, JmapErrorTooManyMethodCalls)
|
||||
}
|
||||
return nil
|
||||
@@ -92,8 +106,8 @@ func (j *Client) maxCallsCheck(calls int, session *Session, logger *log.Logger)
|
||||
// Construct a Request from the given list of Invocation objects.
|
||||
//
|
||||
// If an issue occurs, then it is logged prior to returning it.
|
||||
func (j *Client) request(session *Session, logger *log.Logger, using []JmapNamespace, methodCalls ...Invocation) (Request, Error) {
|
||||
err := j.maxCallsCheck(len(methodCalls), session, logger)
|
||||
func (j *Client) request(ctx Context, using []JmapNamespace, methodCalls ...Invocation) (Request, Error) {
|
||||
err := j.maxCallsCheck(len(methodCalls), ctx)
|
||||
if err != nil {
|
||||
return Request{}, err
|
||||
}
|
||||
|
||||
@@ -217,7 +217,12 @@ func (h *HttpJmapClient) GetSession(ctx context.Context, sessionUrl *url.URL, us
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (h *HttpJmapClient) Command(ctx context.Context, logger *log.Logger, session *Session, request Request, acceptLanguage string) ([]byte, Language, Error) { //NOSONAR
|
||||
func (h *HttpJmapClient) Command(request Request, ctx Context) ([]byte, Language, Error) { //NOSONAR
|
||||
session := ctx.Session
|
||||
logger := ctx.Logger
|
||||
acceptLanguage := ctx.AcceptLanguage
|
||||
cotx := ctx.Context
|
||||
|
||||
jmapUrl := session.JmapUrl.String()
|
||||
endpoint := session.JmapEndpoint
|
||||
logger = log.From(logger.With().Str(logEndpoint, endpoint))
|
||||
@@ -228,7 +233,7 @@ func (h *HttpJmapClient) Command(ctx context.Context, logger *log.Logger, sessio
|
||||
return nil, "", jmapError(err, JmapErrorEncodingRequestBody)
|
||||
}
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, jmapUrl, bytes.NewBuffer(bodyBytes))
|
||||
req, err := http.NewRequestWithContext(cotx, http.MethodPost, jmapUrl, bytes.NewBuffer(bodyBytes))
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msgf("failed to create POST request for %v", jmapUrl)
|
||||
return nil, "", jmapError(err, JmapErrorCreatingRequest)
|
||||
@@ -249,7 +254,7 @@ func (h *HttpJmapClient) Command(ctx context.Context, logger *log.Logger, sessio
|
||||
logger.Trace().Str(logEndpoint, endpoint).Str(logProto, logProtoJmap).Str(logType, logTypeRequest).Msg(string(requestBytes))
|
||||
}
|
||||
}
|
||||
if err := h.auth(ctx, session.Username, logger, req); err != nil {
|
||||
if err := h.auth(cotx, session.Username, logger, req); err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
@@ -295,10 +300,15 @@ func (h *HttpJmapClient) Command(ctx context.Context, logger *log.Logger, sessio
|
||||
return body, language, nil
|
||||
}
|
||||
|
||||
func (h *HttpJmapClient) UploadBinary(ctx context.Context, logger *log.Logger, session *Session, uploadUrl string, endpoint string, contentType string, acceptLanguage string, body io.Reader) (UploadedBlob, Language, Error) { //NOSONAR
|
||||
func (h *HttpJmapClient) UploadBinary(uploadUrl string, endpoint string, contentType string, body io.Reader, ctx Context) (UploadedBlob, Language, Error) { //NOSONAR
|
||||
session := ctx.Session
|
||||
logger := ctx.Logger
|
||||
acceptLanguage := ctx.AcceptLanguage
|
||||
cotx := ctx.Context
|
||||
|
||||
logger = log.From(logger.With().Str(logEndpoint, endpoint))
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, uploadUrl, body)
|
||||
req, err := http.NewRequestWithContext(cotx, http.MethodPost, uploadUrl, body)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msgf("failed to create POST request for %v", uploadUrl)
|
||||
return UploadedBlob{}, "", jmapError(err, JmapErrorCreatingRequest)
|
||||
@@ -315,7 +325,7 @@ func (h *HttpJmapClient) UploadBinary(ctx context.Context, logger *log.Logger, s
|
||||
}
|
||||
}
|
||||
|
||||
if err := h.auth(ctx, session.Username, logger, req); err != nil {
|
||||
if err := h.auth(cotx, session.Username, logger, req); err != nil {
|
||||
return UploadedBlob{}, "", err
|
||||
}
|
||||
|
||||
@@ -357,8 +367,6 @@ func (h *HttpJmapClient) UploadBinary(ctx context.Context, logger *log.Logger, s
|
||||
return UploadedBlob{}, language, jmapError(err, JmapErrorServerResponse)
|
||||
}
|
||||
|
||||
logger.Trace()
|
||||
|
||||
var result UploadedBlob
|
||||
err = json.Unmarshal(responseBody, &result)
|
||||
if err != nil {
|
||||
@@ -370,10 +378,15 @@ func (h *HttpJmapClient) UploadBinary(ctx context.Context, logger *log.Logger, s
|
||||
return result, language, nil
|
||||
}
|
||||
|
||||
func (h *HttpJmapClient) DownloadBinary(ctx context.Context, logger *log.Logger, session *Session, downloadUrl string, endpoint string, acceptLanguage string) (*BlobDownload, Language, Error) { //NOSONAR
|
||||
func (h *HttpJmapClient) DownloadBinary(downloadUrl string, endpoint string, ctx Context) (*BlobDownload, Language, Error) { //NOSONAR
|
||||
session := ctx.Session
|
||||
logger := ctx.Logger
|
||||
acceptLanguage := ctx.AcceptLanguage
|
||||
cotx := ctx.Context
|
||||
|
||||
logger = log.From(logger.With().Str(logEndpoint, endpoint))
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, downloadUrl, nil)
|
||||
req, err := http.NewRequestWithContext(cotx, http.MethodGet, downloadUrl, nil)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msgf("failed to create GET request for %v", downloadUrl)
|
||||
return nil, "", jmapError(err, JmapErrorCreatingRequest)
|
||||
@@ -389,7 +402,7 @@ func (h *HttpJmapClient) DownloadBinary(ctx context.Context, logger *log.Logger,
|
||||
}
|
||||
}
|
||||
|
||||
if err := h.auth(ctx, session.Username, logger, req); err != nil {
|
||||
if err := h.auth(cotx, session.Username, logger, req); err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package jmap
|
||||
|
||||
import (
|
||||
"context"
|
||||
golog "log"
|
||||
"math/rand"
|
||||
"regexp"
|
||||
@@ -20,7 +19,6 @@ import (
|
||||
"github.com/ProtonMail/go-crypto/openpgp"
|
||||
"github.com/brianvoe/gofakeit/v7"
|
||||
"github.com/opencloud-eu/opencloud/pkg/jscontact"
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
"github.com/opencloud-eu/opencloud/pkg/structs"
|
||||
)
|
||||
|
||||
@@ -45,17 +43,17 @@ func TestAddressBooks(t *testing.T) {
|
||||
func(session *Session) string { return session.PrimaryAccounts.Contacts },
|
||||
list,
|
||||
getid,
|
||||
func(s *StalwartTest, accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, ids []string) (AddressBookGetResponse, SessionState, State, Language, Error) {
|
||||
return s.client.GetAddressbooks(accountId, session, ctx, logger, acceptLanguage, ids)
|
||||
func(s *StalwartTest, accountId string, ids []string, ctx Context) (AddressBookGetResponse, SessionState, State, Language, Error) {
|
||||
return s.client.GetAddressbooks(accountId, ids, ctx)
|
||||
},
|
||||
func(s *StalwartTest, accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, id string, change AddressBookChange) (AddressBook, SessionState, State, Language, Error) { //NOSONAR
|
||||
return s.client.UpdateAddressBook(accountId, session, ctx, logger, acceptLanguage, id, change)
|
||||
func(s *StalwartTest, accountId string, id string, change AddressBookChange, ctx Context) (AddressBook, SessionState, State, Language, Error) { //NOSONAR
|
||||
return s.client.UpdateAddressBook(accountId, id, change, ctx)
|
||||
},
|
||||
func(s *StalwartTest, accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, ids []string) (map[string]SetError, SessionState, State, Language, Error) { //NOSONAR
|
||||
return s.client.DeleteAddressBook(accountId, ids, session, ctx, logger, acceptLanguage)
|
||||
func(s *StalwartTest, accountId string, ids []string, ctx Context) (map[string]SetError, SessionState, State, Language, Error) { //NOSONAR
|
||||
return s.client.DeleteAddressBook(accountId, ids, ctx)
|
||||
},
|
||||
func(s *StalwartTest, t *testing.T, accountId string, count uint, session *Session, user User, principalIds []string) (AddressBookBoxes, []AddressBook, SessionState, State, error) {
|
||||
return s.fillAddressBook(t, accountId, count, session, user, principalIds)
|
||||
func(s *StalwartTest, t *testing.T, accountId string, count uint, ctx Context, user User, principalIds []string) (AddressBookBoxes, []AddressBook, SessionState, State, error) {
|
||||
return s.fillAddressBook(t, accountId, count, ctx, user, principalIds)
|
||||
},
|
||||
func(orig AddressBook) AddressBookChange {
|
||||
return AddressBookChange{
|
||||
@@ -86,6 +84,7 @@ func TestContacts(t *testing.T) {
|
||||
|
||||
user := pickUser()
|
||||
session := s.Session(user.name)
|
||||
ctx := s.Context(session)
|
||||
|
||||
accountId, addressbookId, expectedContactCardsById, boxes, err := s.fillContacts(t, count, session, user)
|
||||
require.NoError(err)
|
||||
@@ -99,15 +98,19 @@ func TestContacts(t *testing.T) {
|
||||
{Property: ContactCardPropertyCreated, IsAscending: true},
|
||||
}
|
||||
|
||||
contactsByAccount, _, _, _, err := s.client.QueryContactCards([]string{accountId}, session, t.Context(), s.logger, "", filter, sortBy, 0, 0)
|
||||
contactsByAccount, _, _, _, err := s.client.QueryContactCards([]string{accountId}, filter, sortBy, 0, 0, true, ctx)
|
||||
require.NoError(err)
|
||||
|
||||
require.Len(contactsByAccount, 1)
|
||||
require.Contains(contactsByAccount, accountId)
|
||||
contacts := contactsByAccount[accountId]
|
||||
require.Len(contacts, int(count))
|
||||
results := contactsByAccount[accountId]
|
||||
require.Len(results.Results, int(count))
|
||||
require.Equal(uint(0), results.Limit)
|
||||
require.Equal(uint(0), results.Position)
|
||||
require.Equal(uint(0), results.Total)
|
||||
require.Equal(true, results.CanCalculateChanges)
|
||||
|
||||
for _, actual := range contacts {
|
||||
for _, actual := range results.Results {
|
||||
expected, ok := expectedContactCardsById[actual.Id]
|
||||
require.True(ok, "failed to find created contact by its id")
|
||||
matchContact(t, actual, expected)
|
||||
@@ -115,13 +118,13 @@ func TestContacts(t *testing.T) {
|
||||
|
||||
// retrieve all objects at once
|
||||
{
|
||||
ids := structs.Map(contacts, func(c ContactCard) string { return c.Id })
|
||||
fetched, _, _, _, err := s.client.GetContactCards(accountId, session, t.Context(), s.logger, "", ids)
|
||||
ids := structs.Map(results.Results, func(c ContactCard) string { return c.Id })
|
||||
fetched, _, _, _, 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 })
|
||||
for _, actual := range contacts {
|
||||
for _, actual := range results.Results {
|
||||
expected, ok := byId[actual.Id]
|
||||
require.True(ok, "failed to find created contact by its id")
|
||||
matchContact(t, actual, expected)
|
||||
@@ -129,8 +132,8 @@ func TestContacts(t *testing.T) {
|
||||
}
|
||||
|
||||
// retrieve each object one by one
|
||||
for _, actual := range contacts {
|
||||
fetched, _, _, _, err := s.client.GetContactCards(accountId, session, t.Context(), s.logger, "", []string{actual.Id})
|
||||
for _, actual := range results.Results {
|
||||
fetched, _, _, _, err := s.client.GetContactCards(accountId, []string{actual.Id}, ctx)
|
||||
require.NoError(err)
|
||||
require.Len(fetched.List, 1)
|
||||
matchContact(t, fetched.List[0], actual)
|
||||
@@ -169,7 +172,7 @@ func (s *StalwartTest) fillAddressBook( //NOSONAR
|
||||
t *testing.T,
|
||||
accountId string,
|
||||
count uint,
|
||||
session *Session,
|
||||
ctx Context,
|
||||
_ User,
|
||||
principalIds []string,
|
||||
) (AddressBookBoxes, []AddressBook, SessionState, State, error) {
|
||||
@@ -192,7 +195,7 @@ func (s *StalwartTest) fillAddressBook( //NOSONAR
|
||||
IsSubscribed: &subscribed,
|
||||
}
|
||||
if i%2 == 0 {
|
||||
abook.SortOrder = posUIntPtr(gofakeit.Uint())
|
||||
abook.SortOrder = uintPtr(gofakeit.Uint())
|
||||
boxes.sortOrdered = true
|
||||
}
|
||||
var sharing *AddressBookRights = nil
|
||||
@@ -218,7 +221,7 @@ func (s *StalwartTest) fillAddressBook( //NOSONAR
|
||||
abook.ShareWith = m
|
||||
}
|
||||
|
||||
a, sessionState, state, _, err := s.client.CreateAddressBook(accountId, session, s.ctx, s.logger, "", abook)
|
||||
a, sessionState, state, _, err := s.client.CreateAddressBook(accountId, abook, ctx)
|
||||
if err != nil {
|
||||
return boxes, created, ss, as, err
|
||||
}
|
||||
|
||||
@@ -40,10 +40,11 @@ func TestEmails(t *testing.T) {
|
||||
|
||||
user := pickUser()
|
||||
session := s.Session(user.name)
|
||||
ctx := s.Context(session)
|
||||
|
||||
accountId := session.PrimaryAccounts.Mail
|
||||
|
||||
inboxId, inboxFolder := s.findInbox(t, accountId, session)
|
||||
inboxId, inboxFolder := s.findInbox(t, accountId, ctx)
|
||||
|
||||
var threads int = 0
|
||||
var mails []filledMail = nil
|
||||
@@ -55,7 +56,7 @@ func TestEmails(t *testing.T) {
|
||||
|
||||
{
|
||||
{
|
||||
resp, sessionState, _, _, err := s.client.GetAllIdentities(accountId, session, s.ctx, s.logger, "")
|
||||
resp, sessionState, _, _, err := s.client.GetAllIdentities(accountId, ctx)
|
||||
require.NoError(err)
|
||||
require.Equal(session.State, sessionState)
|
||||
require.Len(resp, 1)
|
||||
@@ -64,7 +65,7 @@ func TestEmails(t *testing.T) {
|
||||
}
|
||||
|
||||
{
|
||||
respByAccountId, sessionState, _, _, err := s.client.GetAllMailboxes([]string{accountId}, session, s.ctx, s.logger, "")
|
||||
respByAccountId, sessionState, _, _, err := s.client.GetAllMailboxes([]string{accountId}, ctx)
|
||||
require.NoError(err)
|
||||
require.Equal(session.State, sessionState)
|
||||
require.Len(respByAccountId, 1)
|
||||
@@ -80,7 +81,7 @@ func TestEmails(t *testing.T) {
|
||||
}
|
||||
|
||||
{
|
||||
resp, sessionState, _, _, err := s.client.GetAllEmailsInMailbox(accountId, session, s.ctx, s.logger, "", inboxId, 0, 0, true, false, 0, true)
|
||||
resp, sessionState, _, _, err := s.client.GetAllEmailsInMailbox(accountId, inboxId, 0, 0, true, false, 0, true, ctx)
|
||||
require.NoError(err)
|
||||
require.Equal(session.State, sessionState)
|
||||
|
||||
@@ -94,7 +95,7 @@ func TestEmails(t *testing.T) {
|
||||
}
|
||||
|
||||
{
|
||||
resp, sessionState, _, _, err := s.client.GetAllEmailsInMailbox(accountId, session, s.ctx, s.logger, "", inboxId, 0, 0, false, false, 0, true)
|
||||
resp, sessionState, _, _, err := s.client.GetAllEmailsInMailbox(accountId, inboxId, 0, 0, false, false, 0, true, ctx)
|
||||
require.NoError(err)
|
||||
require.Equal(session.State, sessionState)
|
||||
|
||||
@@ -122,6 +123,7 @@ func TestSendingEmails(t *testing.T) {
|
||||
|
||||
from := pickUser()
|
||||
session := s.Session(from.name)
|
||||
ctx := s.Context(session)
|
||||
accountId := session.PrimaryAccounts.Mail
|
||||
|
||||
var to User
|
||||
@@ -142,7 +144,7 @@ func TestSendingEmails(t *testing.T) {
|
||||
|
||||
var mailboxPerRole map[string]Mailbox
|
||||
{
|
||||
mailboxes, _, _, _, err := s.client.GetAllMailboxes([]string{accountId}, session, s.ctx, s.logger, "")
|
||||
mailboxes, _, _, _, err := s.client.GetAllMailboxes([]string{accountId}, ctx)
|
||||
require.NoError(err)
|
||||
mailboxPerRole = structs.Index(mailboxes[accountId], func(m Mailbox) string { return m.Role })
|
||||
require.Contains(mailboxPerRole, JmapMailboxRoleInbox)
|
||||
@@ -152,7 +154,7 @@ func TestSendingEmails(t *testing.T) {
|
||||
}
|
||||
{
|
||||
roles := []string{JmapMailboxRoleDrafts, JmapMailboxRoleSent, JmapMailboxRoleInbox}
|
||||
m, _, _, _, err := s.client.SearchMailboxIdsPerRole([]string{accountId}, session, s.ctx, s.logger, "", roles)
|
||||
m, _, _, _, err := s.client.SearchMailboxIdsPerRole([]string{accountId}, roles, ctx)
|
||||
require.NoError(err)
|
||||
require.Contains(m, accountId)
|
||||
a := m[accountId]
|
||||
@@ -166,7 +168,7 @@ func TestSendingEmails(t *testing.T) {
|
||||
accountId string
|
||||
session *Session
|
||||
}{{toAccountId, toSession}, {ccAccountId, ccSession}} {
|
||||
mailboxes, _, _, _, err := s.client.GetAllMailboxes([]string{u.accountId}, u.session, s.ctx, s.logger, "")
|
||||
mailboxes, _, _, _, err := s.client.GetAllMailboxes([]string{u.accountId}, ctx)
|
||||
require.NoError(err)
|
||||
for _, mailbox := range mailboxes[u.accountId] {
|
||||
require.Equal(0, mailbox.TotalEmails)
|
||||
@@ -180,7 +182,7 @@ func TestSendingEmails(t *testing.T) {
|
||||
{
|
||||
var identity Identity
|
||||
{
|
||||
identities, _, _, _, err := s.client.GetAllIdentities(accountId, session, s.ctx, s.logger, "")
|
||||
identities, _, _, _, err := s.client.GetAllIdentities(accountId, ctx)
|
||||
require.NoError(err)
|
||||
require.NotEmpty(identities)
|
||||
identity = identities[0]
|
||||
@@ -191,12 +193,12 @@ func TestSendingEmails(t *testing.T) {
|
||||
Subject: subject,
|
||||
MailboxIds: toBoolMapS(mailboxPerRole[JmapMailboxRoleDrafts].Id),
|
||||
}
|
||||
created, _, _, _, err := s.client.CreateEmail(accountId, create, "", session, s.ctx, s.logger, "")
|
||||
created, _, _, _, err := s.client.CreateEmail(accountId, create, "", ctx)
|
||||
require.NoError(err)
|
||||
require.NotEmpty(created.Id)
|
||||
|
||||
{
|
||||
emails, notFound, _, _, _, err := s.client.GetEmails(accountId, session, s.ctx, s.logger, "", []string{created.Id}, true, 0, false, false)
|
||||
emails, notFound, _, _, _, err := s.client.GetEmails(accountId, []string{created.Id}, true, 0, false, false, ctx)
|
||||
require.NoError(err)
|
||||
require.Len(emails, 1)
|
||||
require.Empty(notFound)
|
||||
@@ -215,14 +217,14 @@ func TestSendingEmails(t *testing.T) {
|
||||
Subject: subject,
|
||||
MailboxIds: toBoolMapS(mailboxPerRole[JmapMailboxRoleDrafts].Id),
|
||||
}
|
||||
updated, _, _, _, err := s.client.CreateEmail(accountId, update, created.Id, session, s.ctx, s.logger, "")
|
||||
updated, _, _, _, err := s.client.CreateEmail(accountId, update, created.Id, ctx)
|
||||
require.NoError(err)
|
||||
require.NotEmpty(updated.Id)
|
||||
require.NotEqual(created.Id, updated.Id)
|
||||
|
||||
var updatedMailboxId string
|
||||
{
|
||||
emails, notFound, _, _, _, err := s.client.GetEmails(accountId, session, s.ctx, s.logger, "", []string{created.Id, updated.Id}, true, 0, false, false)
|
||||
emails, notFound, _, _, _, 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)
|
||||
@@ -241,7 +243,7 @@ func TestSendingEmails(t *testing.T) {
|
||||
ToMailboxId: mailboxPerRole[JmapMailboxRoleSent].Id,
|
||||
}
|
||||
|
||||
sub, _, _, _, err := s.client.SubmitEmail(accountId, identity.Id, updated.Id, &move, session, s.ctx, s.logger, "")
|
||||
sub, _, _, _, err := s.client.SubmitEmail(accountId, identity.Id, updated.Id, &move, ctx)
|
||||
require.NoError(err)
|
||||
require.NotEmpty(sub.Id)
|
||||
require.NotEmpty(sub.ThreadId)
|
||||
@@ -272,7 +274,7 @@ func TestSendingEmails(t *testing.T) {
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
subs, notFound, _, _, _, err := s.client.GetEmailSubmissionStatus(accountId, []string{sub.Id}, session, s.ctx, s.logger, "")
|
||||
subs, notFound, _, _, _, err := s.client.GetEmailSubmissionStatus(accountId, []string{sub.Id}, ctx)
|
||||
require.NoError(err)
|
||||
require.Empty(notFound)
|
||||
require.Contains(subs, sub.Id)
|
||||
@@ -286,7 +288,7 @@ func TestSendingEmails(t *testing.T) {
|
||||
accountId string
|
||||
session *Session
|
||||
}{{to, toAccountId, toSession}, {cc, ccAccountId, ccSession}} {
|
||||
mailboxes, _, _, _, err := s.client.GetAllMailboxes([]string{r.accountId}, r.session, s.ctx, s.logger, "")
|
||||
mailboxes, _, _, _, err := s.client.GetAllMailboxes([]string{r.accountId}, ctx)
|
||||
require.NoError(err)
|
||||
inboxId := ""
|
||||
for _, mailbox := range mailboxes[r.accountId] {
|
||||
@@ -297,7 +299,7 @@ func TestSendingEmails(t *testing.T) {
|
||||
}
|
||||
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}, r.session, s.ctx, s.logger, "", 0, 0, true, 0)
|
||||
emails, _, _, _, err := s.client.QueryEmails([]string{r.accountId}, EmailFilterCondition{InMailbox: inboxId}, 0, 0, true, 0, ctx)
|
||||
require.NoError(err)
|
||||
require.Contains(emails, r.accountId)
|
||||
require.Len(emails[r.accountId].Emails, 1)
|
||||
@@ -354,11 +356,11 @@ func matchEmail(t *testing.T, actual Email, expected filledMail, hasBodies bool)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StalwartTest) findInbox(t *testing.T, accountId string, session *Session) (string, string) {
|
||||
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}, session, s.ctx, s.logger, "")
|
||||
respByAccountId, sessionState, _, _, err := s.client.GetAllMailboxes([]string{accountId}, ctx)
|
||||
require.NoError(err)
|
||||
require.Equal(session.State, sessionState)
|
||||
require.Equal(ctx.Session.State, sessionState)
|
||||
require.Len(respByAccountId, 1)
|
||||
require.Contains(respByAccountId, accountId)
|
||||
resp := respByAccountId[accountId]
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package jmap
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
@@ -17,7 +16,6 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/jscalendar"
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
"github.com/opencloud-eu/opencloud/pkg/structs"
|
||||
)
|
||||
|
||||
@@ -36,17 +34,17 @@ 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, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, ids []string) (CalendarGetResponse, SessionState, State, Language, Error) {
|
||||
return s.client.GetCalendars(accountId, session, ctx, logger, acceptLanguage, ids)
|
||||
func(s *StalwartTest, accountId string, ids []string, ctx Context) (CalendarGetResponse, SessionState, State, Language, Error) {
|
||||
return s.client.GetCalendars(accountId, ids, ctx)
|
||||
},
|
||||
func(s *StalwartTest, accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, id string, change CalendarChange) (Calendar, SessionState, State, Language, Error) { //NOSONAR
|
||||
return s.client.UpdateCalendar(accountId, session, ctx, logger, acceptLanguage, id, change)
|
||||
func(s *StalwartTest, accountId string, id string, change CalendarChange, ctx Context) (Calendar, SessionState, State, Language, Error) { //NOSONAR
|
||||
return s.client.UpdateCalendar(accountId, id, change, ctx)
|
||||
},
|
||||
func(s *StalwartTest, accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, ids []string) (map[string]SetError, SessionState, State, Language, Error) { //NOSONAR
|
||||
return s.client.DeleteCalendar(accountId, ids, session, ctx, logger, acceptLanguage)
|
||||
func(s *StalwartTest, accountId string, ids []string, ctx Context) (map[string]SetError, SessionState, State, Language, Error) { //NOSONAR
|
||||
return s.client.DeleteCalendar(accountId, ids, ctx)
|
||||
},
|
||||
func(s *StalwartTest, t *testing.T, accountId string, count uint, session *Session, user User, principalIds []string) (CalendarBoxes, []Calendar, SessionState, State, error) {
|
||||
return s.fillCalendar(t, accountId, count, session, user, principalIds)
|
||||
func(s *StalwartTest, t *testing.T, accountId string, count uint, ctx Context, user User, principalIds []string) (CalendarBoxes, []Calendar, SessionState, State, error) {
|
||||
return s.fillCalendar(t, accountId, count, ctx, user, principalIds)
|
||||
},
|
||||
func(orig Calendar) CalendarChange {
|
||||
return CalendarChange{
|
||||
@@ -77,6 +75,7 @@ func TestEvents(t *testing.T) {
|
||||
|
||||
user := pickUser()
|
||||
session := s.Session(user.name)
|
||||
ctx := s.Context(session)
|
||||
|
||||
accountId, calendarId, expectedEventsById, boxes, err := s.fillEvents(t, count, session, user)
|
||||
require.NoError(err)
|
||||
@@ -90,18 +89,49 @@ func TestEvents(t *testing.T) {
|
||||
{Property: CalendarEventPropertyStart, IsAscending: true},
|
||||
}
|
||||
|
||||
contactsByAccount, _, _, _, err := s.client.QueryCalendarEvents([]string{accountId}, session, t.Context(), s.logger, "", filter, sortBy, 0, 0)
|
||||
require.NoError(err)
|
||||
{
|
||||
resultsByAccount, _, _, _, err := s.client.QueryCalendarEvents([]string{accountId}, filter, sortBy, 0, 0, true, ctx)
|
||||
require.NoError(err)
|
||||
|
||||
require.Len(contactsByAccount, 1)
|
||||
require.Contains(contactsByAccount, accountId)
|
||||
contacts := contactsByAccount[accountId]
|
||||
require.Len(contacts, int(count))
|
||||
require.Len(resultsByAccount, 1)
|
||||
require.Contains(resultsByAccount, accountId)
|
||||
results := resultsByAccount[accountId]
|
||||
require.Len(results.Results, int(count))
|
||||
require.Equal(uint(0), results.Limit)
|
||||
require.Equal(uint(0), results.Position)
|
||||
require.Equal(true, results.CanCalculateChanges)
|
||||
require.NotNil(results.Total)
|
||||
require.Equal(count, *results.Total)
|
||||
|
||||
for _, actual := range contacts {
|
||||
expected, ok := expectedEventsById[actual.Id]
|
||||
require.True(ok, "failed to find created contact by its id")
|
||||
matchEvent(t, actual, expected)
|
||||
for _, actual := range results.Results {
|
||||
expected, ok := expectedEventsById[actual.Id]
|
||||
require.True(ok, "failed to find created contact by its id")
|
||||
matchEvent(t, actual, expected)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
limit := uint(10)
|
||||
slices := count / limit
|
||||
remainder := count
|
||||
require.Greater(slices, uint(1), "we need to have more than 10 objects in order to test the pagination of search results")
|
||||
for i := range slices {
|
||||
position := int(i * limit)
|
||||
page := min(remainder, limit)
|
||||
m, _, _, _, err := s.client.QueryCalendarEvents([]string{accountId}, filter, sortBy, position, limit, true, ctx)
|
||||
fmt.Printf("=== i=%d | limit=%d | remainder=%d | position=%d | limit=%d | results=%d\n", i, limit, remainder, position, limit, len(m[accountId].Results))
|
||||
require.NoError(err)
|
||||
require.Len(m, 1)
|
||||
require.Contains(m, accountId)
|
||||
results := m[accountId]
|
||||
require.Equal(len(results.Results), int(page))
|
||||
require.Equal(limit, results.Limit)
|
||||
require.Equal(position, results.Position)
|
||||
require.Equal(true, results.CanCalculateChanges)
|
||||
require.NotNil(results.Total)
|
||||
require.Equal(count, *results.Total)
|
||||
remainder -= uint(len(results.Results))
|
||||
}
|
||||
}
|
||||
|
||||
exceptions := []string{}
|
||||
@@ -127,7 +157,7 @@ func (s *StalwartTest) fillCalendar( //NOSONAR
|
||||
t *testing.T,
|
||||
accountId string,
|
||||
count uint,
|
||||
session *Session,
|
||||
ctx Context,
|
||||
_ User,
|
||||
principalIds []string,
|
||||
) (CalendarBoxes, []Calendar, SessionState, State, error) {
|
||||
@@ -180,7 +210,7 @@ func (s *StalwartTest) fillCalendar( //NOSONAR
|
||||
},
|
||||
}
|
||||
if i%2 == 0 {
|
||||
cal.SortOrder = posUIntPtr(gofakeit.Uint())
|
||||
cal.SortOrder = uintPtr(gofakeit.Uint())
|
||||
boxes.sortOrdered = true
|
||||
}
|
||||
var sharing *CalendarRights = nil
|
||||
@@ -233,7 +263,7 @@ func (s *StalwartTest) fillCalendar( //NOSONAR
|
||||
cal.ShareWith = m
|
||||
}
|
||||
|
||||
a, sessionState, state, _, err := s.client.CreateCalendar(accountId, session, s.ctx, s.logger, "", cal)
|
||||
a, sessionState, state, _, err := s.client.CreateCalendar(accountId, cal, ctx)
|
||||
if err != nil {
|
||||
return boxes, created, ss, as, err
|
||||
}
|
||||
|
||||
@@ -175,6 +175,15 @@ func (s *StalwartTest) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *StalwartTest) Context(session *Session) Context {
|
||||
return Context{
|
||||
Session: session,
|
||||
Context: s.ctx,
|
||||
Logger: s.logger,
|
||||
AcceptLanguage: "",
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StalwartTest) Session(username string) *Session {
|
||||
session, jerr := s.client.FetchSession(s.ctx, s.sessionUrl, username, s.logger)
|
||||
require.NoError(s.t, jerr)
|
||||
@@ -1218,10 +1227,10 @@ 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, session *Session, ctx context.Context, logger *clog.Logger, acceptLanguage string, ids []string) (RESP, SessionState, State, Language, Error),
|
||||
update func(s *StalwartTest, accountId string, session *Session, ctx context.Context, logger *clog.Logger, acceptLanguage string, id string, change CHANGE) (OBJ, SessionState, State, Language, Error),
|
||||
destroy func(s *StalwartTest, accountId string, session *Session, ctx context.Context, logger *clog.Logger, acceptLanguage string, ids []string) (map[string]SetError, SessionState, State, Language, Error),
|
||||
fill func(s *StalwartTest, t *testing.T, accountId string, count uint, session *Session, _ User, principalIds []string) (BOXES, []OBJ, SessionState, State, error),
|
||||
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),
|
||||
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),
|
||||
) {
|
||||
@@ -1233,16 +1242,17 @@ func containerTest[OBJ Idable, RESP GetResponse[OBJ], BOXES any, CHANGE Change](
|
||||
|
||||
user := pickUser()
|
||||
session := s.Session(user.name)
|
||||
ctx := s.Context(session)
|
||||
|
||||
accountId := acc(session)
|
||||
|
||||
// we first need to retrieve the list of all the Principals in order to be able to use and test sharing
|
||||
principalIds := []string{}
|
||||
{
|
||||
principals, _, _, _, err := s.client.GetPrincipals(accountId, session, s.ctx, s.logger, "", []string{})
|
||||
principals, _, _, _, err := s.client.GetPrincipals(accountId, []string{}, ctx)
|
||||
require.NoError(err)
|
||||
require.NotEmpty(principals.Principals)
|
||||
principalIds = structs.Map(principals.Principals, func(p Principal) string { return p.Id })
|
||||
require.NotEmpty(principals.List)
|
||||
principalIds = structs.Map(principals.List, func(p Principal) string { return p.Id })
|
||||
}
|
||||
|
||||
ss := SessionState("")
|
||||
@@ -1252,7 +1262,7 @@ func containerTest[OBJ Idable, RESP GetResponse[OBJ], BOXES any, CHANGE Change](
|
||||
// from the tests below
|
||||
defaultContainerId := ""
|
||||
{
|
||||
resp, sessionState, state, _, err := get(s, accountId, session, s.ctx, s.logger, "", []string{})
|
||||
resp, sessionState, state, _, err := get(s, accountId, []string{}, ctx)
|
||||
require.NoError(err)
|
||||
require.Empty(resp.GetNotFound())
|
||||
objs := obj(resp)
|
||||
@@ -1265,7 +1275,7 @@ func containerTest[OBJ Idable, RESP GetResponse[OBJ], BOXES any, CHANGE Change](
|
||||
// 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, session, user, principalIds)
|
||||
boxes, all, sessionState, state, err := fill(s, t, accountId, num, ctx, user, principalIds)
|
||||
require.NoError(err)
|
||||
require.Len(all, int(num))
|
||||
ss = sessionState
|
||||
@@ -1273,7 +1283,7 @@ func containerTest[OBJ Idable, RESP GetResponse[OBJ], BOXES any, CHANGE Change](
|
||||
|
||||
{
|
||||
// lets retrieve all the existing objects by passing an empty ID slice
|
||||
resp, sessionState, state, _, err := get(s, accountId, session, s.ctx, s.logger, "", []string{})
|
||||
resp, sessionState, state, _, err := get(s, accountId, []string{}, ctx)
|
||||
require.NoError(err)
|
||||
require.Empty(resp.GetNotFound())
|
||||
objs := obj(resp)
|
||||
@@ -1300,7 +1310,7 @@ func containerTest[OBJ Idable, RESP GetResponse[OBJ], BOXES any, CHANGE Change](
|
||||
// lets retrieve every object we created by its ID
|
||||
for _, a := range all {
|
||||
i := id(a)
|
||||
resp, sessionState, state, _, err := get(s, accountId, session, s.ctx, s.logger, "", []string{i})
|
||||
resp, sessionState, state, _, err := get(s, accountId, []string{i}, ctx)
|
||||
require.NoError(err)
|
||||
require.Empty(resp.GetNotFound())
|
||||
objs := obj(resp)
|
||||
@@ -1314,7 +1324,7 @@ 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, session, s.ctx, s.logger, "", i, ch)
|
||||
changed, sessionState, state, _, err := update(s, accountId, i, ch, ctx)
|
||||
require.NoError(err)
|
||||
require.NotEqual(a, changed)
|
||||
require.Equal(sessionState, ss)
|
||||
@@ -1325,7 +1335,7 @@ func containerTest[OBJ Idable, RESP GetResponse[OBJ], BOXES any, CHANGE Change](
|
||||
// now lets delete each object that we created, all at once
|
||||
ids := structs.Map(all, id)
|
||||
{
|
||||
errMap, sessionState, state, _, err := destroy(s, accountId, session, s.ctx, s.logger, "", ids)
|
||||
errMap, sessionState, state, _, err := destroy(s, accountId, ids, ctx)
|
||||
require.NoError(err)
|
||||
require.Empty(errMap)
|
||||
require.Equal(sessionState, ss)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package jmap
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
@@ -61,7 +60,7 @@ func TestWs(t *testing.T) {
|
||||
|
||||
require := require.New(t)
|
||||
|
||||
ctx := context.Background()
|
||||
cotx := t.Context()
|
||||
|
||||
s, err := newStalwartTest(t)
|
||||
require.NoError(err)
|
||||
@@ -69,11 +68,12 @@ func TestWs(t *testing.T) {
|
||||
|
||||
user := pickUser()
|
||||
session := s.Session(user.name)
|
||||
ctx := s.Context(session)
|
||||
|
||||
mailAccountId := session.PrimaryAccounts.Mail
|
||||
inboxFolder := ""
|
||||
{
|
||||
_, inboxFolder = s.findInbox(t, mailAccountId, session)
|
||||
_, inboxFolder = s.findInbox(t, mailAccountId, ctx)
|
||||
}
|
||||
|
||||
l := &testWsPushListener{t: t, username: user.name, logger: s.logger, mailAccountId: mailAccountId}
|
||||
@@ -90,7 +90,7 @@ func TestWs(t *testing.T) {
|
||||
|
||||
var initialState State
|
||||
{
|
||||
changes, sessionState, state, _, err := s.client.GetEmailChanges(mailAccountId, session, s.ctx, s.logger, "", State(""), true, 0, 0)
|
||||
changes, sessionState, state, _, err := s.client.GetEmailChanges(mailAccountId, EmptyState, true, 0, 0, ctx)
|
||||
require.NoError(err)
|
||||
require.Equal(session.State, sessionState)
|
||||
require.NotEmpty(state)
|
||||
@@ -104,7 +104,7 @@ func TestWs(t *testing.T) {
|
||||
require.NotEmpty(initialState)
|
||||
|
||||
{
|
||||
changes, sessionState, state, _, err := s.client.GetEmailChanges(mailAccountId, session, s.ctx, s.logger, "", initialState, true, 0, 0)
|
||||
changes, sessionState, state, _, err := s.client.GetEmailChanges(mailAccountId, initialState, true, 0, 0, ctx)
|
||||
require.NoError(err)
|
||||
require.Equal(session.State, sessionState)
|
||||
require.Equal(initialState, state)
|
||||
@@ -114,7 +114,7 @@ func TestWs(t *testing.T) {
|
||||
require.Empty(changes.Updated)
|
||||
}
|
||||
|
||||
wsc, err := s.client.EnablePushNotifications(ctx, initialState, func() (*Session, error) { return session, nil })
|
||||
wsc, err := s.client.EnablePushNotifications(cotx, initialState, func() (*Session, error) { return session, nil })
|
||||
require.NoError(err)
|
||||
defer wsc.Close()
|
||||
|
||||
@@ -147,7 +147,7 @@ func TestWs(t *testing.T) {
|
||||
}
|
||||
var lastState State
|
||||
{
|
||||
changes, sessionState, state, _, err := s.client.GetEmailChanges(mailAccountId, session, s.ctx, s.logger, "", initialState, true, 0, 0)
|
||||
changes, sessionState, state, _, err := s.client.GetEmailChanges(mailAccountId, initialState, true, 0, 0, ctx)
|
||||
require.NoError(err)
|
||||
require.Equal(session.State, sessionState)
|
||||
require.NotEqual(initialState, state)
|
||||
@@ -181,7 +181,7 @@ func TestWs(t *testing.T) {
|
||||
l.m.Unlock()
|
||||
}
|
||||
{
|
||||
changes, sessionState, state, _, err := s.client.GetEmailChanges(mailAccountId, session, s.ctx, s.logger, "", lastState, true, 0, 0)
|
||||
changes, sessionState, state, _, err := s.client.GetEmailChanges(mailAccountId, lastState, true, 0, 0, ctx)
|
||||
require.NoError(err)
|
||||
require.Equal(session.State, sessionState)
|
||||
require.NotEqual(lastState, state)
|
||||
@@ -215,7 +215,7 @@ func TestWs(t *testing.T) {
|
||||
l.m.Unlock()
|
||||
}
|
||||
{
|
||||
changes, sessionState, state, _, err := s.client.GetEmailChanges(mailAccountId, session, s.ctx, s.logger, "", lastState, true, 0, 0)
|
||||
changes, sessionState, state, _, err := s.client.GetEmailChanges(mailAccountId, lastState, true, 0, 0, ctx)
|
||||
require.NoError(err)
|
||||
require.Equal(session.State, sessionState)
|
||||
require.NotEqual(lastState, state)
|
||||
|
||||
@@ -1354,13 +1354,32 @@ type ChangesResponse[T Foo] interface {
|
||||
GetMarker() T
|
||||
}
|
||||
|
||||
type QueryCommand interface {
|
||||
type QueryCommand[T Foo] interface {
|
||||
JmapCommand
|
||||
GetResponse() QueryResponse
|
||||
GetResponse() QueryResponse[T]
|
||||
}
|
||||
|
||||
type QueryResponse interface {
|
||||
type QueryResponse[T Foo] interface {
|
||||
GetQueryState() State
|
||||
GetMarker() T
|
||||
}
|
||||
|
||||
type UploadCommand[T Foo] interface {
|
||||
JmapCommand
|
||||
GetResponse() UploadResponse[T]
|
||||
}
|
||||
|
||||
type UploadResponse[T Foo] interface {
|
||||
GetMarker() T
|
||||
}
|
||||
|
||||
type ParseCommand[T Foo] interface {
|
||||
JmapCommand
|
||||
GetResponse() ParseResponse[T]
|
||||
}
|
||||
|
||||
type ParseResponse[T Foo] interface {
|
||||
GetMarker() T
|
||||
}
|
||||
|
||||
type ChangesTemplate[T Foo] struct {
|
||||
@@ -1372,6 +1391,22 @@ type ChangesTemplate[T Foo] struct {
|
||||
Destroyed []string `json:"destroyed,omitempty"`
|
||||
}
|
||||
|
||||
type SearchResultsTemplate[T Foo] struct {
|
||||
Results []T `json:"results"`
|
||||
CanCalculateChanges bool `json:"canCalculateChanges"`
|
||||
Position uint `json:"position"`
|
||||
Limit uint `json:"limit,omitzero"`
|
||||
Total *uint `json:"total,omitzero"`
|
||||
}
|
||||
|
||||
type SearchResults[T Foo] interface {
|
||||
GetResults() []T
|
||||
GetCanCalculateChanges() bool
|
||||
GetPosition() uint
|
||||
GetTotal() *uint
|
||||
GetLimit() uint
|
||||
}
|
||||
|
||||
type FilterOperatorTerm string
|
||||
|
||||
const (
|
||||
@@ -1656,8 +1691,8 @@ type MailboxSetResponse struct {
|
||||
AccountId string `json:"accountId"`
|
||||
OldState State `json:"oldState,omitempty"`
|
||||
NewState State `json:"newState,omitempty"`
|
||||
Created map[string]Mailbox `json:"created,omitempty"`
|
||||
Updated map[string]Mailbox `json:"updated,omitempty"`
|
||||
Created map[string]*Mailbox `json:"created,omitempty"`
|
||||
Updated map[string]*Mailbox `json:"updated,omitempty"`
|
||||
Destroyed []string `json:"destroyed,omitempty"`
|
||||
NotCreated map[string]SetError `json:"notCreated,omitempty"`
|
||||
NotUpdated map[string]SetError `json:"notUpdated,omitempty"`
|
||||
@@ -1717,11 +1752,11 @@ type MailboxQueryCommand struct {
|
||||
FilterAsTree bool `json:"filterAsTree,omitempty"`
|
||||
}
|
||||
|
||||
var _ QueryCommand = &MailboxQueryCommand{}
|
||||
var _ QueryCommand[Mailbox] = &MailboxQueryCommand{}
|
||||
|
||||
func (c MailboxQueryCommand) GetCommand() Command { return CommandMailboxQuery }
|
||||
func (c MailboxQueryCommand) GetObjectType() ObjectType { return MailboxType }
|
||||
func (c MailboxQueryCommand) GetResponse() QueryResponse { return MailboxQueryResponse{} }
|
||||
func (c MailboxQueryCommand) GetCommand() Command { return CommandMailboxQuery }
|
||||
func (c MailboxQueryCommand) GetObjectType() ObjectType { return MailboxType }
|
||||
func (c MailboxQueryCommand) GetResponse() QueryResponse[Mailbox] { return MailboxQueryResponse{} }
|
||||
|
||||
type EmailFilterElement interface {
|
||||
_isAnEmailFilterElement() // marker method
|
||||
@@ -2013,11 +2048,11 @@ type EmailQueryCommand struct {
|
||||
CalculateTotal bool `json:"calculateTotal,omitempty"`
|
||||
}
|
||||
|
||||
var _ QueryCommand = &EmailQueryCommand{}
|
||||
var _ QueryCommand[Email] = &EmailQueryCommand{}
|
||||
|
||||
func (c EmailQueryCommand) GetCommand() Command { return CommandEmailQuery }
|
||||
func (c EmailQueryCommand) GetObjectType() ObjectType { return MailboxType }
|
||||
func (c EmailQueryCommand) GetResponse() QueryResponse { return EmailQueryResponse{} }
|
||||
func (c EmailQueryCommand) GetCommand() Command { return CommandEmailQuery }
|
||||
func (c EmailQueryCommand) GetObjectType() ObjectType { return MailboxType }
|
||||
func (c EmailQueryCommand) GetResponse() QueryResponse[Email] { return EmailQueryResponse{} }
|
||||
|
||||
type EmailGetCommand struct {
|
||||
// The ids of the Email objects to return.
|
||||
@@ -3063,9 +3098,10 @@ type EmailQueryResponse struct {
|
||||
Limit uint `json:"limit,omitempty,omitzero"`
|
||||
}
|
||||
|
||||
var _ QueryResponse = &EmailQueryResponse{}
|
||||
var _ QueryResponse[Email] = &EmailQueryResponse{}
|
||||
|
||||
func (r EmailQueryResponse) GetQueryState() State { return r.QueryState }
|
||||
func (r EmailQueryResponse) GetMarker() Email { return Email{} }
|
||||
|
||||
type EmailGetResponse struct {
|
||||
// The id of the account used for the call.
|
||||
@@ -3284,9 +3320,10 @@ type MailboxQueryResponse struct {
|
||||
Limit int `json:"limit,omitzero"`
|
||||
}
|
||||
|
||||
var _ QueryResponse = &MailboxQueryResponse{}
|
||||
var _ QueryResponse[Mailbox] = &MailboxQueryResponse{}
|
||||
|
||||
func (r MailboxQueryResponse) GetQueryState() State { return r.QueryState }
|
||||
func (r MailboxQueryResponse) GetMarker() Mailbox { return Mailbox{} }
|
||||
|
||||
type EmailCreate struct {
|
||||
// The set of Mailbox ids this Email belongs to.
|
||||
@@ -3727,11 +3764,11 @@ func (r IdentityChangesResponse) GetDestroyed() []string { return r.Destroyed }
|
||||
func (r IdentityChangesResponse) GetMarker() Identity { return Identity{} }
|
||||
|
||||
type IdentitySetCommand struct {
|
||||
AccountId string `json:"accountId"`
|
||||
IfInState string `json:"ifInState,omitempty"`
|
||||
Create map[string]Identity `json:"create,omitempty"`
|
||||
Update map[string]PatchObject `json:"update,omitempty"`
|
||||
Destroy []string `json:"destroy,omitempty"`
|
||||
AccountId string `json:"accountId"`
|
||||
IfInState string `json:"ifInState,omitempty"`
|
||||
Create map[string]IdentityChange `json:"create,omitempty"`
|
||||
Update map[string]PatchObject `json:"update,omitempty"`
|
||||
Destroy []string `json:"destroy,omitempty"`
|
||||
}
|
||||
|
||||
var _ SetCommand[Identity] = &IdentitySetCommand{}
|
||||
@@ -3741,15 +3778,15 @@ func (c IdentitySetCommand) GetObjectType() ObjectType { return Identit
|
||||
func (c IdentitySetCommand) GetResponse() SetResponse[Identity] { return IdentitySetResponse{} }
|
||||
|
||||
type IdentitySetResponse struct {
|
||||
AccountId string `json:"accountId"`
|
||||
OldState State `json:"oldState,omitempty"`
|
||||
NewState State `json:"newState,omitempty"`
|
||||
Created map[string]Identity `json:"created,omitempty"`
|
||||
Updated map[string]Identity `json:"updated,omitempty"`
|
||||
Destroyed []string `json:"destroyed,omitempty"`
|
||||
NotCreated map[string]SetError `json:"notCreated,omitempty"`
|
||||
NotUpdated map[string]SetError `json:"notUpdated,omitempty"`
|
||||
NotDestroyed map[string]SetError `json:"notDestroyed,omitempty"`
|
||||
AccountId string `json:"accountId"`
|
||||
OldState State `json:"oldState,omitempty"`
|
||||
NewState State `json:"newState,omitempty"`
|
||||
Created map[string]*Identity `json:"created,omitempty"`
|
||||
Updated map[string]*Identity `json:"updated,omitempty"`
|
||||
Destroyed []string `json:"destroyed,omitempty"`
|
||||
NotCreated map[string]SetError `json:"notCreated,omitempty"`
|
||||
NotUpdated map[string]SetError `json:"notUpdated,omitempty"`
|
||||
NotDestroyed map[string]SetError `json:"notDestroyed,omitempty"`
|
||||
}
|
||||
|
||||
var _ SetResponse[Identity] = &IdentitySetResponse{}
|
||||
@@ -3810,9 +3847,41 @@ var _ Idable = &Identity{}
|
||||
func (f Identity) GetObjectType() ObjectType { return IdentityType }
|
||||
func (f Identity) GetId() string { return f.Id }
|
||||
|
||||
var _ Change = Identity{}
|
||||
type IdentityChange struct {
|
||||
// The “From” name the client SHOULD use when creating a new Email from this Identity.
|
||||
Name string `json:"name,omitempty" doc:"req"`
|
||||
|
||||
func (i Identity) AsPatch() PatchObject {
|
||||
// The “From” email address the client MUST use when creating a new Email from this Identity.
|
||||
//
|
||||
// If the mailbox part of the address (the section before the “@”) is the single character
|
||||
// * (e.g., *@example.com) then the client may use any valid address ending in that domain
|
||||
// (e.g., foo@example.com).
|
||||
Email string `json:"email,omitempty"`
|
||||
|
||||
// The Reply-To value the client SHOULD set when creating a new Email from this Identity.
|
||||
ReplyTo string `json:"replyTo,omitempty"`
|
||||
|
||||
// The Bcc value the client SHOULD set when creating a new Email from this Identity.
|
||||
Bcc *[]EmailAddress `json:"bcc,omitempty"`
|
||||
|
||||
// A signature the client SHOULD insert into new plaintext messages that will be sent from
|
||||
// this Identity.
|
||||
//
|
||||
// Clients MAY ignore this and/or combine this with a client-specific signature preference.
|
||||
TextSignature *string `json:"textSignature,omitempty"`
|
||||
|
||||
// A signature the client SHOULD insert into new HTML messages that will be sent from this
|
||||
// Identity.
|
||||
//
|
||||
// This text MUST be an HTML snippet to be inserted into the <body></body> section of the HTML.
|
||||
//
|
||||
// Clients MAY ignore this and/or combine this with a client-specific signature preference.
|
||||
HtmlSignature *string `json:"htmlSignature,omitempty"`
|
||||
}
|
||||
|
||||
var _ Change = IdentityChange{}
|
||||
|
||||
func (i IdentityChange) AsPatch() PatchObject {
|
||||
p := PatchObject{}
|
||||
if i.Name != "" {
|
||||
p["name"] = i.Name
|
||||
@@ -3985,10 +4054,11 @@ type BlobUploadCommand struct {
|
||||
Create map[string]UploadObject `json:"create"`
|
||||
}
|
||||
|
||||
var _ JmapCommand = &BlobUploadCommand{}
|
||||
var _ UploadCommand[Blob] = &BlobUploadCommand{}
|
||||
|
||||
func (c BlobUploadCommand) GetCommand() Command { return CommandBlobUpload }
|
||||
func (c BlobUploadCommand) GetObjectType() ObjectType { return BlobType }
|
||||
func (c BlobUploadCommand) GetCommand() Command { return CommandBlobUpload }
|
||||
func (c BlobUploadCommand) GetObjectType() ObjectType { return BlobType }
|
||||
func (c BlobUploadCommand) GetResponse() UploadResponse[Blob] { return BlobUploadResponse{} }
|
||||
|
||||
type BlobUploadCreateResult struct {
|
||||
Id string `json:"id"`
|
||||
@@ -4001,6 +4071,10 @@ type BlobUploadResponse struct {
|
||||
Created map[string]BlobUploadCreateResult `json:"created"`
|
||||
}
|
||||
|
||||
var _ UploadResponse[Blob] = &BlobUploadResponse{}
|
||||
|
||||
func (r BlobUploadResponse) GetMarker() Blob { return Blob{} }
|
||||
|
||||
const (
|
||||
BlobPropertyDataAsText = "data:asText"
|
||||
BlobPropertyDataAsBase64 = "data:asBase64"
|
||||
@@ -5837,6 +5911,28 @@ var _ Idable = &Principal{}
|
||||
func (f Principal) GetObjectType() ObjectType { return PrincipalType }
|
||||
func (f Principal) GetId() string { return f.Id }
|
||||
|
||||
const (
|
||||
PrincipalPropertyId = "id"
|
||||
PrincipalPropertyType = "type"
|
||||
PrincipalPropertyName = "name"
|
||||
PrincipalPropertyDescription = "description"
|
||||
PrincipalPropertyEmail = "email"
|
||||
PrincipalPropertyTimeZone = "timeZone"
|
||||
PrincipalPropertyCapabilities = "capabilites"
|
||||
PrincipalPropertyAccounts = "accounts"
|
||||
)
|
||||
|
||||
var PrincipalProperties = []string{
|
||||
PrincipalPropertyId,
|
||||
PrincipalPropertyType,
|
||||
PrincipalPropertyName,
|
||||
PrincipalPropertyDescription,
|
||||
PrincipalPropertyEmail,
|
||||
PrincipalPropertyTimeZone,
|
||||
PrincipalPropertyCapabilities,
|
||||
PrincipalPropertyAccounts,
|
||||
}
|
||||
|
||||
type ShareChangePerson struct {
|
||||
// The name of the person who made the change.
|
||||
Name string `json:"name"`
|
||||
@@ -6589,7 +6685,7 @@ type ContactCardQueryCommand struct {
|
||||
//
|
||||
// If the index is greater than or equal to the total number of objects in the results
|
||||
// list, then the ids array in the response will be empty, but this is not an error.
|
||||
Position uint `json:"position,omitzero" default:"0" doc:"opt"`
|
||||
Position int `json:"position,omitzero" default:"0" doc:"opt"`
|
||||
|
||||
// An Email id.
|
||||
//
|
||||
@@ -6615,7 +6711,7 @@ type ContactCardQueryCommand struct {
|
||||
// to the maximum; the new limit is returned with the response so the client is aware.
|
||||
//
|
||||
// If a negative value is given, the call MUST be rejected with an invalidArguments error.
|
||||
Limit uint `json:"limit,omitzero" doc:"opt"`
|
||||
Limit *uint `json:"limit,omitzero" doc:"opt"`
|
||||
|
||||
// Does the client wish to know the total number of results in the query?
|
||||
//
|
||||
@@ -6624,11 +6720,13 @@ type ContactCardQueryCommand struct {
|
||||
CalculateTotal bool `json:"calculateTotal,omitzero"`
|
||||
}
|
||||
|
||||
var _ QueryCommand = &ContactCardQueryCommand{}
|
||||
var _ QueryCommand[ContactCard] = &ContactCardQueryCommand{}
|
||||
|
||||
func (c ContactCardQueryCommand) GetCommand() Command { return CommandContactCardQuery }
|
||||
func (c ContactCardQueryCommand) GetObjectType() ObjectType { return ContactCardType }
|
||||
func (c ContactCardQueryCommand) GetResponse() QueryResponse { return ContactCardQueryResponse{} }
|
||||
func (c ContactCardQueryCommand) GetCommand() Command { return CommandContactCardQuery }
|
||||
func (c ContactCardQueryCommand) GetObjectType() ObjectType { return ContactCardType }
|
||||
func (c ContactCardQueryCommand) GetResponse() QueryResponse[ContactCard] {
|
||||
return ContactCardQueryResponse{}
|
||||
}
|
||||
|
||||
type ContactCardQueryResponse struct {
|
||||
// The id of the account used for the call.
|
||||
@@ -6680,9 +6778,10 @@ type ContactCardQueryResponse struct {
|
||||
Limit uint `json:"limit,omitempty,omitzero"`
|
||||
}
|
||||
|
||||
var _ QueryResponse = &ContactCardQueryResponse{}
|
||||
var _ QueryResponse[ContactCard] = &ContactCardQueryResponse{}
|
||||
|
||||
func (r ContactCardQueryResponse) GetQueryState() State { return r.QueryState }
|
||||
func (r ContactCardQueryResponse) GetQueryState() State { return r.QueryState }
|
||||
func (r ContactCardQueryResponse) GetMarker() ContactCard { return ContactCard{} }
|
||||
|
||||
type ContactCardGetCommand struct {
|
||||
// The ids of the ContactCard objects to return.
|
||||
@@ -6960,10 +7059,13 @@ type CalendarEventParseCommand struct {
|
||||
Properties []string `json:"properties,omitempty"`
|
||||
}
|
||||
|
||||
var _ JmapCommand = &CalendarEventParseCommand{}
|
||||
var _ ParseCommand[CalendarEvent] = &CalendarEventParseCommand{}
|
||||
|
||||
func (c CalendarEventParseCommand) GetCommand() Command { return CommandCalendarEventParse }
|
||||
func (c CalendarEventParseCommand) GetObjectType() ObjectType { return CalendarEventType }
|
||||
func (c CalendarEventParseCommand) GetResponse() ParseResponse[CalendarEvent] {
|
||||
return CalendarEventParseResponse{}
|
||||
}
|
||||
|
||||
type CalendarEventParseResponse struct {
|
||||
// The id of the account used for the call.
|
||||
@@ -6981,6 +7083,10 @@ type CalendarEventParseResponse struct {
|
||||
NotParsable []string `json:"notParsable,omitempty"`
|
||||
}
|
||||
|
||||
var _ ParseResponse[CalendarEvent] = &CalendarEventParseResponse{}
|
||||
|
||||
func (r CalendarEventParseResponse) GetMarker() CalendarEvent { return CalendarEvent{} }
|
||||
|
||||
type CalendarGetCommand struct {
|
||||
AccountId string `json:"accountId"`
|
||||
Ids []string `json:"ids,omitempty"`
|
||||
@@ -7309,7 +7415,7 @@ type CalendarEventQueryCommand struct {
|
||||
//
|
||||
// If the index is greater than or equal to the total number of objects in the results
|
||||
// list, then the ids array in the response will be empty, but this is not an error.
|
||||
Position uint `json:"position,omitempty" doc:"opt"`
|
||||
Position int `json:"position,omitempty" doc:"opt"`
|
||||
|
||||
// An Email id.
|
||||
//
|
||||
@@ -7335,7 +7441,7 @@ type CalendarEventQueryCommand struct {
|
||||
// to the maximum; the new limit is returned with the response so the client is aware.
|
||||
//
|
||||
// If a negative value is given, the call MUST be rejected with an invalidArguments error.
|
||||
Limit uint `json:"limit,omitempty" doc:"opt" default:"0"`
|
||||
Limit *uint `json:"limit,omitempty" doc:"opt" default:"0"`
|
||||
|
||||
// Does the client wish to know the total number of results in the query?
|
||||
//
|
||||
@@ -7344,11 +7450,13 @@ type CalendarEventQueryCommand struct {
|
||||
CalculateTotal bool `json:"calculateTotal,omitempty" doc:"opt" default:"false"`
|
||||
}
|
||||
|
||||
var _ QueryCommand = &CalendarEventQueryCommand{}
|
||||
var _ QueryCommand[CalendarEvent] = &CalendarEventQueryCommand{}
|
||||
|
||||
func (c CalendarEventQueryCommand) GetCommand() Command { return CommandCalendarEventQuery }
|
||||
func (c CalendarEventQueryCommand) GetObjectType() ObjectType { return CalendarEventType }
|
||||
func (c CalendarEventQueryCommand) GetResponse() QueryResponse { return CalendarEventQueryResponse{} }
|
||||
func (c CalendarEventQueryCommand) GetCommand() Command { return CommandCalendarEventQuery }
|
||||
func (c CalendarEventQueryCommand) GetObjectType() ObjectType { return CalendarEventType }
|
||||
func (c CalendarEventQueryCommand) GetResponse() QueryResponse[CalendarEvent] {
|
||||
return CalendarEventQueryResponse{}
|
||||
}
|
||||
|
||||
type CalendarEventQueryResponse struct {
|
||||
// The id of the account used for the call.
|
||||
@@ -7400,9 +7508,10 @@ type CalendarEventQueryResponse struct {
|
||||
Limit uint `json:"limit,omitempty,omitzero"`
|
||||
}
|
||||
|
||||
var _ QueryResponse = &CalendarEventQueryResponse{}
|
||||
var _ QueryResponse[CalendarEvent] = &CalendarEventQueryResponse{}
|
||||
|
||||
func (r CalendarEventQueryResponse) GetQueryState() State { return r.QueryState }
|
||||
func (r CalendarEventQueryResponse) GetQueryState() State { return r.QueryState }
|
||||
func (r CalendarEventQueryResponse) GetMarker() CalendarEvent { return CalendarEvent{} }
|
||||
|
||||
type CalendarEventGetCommand struct {
|
||||
// The ids of the CalendarEvent objects to return.
|
||||
@@ -7771,11 +7880,60 @@ type PrincipalComparator struct {
|
||||
}
|
||||
|
||||
type PrincipalQueryCommand struct {
|
||||
AccountId string `json:"accountId"`
|
||||
Filter PrincipalFilterElement `json:"filter,omitempty"`
|
||||
Sort []PrincipalComparator `json:"sort,omitempty"`
|
||||
SortAsTree bool `json:"sortAsTree,omitempty"`
|
||||
FilterAsTree bool `json:"filterAsTree,omitempty"`
|
||||
AccountId string `json:"accountId"`
|
||||
Filter PrincipalFilterElement `json:"filter,omitempty"`
|
||||
Sort []PrincipalComparator `json:"sort,omitempty"`
|
||||
|
||||
// The zero-based index of the first id in the full list of results to return.
|
||||
//
|
||||
// If a negative value is given, it is an offset from the end of the list.
|
||||
// Specifically, the negative value MUST be added to the total number of results given
|
||||
// the filter, and if still negative, it’s clamped to 0. This is now the zero-based
|
||||
// index of the first id to return.
|
||||
//
|
||||
// If the index is greater than or equal to the total number of objects in the results
|
||||
// list, then the ids array in the response will be empty, but this is not an error.
|
||||
Position uint `json:"position,omitzero" default:"0" doc:"opt"`
|
||||
|
||||
// An Email id.
|
||||
//
|
||||
// If supplied, the position argument is ignored.
|
||||
// The index of this id in the results will be used in combination with the anchorOffset
|
||||
// argument to determine the index of the first result to return.
|
||||
Anchor string `json:"anchor,omitempty" doc:"opt"`
|
||||
|
||||
// The index of the first result to return relative to the index of the anchor,
|
||||
// if an anchor is given.
|
||||
//
|
||||
// This MAY be negative.
|
||||
//
|
||||
// For example, -1 means the Principal immediately preceding the anchor is the first result in
|
||||
// the list returned.
|
||||
AnchorOffset int `json:"anchorOffset,omitzero" default:"0" doc:"opt"`
|
||||
|
||||
// The maximum number of results to return.
|
||||
//
|
||||
// If null, no limit presumed.
|
||||
// The server MAY choose to enforce a maximum limit argument.
|
||||
// In this case, if a greater value is given (or if it is null), the limit is clamped
|
||||
// to the maximum; the new limit is returned with the response so the client is aware.
|
||||
//
|
||||
// If a negative value is given, the call MUST be rejected with an invalidArguments error.
|
||||
Limit uint `json:"limit,omitzero" doc:"opt"`
|
||||
|
||||
// Does the client wish to know the total number of results in the query?
|
||||
//
|
||||
// This may be slow and expensive for servers to calculate, particularly with complex filters,
|
||||
// so clients should take care to only request the total when needed.
|
||||
CalculateTotal bool `json:"calculateTotal,omitzero"`
|
||||
}
|
||||
|
||||
var _ QueryCommand[Principal] = PrincipalQueryCommand{}
|
||||
|
||||
func (c PrincipalQueryCommand) GetCommand() Command { return CommandPrincipalQuery }
|
||||
func (c PrincipalQueryCommand) GetObjectType() ObjectType { return PrincipalType }
|
||||
func (c PrincipalQueryCommand) GetResponse() QueryResponse[Principal] {
|
||||
return PrincipalQueryResponse{}
|
||||
}
|
||||
|
||||
type PrincipalQueryResponse struct {
|
||||
@@ -7796,38 +7954,39 @@ type PrincipalQueryResponse struct {
|
||||
//
|
||||
// Should a client receive back a response with a different queryState string to a previous call, it MUST either
|
||||
// throw away the currently cached query and fetch it again (note, this does not require fetching the records
|
||||
// again, just the list of ids) or call Mailbox/queryChanges to get the difference.
|
||||
// again, just the list of ids) or call Principal/queryChanges to get the difference.
|
||||
QueryState State `json:"queryState"`
|
||||
|
||||
// This is true if the server supports calling Mailbox/queryChanges with these filter/sort parameters.
|
||||
// This is true if the server supports calling Principal/queryChanges with these filter/sort parameters.
|
||||
//
|
||||
// Note, this does not guarantee that the Mailbox/queryChanges call will succeed, as it may only be possible for
|
||||
// Note, this does not guarantee that the Principal/queryChanges call will succeed, as it may only be possible for
|
||||
// a limited time afterwards due to server internal implementation details.
|
||||
CanCalculateChanges bool `json:"canCalculateChanges"`
|
||||
|
||||
// The zero-based index of the first result in the ids array within the complete list of query results.
|
||||
Position int `json:"position"`
|
||||
Position uint `json:"position"`
|
||||
|
||||
// The list of ids for each Mailbox in the query results, starting at the index given by the position argument
|
||||
// The list of ids for each Principal in the query results, starting at the index given by the position argument
|
||||
// of this response and continuing until it hits the end of the results or reaches the limit number of ids.
|
||||
//
|
||||
// If position is >= total, this MUST be the empty list.
|
||||
Ids []string `json:"ids"`
|
||||
|
||||
// The total number of Mailbox in the results (given the filter) (only if requested).
|
||||
// The total number of Principal in the results (given the filter) (only if requested).
|
||||
//
|
||||
// This argument MUST be omitted if the calculateTotal request argument is not true.
|
||||
Total int `json:"total,omitzero"`
|
||||
Total uint `json:"total,omitzero"`
|
||||
|
||||
// The limit enforced by the server on the maximum number of results to return (if set by the server).
|
||||
//
|
||||
// This is only returned if the server set a limit or used a different limit than that given in the request.
|
||||
Limit int `json:"limit,omitzero"`
|
||||
Limit uint `json:"limit,omitzero"`
|
||||
}
|
||||
|
||||
var _ QueryResponse = &PrincipalQueryResponse{}
|
||||
var _ QueryResponse[Principal] = &PrincipalQueryResponse{}
|
||||
|
||||
func (r PrincipalQueryResponse) GetQueryState() State { return r.QueryState }
|
||||
func (r PrincipalQueryResponse) GetMarker() Principal { return Principal{} }
|
||||
|
||||
type ErrorResponse struct {
|
||||
Type string `json:"type"`
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package jmap
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
@@ -48,25 +47,28 @@ func (f Mailboxes) MapChanges(oldState, newState State, hasMoreChanges bool, cre
|
||||
func fget[F Factory[T, GETREQ, GETRESP, CHANGES], T Foo, GETREQ GetCommand[T], GETRESP GetResponse[T], CHANGES any](f Factory[T, GETREQ, GETRESP, CHANGES], //NOSONAR
|
||||
client *Client, name string,
|
||||
accountId string, ids []string,
|
||||
session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (GETRESP, SessionState, State, Language, Error) {
|
||||
ctx Context) (GETRESP, SessionState, State, Language, Error) {
|
||||
var getresp GETRESP
|
||||
return get(client, name, f.Namespaces(),
|
||||
f.CreateGetCommand,
|
||||
getresp,
|
||||
identity1,
|
||||
accountId, session, ctx, logger, acceptLanguage, ids,
|
||||
accountId, ids,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
func fgetA[F Factory[T, GETREQ, GETRESP, CHANGES], T Foo, GETREQ GetCommand[T], GETRESP GetResponse[T], CHANGES any](f Factory[T, GETREQ, GETRESP, CHANGES], //NOSONAR
|
||||
client *Client, name string,
|
||||
accountId string, ids []string,
|
||||
session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) ([]T, SessionState, State, Language, Error) {
|
||||
ctx Context) ([]T, SessionState, State, Language, Error) {
|
||||
var getresp GETRESP
|
||||
return getA(client, name, f.Namespaces(),
|
||||
f.CreateGetCommand,
|
||||
getresp,
|
||||
accountId, session, ctx, logger, acceptLanguage, ids,
|
||||
accountId,
|
||||
ids,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -75,22 +77,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, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, ids []string) (RESP, SessionState, State, Language, Error) {
|
||||
logger = client.logger(name, session, logger)
|
||||
accountId string, ids []string, ctx Context) (RESP, SessionState, State, Language, Error) {
|
||||
ctx = ctx.WithLogger(client.logger(name, ctx))
|
||||
|
||||
var zero RESP
|
||||
|
||||
get := getCommandFactory(accountId, ids)
|
||||
cmd, err := client.request(session, logger, using,
|
||||
invocation(get, "0"),
|
||||
)
|
||||
cmd, err := client.request(ctx, using, invocation(get, "0"))
|
||||
if err != nil {
|
||||
return zero, "", "", "", err
|
||||
}
|
||||
|
||||
return command(client.api, logger, ctx, session, client.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (RESP, State, Error) {
|
||||
return command(client, ctx, cmd, func(body *Response) (RESP, State, Error) {
|
||||
var response GETRESP
|
||||
err = retrieveGet(logger, body, get, "0", &response)
|
||||
err = retrieveGet(ctx, body, get, "0", &response)
|
||||
if err != nil {
|
||||
return zero, "", err
|
||||
}
|
||||
@@ -103,21 +103,22 @@ func getA[T Foo, GETREQ GetCommand[T], GETRESP GetResponse[T]]( //NOSONAR
|
||||
client *Client, name string, using []JmapNamespace,
|
||||
getCommandFactory func(string, []string) GETREQ,
|
||||
resp GETRESP,
|
||||
accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, ids []string) ([]T, SessionState, State, Language, Error) {
|
||||
return get(client, name, using, getCommandFactory, resp, func(r GETRESP) []T { return r.GetList() }, accountId, session, ctx, logger, acceptLanguage, ids)
|
||||
accountId string, ids []string, ctx Context) ([]T, SessionState, State, Language, Error) {
|
||||
return get(client, name, using, getCommandFactory, resp, func(r GETRESP) []T { return r.GetList() }, accountId, ids, ctx)
|
||||
}
|
||||
|
||||
func fgetAN[F Factory[T, GETREQ, GETRESP, CHANGES], T Foo, GETREQ GetCommand[T], GETRESP GetResponse[T], RESP any, CHANGES any](f Factory[T, GETREQ, GETRESP, CHANGES], //NOSONAR
|
||||
client *Client, name string,
|
||||
respMapper func(map[string][]T) RESP,
|
||||
accountIds []string, ids []string,
|
||||
session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (RESP, SessionState, State, Language, Error) {
|
||||
ctx Context) (RESP, SessionState, State, Language, Error) {
|
||||
var getresp GETRESP
|
||||
return getAN(client, name, f.Namespaces(),
|
||||
f.CreateGetCommand,
|
||||
getresp,
|
||||
respMapper,
|
||||
accountIds, session, ctx, logger, acceptLanguage, ids,
|
||||
accountIds, ids,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -126,11 +127,12 @@ 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, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, ids []string) (RESP, SessionState, State, Language, Error) {
|
||||
accountIds []string, ids []string, ctx Context) (RESP, SessionState, State, Language, Error) {
|
||||
return getN(client, name, using, getCommandFactory, resp,
|
||||
func(r GETRESP) []T { return r.GetList() },
|
||||
respMapper,
|
||||
accountIds, session, ctx, logger, acceptLanguage, ids,
|
||||
accountIds, ids,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -140,8 +142,9 @@ 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, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, ids []string) (RESP, SessionState, State, Language, Error) {
|
||||
logger = client.logger(name, session, logger)
|
||||
accountIds []string, ids []string, ctx Context) (RESP, SessionState, State, Language, Error) {
|
||||
logger := client.logger(name, ctx)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
var zero RESP
|
||||
|
||||
@@ -155,17 +158,17 @@ func getN[T Foo, ITEM any, GETREQ GetCommand[T], GETRESP GetResponse[T], RESP an
|
||||
invocations[i] = invocation(get, mcid(accountId, "0"))
|
||||
}
|
||||
|
||||
cmd, err := client.request(session, logger, using, invocations...)
|
||||
cmd, err := client.request(ctx, using, invocations...)
|
||||
if err != nil {
|
||||
return zero, "", "", "", err
|
||||
}
|
||||
|
||||
return command(client.api, logger, ctx, session, client.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (RESP, State, Error) {
|
||||
return command(client, ctx, cmd, func(body *Response) (RESP, State, Error) {
|
||||
result := map[string]ITEM{}
|
||||
responses := map[string]GETRESP{}
|
||||
for _, accountId := range uniqueAccountIds {
|
||||
var resp GETRESP
|
||||
err = retrieveResponseMatchParameters(logger, body, c, mcid(accountId, "0"), &resp)
|
||||
err = retrieveResponseMatchParameters(ctx, body, c, mcid(accountId, "0"), &resp)
|
||||
if err != nil {
|
||||
return zero, "", err
|
||||
}
|
||||
@@ -182,13 +185,15 @@ func create[T Foo, C any, SETREQ SetCommand[T], GETREQ GetCommand[T], SETRESP Se
|
||||
getCommandFactory func(string, string) GETREQ,
|
||||
createdMapper func(SETRESP) map[string]*T,
|
||||
listMapper func(GETRESP) []T,
|
||||
accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, create C) (*T, SessionState, State, Language, Error) {
|
||||
logger = client.logger(name, session, logger)
|
||||
accountId string, create C,
|
||||
ctx Context) (*T, SessionState, State, Language, Error) {
|
||||
logger := client.logger(name, ctx)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
createMap := map[string]C{"c": create}
|
||||
get := getCommandFactory(accountId, "#c")
|
||||
set := setCommandFactory(accountId, createMap)
|
||||
cmd, err := client.request(session, logger, using,
|
||||
cmd, err := client.request(ctx, using,
|
||||
invocation(set, "0"),
|
||||
invocation(get, "1"),
|
||||
)
|
||||
@@ -196,9 +201,9 @@ func create[T Foo, C any, SETREQ SetCommand[T], GETREQ GetCommand[T], SETRESP Se
|
||||
return nil, "", "", "", err
|
||||
}
|
||||
|
||||
return command(client.api, logger, ctx, session, client.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (*T, State, Error) {
|
||||
return command(client, ctx, cmd, func(body *Response) (*T, State, Error) {
|
||||
var setResponse SETRESP
|
||||
err = retrieveSet(logger, body, set, "0", &setResponse)
|
||||
err = retrieveSet(ctx, body, set, "0", &setResponse)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
@@ -218,7 +223,7 @@ func create[T Foo, C any, SETREQ SetCommand[T], GETREQ GetCommand[T], SETRESP Se
|
||||
}
|
||||
|
||||
var getResponse GETRESP
|
||||
err = retrieveGet(logger, body, get, "1", &getResponse)
|
||||
err = retrieveGet(ctx, body, get, "1", &getResponse)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
@@ -237,20 +242,21 @@ 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, using []JmapNamespace, //NOSONAR
|
||||
setCommandFactory func(string, []string) REQ, _ RESP,
|
||||
accountId string, destroy []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (map[string]SetError, SessionState, State, Language, Error) {
|
||||
logger = client.logger(name, session, logger)
|
||||
accountId string, destroy []string, ctx Context) (map[string]SetError, SessionState, State, Language, Error) {
|
||||
logger := client.logger(name, ctx)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
set := setCommandFactory(accountId, destroy)
|
||||
cmd, err := client.request(session, logger, using,
|
||||
cmd, err := client.request(ctx, using,
|
||||
invocation(set, "0"),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
}
|
||||
|
||||
return command(client.api, logger, ctx, session, client.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (map[string]SetError, State, Error) {
|
||||
return command(client, ctx, cmd, func(body *Response) (map[string]SetError, State, Error) {
|
||||
var setResponse RESP
|
||||
err = retrieveSet(logger, body, set, "0", &setResponse)
|
||||
err = retrieveSet(ctx, body, set, "0", &setResponse)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
@@ -265,12 +271,12 @@ 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,
|
||||
session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (RESP, SessionState, State, Language, Error) {
|
||||
ctx Context) (RESP, SessionState, State, Language, Error) {
|
||||
|
||||
return changes(client, name, using, changesCommandFactory, changesResp, getCommandFactory,
|
||||
func(r GETRESP) []T { return r.GetList() },
|
||||
respMapper,
|
||||
session, ctx, logger, acceptLanguage,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -281,15 +287,15 @@ 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,
|
||||
session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (RESP, SessionState, State, Language, Error) {
|
||||
logger = client.logger(name, session, logger)
|
||||
ctx Context) (RESP, SessionState, State, Language, Error) {
|
||||
logger := client.logger(name, ctx)
|
||||
var zero RESP
|
||||
|
||||
changes := changesCommandFactory()
|
||||
getCreated := getCommandFactory("/created", "0") //NOSONAR
|
||||
getUpdated := getCommandFactory("/updated", "0") //NOSONAR
|
||||
|
||||
cmd, err := client.request(session, logger, using,
|
||||
cmd, err := client.request(ctx.WithLogger(logger), using,
|
||||
invocation(changes, "0"),
|
||||
invocation(getCreated, "1"),
|
||||
invocation(getUpdated, "2"),
|
||||
@@ -298,22 +304,22 @@ func changes[T Foo, CHANGESREQ ChangesCommand[T], GETREQ GetCommand[T], CHANGESR
|
||||
return zero, "", "", "", err
|
||||
}
|
||||
|
||||
return command(client.api, logger, ctx, session, client.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (RESP, State, Error) {
|
||||
return command(client, ctx, cmd, func(body *Response) (RESP, State, Error) {
|
||||
var changesResponse CHANGESRESP
|
||||
err = retrieveChanges(logger, body, changes, "0", &changesResponse)
|
||||
err = retrieveChanges(ctx, body, changes, "0", &changesResponse)
|
||||
if err != nil {
|
||||
return zero, "", err
|
||||
}
|
||||
|
||||
var createdResponse GETRESP
|
||||
err = retrieveGet(logger, body, getCreated, "1", &createdResponse)
|
||||
err = retrieveGet(ctx, body, getCreated, "1", &createdResponse)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Send()
|
||||
return zero, "", err
|
||||
}
|
||||
|
||||
var updatedResponse GETRESP
|
||||
err = retrieveGet(logger, body, getUpdated, "2", &updatedResponse)
|
||||
err = retrieveGet(ctx, body, getUpdated, "2", &updatedResponse)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Send()
|
||||
return zero, "", err
|
||||
@@ -338,8 +344,8 @@ 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,
|
||||
session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (RESP, SessionState, State, Language, Error) {
|
||||
logger = client.loggerParams(name, session, logger, func(z zerolog.Context) zerolog.Context {
|
||||
ctx Context) (RESP, SessionState, State, Language, Error) {
|
||||
logger := client.loggerParams(name, ctx, func(z zerolog.Context) zerolog.Context {
|
||||
sinceStateLogDict := zerolog.Dict()
|
||||
for k, v := range sinceStateMap {
|
||||
sinceStateLogDict.Str(log.SafeString(k), log.SafeString(string(v)))
|
||||
@@ -377,29 +383,31 @@ func changesN[T Foo, CHANGESREQ ChangesCommand[T], GETREQ GetCommand[T], CHANGES
|
||||
getCommand = getCreated.GetCommand()
|
||||
}
|
||||
|
||||
cmd, err := client.request(session, logger, using, invocations...)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
cmd, err := client.request(ctx, using, invocations...)
|
||||
if err != nil {
|
||||
return zero, "", "", "", err
|
||||
}
|
||||
|
||||
return command(client.api, logger, ctx, session, client.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (RESP, State, Error) {
|
||||
return command(client, ctx, cmd, func(body *Response) (RESP, State, Error) {
|
||||
changesItemByAccount := make(map[string]CHANGESITEM, n)
|
||||
stateByAccountId := make(map[string]State, n)
|
||||
for _, accountId := range uniqueAccountIds {
|
||||
var changesResponse CHANGESRESP
|
||||
err = retrieveResponseMatchParameters(logger, body, changesCommand, mcid(accountId, "0"), &changesResponse)
|
||||
err = retrieveResponseMatchParameters(ctx, body, changesCommand, mcid(accountId, "0"), &changesResponse)
|
||||
if err != nil {
|
||||
return zero, "", err
|
||||
}
|
||||
|
||||
var createdResponse GETRESP
|
||||
err = retrieveResponseMatchParameters(logger, body, getCommand, mcid(accountId, "1"), &createdResponse)
|
||||
err = retrieveResponseMatchParameters(ctx, body, getCommand, mcid(accountId, "1"), &createdResponse)
|
||||
if err != nil {
|
||||
return zero, "", err
|
||||
}
|
||||
|
||||
var updatedResponse GETRESP
|
||||
err = retrieveResponseMatchParameters(logger, body, getCommand, mcid(accountId, "2"), &updatedResponse)
|
||||
err = retrieveResponseMatchParameters(ctx, body, getCommand, mcid(accountId, "2"), &updatedResponse)
|
||||
if err != nil {
|
||||
return zero, "", err
|
||||
}
|
||||
@@ -420,13 +428,14 @@ 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,
|
||||
session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (RESP, SessionState, State, Language, Error) {
|
||||
logger = client.logger(name, session, logger)
|
||||
ctx Context) (RESP, SessionState, State, Language, Error) {
|
||||
logger := client.logger(name, ctx)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
var zero RESP
|
||||
|
||||
changes := changesCommandFactory()
|
||||
getUpdated := getCommandFactory("/updated", "0") //NOSONAR
|
||||
cmd, err := client.request(session, logger, using,
|
||||
cmd, err := client.request(ctx, using,
|
||||
invocation(changes, "0"),
|
||||
invocation(getUpdated, "1"),
|
||||
)
|
||||
@@ -434,15 +443,15 @@ func updates[T Foo, CHANGESREQ ChangesCommand[T], GETREQ GetCommand[T], CHANGESR
|
||||
return zero, "", "", "", err
|
||||
}
|
||||
|
||||
return command(client.api, logger, ctx, session, client.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (RESP, State, Error) {
|
||||
return command(client, ctx, cmd, func(body *Response) (RESP, State, Error) {
|
||||
var changesResponse CHANGESRESP
|
||||
err = retrieveChanges(logger, body, changes, "0", &changesResponse)
|
||||
err = retrieveChanges(ctx, body, changes, "0", &changesResponse)
|
||||
if err != nil {
|
||||
return zero, "", err
|
||||
}
|
||||
|
||||
var updatedResponse GETRESP
|
||||
err = retrieveGet(logger, body, getUpdated, "1", &updatedResponse)
|
||||
err = retrieveGet(ctx, body, getUpdated, "1", &updatedResponse)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Send()
|
||||
return zero, "", err
|
||||
@@ -461,19 +470,20 @@ 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,
|
||||
session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (RESP, SessionState, State, Language, Error) {
|
||||
logger = client.logger(name, session, logger)
|
||||
ctx Context) (RESP, SessionState, State, Language, Error) {
|
||||
logger := client.logger(name, ctx)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
update := setCommandFactory(map[string]PatchObject{id: changes.AsPatch()})
|
||||
get := getCommandFactory(id)
|
||||
cmd, err := client.request(session, logger, using, invocation(update, "0"), invocation(get, "1"))
|
||||
cmd, err := client.request(ctx, using, invocation(update, "0"), invocation(get, "1"))
|
||||
var zero RESP
|
||||
if err != nil {
|
||||
return zero, "", "", "", err
|
||||
}
|
||||
|
||||
return command(client.api, logger, ctx, session, client.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (RESP, State, Error) {
|
||||
return command(client, ctx, cmd, func(body *Response) (RESP, State, Error) {
|
||||
var setResponse SETRESP
|
||||
err = retrieveSet(logger, body, update, "0", &setResponse)
|
||||
err = retrieveSet(ctx, body, update, "0", &setResponse)
|
||||
if err != nil {
|
||||
return zero, setResponse.GetNewState(), err
|
||||
}
|
||||
@@ -484,10 +494,107 @@ func update[T Foo, CHANGES Change, SET SetCommand[T], GET GetCommand[T], RESP an
|
||||
return zero, "", setErrorError(setErr, update.GetObjectType())
|
||||
}
|
||||
var getResponse GETRESP
|
||||
err = retrieveGet(logger, body, get, "1", &getResponse)
|
||||
err = retrieveGet(ctx, body, get, "1", &getResponse)
|
||||
if err != nil {
|
||||
return zero, setResponse.GetNewState(), err
|
||||
}
|
||||
return objExtractor(getResponse), setResponse.GetNewState(), nil
|
||||
})
|
||||
}
|
||||
|
||||
func query[T Foo, FILTER any, SORT any, QUERY QueryCommand[T], GET GetCommand[T], QUERYRESP QueryResponse[T], GETRESP GetResponse[T], RESP any]( //NOSONAR
|
||||
client *Client, name string, using []JmapNamespace,
|
||||
defaultSortBy []SORT,
|
||||
queryCommandFactory func(filter FILTER, sortBy []SORT, limit uint, position uint) QUERY,
|
||||
getCommandFactory func(cmd Command, path string, rof string) GET,
|
||||
respMapper func(query QUERYRESP, get GETRESP) RESP,
|
||||
filter FILTER, sortBy []SORT, limit uint, position uint,
|
||||
ctx Context) (RESP, SessionState, State, Language, Error) {
|
||||
|
||||
logger := client.logger(name, ctx)
|
||||
ctx = ctx.WithLogger(logger)
|
||||
|
||||
if sortBy == nil {
|
||||
sortBy = defaultSortBy
|
||||
}
|
||||
|
||||
query := queryCommandFactory(filter, sortBy, limit, position)
|
||||
get := getCommandFactory(query.GetCommand(), "/ids/*", "0")
|
||||
|
||||
var zero RESP
|
||||
|
||||
cmd, err := client.request(ctx, using, invocation(query, "0"), invocation(get, "1"))
|
||||
if err != nil {
|
||||
return zero, "", "", "", err
|
||||
}
|
||||
|
||||
return command(client, ctx, cmd, func(body *Response) (RESP, State, Error) {
|
||||
var queryResponse QUERYRESP
|
||||
err = retrieveQuery(ctx, body, query, "0", &queryResponse)
|
||||
if err != nil {
|
||||
return zero, EmptyState, err
|
||||
}
|
||||
var getResponse GETRESP
|
||||
err = retrieveGet(ctx, body, get, "1", &getResponse)
|
||||
if err != nil {
|
||||
return zero, EmptyState, err
|
||||
}
|
||||
return respMapper(queryResponse, getResponse), queryResponse.GetQueryState(), nil
|
||||
})
|
||||
}
|
||||
|
||||
func queryN[T Foo, FILTER any, SORT any, QUERY QueryCommand[T], GET GetCommand[T], QUERYRESP QueryResponse[T], GETRESP GetResponse[T], RESP any]( //NOSONAR
|
||||
client *Client, name string, using []JmapNamespace,
|
||||
defaultSortBy []SORT,
|
||||
queryCommandFactory func(accountId string, filter FILTER, sortBy []SORT, position int, limit uint) QUERY,
|
||||
getCommandFactory func(accountId string, cmd Command, path string, rof string) GET,
|
||||
respMapper func(query QUERYRESP, get GETRESP) RESP,
|
||||
accountIds []string,
|
||||
filter FILTER, sortBy []SORT, limit uint, position int,
|
||||
ctx Context) (map[string]RESP, SessionState, State, Language, Error) {
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
|
||||
if sortBy == nil {
|
||||
sortBy = defaultSortBy
|
||||
}
|
||||
|
||||
invocations := make([]Invocation, len(uniqueAccountIds)*2)
|
||||
var g GET
|
||||
var q QUERY
|
||||
for i, accountId := range uniqueAccountIds {
|
||||
query := queryCommandFactory(accountId, filter, sortBy, position, limit)
|
||||
get := getCommandFactory(accountId, query.GetCommand(), "/ids/*", mcid(accountId, "0"))
|
||||
invocations[i*2+0] = invocation(query, mcid(accountId, "0"))
|
||||
invocations[i*2+1] = invocation(get, mcid(accountId, "1"))
|
||||
q = query
|
||||
g = get
|
||||
}
|
||||
|
||||
cmd, err := client.request(ctx, NS_CALENDARS, invocations...)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
}
|
||||
|
||||
return command(client, ctx, cmd, func(body *Response) (map[string]RESP, State, Error) {
|
||||
resp := map[string]RESP{}
|
||||
stateByAccountId := map[string]State{}
|
||||
for _, accountId := range uniqueAccountIds {
|
||||
var queryResponse QUERYRESP
|
||||
err = retrieveQuery(ctx, body, q, mcid(accountId, "0"), &queryResponse)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
var getResponse GETRESP
|
||||
err = retrieveGet(ctx, body, g, mcid(accountId, "1"), &getResponse)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
if len(getResponse.GetNotFound()) > 0 {
|
||||
// TODO what to do when there are not-found calendarevents here? potentially nothing, they could have been deleted between query and get?
|
||||
}
|
||||
resp[accountId] = respMapper(queryResponse, getResponse)
|
||||
stateByAccountId[accountId] = getResponse.GetState()
|
||||
}
|
||||
return resp, squashState(stateByAccountId), nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package jmap
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -13,7 +12,6 @@ import (
|
||||
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/opencloud-eu/opencloud/pkg/jscalendar"
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
)
|
||||
|
||||
type eventListeners[T any] struct {
|
||||
@@ -52,16 +50,19 @@ func mcid(accountId string, tag string) string {
|
||||
return accountId + ":" + tag
|
||||
}
|
||||
|
||||
func command[T any](api ApiClient, //NOSONAR
|
||||
logger *log.Logger,
|
||||
ctx context.Context,
|
||||
session *Session,
|
||||
sessionOutdatedHandler func(session *Session, newState SessionState),
|
||||
type Cmdr interface {
|
||||
ApiSupplier
|
||||
Hooks
|
||||
}
|
||||
|
||||
func command[T any](client Cmdr, //NOSONAR
|
||||
ctx Context,
|
||||
request Request,
|
||||
acceptLanguage string,
|
||||
mapper func(body *Response) (T, State, Error)) (T, SessionState, State, Language, Error) {
|
||||
|
||||
responseBody, language, jmapErr := api.Command(ctx, logger, session, request, acceptLanguage)
|
||||
logger := ctx.Logger
|
||||
|
||||
responseBody, language, jmapErr := client.Api().Command(request, ctx)
|
||||
if jmapErr != nil {
|
||||
var zero T
|
||||
return zero, "", "", language, jmapErr
|
||||
@@ -75,10 +76,8 @@ func command[T any](api ApiClient, //NOSONAR
|
||||
return zero, "", "", language, jmapError(err, JmapErrorDecodingResponseBody)
|
||||
}
|
||||
|
||||
if response.SessionState != session.State {
|
||||
if sessionOutdatedHandler != nil {
|
||||
sessionOutdatedHandler(session, response.SessionState)
|
||||
}
|
||||
if response.SessionState != ctx.Session.State {
|
||||
client.OnSessionOutdated(ctx.Session, response.SessionState)
|
||||
}
|
||||
|
||||
// search for an "error" response
|
||||
@@ -199,25 +198,25 @@ func retrieveResponseMatch(data *Response, command Command, tag string) (Invocat
|
||||
return Invocation{}, false
|
||||
}
|
||||
|
||||
func retrieveResponseMatchParameters[T any](logger *log.Logger, data *Response, command Command, tag string, target *T) Error {
|
||||
func retrieveResponseMatchParameters[T any](ctx Context, data *Response, command Command, tag string, target *T) Error {
|
||||
match, ok := retrieveResponseMatch(data, command, tag)
|
||||
if !ok {
|
||||
err := fmt.Errorf("failed to find JMAP response invocation match for command '%v' and tag '%v'", command, tag) // NOSONAR
|
||||
logger.Error().Msg(err.Error())
|
||||
ctx.Logger.Error().Msg(err.Error())
|
||||
return jmapError(err, JmapErrorInvalidJmapResponsePayload)
|
||||
}
|
||||
params := match.Parameters
|
||||
typedParams, ok := params.(T)
|
||||
if !ok {
|
||||
err := fmt.Errorf("JMAP response invocation matches command '%v' and tag '%v' but the type %T does not match the expected %T", command, tag, params, *target) // NOSONAR
|
||||
logger.Error().Msg(err.Error())
|
||||
ctx.Logger.Error().Msg(err.Error())
|
||||
return jmapError(err, JmapErrorInvalidJmapResponsePayload)
|
||||
}
|
||||
*target = typedParams
|
||||
return nil
|
||||
}
|
||||
|
||||
func tryRetrieveResponseMatchParameters[T any](logger *log.Logger, data *Response, command Command, tag string, target *T) (bool, Error) {
|
||||
func tryRetrieveResponseMatchParameters[T any](ctx Context, data *Response, command Command, tag string, target *T) (bool, Error) {
|
||||
match, ok := retrieveResponseMatch(data, command, tag)
|
||||
if !ok {
|
||||
return false, nil
|
||||
@@ -226,23 +225,35 @@ func tryRetrieveResponseMatchParameters[T any](logger *log.Logger, data *Respons
|
||||
typedParams, ok := params.(T)
|
||||
if !ok {
|
||||
err := fmt.Errorf("JMAP response invocation matches command '%v' and tag '%v' but the type %T does not match the expected %T", command, tag, params, *target)
|
||||
logger.Error().Msg(err.Error())
|
||||
ctx.Logger.Error().Msg(err.Error())
|
||||
return true, jmapError(err, JmapErrorInvalidJmapResponsePayload)
|
||||
}
|
||||
*target = typedParams
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func retrieveGet[T Foo, C GetCommand[T], R GetResponse[T]](logger *log.Logger, data *Response, command C, tag string, target *R) Error {
|
||||
return retrieveResponseMatchParameters(logger, data, command.GetCommand(), tag, target)
|
||||
func retrieveGet[T Foo, C GetCommand[T], R GetResponse[T]](ctx Context, data *Response, command C, tag string, target *R) Error {
|
||||
return retrieveResponseMatchParameters(ctx, data, command.GetCommand(), tag, target)
|
||||
}
|
||||
|
||||
func retrieveSet[T Foo, C SetCommand[T], R SetResponse[T]](logger *log.Logger, data *Response, command C, tag string, target *R) Error {
|
||||
return retrieveResponseMatchParameters(logger, data, command.GetCommand(), tag, target)
|
||||
func retrieveSet[T Foo, C SetCommand[T], R SetResponse[T]](ctx Context, data *Response, command C, tag string, target *R) Error {
|
||||
return retrieveResponseMatchParameters(ctx, data, command.GetCommand(), tag, target)
|
||||
}
|
||||
|
||||
func retrieveChanges[T Foo, C ChangesCommand[T], R ChangesResponse[T]](logger *log.Logger, data *Response, command C, tag string, target *R) Error {
|
||||
return retrieveResponseMatchParameters(logger, data, command.GetCommand(), tag, target)
|
||||
func retrieveQuery[T Foo, C QueryCommand[T], R QueryResponse[T]](ctx Context, data *Response, command C, tag string, target *R) Error {
|
||||
return retrieveResponseMatchParameters(ctx, data, command.GetCommand(), tag, target)
|
||||
}
|
||||
|
||||
func retrieveChanges[T Foo, C ChangesCommand[T], R ChangesResponse[T]](ctx Context, data *Response, command C, tag string, target *R) Error {
|
||||
return retrieveResponseMatchParameters(ctx, data, command.GetCommand(), tag, target)
|
||||
}
|
||||
|
||||
func retrieveUpload[T Foo, C UploadCommand[T], R UploadResponse[T]](ctx Context, data *Response, command C, tag string, target *R) Error {
|
||||
return retrieveResponseMatchParameters(ctx, data, command.GetCommand(), tag, target)
|
||||
}
|
||||
|
||||
func retrieveParse[T Foo, C ParseCommand[T], R ParseResponse[T]](ctx Context, data *Response, command C, tag string, target *R) Error {
|
||||
return retrieveResponseMatchParameters(ctx, data, command.GetCommand(), tag, target)
|
||||
}
|
||||
|
||||
func (i *Invocation) MarshalJSON() ([]byte, error) {
|
||||
@@ -396,7 +407,7 @@ func identity1[T any](t T) T {
|
||||
func list[T Foo, GETRESP GetResponse[T]](r GETRESP) []T { return r.GetList() }
|
||||
func getid[T Idable](r T) string { return r.GetId() }
|
||||
|
||||
func posUIntPtr(i uint) *uint {
|
||||
func uintPtr(i uint) *uint {
|
||||
if i > 0 {
|
||||
return &i
|
||||
} else {
|
||||
@@ -404,6 +415,14 @@ func posUIntPtr(i uint) *uint {
|
||||
}
|
||||
}
|
||||
|
||||
func uintPtrIf(i uint, condition bool) *uint {
|
||||
if condition {
|
||||
return uintPtr(i)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func ns(namespaces ...JmapNamespace) []JmapNamespace {
|
||||
result := make([]JmapNamespace, len(namespaces)+1)
|
||||
result[0] = JmapCore
|
||||
|
||||
@@ -2012,324 +2012,3 @@ type PersonalInfo struct {
|
||||
// Note that succinct labels are best for proper display on small graphical interfaces and screens.
|
||||
Label string `json:"label,omitempty"`
|
||||
}
|
||||
|
||||
// A ContactCard object contains information about a person, company, or other entity, or represents a group of such entities.
|
||||
//
|
||||
// It is a JSCard (JSContact) object, as defined in [RFC9553], with two additional properties.
|
||||
//
|
||||
// A contact card with a `kind` property equal to `group` represents a group of contacts.
|
||||
// Clients often present these separately from other contact cards.
|
||||
//
|
||||
// The `members` property, as defined in RFC XXX, Section XXX, contains a set of UIDs for other contacts that are the members
|
||||
// of this group.
|
||||
// Clients should consider the group to contain any `ContactCard` with a matching UID, from any account they have access to with
|
||||
// support for the `urn:ietf:params:jmap:contacts` capability.
|
||||
// UIDs that cannot be found SHOULD be ignored but preserved.
|
||||
//
|
||||
// For example, suppose a user adds contacts from a shared address book to their private group, then temporarily loses access to
|
||||
// this address book.
|
||||
// The UIDs cannot be resolved so the contacts will disappear from the group.
|
||||
// However, if they are given permission to access the data again the UIDs will be found and the contacts will reappear.
|
||||
type ContactCard struct {
|
||||
// The id of the Card (immutable; server-set).
|
||||
//
|
||||
// The id uniquely identifies a Card with a particular “uid” within a particular account.
|
||||
//
|
||||
// This is a JMAP extension and not part of [RFC9553].
|
||||
Id string `json:"id,omitempty" doc:"!request,req"`
|
||||
|
||||
// The set of AddressBook ids this Card belongs to.
|
||||
//
|
||||
// A card MUST belong to at least one AddressBook at all times (until it is destroyed).
|
||||
//
|
||||
// The set is represented as an object, with each key being an AddressBook id.
|
||||
//
|
||||
// The value for each key in the object MUST be true.
|
||||
//
|
||||
// This is a JMAP extension and not part of [RFC9553].
|
||||
AddressBookIds map[string]bool `json:"addressBookIds,omitempty"`
|
||||
|
||||
// The JSContact type of the Card object: the value MUST be "Card".
|
||||
Type TypeOfContactCard `json:"@type,omitempty"`
|
||||
|
||||
// The JSContact version of this Card.
|
||||
//
|
||||
// The value MUST be one of the IANA-registered JSContact Version values for the version property.
|
||||
Version JSContactVersion `json:"version"`
|
||||
|
||||
// The date and time when the Card was created (UTCDateTime).
|
||||
Created time.Time `json:"created,omitzero"`
|
||||
|
||||
// The kind of the entity the Card represents (default: `individual`).
|
||||
//
|
||||
// Values are:
|
||||
// * `individual`: a single person
|
||||
// * `group`: a group of people or entities
|
||||
// * `org`: an organization
|
||||
// * `location`: a named location
|
||||
// * `device`: a device such as an appliance, a computer, or a network element
|
||||
// * `application`: a software application
|
||||
Kind ContactCardKind `json:"kind,omitempty"`
|
||||
|
||||
// The language tag, as defined in [RFC5646].
|
||||
//
|
||||
// The language tag that best describes the language used for text in the Card, optionally including
|
||||
// additional information such as the script.
|
||||
//
|
||||
// Note that values MAY be localized in the `localizations` property.
|
||||
Language string `json:"language,omitempty"`
|
||||
|
||||
// The set of Cards that are members of this group Card.
|
||||
//
|
||||
// Each key in the set is the uid property value of the member, and each boolean value MUST be `true`.
|
||||
// If this property is set, then the value of the kind property MUST be `group`.
|
||||
//
|
||||
// The opposite is not true. A group Card will usually contain the members property to specify the members
|
||||
// of the group, but it is not required to.
|
||||
//
|
||||
// A group Card without the members property can be considered an abstract grouping or one whose members
|
||||
// are known empirically (e.g., `IETF Participants`).
|
||||
Members map[string]bool `json:"members,omitempty"`
|
||||
|
||||
// The identifier for the product that created the Card.
|
||||
//
|
||||
// If set, the value MUST be at least one character long.
|
||||
ProdId string `json:"prodId,omitempty"`
|
||||
|
||||
// The set of Card objects that relate to the Card.
|
||||
//
|
||||
// The value is a map, where each key is the uid property value of the related Card, and the value
|
||||
// defines the relation
|
||||
//
|
||||
// ```json
|
||||
// {
|
||||
// "relatedTo": {
|
||||
// "urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6": {
|
||||
// "relation": {"friend": true}
|
||||
// },
|
||||
// "8cacdfb7d1ffdb59@example.com": {
|
||||
// "relation": {}
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// ```
|
||||
RelatedTo map[string]Relation `json:"relatedTo,omitempty"`
|
||||
|
||||
// An identifier that associates the object as the same across different systems, address books, and views.
|
||||
//
|
||||
// The value SHOULD be a URN [RFC8141], but for compatibility with [RFC6350], it MAY also be a URI [RFC3986]
|
||||
// or free-text value.
|
||||
//
|
||||
// The value of the URN SHOULD be in the "uuid" namespace [RFC9562].
|
||||
//
|
||||
// [RFC9562] describes multiple versions of Universally Unique IDentifiers (UUIDs); UUID version 4 is RECOMMENDED.
|
||||
Uid string `json:"uid,omitempty"`
|
||||
|
||||
// The date and time when the data in the Card was last modified (UTCDateTime).
|
||||
Updated time.Time `json:"updated,omitzero"`
|
||||
|
||||
// The name of the entity represented by the Card.
|
||||
//
|
||||
// This can be any type of name, e.g., it can, but need not, be the legal name of a person.
|
||||
Name *Name `json:"name,omitempty"`
|
||||
|
||||
// The nicknames of the entity represented by the Card.
|
||||
Nicknames map[string]Nickname `json:"nicknames,omitempty"`
|
||||
|
||||
// The company or organization names and units associated with the Card.
|
||||
Organizations map[string]Organization `json:"organizations,omitempty"`
|
||||
|
||||
// The information that directs how to address, speak to, or refer to the entity that is represented by the Card.
|
||||
SpeakToAs *SpeakToAs `json:"speakToAs,omitempty"`
|
||||
|
||||
// The job titles or functional positions of the entity represented by the Card.
|
||||
Titles map[string]Title `json:"titles,omitempty"`
|
||||
|
||||
// The email addresses in which to contact the entity represented by the Card.
|
||||
Emails map[string]EmailAddress `json:"emails,omitempty"`
|
||||
|
||||
// The online services that are associated with the entity represented by the Card.
|
||||
//
|
||||
// This can be messaging services, social media profiles, and other.
|
||||
OnlineServices map[string]OnlineService `json:"onlineServices,omitempty"`
|
||||
|
||||
// The phone numbers by which to contact the entity represented by the Card.
|
||||
Phones map[string]Phone `json:"phones,omitempty"`
|
||||
|
||||
// The preferred languages for contacting the entity associated with the Card.
|
||||
PreferredLanguages map[string]LanguagePref `json:"preferredLanguages,omitempty"`
|
||||
|
||||
// The calendaring resources of the entity represented by the Card, such as to look up free-busy information.
|
||||
//
|
||||
// A Calendar object has all properties of the Resource data type, with the following additional definitions:
|
||||
// * The `@type` property value MUST be `Calendar`, if set
|
||||
// * The `kind` property is mandatory. Its enumerated values are:
|
||||
// * `calendar`: The resource is a calendar that contains entries such as calendar events or tasks
|
||||
// * `freeBusy`: The resource allows for free-busy lookups, for example, to schedule group events
|
||||
Calendars map[string]Calendar `json:"calendars,omitempty"`
|
||||
|
||||
// The scheduling addresses by which the entity may receive calendar scheduling invitations.
|
||||
SchedulingAddresses map[string]SchedulingAddress `json:"schedulingAddresses,omitempty"`
|
||||
|
||||
// The addresses of the entity represented by the Card, such as postal addresses or geographic locations.
|
||||
Addresses map[string]Address `json:"addresses,omitempty"`
|
||||
|
||||
// The cryptographic resources such as public keys and certificates associated with the entity represented by the Card.
|
||||
//
|
||||
// A CryptoKey object has all properties of the `Resource` data type, with the following additional definition:
|
||||
// the `@type` property value MUST be `CryptoKey`, if set.
|
||||
//
|
||||
// The following example shows how to refer to an external cryptographic resource:
|
||||
// ```json
|
||||
// "cryptoKeys": {
|
||||
// "mykey1": {
|
||||
// "uri": "https://www.example.com/keys/jdoe.cer"
|
||||
// }
|
||||
// }
|
||||
// ```
|
||||
CryptoKeys map[string]CryptoKey `json:"cryptoKeys,omitempty"`
|
||||
|
||||
// The directories containing information about the entity represented by the Card.
|
||||
//
|
||||
// A Directory object has all properties of the `Resource` data type, with the following additional definitions:
|
||||
// * The `@type` property value MUST be `Directory`, if set
|
||||
// * The `kind` property is mandatory; tts enumerated values are:
|
||||
// * `directory`: the resource is a directory service that the entity represented by the Card is a part of; this
|
||||
// typically is an organizational directory that also contains associated entities, e.g., co-workers and management
|
||||
// in a company directory
|
||||
// * `entry`: the resource is a directory entry of the entity represented by the Card; in contrast to the `directory`
|
||||
// type, this is the specific URI for the entity within a directory
|
||||
Directories map[string]Directory `json:"directories,omitempty"`
|
||||
|
||||
// The links to resources that do not fit any of the other use-case-specific resource properties.
|
||||
//
|
||||
// A Link object has all properties of the `Resource` data type, with the following additional definitions:
|
||||
// * The `@type` property value MUST be `Link`, if set
|
||||
// * The `kind` property is optional; tts enumerated values are:
|
||||
// * `contact`: the resource is a URI by which the entity represented by the Card may be contacted;
|
||||
// this includes web forms or other media that require user interaction
|
||||
Links map[string]Link `json:"links,omitempty"`
|
||||
|
||||
// The media resources such as photographs, avatars, or sounds that are associated with the entity represented by the Card.
|
||||
//
|
||||
// A Media object has all properties of the Resource data type, with the following additional definitions:
|
||||
// * the `@type` property value MUST be `Media`, if set
|
||||
// * the `kind` property is mandatory; its enumerated values are:
|
||||
// * `photo`: the resource is a photograph or avatar
|
||||
// * `sound`: the resource is audio media, e.g., to specify the proper pronunciation of the name property contents
|
||||
// * `logo`: the resource is a graphic image or logo associated with the entity represented by the Card
|
||||
Media map[string]Media `json:"media,omitempty"`
|
||||
|
||||
// The property values localized to languages other than the main `language` of the Card.
|
||||
//
|
||||
// Localizations provide language-specific alternatives for existing property values and SHOULD NOT add new properties.
|
||||
//
|
||||
// The keys in the localizations property value are language tags [RFC5646]; the values are of type `PatchObject` and
|
||||
// localize the Card in that language tag.
|
||||
//
|
||||
// The paths in the `PatchObject` are relative to the Card that includes the localizations property.
|
||||
//
|
||||
// A patch MUST NOT target the localizations property.
|
||||
//
|
||||
// Conceptually, a Card is localized as follows:
|
||||
// * Determine the language tag in which the Card should be localized.
|
||||
// * If the localizations property includes a key for that language, obtain the PatchObject value;
|
||||
// if there is no such key, stop.
|
||||
// * Create a copy of the Card, but do not copy the localizations property.
|
||||
// * Apply all patches in the PatchObject to the copy of the Card.
|
||||
// * Optionally, set the language property in the copy of the Card.
|
||||
// * Use the patched copy of the Card as the localized variant of the original Card.
|
||||
//
|
||||
// A patch in the `PatchObject` may contain any value type.
|
||||
//
|
||||
// Its value MUST be a valid value according to the definition of the patched property.
|
||||
Localizations map[string]PatchObject `json:"localizations,omitempty"`
|
||||
|
||||
// The memorable dates and events for the entity represented by the Card.
|
||||
Anniversaries map[string]Anniversary `json:"anniversaries,omitempty"`
|
||||
|
||||
// The set of free-text keywords, also known as tags.
|
||||
//
|
||||
// Each key in the set is a keyword, and each boolean value MUST be `true`.
|
||||
Keywords map[string]bool `json:"keywords,omitempty"`
|
||||
|
||||
// The free-text notes that are associated with the Card.
|
||||
Notes map[string]Note `json:"notes,omitempty"`
|
||||
|
||||
// The personal information of the entity represented by the Card.
|
||||
PersonalInfo map[string]PersonalInfo `json:"personalInfo,omitempty"`
|
||||
}
|
||||
|
||||
func (f ContactCard) GetId() string { return f.Id }
|
||||
|
||||
const (
|
||||
ContactCardPropertyId = "id"
|
||||
ContactCardPropertyAddressBookIds = "addressBookIds"
|
||||
ContactCardPropertyType = "@type"
|
||||
ContactCardPropertyVersion = "version"
|
||||
ContactCardPropertyCreated = "created"
|
||||
ContactCardPropertyKind = "kind"
|
||||
ContactCardPropertyLanguage = "language"
|
||||
ContactCardPropertyMembers = "members"
|
||||
ContactCardPropertyProdId = "prodId"
|
||||
ContactCardPropertyRelatedTo = "relatedTo"
|
||||
ContactCardPropertyUid = "uid"
|
||||
ContactCardPropertyUpdated = "updated"
|
||||
ContactCardPropertyName = "name"
|
||||
ContactCardPropertyNicknames = "nicknames"
|
||||
ContactCardPropertyOrganizations = "organizations"
|
||||
ContactCardPropertySpeakToAs = "speakToAs"
|
||||
ContactCardPropertyTitles = "titles"
|
||||
ContactCardPropertyEmails = "emails"
|
||||
ContactCardPropertyOnlineServices = "onlineServices"
|
||||
ContactCardPropertyPhones = "phones"
|
||||
ContactCardPropertyPreferredLanguages = "preferredLanguages"
|
||||
ContactCardPropertyCalendars = "calendars"
|
||||
ContactCardPropertySchedulingAddresses = "schedulingAddresses"
|
||||
ContactCardPropertyAddresses = "addresses"
|
||||
ContactCardPropertyCryptoKeys = "cryptoKeys"
|
||||
ContactCardPropertyDirectories = "directories"
|
||||
ContactCardPropertyLinks = "links"
|
||||
ContactCardPropertyMedia = "media"
|
||||
ContactCardPropertyLocalizations = "localizations"
|
||||
ContactCardPropertyAnniversaries = "anniversaries"
|
||||
ContactCardPropertyKeywords = "keywords"
|
||||
ContactCardPropertyNotes = "notes"
|
||||
ContactCardPropertyPersonalInfo = "personalInfo"
|
||||
)
|
||||
|
||||
var ContactCardProperties = []string{
|
||||
ContactCardPropertyId,
|
||||
ContactCardPropertyAddressBookIds,
|
||||
ContactCardPropertyType,
|
||||
ContactCardPropertyVersion,
|
||||
ContactCardPropertyCreated,
|
||||
ContactCardPropertyKind,
|
||||
ContactCardPropertyLanguage,
|
||||
ContactCardPropertyMembers,
|
||||
ContactCardPropertyProdId,
|
||||
ContactCardPropertyRelatedTo,
|
||||
ContactCardPropertyUid,
|
||||
ContactCardPropertyUpdated,
|
||||
ContactCardPropertyName,
|
||||
ContactCardPropertyNicknames,
|
||||
ContactCardPropertyOrganizations,
|
||||
ContactCardPropertySpeakToAs,
|
||||
ContactCardPropertyTitles,
|
||||
ContactCardPropertyEmails,
|
||||
ContactCardPropertyOnlineServices,
|
||||
ContactCardPropertyPhones,
|
||||
ContactCardPropertyPreferredLanguages,
|
||||
ContactCardPropertyCalendars,
|
||||
ContactCardPropertySchedulingAddresses,
|
||||
ContactCardPropertyAddresses,
|
||||
ContactCardPropertyCryptoKeys,
|
||||
ContactCardPropertyDirectories,
|
||||
ContactCardPropertyLinks,
|
||||
ContactCardPropertyMedia,
|
||||
ContactCardPropertyLocalizations,
|
||||
ContactCardPropertyAnniversaries,
|
||||
ContactCardPropertyKeywords,
|
||||
ContactCardPropertyNotes,
|
||||
ContactCardPropertyPersonalInfo,
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ 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.session, req.ctx, req.logger, req.language())
|
||||
resp, sessionState, state, lang, err := g.jmap.GetIdentitiesForAllAccounts(allAccountIds, req.ctx)
|
||||
if err != nil {
|
||||
return req.jmapErrorN(allAccountIds, err, sessionState, lang)
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ func (g *Groupware) GetAddressbooks(w http.ResponseWriter, r *http.Request) {
|
||||
return resp
|
||||
}
|
||||
|
||||
addressbooks, sessionState, state, lang, jerr := g.jmap.GetAddressbooks(accountId, req.session, req.ctx, req.logger, req.language(), nil)
|
||||
addressbooks, sessionState, state, lang, jerr := g.jmap.GetAddressbooks(accountId, []string{}, req.ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -42,7 +42,7 @@ func (g *Groupware) GetAddressbook(w http.ResponseWriter, r *http.Request) {
|
||||
l = l.Str(UriParamAddressBookId, log.SafeString(addressBookId))
|
||||
|
||||
logger := log.From(l)
|
||||
addressbooks, sessionState, state, lang, jerr := g.jmap.GetAddressbooks(accountId, req.session, req.ctx, logger, req.language(), []string{addressBookId})
|
||||
addressbooks, sessionState, state, lang, jerr := g.jmap.GetAddressbooks(accountId, []string{addressBookId}, req.ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -84,8 +84,8 @@ func (g *Groupware) GetAddressBookChanges(w http.ResponseWriter, r *http.Request
|
||||
}
|
||||
|
||||
logger := log.From(l)
|
||||
|
||||
changes, sessionState, state, lang, jerr := g.jmap.GetAddressbookChanges(accountId, req.session, req.ctx, logger, req.language(), sinceState, maxChanges)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
changes, sessionState, state, lang, jerr := g.jmap.GetAddressbookChanges(accountId, sinceState, maxChanges, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -110,7 +110,8 @@ func (g *Groupware) CreateAddressBook(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
logger := log.From(l)
|
||||
created, sessionState, state, lang, jerr := g.jmap.CreateAddressBook(accountId, req.session, req.ctx, logger, req.language(), create)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
created, sessionState, state, lang, jerr := g.jmap.CreateAddressBook(accountId, create, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -133,8 +134,8 @@ func (g *Groupware) DeleteAddressBook(w http.ResponseWriter, r *http.Request) {
|
||||
l.Str(UriParamAddressBookId, log.SafeString(addressBookId))
|
||||
|
||||
logger := log.From(l)
|
||||
|
||||
deleted, sessionState, state, lang, jerr := g.jmap.DeleteAddressBook(accountId, []string{addressBookId}, req.session, req.ctx, logger, req.language())
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
deleted, sessionState, state, lang, jerr := g.jmap.DeleteAddressBook(accountId, []string{addressBookId}, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/jmap"
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
)
|
||||
|
||||
@@ -27,8 +28,9 @@ func (g *Groupware) GetBlobMeta(w http.ResponseWriter, r *http.Request) {
|
||||
l = l.Str(UriParamBlobId, blobId)
|
||||
|
||||
logger := log.From(l)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
|
||||
res, sessionState, state, lang, jerr := g.jmap.GetBlobMetadata(accountId, req.session, req.ctx, logger, req.language(), blobId)
|
||||
res, sessionState, state, lang, jerr := g.jmap.GetBlobMetadata(accountId, blobId, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -57,8 +59,8 @@ func (g *Groupware) UploadBlob(w http.ResponseWriter, r *http.Request) {
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
logger := log.From(req.logger.With().Str(logAccountId, accountId))
|
||||
|
||||
resp, lang, jerr := g.jmap.UploadBlobStream(accountId, req.session, req.ctx, logger, req.language(), contentType, body)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
resp, lang, jerr := g.jmap.UploadBlobStream(accountId, contentType, body, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, req.session.State, lang)
|
||||
}
|
||||
@@ -85,21 +87,22 @@ func (g *Groupware) DownloadBlob(w http.ResponseWriter, r *http.Request) {
|
||||
return gwerr
|
||||
}
|
||||
logger := log.From(req.logger.With().Str(logAccountId, accountId).Str(UriParamBlobId, blobId))
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
|
||||
return req.serveBlob(blobId, name, typ, logger, accountId, w)
|
||||
return req.serveBlob(blobId, name, typ, ctx, accountId, w)
|
||||
})
|
||||
}
|
||||
|
||||
func (r *Request) serveBlob(blobId string, name string, typ string, logger *log.Logger, accountId string, w http.ResponseWriter) *Error {
|
||||
func (r *Request) serveBlob(blobId string, name string, typ string, ctx jmap.Context, accountId string, w http.ResponseWriter) *Error {
|
||||
if typ == "" {
|
||||
typ = DefaultBlobDownloadType
|
||||
}
|
||||
blob, lang, jerr := r.g.jmap.DownloadBlobStream(accountId, blobId, name, typ, r.session, r.ctx, logger, r.language())
|
||||
blob, lang, jerr := r.g.jmap.DownloadBlobStream(accountId, blobId, name, typ, ctx)
|
||||
if blob != nil && blob.Body != nil {
|
||||
defer func(Body io.ReadCloser) {
|
||||
err := Body.Close()
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msg("failed to close response body")
|
||||
ctx.Logger.Error().Err(err).Msg("failed to close response body")
|
||||
}
|
||||
}(blob.Body)
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ func (g *Groupware) GetCalendars(w http.ResponseWriter, r *http.Request) {
|
||||
return resp
|
||||
}
|
||||
|
||||
calendars, sessionState, state, lang, jerr := g.jmap.GetCalendars(accountId, req.session, req.ctx, req.logger, req.language(), nil)
|
||||
calendars, sessionState, state, lang, jerr := g.jmap.GetCalendars(accountId, nil, req.ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -41,7 +41,7 @@ func (g *Groupware) GetCalendarById(w http.ResponseWriter, r *http.Request) {
|
||||
l = l.Str(UriParamCalendarId, log.SafeString(calendarId))
|
||||
|
||||
logger := log.From(l)
|
||||
calendars, sessionState, state, lang, jerr := g.jmap.GetCalendars(accountId, req.session, req.ctx, logger, req.language(), []string{calendarId})
|
||||
calendars, sessionState, state, lang, jerr := g.jmap.GetCalendars(accountId, single(calendarId), req.ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -83,8 +83,8 @@ func (g *Groupware) GetCalendarChanges(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
logger := log.From(l)
|
||||
|
||||
changes, sessionState, state, lang, jerr := g.jmap.GetCalendarChanges(accountId, req.session, req.ctx, logger, req.language(), sinceState, maxChanges)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
changes, sessionState, state, lang, jerr := g.jmap.GetCalendarChanges(accountId, sinceState, maxChanges, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -109,7 +109,8 @@ func (g *Groupware) CreateCalendar(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
logger := log.From(l)
|
||||
created, sessionState, state, lang, jerr := g.jmap.CreateCalendar(accountId, req.session, req.ctx, logger, req.language(), create)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
created, sessionState, state, lang, jerr := g.jmap.CreateCalendar(accountId, create, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -132,8 +133,8 @@ func (g *Groupware) DeleteCalendar(w http.ResponseWriter, r *http.Request) {
|
||||
l.Str(UriParamCalendarId, log.SafeString(calendarId))
|
||||
|
||||
logger := log.From(l)
|
||||
|
||||
deleted, sessionState, state, lang, jerr := g.jmap.DeleteCalendar(accountId, []string{calendarId}, req.session, req.ctx, logger, req.language())
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
deleted, sessionState, state, lang, jerr := g.jmap.DeleteCalendar(accountId, single(calendarId), ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
@@ -77,7 +77,8 @@ func (g *Groupware) GetChanges(w http.ResponseWriter, r *http.Request) { //NOSON
|
||||
}
|
||||
|
||||
logger := log.From(l)
|
||||
changes, sessionState, state, lang, jerr := g.jmap.GetChanges(accountId, req.session, req.ctx, logger, req.language(), sinceState, maxChanges)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
changes, sessionState, state, lang, jerr := g.jmap.GetChanges(accountId, sinceState, maxChanges, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
@@ -57,12 +57,12 @@ func (g *Groupware) GetContactsInAddressbook(w http.ResponseWriter, r *http.Requ
|
||||
}
|
||||
l = l.Str(UriParamAddressBookId, log.SafeString(addressBookId))
|
||||
|
||||
offset, ok, err := req.parseUIntParam(QueryParamOffset, 0)
|
||||
offset, ok, err := req.parseIntParam(QueryParamOffset, 0)
|
||||
if err != nil {
|
||||
return req.errorN(accountIds, err)
|
||||
}
|
||||
if ok {
|
||||
l = l.Uint(QueryParamOffset, offset)
|
||||
l = l.Int(QueryParamOffset, offset)
|
||||
}
|
||||
|
||||
limit, ok, err := req.parseUIntParam(QueryParamLimit, g.defaults.contactLimit)
|
||||
@@ -84,7 +84,8 @@ func (g *Groupware) GetContactsInAddressbook(w http.ResponseWriter, r *http.Requ
|
||||
}
|
||||
|
||||
logger := log.From(l)
|
||||
contactsByAccountId, sessionState, state, lang, jerr := g.jmap.QueryContactCards(accountIds, req.session, req.ctx, logger, req.language(), filter, sortBy, offset, limit)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
contactsByAccountId, sessionState, state, lang, jerr := g.jmap.QueryContactCards(accountIds, filter, sortBy, offset, limit, true, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapErrorN(accountIds, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -113,7 +114,8 @@ func (g *Groupware) GetContactById(w http.ResponseWriter, r *http.Request) {
|
||||
l = l.Str(UriParamContactId, log.SafeString(contactId))
|
||||
|
||||
logger := log.From(l)
|
||||
contacts, sessionState, state, lang, jerr := g.jmap.GetContactCards(accountId, req.session, req.ctx, logger, req.language(), []string{contactId})
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
contacts, sessionState, state, lang, jerr := g.jmap.GetContactCards(accountId, single(contactId), ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -140,7 +142,8 @@ func (g *Groupware) GetAllContacts(w http.ResponseWriter, r *http.Request) {
|
||||
l := req.logger.With()
|
||||
|
||||
logger := log.From(l)
|
||||
contacts, sessionState, state, lang, jerr := g.jmap.GetContactCards(accountId, req.session, req.ctx, logger, req.language(), []string{})
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
contacts, sessionState, state, lang, jerr := g.jmap.GetContactCards(accountId, []string{}, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -173,7 +176,8 @@ func (g *Groupware) GetContactsChanges(w http.ResponseWriter, r *http.Request) {
|
||||
l = l.Str(HeaderParamSince, log.SafeString(string(sinceState)))
|
||||
|
||||
logger := log.From(l)
|
||||
changes, sessionState, state, lang, jerr := g.jmap.GetContactCardChanges(accountId, req.session, req.ctx, logger, req.language(), sinceState, maxChanges)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
changes, sessionState, state, lang, jerr := g.jmap.GetContactCardChanges(accountId, sinceState, maxChanges, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -205,7 +209,8 @@ func (g *Groupware) CreateContact(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
logger := log.From(l)
|
||||
created, sessionState, state, lang, jerr := g.jmap.CreateContactCard(accountId, req.session, req.ctx, logger, req.language(), create)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
created, sessionState, state, lang, jerr := g.jmap.CreateContactCard(accountId, create, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -228,8 +233,8 @@ func (g *Groupware) DeleteContact(w http.ResponseWriter, r *http.Request) {
|
||||
l.Str(UriParamContactId, log.SafeString(contactId))
|
||||
|
||||
logger := log.From(l)
|
||||
|
||||
deleted, sessionState, state, lang, jerr := g.jmap.DeleteContactCard(accountId, []string{contactId}, req.session, req.ctx, logger, req.language())
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
deleted, sessionState, state, lang, jerr := g.jmap.DeleteContactCard(accountId, single(contactId), ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
@@ -48,8 +48,8 @@ func (g *Groupware) GetEmailChanges(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
logger := log.From(l)
|
||||
|
||||
changes, sessionState, state, lang, jerr := g.jmap.GetEmailChanges(accountId, req.session, req.ctx, logger, req.language(), sinceState, true, g.config.maxBodyValueBytes, maxChanges)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
changes, sessionState, state, lang, jerr := g.jmap.GetEmailChanges(accountId, sinceState, true, g.config.maxBodyValueBytes, maxChanges, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -98,12 +98,13 @@ func (g *Groupware) GetAllEmailsInMailbox(w http.ResponseWriter, r *http.Request
|
||||
}
|
||||
|
||||
logger := log.From(l)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
|
||||
collapseThreads := false
|
||||
fetchBodies := false
|
||||
withThreads := true
|
||||
|
||||
emails, sessionState, state, lang, jerr := g.jmap.GetAllEmailsInMailbox(accountId, req.session, req.ctx, logger, req.language(), mailboxId, offset, limit, collapseThreads, fetchBodies, g.config.maxBodyValueBytes, withThreads)
|
||||
emails, sessionState, state, lang, jerr := g.jmap.GetAllEmailsInMailbox(accountId, mailboxId, offset, limit, collapseThreads, fetchBodies, g.config.maxBodyValueBytes, withThreads, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -151,8 +152,8 @@ 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)))
|
||||
|
||||
blobId, _, _, _, jerr := g.jmap.GetEmailBlobId(accountId, req.session, req.ctx, logger, req.language(), id)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
blobId, _, _, _, jerr := g.jmap.GetEmailBlobId(accountId, id, ctx)
|
||||
if jerr != nil {
|
||||
return req.apiErrorFromJmap(req.observeJmapError(jerr))
|
||||
}
|
||||
@@ -165,7 +166,7 @@ func (g *Groupware) GetEmailsById(w http.ResponseWriter, r *http.Request) { //NO
|
||||
if gwerr != nil {
|
||||
return gwerr
|
||||
}
|
||||
return req.serveBlob(blobId, name, typ, logger, accountId, w)
|
||||
return req.serveBlob(blobId, name, typ, ctx, accountId, w)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
@@ -195,8 +196,8 @@ func (g *Groupware) GetEmailsById(w http.ResponseWriter, r *http.Request) { //NO
|
||||
|
||||
if len(ids) == 1 {
|
||||
logger := log.From(l.Str("id", log.SafeString(id)))
|
||||
|
||||
emails, _, sessionState, state, lang, jerr := g.jmap.GetEmails(accountId, req.session, req.ctx, logger, req.language(), ids, true, g.config.maxBodyValueBytes, markAsSeen, true)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
emails, _, sessionState, state, lang, jerr := g.jmap.GetEmails(accountId, ids, true, g.config.maxBodyValueBytes, markAsSeen, true, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -211,8 +212,8 @@ func (g *Groupware) GetEmailsById(w http.ResponseWriter, r *http.Request) { //NO
|
||||
}
|
||||
} else {
|
||||
logger := log.From(l.Array("ids", log.SafeStringArray(ids)))
|
||||
|
||||
emails, _, sessionState, state, lang, jerr := g.jmap.GetEmails(accountId, req.session, req.ctx, logger, req.language(), ids, true, g.config.maxBodyValueBytes, markAsSeen, false)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
emails, _, sessionState, state, lang, jerr := g.jmap.GetEmails(accountId, ids, true, g.config.maxBodyValueBytes, markAsSeen, false, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -269,7 +270,8 @@ func (g *Groupware) GetEmailAttachments(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
|
||||
logger := log.From(l)
|
||||
emails, _, sessionState, state, lang, jerr := g.jmap.GetEmails(accountId, req.session, req.ctx, logger, req.language(), []string{id}, false, 0, false, false)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
emails, _, sessionState, state, lang, jerr := g.jmap.GetEmails(accountId, single(id), false, 0, false, false, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -305,8 +307,8 @@ func (g *Groupware) GetEmailAttachments(w http.ResponseWriter, r *http.Request)
|
||||
Str(UriParamEmailId, log.SafeString(id))
|
||||
l = contextAppender(l)
|
||||
logger := log.From(l)
|
||||
|
||||
emails, _, _, _, lang, jerr := g.jmap.GetEmails(mailAccountId, req.session, req.ctx, logger, req.language(), []string{id}, false, 0, false, false)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
emails, _, _, _, lang, jerr := g.jmap.GetEmails(mailAccountId, single(id), false, 0, false, false, ctx)
|
||||
if jerr != nil {
|
||||
return req.apiErrorFromJmap(req.observeJmapError(jerr))
|
||||
}
|
||||
@@ -329,7 +331,7 @@ func (g *Groupware) GetEmailAttachments(w http.ResponseWriter, r *http.Request)
|
||||
return nil
|
||||
}
|
||||
|
||||
blob, lang, jerr := g.jmap.DownloadBlobStream(blobAccountId, attachment.BlobId, attachment.Name, attachment.Type, req.session, req.ctx, logger, req.language())
|
||||
blob, lang, jerr := g.jmap.DownloadBlobStream(blobAccountId, attachment.BlobId, attachment.Name, attachment.Type, ctx)
|
||||
if blob != nil && blob.Body != nil {
|
||||
defer func(Body io.ReadCloser) {
|
||||
err := Body.Close()
|
||||
@@ -390,8 +392,8 @@ func (g *Groupware) getEmailsSince(w http.ResponseWriter, r *http.Request, since
|
||||
}
|
||||
|
||||
logger := log.From(l)
|
||||
|
||||
changes, sessionState, state, lang, jerr := g.jmap.GetEmailChanges(accountId, req.session, req.ctx, logger, req.language(), since, true, g.config.maxBodyValueBytes, maxChanges)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
changes, sessionState, state, lang, jerr := g.jmap.GetEmailChanges(accountId, since, true, g.config.maxBodyValueBytes, maxChanges, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -612,6 +614,7 @@ func (g *Groupware) GetEmails(w http.ResponseWriter, r *http.Request) { //NOSONA
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
logger = log.From(req.logger.With().Str(logAccountId, log.SafeString(accountId)))
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
|
||||
if !filter.IsNotEmpty() {
|
||||
filter = nil
|
||||
@@ -619,7 +622,7 @@ func (g *Groupware) GetEmails(w http.ResponseWriter, r *http.Request) { //NOSONA
|
||||
|
||||
fetchBodies := false
|
||||
|
||||
resultsByAccount, sessionState, state, lang, jerr := g.jmap.QueryEmailsWithSnippets(single(accountId), filter, req.session, req.ctx, logger, req.language(), offset, limit, fetchBodies, g.config.maxBodyValueBytes)
|
||||
resultsByAccount, sessionState, state, lang, jerr := g.jmap.QueryEmailsWithSnippets(single(accountId), filter, offset, limit, fetchBodies, g.config.maxBodyValueBytes, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -671,13 +674,14 @@ func (g *Groupware) GetEmailsForAllAccounts(w http.ResponseWriter, r *http.Reque
|
||||
return req.errorN(allAccountIds, err)
|
||||
}
|
||||
logger = log.From(req.logger.With().Array(logAccountId, log.SafeStringArray(allAccountIds)))
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
|
||||
if !filter.IsNotEmpty() {
|
||||
filter = nil
|
||||
}
|
||||
|
||||
if makesSnippets {
|
||||
resultsByAccountId, sessionState, state, lang, jerr := g.jmap.QueryEmailSnippets(allAccountIds, filter, req.session, req.ctx, logger, req.language(), offset, limit)
|
||||
resultsByAccountId, sessionState, state, lang, jerr := g.jmap.QueryEmailSnippets(allAccountIds, filter, offset, limit, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapErrorN(allAccountIds, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -717,7 +721,7 @@ func (g *Groupware) GetEmailsForAllAccounts(w http.ResponseWriter, r *http.Reque
|
||||
} else {
|
||||
withThreads := true
|
||||
|
||||
resultsByAccountId, sessionState, state, lang, jerr := g.jmap.QueryEmailSummaries(allAccountIds, req.session, req.ctx, logger, req.language(), filter, limit, withThreads)
|
||||
resultsByAccountId, sessionState, state, lang, jerr := g.jmap.QueryEmailSummaries(allAccountIds, filter, limit, withThreads, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapErrorN(allAccountIds, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -762,8 +766,8 @@ var draftEmailAutoMailboxRolePrecedence = []string{
|
||||
jmap.JmapMailboxRoleInbox, // but if there is none, we will use the Mailbox with the inbox role instead
|
||||
}
|
||||
|
||||
func findDraftsMailboxId(j *jmap.Client, accountId string, req Request, logger *log.Logger) (string, Response) {
|
||||
mailboxIdsPerAccountIds, sessionState, _, lang, jerr := j.SearchMailboxIdsPerRole(single(accountId), req.session, req.ctx, logger, req.language(), draftEmailAutoMailboxRolePrecedence)
|
||||
func findDraftsMailboxId(j *jmap.Client, accountId string, req Request, ctx jmap.Context) (string, Response) {
|
||||
mailboxIdsPerAccountIds, sessionState, _, lang, jerr := j.SearchMailboxIdsPerRole(single(accountId), draftEmailAutoMailboxRolePrecedence, ctx)
|
||||
if jerr != nil {
|
||||
return "", req.jmapError(accountId, jerr, sessionState, lang)
|
||||
} else {
|
||||
@@ -785,8 +789,8 @@ var sentEmailAutoMailboxRolePrecedence = []string{
|
||||
|
||||
var draftAndSentMailboxRoles = structs.Uniq(structs.Concat(draftEmailAutoMailboxRolePrecedence, sentEmailAutoMailboxRolePrecedence))
|
||||
|
||||
func findSentMailboxId(j *jmap.Client, accountId string, req Request, logger *log.Logger) (string, string, Response) { //NOSONAR
|
||||
mailboxIdsPerAccountIds, sessionState, _, lang, jerr := j.SearchMailboxIdsPerRole(single(accountId), req.session, req.ctx, logger, req.language(), draftAndSentMailboxRoles)
|
||||
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)
|
||||
if jerr != nil {
|
||||
return "", "", req.jmapError(accountId, jerr, sessionState, lang)
|
||||
} else {
|
||||
@@ -823,6 +827,7 @@ func (g *Groupware) CreateEmail(w http.ResponseWriter, r *http.Request) {
|
||||
return req.error(accountId, gwerr)
|
||||
}
|
||||
logger = log.From(logger.With().Str(logAccountId, log.SafeString(accountId)))
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
|
||||
var body jmap.EmailCreate
|
||||
err := req.body(&body)
|
||||
@@ -831,7 +836,7 @@ func (g *Groupware) CreateEmail(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
if len(body.MailboxIds) < 1 {
|
||||
mailboxId, resp := findDraftsMailboxId(g.jmap, accountId, req, logger)
|
||||
mailboxId, resp := findDraftsMailboxId(g.jmap, accountId, req, ctx)
|
||||
if mailboxId != "" {
|
||||
body.MailboxIds[mailboxId] = true
|
||||
} else {
|
||||
@@ -839,7 +844,7 @@ func (g *Groupware) CreateEmail(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
created, sessionState, state, lang, jerr := g.jmap.CreateEmail(accountId, body, "", req.session, req.ctx, logger, req.language())
|
||||
created, sessionState, state, lang, jerr := g.jmap.CreateEmail(accountId, body, "", ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -863,6 +868,7 @@ func (g *Groupware) ReplaceEmail(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
logger = log.From(logger.With().Str(logAccountId, log.SafeString(accountId)))
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
|
||||
var body jmap.EmailCreate
|
||||
err = req.body(&body)
|
||||
@@ -871,7 +877,7 @@ func (g *Groupware) ReplaceEmail(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
if len(body.MailboxIds) < 1 {
|
||||
mailboxId, resp := findDraftsMailboxId(g.jmap, accountId, req, logger)
|
||||
mailboxId, resp := findDraftsMailboxId(g.jmap, accountId, req, ctx)
|
||||
if mailboxId != "" {
|
||||
body.MailboxIds[mailboxId] = true
|
||||
} else {
|
||||
@@ -879,7 +885,7 @@ func (g *Groupware) ReplaceEmail(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
created, sessionState, state, lang, jerr := g.jmap.CreateEmail(accountId, body, replaceId, req.session, req.ctx, logger, req.language())
|
||||
created, sessionState, state, lang, jerr := g.jmap.CreateEmail(accountId, body, replaceId, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -905,6 +911,7 @@ func (g *Groupware) UpdateEmail(w http.ResponseWriter, r *http.Request) {
|
||||
l.Str(UriParamEmailId, log.SafeString(emailId))
|
||||
|
||||
logger := log.From(l)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
|
||||
var body map[string]any
|
||||
err = req.body(&body)
|
||||
@@ -916,7 +923,7 @@ func (g *Groupware) UpdateEmail(w http.ResponseWriter, r *http.Request) {
|
||||
emailId: body,
|
||||
}
|
||||
|
||||
result, sessionState, state, lang, jerr := g.jmap.UpdateEmails(accountId, updates, req.session, req.ctx, logger, req.language())
|
||||
result, sessionState, state, lang, jerr := g.jmap.UpdateEmails(accountId, updates, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -964,6 +971,7 @@ func (g *Groupware) UpdateEmailKeywords(w http.ResponseWriter, r *http.Request)
|
||||
l.Str(UriParamEmailId, log.SafeString(emailId))
|
||||
|
||||
logger := log.From(l)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
|
||||
var body emailKeywordUpdates
|
||||
err = req.body(&body)
|
||||
@@ -986,7 +994,7 @@ func (g *Groupware) UpdateEmailKeywords(w http.ResponseWriter, r *http.Request)
|
||||
emailId: patch,
|
||||
}
|
||||
|
||||
result, sessionState, state, lang, jerr := g.jmap.UpdateEmails(accountId, patches, req.session, req.ctx, logger, req.language())
|
||||
result, sessionState, state, lang, jerr := g.jmap.UpdateEmails(accountId, patches, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -1025,6 +1033,7 @@ func (g *Groupware) AddEmailKeywords(w http.ResponseWriter, r *http.Request) { /
|
||||
l.Str(UriParamEmailId, log.SafeString(emailId))
|
||||
|
||||
logger := log.From(l)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
|
||||
var body []string
|
||||
err = req.body(&body)
|
||||
@@ -1044,7 +1053,7 @@ func (g *Groupware) AddEmailKeywords(w http.ResponseWriter, r *http.Request) { /
|
||||
emailId: patch,
|
||||
}
|
||||
|
||||
result, sessionState, state, lang, jerr := g.jmap.UpdateEmails(accountId, patches, req.session, req.ctx, logger, req.language())
|
||||
result, sessionState, state, lang, jerr := g.jmap.UpdateEmails(accountId, patches, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -1087,6 +1096,7 @@ func (g *Groupware) RemoveEmailKeywords(w http.ResponseWriter, r *http.Request)
|
||||
l.Str(UriParamEmailId, log.SafeString(emailId))
|
||||
|
||||
logger := log.From(l)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
|
||||
var body []string
|
||||
err = req.body(&body)
|
||||
@@ -1106,7 +1116,7 @@ func (g *Groupware) RemoveEmailKeywords(w http.ResponseWriter, r *http.Request)
|
||||
emailId: patch,
|
||||
}
|
||||
|
||||
result, sessionState, state, lang, jerr := g.jmap.UpdateEmails(accountId, patches, req.session, req.ctx, logger, req.language())
|
||||
result, sessionState, state, lang, jerr := g.jmap.UpdateEmails(accountId, patches, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -1147,8 +1157,8 @@ func (g *Groupware) DeleteEmail(w http.ResponseWriter, r *http.Request) {
|
||||
l.Str(UriParamEmailId, log.SafeString(emailId))
|
||||
|
||||
logger := log.From(l)
|
||||
|
||||
resp, sessionState, state, lang, jerr := g.jmap.DeleteEmails(accountId, []string{emailId}, req.session, req.ctx, logger, req.language())
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
resp, sessionState, state, lang, jerr := g.jmap.DeleteEmails(accountId, single(emailId), ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -1196,8 +1206,8 @@ func (g *Groupware) DeleteEmails(w http.ResponseWriter, r *http.Request) {
|
||||
l.Array("emailIds", log.SafeStringArray(emailIds))
|
||||
|
||||
logger := log.From(l)
|
||||
|
||||
resp, sessionState, state, lang, jerr := g.jmap.DeleteEmails(accountId, emailIds, req.session, req.ctx, logger, req.language())
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
resp, sessionState, state, lang, jerr := g.jmap.DeleteEmails(accountId, emailIds, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -1245,7 +1255,8 @@ func (g *Groupware) SendEmail(w http.ResponseWriter, r *http.Request) { //NOSONA
|
||||
moveToMailboxId, _ := req.getStringParam(QueryParamMoveToMailboxId, "")
|
||||
|
||||
if moveFromMailboxId == "" || moveToMailboxId == "" {
|
||||
draftsMailboxId, sentMailboxId, resp := findSentMailboxId(g.jmap, accountId, req, req.logger)
|
||||
ctx := req.ctx.WithLogger(log.From(l))
|
||||
draftsMailboxId, sentMailboxId, resp := findSentMailboxId(g.jmap, accountId, req, ctx)
|
||||
if draftsMailboxId != "" && sentMailboxId != "" {
|
||||
if moveFromMailboxId == "" {
|
||||
moveFromMailboxId = draftsMailboxId
|
||||
@@ -1265,8 +1276,8 @@ func (g *Groupware) SendEmail(w http.ResponseWriter, r *http.Request) { //NOSONA
|
||||
}
|
||||
|
||||
logger := log.From(l)
|
||||
|
||||
resp, sessionState, state, lang, jerr := g.jmap.SubmitEmail(accountId, identityId, emailId, move, req.session, req.ctx, logger, req.language())
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
resp, sessionState, state, lang, jerr := g.jmap.SubmitEmail(accountId, identityId, emailId, move, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -1366,10 +1377,11 @@ func (g *Groupware) RelatedToEmail(w http.ResponseWriter, r *http.Request) { //N
|
||||
}
|
||||
|
||||
logger := log.From(l)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
|
||||
reqId := req.GetRequestId()
|
||||
getEmailsBefore := time.Now()
|
||||
emails, _, sessionState, state, lang, jerr := g.jmap.GetEmails(accountId, req.session, req.ctx, logger, req.language(), []string{id}, true, g.config.maxBodyValueBytes, false, false)
|
||||
emails, _, sessionState, state, lang, 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)
|
||||
@@ -1394,7 +1406,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()
|
||||
resultsByAccountId, _, _, lang, jerr := g.jmap.QueryEmails(single(accountId), filter, req.session, bgctx, l, req.language(), 0, limit, false, g.config.maxBodyValueBytes)
|
||||
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 {
|
||||
duration := time.Since(before)
|
||||
if jerr != nil {
|
||||
@@ -1415,7 +1428,8 @@ func (g *Groupware) RelatedToEmail(w http.ResponseWriter, r *http.Request) { //N
|
||||
|
||||
g.job(logger, RelationTypeSameThread, func(jobId uint64, l *log.Logger) {
|
||||
before := time.Now()
|
||||
emails, _, _, lang, jerr := g.jmap.EmailsInThread(accountId, email.ThreadId, req.session, bgctx, l, req.language(), false, g.config.maxBodyValueBytes)
|
||||
ctx = ctx.WithLogger(logger).WithContext(bgctx)
|
||||
emails, _, _, lang, jerr := g.jmap.EmailsInThread(accountId, email.ThreadId, false, g.config.maxBodyValueBytes, ctx)
|
||||
duration := time.Since(before)
|
||||
if jerr != nil {
|
||||
_ = req.observeJmapError(jerr)
|
||||
@@ -1683,8 +1697,9 @@ func (g *Groupware) GetLatestEmailsSummaryForAllAccounts(w http.ResponseWriter,
|
||||
}
|
||||
|
||||
logger := log.From(l)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
|
||||
emailsSummariesByAccount, sessionState, state, lang, jerr := g.jmap.QueryEmailSummaries(allAccountIds, req.session, req.ctx, logger, req.language(), filter, limit, true)
|
||||
emailsSummariesByAccount, sessionState, state, lang, jerr := g.jmap.QueryEmailSummaries(allAccountIds, filter, limit, true, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapErrorN(allAccountIds, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
@@ -24,12 +24,12 @@ func (g *Groupware) GetEventsInCalendar(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
l = l.Str(UriParamCalendarId, log.SafeString(calendarId))
|
||||
|
||||
offset, ok, err := req.parseUIntParam(QueryParamOffset, 0)
|
||||
offset, ok, err := req.parseIntParam(QueryParamOffset, 0)
|
||||
if err != nil {
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
if ok {
|
||||
l = l.Uint(QueryParamOffset, offset)
|
||||
l = l.Int(QueryParamOffset, offset)
|
||||
}
|
||||
|
||||
limit, ok, err := req.parseUIntParam(QueryParamLimit, g.defaults.contactLimit)
|
||||
@@ -46,7 +46,8 @@ func (g *Groupware) GetEventsInCalendar(w http.ResponseWriter, r *http.Request)
|
||||
sortBy := []jmap.CalendarEventComparator{{Property: jmap.CalendarEventPropertyUpdated, IsAscending: false}}
|
||||
|
||||
logger := log.From(l)
|
||||
eventsByAccountId, sessionState, state, lang, jerr := g.jmap.QueryCalendarEvents(single(accountId), req.session, req.ctx, logger, req.language(), filter, sortBy, offset, limit)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
eventsByAccountId, sessionState, state, lang, jerr := g.jmap.QueryCalendarEvents(single(accountId), filter, sortBy, offset, limit, true, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -82,7 +83,8 @@ func (g *Groupware) GetEventChanges(w http.ResponseWriter, r *http.Request) {
|
||||
l = l.Str(HeaderParamSince, log.SafeString(string(sinceState)))
|
||||
|
||||
logger := log.From(l)
|
||||
changes, sessionState, state, lang, jerr := g.jmap.GetCalendarEventChanges(accountId, req.session, req.ctx, logger, req.language(), sinceState, maxChanges)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
changes, sessionState, state, lang, jerr := g.jmap.GetCalendarEventChanges(accountId, sinceState, maxChanges, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -108,7 +110,8 @@ func (g *Groupware) CreateCalendarEvent(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
|
||||
logger := log.From(l)
|
||||
created, sessionState, state, lang, jerr := g.jmap.CreateCalendarEvent(accountId, req.session, req.ctx, logger, req.language(), create)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
created, sessionState, state, lang, jerr := g.jmap.CreateCalendarEvent(accountId, create, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -131,8 +134,8 @@ func (g *Groupware) DeleteCalendarEvent(w http.ResponseWriter, r *http.Request)
|
||||
l.Str(UriParamEventId, log.SafeString(eventId))
|
||||
|
||||
logger := log.From(l)
|
||||
|
||||
deleted, sessionState, state, lang, jerr := g.jmap.DeleteCalendarEvent(accountId, []string{eventId}, req.session, req.ctx, logger, req.language())
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
deleted, sessionState, state, lang, jerr := g.jmap.DeleteCalendarEvent(accountId, single(eventId), ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -174,8 +177,8 @@ func (g *Groupware) ParseIcalBlob(w http.ResponseWriter, r *http.Request) {
|
||||
blobIds := strings.Split(blobId, ",")
|
||||
l := req.logger.With().Array(UriParamBlobId, log.SafeStringArray(blobIds))
|
||||
logger := log.From(l)
|
||||
|
||||
resp, sessionState, state, lang, jerr := g.jmap.ParseICalendarBlob(accountId, req.session, req.ctx, logger, req.language(), blobIds)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
resp, sessionState, state, lang, jerr := g.jmap.ParseICalendarBlob(accountId, blobIds, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/jmap"
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
"github.com/opencloud-eu/opencloud/pkg/structs"
|
||||
)
|
||||
|
||||
// Get the list of identities that are associated with an account.
|
||||
@@ -18,7 +17,8 @@ func (g *Groupware) GetIdentities(w http.ResponseWriter, r *http.Request) {
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
logger := log.From(req.logger.With().Str(logAccountId, accountId))
|
||||
res, sessionState, state, lang, jerr := g.jmap.GetAllIdentities(accountId, req.session, req.ctx, logger, req.language())
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
res, sessionState, state, lang, jerr := g.jmap.GetAllIdentities(accountId, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -37,7 +37,8 @@ func (g *Groupware) GetIdentityById(w http.ResponseWriter, r *http.Request) {
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
logger := log.From(req.logger.With().Str(logAccountId, accountId).Str(logIdentityId, id))
|
||||
res, sessionState, state, lang, jerr := g.jmap.GetIdentities(accountId, req.session, req.ctx, logger, req.language(), []string{id})
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
res, sessionState, state, lang, jerr := g.jmap.GetIdentities(accountId, single(id), ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -56,14 +57,15 @@ func (g *Groupware) AddIdentity(w http.ResponseWriter, r *http.Request) {
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
logger := log.From(req.logger.With().Str(logAccountId, accountId))
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
|
||||
var identity jmap.Identity
|
||||
var identity jmap.IdentityChange
|
||||
err = req.body(&identity)
|
||||
if err != nil {
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
|
||||
created, sessionState, state, lang, jerr := g.jmap.CreateIdentity(accountId, req.session, req.ctx, logger, req.language(), identity)
|
||||
created, sessionState, state, lang, jerr := g.jmap.CreateIdentity(accountId, identity, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -77,15 +79,21 @@ func (g *Groupware) ModifyIdentity(w http.ResponseWriter, r *http.Request) {
|
||||
if err != nil {
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
logger := log.From(req.logger.With().Str(logAccountId, accountId))
|
||||
id, err := req.PathParamDoc(UriParamIdentityId, "The unique identifier of the Identity to modify")
|
||||
if err != nil {
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
|
||||
var identity jmap.Identity
|
||||
logger := log.From(req.logger.With().Str(logAccountId, accountId).Str(UriParamIdentityId, log.SafeString(id)))
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
|
||||
var identity jmap.IdentityChange
|
||||
err = req.body(&identity)
|
||||
if err != nil {
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
|
||||
updated, sessionState, state, lang, jerr := g.jmap.UpdateIdentity(accountId, req.session, req.ctx, logger, req.language(), identity)
|
||||
updated, sessionState, state, lang, jerr := g.jmap.UpdateIdentity(accountId, id, identity, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -100,7 +108,6 @@ func (g *Groupware) DeleteIdentity(w http.ResponseWriter, r *http.Request) {
|
||||
if err != nil {
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
logger := log.From(req.logger.With().Str(logAccountId, accountId))
|
||||
|
||||
id, err := req.PathParam(UriParamIdentityId)
|
||||
if err != nil {
|
||||
@@ -111,18 +118,19 @@ func (g *Groupware) DeleteIdentity(w http.ResponseWriter, r *http.Request) {
|
||||
return req.parameterErrorResponse(single(accountId), UriParamIdentityId, fmt.Sprintf("Invalid value for path parameter '%v': '%s': %s", UriParamIdentityId, log.SafeString(id), "empty list of identity ids"))
|
||||
}
|
||||
|
||||
deletion, sessionState, state, lang, jerr := g.jmap.DeleteIdentity(accountId, req.session, req.ctx, logger, req.language(), ids)
|
||||
logger := log.From(req.logger.With().Str(logAccountId, accountId).Array(UriParamIdentityId, log.SafeStringArray(ids)))
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
|
||||
notDeleted, sessionState, state, lang, jerr := g.jmap.DeleteIdentity(accountId, ids, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
notDeletedIds := structs.Missing(ids, deletion)
|
||||
if len(notDeletedIds) == 0 {
|
||||
if len(notDeleted) == 0 {
|
||||
return req.noContent(accountId, sessionState, IdentityResponseObjectType, state)
|
||||
} else {
|
||||
logger.Error().Array("not-deleted", log.SafeStringArray(notDeletedIds)).Msgf("failed to delete %d identities", len(notDeletedIds))
|
||||
return req.errorS(accountId, req.apiError(&ErrorFailedToDeleteSomeIdentities,
|
||||
withMeta(map[string]any{"ids": notDeletedIds})), sessionState)
|
||||
logger.Error().Msgf("failed to delete %d identities", len(notDeleted))
|
||||
return req.errorS(accountId, req.apiError(&ErrorFailedToDeleteSomeIdentities), sessionState)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -150,7 +158,8 @@ func (g *Groupware) GetIdentityChanges(w http.ResponseWriter, r *http.Request) {
|
||||
l = l.Str(HeaderParamSince, log.SafeString(string(sinceState)))
|
||||
|
||||
logger := log.From(l)
|
||||
changes, sessionState, state, lang, jerr := g.jmap.GetIdentityChanges(accountId, req.session, req.ctx, logger, req.language(), sinceState, maxChanges)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
changes, sessionState, state, lang, jerr := g.jmap.GetIdentityChanges(accountId, sinceState, maxChanges, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ 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.session, req.ctx, req.logger, req.language())
|
||||
boot, sessionState, state, lang, err := g.jmap.GetBootstrap(accountIds, req.ctx)
|
||||
if err != nil {
|
||||
return req.jmapErrorN(accountIds, err, sessionState, lang)
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ func (g *Groupware) GetMailbox(w http.ResponseWriter, r *http.Request) {
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
|
||||
mailboxes, sessionState, state, lang, jerr := g.jmap.GetMailbox(accountId, req.session, req.ctx, req.logger, req.language(), []string{mailboxId})
|
||||
mailboxes, sessionState, state, lang, jerr := g.jmap.GetMailbox(accountId, single(mailboxId), req.ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -83,9 +83,10 @@ func (g *Groupware) GetMailboxes(w http.ResponseWriter, r *http.Request) { //NOS
|
||||
}
|
||||
|
||||
logger := log.From(req.logger.With().Str(logAccountId, accountId))
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
|
||||
if hasCriteria {
|
||||
mailboxesByAccountId, sessionState, state, lang, err := g.jmap.SearchMailboxes(single(accountId), req.session, req.ctx, logger, req.language(), filter)
|
||||
mailboxesByAccountId, sessionState, state, lang, err := g.jmap.SearchMailboxes(single(accountId), filter, ctx)
|
||||
if err != nil {
|
||||
return req.jmapError(accountId, err, sessionState, lang)
|
||||
}
|
||||
@@ -96,7 +97,7 @@ func (g *Groupware) GetMailboxes(w http.ResponseWriter, r *http.Request) { //NOS
|
||||
return req.notFound(accountId, sessionState, MailboxResponseObjectType, state)
|
||||
}
|
||||
} else {
|
||||
mailboxesByAccountId, sessionState, state, lang, err := g.jmap.GetAllMailboxes(single(accountId), req.session, req.ctx, logger, req.language())
|
||||
mailboxesByAccountId, sessionState, state, lang, err := g.jmap.GetAllMailboxes(single(accountId), ctx)
|
||||
if err != nil {
|
||||
return req.jmapError(accountId, err, sessionState, lang)
|
||||
}
|
||||
@@ -117,6 +118,7 @@ func (g *Groupware) GetMailboxesForAllAccounts(w http.ResponseWriter, r *http.Re
|
||||
return req.noopN(nil) // when the user has no accounts
|
||||
}
|
||||
logger := log.From(req.logger.With().Array(logAccountId, log.SafeStringArray(accountIds)))
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
|
||||
var filter jmap.MailboxFilterCondition
|
||||
hasCriteria := false
|
||||
@@ -134,13 +136,13 @@ func (g *Groupware) GetMailboxesForAllAccounts(w http.ResponseWriter, r *http.Re
|
||||
}
|
||||
|
||||
if hasCriteria {
|
||||
mailboxesByAccountId, sessionState, state, lang, err := g.jmap.SearchMailboxes(accountIds, req.session, req.ctx, logger, req.language(), filter)
|
||||
mailboxesByAccountId, sessionState, state, lang, err := g.jmap.SearchMailboxes(accountIds, filter, ctx)
|
||||
if err != nil {
|
||||
return req.jmapErrorN(accountIds, err, sessionState, lang)
|
||||
}
|
||||
return req.respondN(accountIds, sortMailboxesMap(mailboxesByAccountId), sessionState, MailboxResponseObjectType, state)
|
||||
} else {
|
||||
mailboxesByAccountId, sessionState, state, lang, err := g.jmap.GetAllMailboxes(accountIds, req.session, req.ctx, logger, req.language())
|
||||
mailboxesByAccountId, sessionState, state, lang, err := g.jmap.GetAllMailboxes(accountIds, ctx)
|
||||
if err != nil {
|
||||
return req.jmapErrorN(accountIds, err, sessionState, lang)
|
||||
}
|
||||
@@ -163,12 +165,13 @@ func (g *Groupware) GetMailboxByRoleForAllAccounts(w http.ResponseWriter, r *htt
|
||||
}
|
||||
|
||||
logger := log.From(req.logger.With().Array(logAccountId, log.SafeStringArray(accountIds)).Str("role", role))
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
|
||||
filter := jmap.MailboxFilterCondition{
|
||||
Role: role,
|
||||
}
|
||||
|
||||
mailboxesByAccountId, sessionState, state, lang, jerr := g.jmap.SearchMailboxes(accountIds, req.session, req.ctx, logger, req.language(), filter)
|
||||
mailboxesByAccountId, sessionState, state, lang, jerr := g.jmap.SearchMailboxes(accountIds, filter, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapErrorN(accountIds, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -202,6 +205,7 @@ func (g *Groupware) GetMailboxChanges(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
logger := log.From(l)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
|
||||
// As for Emails and Contacts, one would expect this request without any prior state to
|
||||
// be usable to list all the objects that currently exist, but that is not the case for
|
||||
@@ -216,7 +220,7 @@ func (g *Groupware) GetMailboxChanges(w http.ResponseWriter, r *http.Request) {
|
||||
)))
|
||||
}
|
||||
|
||||
changes, sessionState, state, lang, jerr := g.jmap.GetMailboxChanges(accountId, req.session, req.ctx, logger, req.language(), sinceState, maxChanges)
|
||||
changes, sessionState, state, lang, jerr := g.jmap.GetMailboxChanges(accountId, sinceState, maxChanges, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -254,9 +258,10 @@ func (g *Groupware) GetMailboxChangesForAllAccounts(w http.ResponseWriter, r *ht
|
||||
}
|
||||
|
||||
logger := log.From(l)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
|
||||
sinceStateMap := structs.MapValues(sinceStateStrMap, toState)
|
||||
changesByAccountId, sessionState, state, lang, jerr := g.jmap.GetMailboxChangesForMultipleAccounts(allAccountIds, req.session, req.ctx, logger, req.language(), sinceStateMap, maxChanges)
|
||||
changesByAccountId, sessionState, state, lang, jerr := g.jmap.GetMailboxChangesForMultipleAccounts(allAccountIds, sinceStateMap, maxChanges, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapErrorN(allAccountIds, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -273,8 +278,9 @@ func (g *Groupware) GetMailboxRoles(w http.ResponseWriter, r *http.Request) {
|
||||
allAccountIds := req.AllAccountIds()
|
||||
l.Array(logAccountId, log.SafeStringArray(allAccountIds))
|
||||
logger := log.From(l)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
|
||||
rolesByAccountId, sessionState, state, lang, jerr := g.jmap.GetMailboxRolesForMultipleAccounts(allAccountIds, req.session, req.ctx, logger, req.language())
|
||||
rolesByAccountId, sessionState, state, lang, jerr := g.jmap.GetMailboxRolesForMultipleAccounts(allAccountIds, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapErrorN(allAccountIds, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -305,8 +311,9 @@ func (g *Groupware) UpdateMailbox(w http.ResponseWriter, r *http.Request) {
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
logger := log.From(l)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
|
||||
updated, sessionState, state, lang, jerr := g.jmap.UpdateMailbox(accountId, req.session, req.ctx, logger, req.language(), mailboxId, "", body)
|
||||
updated, sessionState, state, lang, jerr := g.jmap.UpdateMailbox(accountId, mailboxId, body, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -330,8 +337,9 @@ func (g *Groupware) CreateMailbox(w http.ResponseWriter, r *http.Request) {
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
logger := log.From(l)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
|
||||
created, sessionState, state, lang, jerr := g.jmap.CreateMailbox(accountId, req.session, req.ctx, logger, req.language(), "", body)
|
||||
created, sessionState, state, lang, jerr := g.jmap.CreateMailbox(accountId, body, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -365,8 +373,9 @@ func (g *Groupware) DeleteMailbox(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
logger := log.From(l)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
|
||||
deleted, sessionState, state, lang, jerr := g.jmap.DeleteMailboxes(accountId, req.session, req.ctx, logger, req.language(), "", mailboxIds)
|
||||
deleted, sessionState, state, lang, jerr := g.jmap.DeleteMailboxes(accountId, mailboxIds, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
@@ -120,8 +120,11 @@ func (g *Groupware) GetObjects(w http.ResponseWriter, r *http.Request) { //NOSON
|
||||
}
|
||||
|
||||
logger := log.From(l)
|
||||
objs, sessionState, state, lang, jerr := g.jmap.GetObjects(accountId, req.session, req.ctx, logger, req.language(),
|
||||
mailboxIds, emailIds, addressbookIds, contactIds, calendarIds, eventIds, quotaIds, identityIds, emailSubmissionIds)
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
objs, sessionState, state, lang, 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)
|
||||
}
|
||||
|
||||
@@ -19,8 +19,9 @@ func (g *Groupware) GetQuota(w http.ResponseWriter, r *http.Request) {
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
logger := log.From(req.logger.With().Str(logAccountId, accountId))
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
|
||||
res, sessionState, state, lang, jerr := g.jmap.GetQuotas(single(accountId), req.session, req.ctx, logger, req.language())
|
||||
res, sessionState, state, lang, jerr := g.jmap.GetQuotas(single(accountId), ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -47,8 +48,9 @@ func (g *Groupware) GetQuotaForAllAccounts(w http.ResponseWriter, r *http.Reques
|
||||
return req.noopN(accountIds) // user has no accounts
|
||||
}
|
||||
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, req.session, req.ctx, logger, req.language())
|
||||
res, sessionState, state, lang, jerr := g.jmap.GetQuotas(accountIds, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapErrorN(accountIds, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
@@ -20,8 +20,9 @@ func (g *Groupware) GetVacation(w http.ResponseWriter, r *http.Request) {
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
logger := log.From(req.logger.With().Str(logAccountId, accountId))
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
|
||||
res, sessionState, state, lang, jerr := g.jmap.GetVacationResponse(accountId, req.session, req.ctx, logger, req.language())
|
||||
res, sessionState, state, lang, jerr := g.jmap.GetVacationResponse(accountId, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
@@ -40,14 +41,15 @@ func (g *Groupware) SetVacation(w http.ResponseWriter, r *http.Request) {
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
logger := log.From(req.logger.With().Str(logAccountId, accountId))
|
||||
ctx := req.ctx.WithLogger(logger)
|
||||
|
||||
var body jmap.VacationResponsePayload
|
||||
var body jmap.VacationResponseChange
|
||||
err = req.body(&body)
|
||||
if err != nil {
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
|
||||
res, sessionState, state, lang, jerr := g.jmap.SetVacationResponse(accountId, body, req.session, req.ctx, logger, req.language())
|
||||
res, sessionState, state, lang, jerr := g.jmap.SetVacationResponse(accountId, body, ctx)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
@@ -632,7 +632,7 @@ func errorId(r *http.Request, ctx context.Context) string {
|
||||
}
|
||||
|
||||
func (r *Request) errorId() string {
|
||||
return errorId(r.r, r.ctx)
|
||||
return errorId(r.r, r.cotx)
|
||||
}
|
||||
|
||||
func apiError(id string, gwerr GroupwareError, options ...ErrorOpt) *Error {
|
||||
|
||||
@@ -582,6 +582,15 @@ func (g *Groupware) serveError(w http.ResponseWriter, r *http.Request, error *Er
|
||||
}
|
||||
}
|
||||
|
||||
func newContext(session *jmap.Session, cotx context.Context, logger *log.Logger, acceptLanguage string) jmap.Context {
|
||||
return jmap.Context{
|
||||
Session: session,
|
||||
Context: cotx,
|
||||
Logger: logger,
|
||||
AcceptLanguage: acceptLanguage,
|
||||
}
|
||||
}
|
||||
|
||||
// Execute a closure with a JMAP Session.
|
||||
//
|
||||
// Returns
|
||||
@@ -589,23 +598,23 @@ func (g *Groupware) serveError(w http.ResponseWriter, r *http.Request, error *Er
|
||||
// - if an error occurs, after which timestamp a retry is allowed
|
||||
// - whether the request was sent to the server or not
|
||||
func (g *Groupware) withSession(w http.ResponseWriter, r *http.Request, handler func(r Request) Response) (Response, time.Time, bool) {
|
||||
ctx := r.Context()
|
||||
sl := g.logger.SubloggerWithRequestID(ctx)
|
||||
cotx := r.Context()
|
||||
sl := g.logger.SubloggerWithRequestID(cotx)
|
||||
logger := &sl
|
||||
|
||||
// retrieve the current user from the inbound request
|
||||
var user user
|
||||
{
|
||||
var err error
|
||||
user, err = g.userProvider.GetUser(r, ctx, logger)
|
||||
user, err = g.userProvider.GetUser(r, cotx, logger)
|
||||
if err != nil {
|
||||
g.metrics.AuthenticationFailureCounter.Inc()
|
||||
g.serveError(w, r, apiError(errorId(r, ctx), ErrorInvalidAuthentication), time.Time{})
|
||||
g.serveError(w, r, apiError(errorId(r, cotx), ErrorInvalidAuthentication), time.Time{})
|
||||
return Response{}, time.Time{}, false
|
||||
}
|
||||
if user == nil {
|
||||
g.metrics.AuthenticationFailureCounter.Inc()
|
||||
g.serveError(w, r, apiError(errorId(r, ctx), ErrorMissingAuthentication), time.Time{})
|
||||
g.serveError(w, r, apiError(errorId(r, cotx), ErrorMissingAuthentication), time.Time{})
|
||||
return Response{}, time.Time{}, false
|
||||
}
|
||||
|
||||
@@ -615,10 +624,10 @@ func (g *Groupware) withSession(w http.ResponseWriter, r *http.Request, handler
|
||||
// retrieve a JMAP Session for that user
|
||||
var session jmap.Session
|
||||
{
|
||||
s, ok, gwerr, retryAfter := g.session(ctx, user, logger)
|
||||
s, ok, gwerr, retryAfter := g.session(cotx, user, logger)
|
||||
if gwerr != nil {
|
||||
g.metrics.SessionFailureCounter.Inc()
|
||||
errorId := errorId(r, ctx)
|
||||
errorId := errorId(r, cotx)
|
||||
logger.Error().Str("code", gwerr.Code).Str("error", gwerr.Title).Str("detail", gwerr.Detail).Str(logErrorId, errorId).Msg("failed to determine JMAP session")
|
||||
g.serveError(w, r, apiError(errorId, *gwerr), retryAfter)
|
||||
return Response{}, retryAfter, false
|
||||
@@ -628,7 +637,7 @@ func (g *Groupware) withSession(w http.ResponseWriter, r *http.Request, handler
|
||||
} else {
|
||||
// no session = authentication failed
|
||||
g.metrics.SessionFailureCounter.Inc()
|
||||
errorId := errorId(r, ctx)
|
||||
errorId := errorId(r, cotx)
|
||||
logger.Error().Str(logErrorId, errorId).Msg("could not authenticate, failed to find Session")
|
||||
gwerr = &ErrorInvalidAuthentication
|
||||
g.serveError(w, r, apiError(errorId, *gwerr), retryAfter)
|
||||
@@ -638,11 +647,16 @@ func (g *Groupware) withSession(w http.ResponseWriter, r *http.Request, handler
|
||||
|
||||
decoratedLogger := decorateLogger(logger, session)
|
||||
|
||||
language := r.Header.Get("Accept-Language")
|
||||
|
||||
ctx := newContext(&session, cotx, decoratedLogger, language)
|
||||
|
||||
// build the Request object
|
||||
req := Request{
|
||||
g: g,
|
||||
user: user,
|
||||
r: r,
|
||||
cotx: cotx,
|
||||
ctx: ctx,
|
||||
logger: decoratedLogger,
|
||||
session: &session,
|
||||
@@ -735,32 +749,32 @@ func (g *Groupware) respond(w http.ResponseWriter, r *http.Request, handler func
|
||||
}
|
||||
|
||||
func (g *Groupware) stream(w http.ResponseWriter, r *http.Request, handler func(r Request, w http.ResponseWriter) *Error) {
|
||||
ctx := r.Context()
|
||||
sl := g.logger.SubloggerWithRequestID(ctx)
|
||||
cotx := r.Context()
|
||||
sl := g.logger.SubloggerWithRequestID(cotx)
|
||||
logger := &sl
|
||||
|
||||
user, err := g.userProvider.GetUser(r, ctx, logger)
|
||||
user, err := g.userProvider.GetUser(r, cotx, logger)
|
||||
if err != nil {
|
||||
g.serveError(w, r, apiError(errorId(r, ctx), ErrorInvalidAuthentication), time.Time{})
|
||||
g.serveError(w, r, apiError(errorId(r, cotx), ErrorInvalidAuthentication), time.Time{})
|
||||
return
|
||||
}
|
||||
if user == nil {
|
||||
g.serveError(w, r, apiError(errorId(r, ctx), ErrorMissingAuthentication), time.Time{})
|
||||
g.serveError(w, r, apiError(errorId(r, cotx), ErrorMissingAuthentication), time.Time{})
|
||||
return
|
||||
}
|
||||
|
||||
logger = log.From(logger.With().Str(logUserId, log.SafeString(user.GetId())))
|
||||
|
||||
session, ok, gwerr, retryAfter := g.session(ctx, user, logger)
|
||||
session, ok, gwerr, retryAfter := g.session(cotx, user, logger)
|
||||
if gwerr != nil {
|
||||
errorId := errorId(r, ctx)
|
||||
errorId := errorId(r, cotx)
|
||||
logger.Error().Str("code", gwerr.Code).Str("error", gwerr.Title).Str("detail", gwerr.Detail).Str(logErrorId, errorId).Msg("failed to determine JMAP session")
|
||||
g.serveError(w, r, apiError(errorId, *gwerr), retryAfter)
|
||||
return
|
||||
}
|
||||
if !ok {
|
||||
// no session = authentication failed
|
||||
errorId := errorId(r, ctx)
|
||||
errorId := errorId(r, cotx)
|
||||
logger.Error().Str(logErrorId, errorId).Msg("could not authenticate, failed to find Session")
|
||||
gwerr = &ErrorInvalidAuthentication
|
||||
g.serveError(w, r, apiError(errorId, *gwerr), retryAfter)
|
||||
@@ -769,13 +783,18 @@ func (g *Groupware) stream(w http.ResponseWriter, r *http.Request, handler func(
|
||||
|
||||
decoratedLogger := decorateLogger(logger, session)
|
||||
|
||||
language := r.Header.Get("Accept-Language")
|
||||
|
||||
ctx := newContext(&session, cotx, decoratedLogger, language)
|
||||
|
||||
req := Request{
|
||||
g: g,
|
||||
user: user,
|
||||
r: r,
|
||||
ctx: ctx,
|
||||
cotx: cotx,
|
||||
logger: decoratedLogger,
|
||||
session: &session,
|
||||
ctx: ctx,
|
||||
}
|
||||
|
||||
apierr := handler(req, w)
|
||||
|
||||
@@ -39,9 +39,10 @@ type Request struct {
|
||||
g *Groupware
|
||||
user user
|
||||
r *http.Request
|
||||
ctx context.Context
|
||||
cotx context.Context
|
||||
logger *log.Logger
|
||||
session *jmap.Session
|
||||
ctx jmap.Context
|
||||
}
|
||||
|
||||
func isDefaultAccountId(accountId string) bool {
|
||||
@@ -57,11 +58,11 @@ func (r *Request) GetUser() user {
|
||||
}
|
||||
|
||||
func (r *Request) GetRequestId() string {
|
||||
return chimiddleware.GetReqID(r.ctx)
|
||||
return chimiddleware.GetReqID(r.cotx)
|
||||
}
|
||||
|
||||
func (r *Request) GetTraceId() string {
|
||||
return groupwaremiddleware.GetTraceID(r.ctx)
|
||||
return groupwaremiddleware.GetTraceID(r.cotx)
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package groupware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -12,8 +11,8 @@ import (
|
||||
|
||||
func TestParseSort(t *testing.T) {
|
||||
req := Request{
|
||||
r: &http.Request{},
|
||||
ctx: context.Background(),
|
||||
r: &http.Request{},
|
||||
cotx: t.Context(),
|
||||
}
|
||||
require := require.New(t)
|
||||
{
|
||||
@@ -84,7 +83,7 @@ func TestParseMap(t *testing.T) {
|
||||
{
|
||||
u, err := url.Parse(tt.uri)
|
||||
require.NoError(err)
|
||||
req = Request{r: &http.Request{URL: u}, ctx: context.Background()}
|
||||
req = Request{r: &http.Request{URL: u}, cotx: t.Context()}
|
||||
}
|
||||
res, ok, err := req.parseMapParam("map")
|
||||
require.Nil(err)
|
||||
|
||||
Reference in New Issue
Block a user