mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-04-13 11:57:33 -04:00
groupware: refactor contactcard changes, and Request framework
* implement ContactCard retrieval endpoint for syncing * re-implement that endpoint for Email too * fix the Mailbox changes endpoint to actually return changes about Mailboxes, and not about Emails * when querying the diff of Mailboxes without any prior state, return an error since the result is not what one would expect * introduce the 'changes' API tag and group * refactor the successful response functions to consistently return an object type and object state whenever possible * move the syncing endpoints under /accounts/*/changes/ for better clarity, e.g. /changes/emails instead of /emails/mailbox/*/changes
This commit is contained in:
@@ -63,6 +63,103 @@ func (j *Client) GetContactCardsById(accountId string, session *Session, ctx con
|
||||
})
|
||||
}
|
||||
|
||||
func (j *Client) GetContactCards(accountId string, session *Session, ctx context.Context, logger *log.Logger,
|
||||
acceptLanguage string, contactIds []string) ([]jscontact.ContactCard, SessionState, State, Language, Error) {
|
||||
logger = j.logger("GetContactCards", session, logger)
|
||||
|
||||
cmd, err := j.request(session, logger, invocation(CommandContactCardGet, ContactCardGetCommand{
|
||||
Ids: contactIds,
|
||||
AccountId: accountId,
|
||||
}, "0"))
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) ([]jscontact.ContactCard, State, Error) {
|
||||
var response ContactCardGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandContactCardGet, "0", &response)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
return response.List, response.State, nil
|
||||
})
|
||||
}
|
||||
|
||||
type ContactCardChanges struct {
|
||||
OldState State `json:"oldState,omitempty"`
|
||||
NewState State `json:"newState"`
|
||||
HasMoreChanges bool `json:"hasMoreChanges"`
|
||||
Created []jscontact.ContactCard `json:"created,omitempty"`
|
||||
Updated []jscontact.ContactCard `json:"updated,omitempty"`
|
||||
Destroyed []string `json:"destroyed,omitempty"`
|
||||
}
|
||||
|
||||
func (j *Client) GetContactCardsSince(accountId string, session *Session, ctx context.Context, logger *log.Logger,
|
||||
acceptLanguage string, sinceState string, maxChanges uint) (ContactCardChanges, SessionState, State, Language, Error) {
|
||||
logger = j.logger("GetContactCards", session, logger)
|
||||
|
||||
maxChangesPtr := &maxChanges
|
||||
if maxChanges < 1 {
|
||||
maxChangesPtr = nil
|
||||
}
|
||||
|
||||
cmd, err := j.request(session, logger,
|
||||
invocation(CommandContactCardChanges, ContactCardChangesCommand{
|
||||
AccountId: accountId,
|
||||
SinceState: sinceState,
|
||||
MaxChanges: maxChangesPtr,
|
||||
}, "0"),
|
||||
invocation(CommandContactCardGet, ContactCardGetRefCommand{
|
||||
AccountId: accountId,
|
||||
IdsRef: &ResultReference{
|
||||
ResultOf: "0",
|
||||
Name: CommandContactCardChanges,
|
||||
Path: "/created",
|
||||
},
|
||||
}, "1"),
|
||||
invocation(CommandContactCardGet, ContactCardGetRefCommand{
|
||||
AccountId: accountId,
|
||||
IdsRef: &ResultReference{
|
||||
ResultOf: "0",
|
||||
Name: CommandContactCardChanges,
|
||||
Path: "/updated",
|
||||
},
|
||||
}, "2"),
|
||||
)
|
||||
if err != nil {
|
||||
return ContactCardChanges{}, "", "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (ContactCardChanges, State, Error) {
|
||||
result := ContactCardChanges{}
|
||||
var changes ContactCardChangesResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandContactCardChanges, "0", &changes)
|
||||
if err != nil {
|
||||
return ContactCardChanges{}, "", err
|
||||
}
|
||||
result.NewState = changes.NewState
|
||||
result.OldState = changes.OldState
|
||||
result.HasMoreChanges = changes.HasMoreChanges
|
||||
result.Destroyed = changes.Destroyed
|
||||
|
||||
var created ContactCardGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandContactCardGet, "1", &created)
|
||||
if err != nil {
|
||||
return ContactCardChanges{}, "", err
|
||||
}
|
||||
result.Created = created.List
|
||||
|
||||
var updated ContactCardGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandContactCardGet, "2", &updated)
|
||||
if err != nil {
|
||||
return ContactCardChanges{}, "", err
|
||||
}
|
||||
result.Updated = updated.List
|
||||
|
||||
return result, changes.NewState, nil
|
||||
})
|
||||
}
|
||||
|
||||
func (j *Client) QueryContactCards(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string,
|
||||
filter ContactCardFilterElement, sortBy []ContactCardComparator,
|
||||
position uint, limit uint) (map[string][]jscontact.ContactCard, SessionState, State, Language, Error) {
|
||||
|
||||
@@ -194,38 +194,18 @@ func (j *Client) GetAllEmailsInMailbox(accountId string, session *Session, ctx c
|
||||
})
|
||||
}
|
||||
|
||||
func (j *Client) GetEmailChanges(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, sinceState State, maxChanges uint) (EmailChangesResponse, SessionState, State, Language, Error) {
|
||||
logger = j.loggerParams("GetEmailChanges", session, logger, func(z zerolog.Context) zerolog.Context {
|
||||
return z.Str(logSinceState, string(sinceState))
|
||||
})
|
||||
|
||||
changes := EmailChangesCommand{
|
||||
AccountId: accountId,
|
||||
SinceState: sinceState,
|
||||
}
|
||||
if maxChanges > 0 {
|
||||
changes.MaxChanges = maxChanges
|
||||
}
|
||||
|
||||
cmd, err := j.request(session, logger, invocation(CommandEmailChanges, changes, "0"))
|
||||
if err != nil {
|
||||
return EmailChangesResponse{}, "", "", "", simpleError(err, JmapErrorInvalidJmapRequestPayload)
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (EmailChangesResponse, State, Error) {
|
||||
var changesResponse EmailChangesResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailChanges, "0", &changesResponse)
|
||||
if err != nil {
|
||||
return EmailChangesResponse{}, "", err
|
||||
}
|
||||
|
||||
return changesResponse, changesResponse.NewState, nil
|
||||
})
|
||||
type EmailChanges struct {
|
||||
HasMoreChanges bool `json:"hasMoreChanges"`
|
||||
OldState State `json:"oldState,omitempty"`
|
||||
NewState State `json:"newState"`
|
||||
Created []Email `json:"created,omitempty"`
|
||||
Updated []Email `json:"updated,omitempty"`
|
||||
Destroyed []string `json:"destroyed,omitempty"`
|
||||
}
|
||||
|
||||
// Get all the Emails that have been created, updated or deleted since a given state.
|
||||
func (j *Client) GetEmailsSince(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, sinceState State, fetchBodies bool, maxBodyValueBytes uint, maxChanges uint) (MailboxChanges, SessionState, State, Language, Error) {
|
||||
logger = j.loggerParams("GetEmailsSince", session, logger, func(z zerolog.Context) zerolog.Context {
|
||||
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) {
|
||||
logger = j.loggerParams("GetEmailChanges", session, logger, func(z zerolog.Context) zerolog.Context {
|
||||
return z.Bool(logFetchBodies, fetchBodies).Str(logSinceState, string(sinceState))
|
||||
})
|
||||
|
||||
@@ -234,7 +214,7 @@ func (j *Client) GetEmailsSince(accountId string, session *Session, ctx context.
|
||||
SinceState: sinceState,
|
||||
}
|
||||
if maxChanges > 0 {
|
||||
changes.MaxChanges = maxChanges
|
||||
changes.MaxChanges = &maxChanges
|
||||
}
|
||||
|
||||
getCreated := EmailGetRefCommand{
|
||||
@@ -260,33 +240,34 @@ func (j *Client) GetEmailsSince(accountId string, session *Session, ctx context.
|
||||
invocation(CommandEmailGet, getUpdated, "2"),
|
||||
)
|
||||
if err != nil {
|
||||
return MailboxChanges{}, "", "", "", simpleError(err, JmapErrorInvalidJmapRequestPayload)
|
||||
return EmailChanges{}, "", "", "", simpleError(err, JmapErrorInvalidJmapRequestPayload)
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (MailboxChanges, State, Error) {
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (EmailChanges, State, Error) {
|
||||
var changesResponse EmailChangesResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailChanges, "0", &changesResponse)
|
||||
if err != nil {
|
||||
return MailboxChanges{}, "", err
|
||||
return EmailChanges{}, "", err
|
||||
}
|
||||
|
||||
var createdResponse EmailGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailGet, "1", &createdResponse)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Send()
|
||||
return MailboxChanges{}, "", err
|
||||
return EmailChanges{}, "", err
|
||||
}
|
||||
|
||||
var updatedResponse EmailGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailGet, "2", &updatedResponse)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Send()
|
||||
return MailboxChanges{}, "", err
|
||||
return EmailChanges{}, "", err
|
||||
}
|
||||
|
||||
return MailboxChanges{
|
||||
return EmailChanges{
|
||||
Destroyed: changesResponse.Destroyed,
|
||||
HasMoreChanges: changesResponse.HasMoreChanges,
|
||||
OldState: changesResponse.OldState,
|
||||
NewState: changesResponse.NewState,
|
||||
Created: createdResponse.List,
|
||||
Updated: updatedResponse.List,
|
||||
|
||||
@@ -155,48 +155,41 @@ func (j *Client) SearchMailboxIdsPerRole(accountIds []string, session *Session,
|
||||
}
|
||||
|
||||
type MailboxChanges struct {
|
||||
Destroyed []string `json:"destroyed,omitzero"`
|
||||
HasMoreChanges bool `json:"hasMoreChanges,omitzero"`
|
||||
NewState State `json:"newState"`
|
||||
Created []Email `json:"created,omitempty"`
|
||||
Updated []Email `json:"updated,omitempty"`
|
||||
HasMoreChanges bool `json:"hasMoreChanges"`
|
||||
OldState State `json:"oldState,omitempty"`
|
||||
NewState State `json:"newState"`
|
||||
Created []Mailbox `json:"created,omitempty"`
|
||||
Updated []Mailbox `json:"updated,omitempty"`
|
||||
Destroyed []string `json:"destroyed,omitempty"`
|
||||
}
|
||||
|
||||
// Retrieve Email changes in a given Mailbox since a given state.
|
||||
func (j *Client) GetMailboxChanges(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, mailboxId string, sinceState string, fetchBodies bool, maxBodyValueBytes uint, maxChanges uint) (MailboxChanges, SessionState, State, Language, Error) {
|
||||
logger = j.loggerParams("GetMailboxChanges", session, logger, func(z zerolog.Context) zerolog.Context {
|
||||
return z.Bool(logFetchBodies, fetchBodies).Str(logSinceState, sinceState)
|
||||
})
|
||||
// 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 string, maxChanges uint) (MailboxChanges, SessionState, State, Language, Error) {
|
||||
logger = j.logger("GetMailboxChanges", session, logger)
|
||||
|
||||
changes := MailboxChangesCommand{
|
||||
AccountId: accountId,
|
||||
SinceState: sinceState,
|
||||
MaxChanges: nil,
|
||||
}
|
||||
if maxChanges > 0 {
|
||||
changes.MaxChanges = maxChanges
|
||||
changes.MaxChanges = &maxChanges
|
||||
}
|
||||
|
||||
getCreated := EmailGetRefCommand{
|
||||
AccountId: accountId,
|
||||
FetchAllBodyValues: fetchBodies,
|
||||
IdsRef: &ResultReference{Name: CommandMailboxChanges, Path: "/created", ResultOf: "0"},
|
||||
getCreated := MailboxGetRefCommand{
|
||||
AccountId: accountId,
|
||||
IdsRef: &ResultReference{Name: CommandMailboxChanges, Path: "/created", ResultOf: "0"},
|
||||
}
|
||||
if maxBodyValueBytes > 0 {
|
||||
getCreated.MaxBodyValueBytes = maxBodyValueBytes
|
||||
}
|
||||
getUpdated := EmailGetRefCommand{
|
||||
AccountId: accountId,
|
||||
FetchAllBodyValues: fetchBodies,
|
||||
IdsRef: &ResultReference{Name: CommandMailboxChanges, Path: "/updated", ResultOf: "0"},
|
||||
}
|
||||
if maxBodyValueBytes > 0 {
|
||||
getUpdated.MaxBodyValueBytes = maxBodyValueBytes
|
||||
getUpdated := MailboxGetRefCommand{
|
||||
AccountId: accountId,
|
||||
IdsRef: &ResultReference{Name: CommandMailboxChanges, Path: "/updated", ResultOf: "0"},
|
||||
}
|
||||
|
||||
cmd, err := j.request(session, logger,
|
||||
invocation(CommandMailboxChanges, changes, "0"),
|
||||
invocation(CommandEmailGet, getCreated, "1"),
|
||||
invocation(CommandEmailGet, getUpdated, "2"),
|
||||
invocation(CommandMailboxGet, getCreated, "1"),
|
||||
invocation(CommandMailboxGet, getUpdated, "2"),
|
||||
)
|
||||
if err != nil {
|
||||
return MailboxChanges{}, "", "", "", err
|
||||
@@ -209,15 +202,15 @@ func (j *Client) GetMailboxChanges(accountId string, session *Session, ctx conte
|
||||
return MailboxChanges{}, "", err
|
||||
}
|
||||
|
||||
var createdResponse EmailGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailGet, "1", &createdResponse)
|
||||
var createdResponse MailboxGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandMailboxGet, "1", &createdResponse)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Send()
|
||||
return MailboxChanges{}, "", err
|
||||
}
|
||||
|
||||
var updatedResponse EmailGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailGet, "2", &updatedResponse)
|
||||
var updatedResponse MailboxGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandMailboxGet, "2", &updatedResponse)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Send()
|
||||
return MailboxChanges{}, "", err
|
||||
@@ -226,6 +219,7 @@ func (j *Client) GetMailboxChanges(accountId string, session *Session, ctx conte
|
||||
return MailboxChanges{
|
||||
Destroyed: mailboxResponse.Destroyed,
|
||||
HasMoreChanges: mailboxResponse.HasMoreChanges,
|
||||
OldState: mailboxResponse.OldState,
|
||||
NewState: mailboxResponse.NewState,
|
||||
Created: createdResponse.List,
|
||||
Updated: createdResponse.List,
|
||||
@@ -234,13 +228,13 @@ func (j *Client) GetMailboxChanges(accountId string, session *Session, ctx conte
|
||||
}
|
||||
|
||||
// Retrieve Email changes in Mailboxes of multiple Accounts.
|
||||
func (j *Client) GetMailboxChangesForMultipleAccounts(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, sinceStateMap map[string]string, fetchBodies bool, maxBodyValueBytes uint, maxChanges uint) (map[string]MailboxChanges, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetMailboxChangesForMultipleAccounts(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, sinceStateMap map[string]string, maxChanges uint) (map[string]MailboxChanges, SessionState, State, Language, Error) {
|
||||
logger = j.loggerParams("GetMailboxChangesForMultipleAccounts", session, logger, func(z zerolog.Context) zerolog.Context {
|
||||
sinceStateLogDict := zerolog.Dict()
|
||||
for k, v := range sinceStateMap {
|
||||
sinceStateLogDict.Str(log.SafeString(k), log.SafeString(v))
|
||||
}
|
||||
return z.Bool(logFetchBodies, fetchBodies).Dict(logSinceState, sinceStateLogDict)
|
||||
return z.Dict(logSinceState, sinceStateLogDict)
|
||||
})
|
||||
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
@@ -261,29 +255,21 @@ func (j *Client) GetMailboxChangesForMultipleAccounts(accountIds []string, sessi
|
||||
}
|
||||
|
||||
if maxChanges > 0 {
|
||||
changes.MaxChanges = maxChanges
|
||||
changes.MaxChanges = &maxChanges
|
||||
}
|
||||
|
||||
getCreated := EmailGetRefCommand{
|
||||
AccountId: accountId,
|
||||
FetchAllBodyValues: fetchBodies,
|
||||
IdsRef: &ResultReference{Name: CommandMailboxChanges, Path: "/created", ResultOf: mcid(accountId, "0")},
|
||||
getCreated := MailboxGetRefCommand{
|
||||
AccountId: accountId,
|
||||
IdsRef: &ResultReference{Name: CommandMailboxChanges, Path: "/created", ResultOf: mcid(accountId, "0")},
|
||||
}
|
||||
if maxBodyValueBytes > 0 {
|
||||
getCreated.MaxBodyValueBytes = maxBodyValueBytes
|
||||
}
|
||||
getUpdated := EmailGetRefCommand{
|
||||
AccountId: accountId,
|
||||
FetchAllBodyValues: fetchBodies,
|
||||
IdsRef: &ResultReference{Name: CommandMailboxChanges, Path: "/updated", ResultOf: mcid(accountId, "0")},
|
||||
}
|
||||
if maxBodyValueBytes > 0 {
|
||||
getUpdated.MaxBodyValueBytes = maxBodyValueBytes
|
||||
getUpdated := MailboxGetRefCommand{
|
||||
AccountId: accountId,
|
||||
IdsRef: &ResultReference{Name: CommandMailboxChanges, Path: "/updated", ResultOf: mcid(accountId, "0")},
|
||||
}
|
||||
|
||||
invocations[i*3+0] = invocation(CommandMailboxChanges, changes, mcid(accountId, "0"))
|
||||
invocations[i*3+1] = invocation(CommandEmailGet, getCreated, mcid(accountId, "1"))
|
||||
invocations[i*3+2] = invocation(CommandEmailGet, getUpdated, mcid(accountId, "2"))
|
||||
invocations[i*3+1] = invocation(CommandMailboxGet, getCreated, mcid(accountId, "1"))
|
||||
invocations[i*3+2] = invocation(CommandMailboxGet, getUpdated, mcid(accountId, "2"))
|
||||
}
|
||||
|
||||
cmd, err := j.request(session, logger, invocations...)
|
||||
@@ -301,14 +287,14 @@ func (j *Client) GetMailboxChangesForMultipleAccounts(accountIds []string, sessi
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
var createdResponse EmailGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailGet, mcid(accountId, "1"), &createdResponse)
|
||||
var createdResponse MailboxGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandMailboxGet, mcid(accountId, "1"), &createdResponse)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
var updatedResponse EmailGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailGet, mcid(accountId, "2"), &updatedResponse)
|
||||
var updatedResponse MailboxGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandMailboxGet, mcid(accountId, "2"), &updatedResponse)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
@@ -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, "", "", 0)
|
||||
changes, sessionState, state, _, err := s.client.GetEmailChanges(mailAccountId, session, s.ctx, s.logger, "", State(""), true, 0, 0)
|
||||
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, 0)
|
||||
changes, sessionState, state, _, err := s.client.GetEmailChanges(mailAccountId, session, s.ctx, s.logger, "", initialState, true, 0, 0)
|
||||
require.NoError(err)
|
||||
require.Equal(session.State, sessionState)
|
||||
require.Equal(initialState, state)
|
||||
@@ -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, 0)
|
||||
changes, sessionState, state, _, err := s.client.GetEmailChanges(mailAccountId, session, s.ctx, s.logger, "", initialState, true, 0, 0)
|
||||
require.NoError(err)
|
||||
require.Equal(session.State, sessionState)
|
||||
require.NotEqual(initialState, state)
|
||||
@@ -158,7 +158,7 @@ func TestWs(t *testing.T) {
|
||||
require.Empty(changes.Updated)
|
||||
lastState = state
|
||||
|
||||
emailIds = append(emailIds, changes.Created...)
|
||||
emailIds = append(emailIds, structs.Map(changes.Created, func(e Email) string { return e.Id })...)
|
||||
}
|
||||
|
||||
{
|
||||
@@ -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, 0)
|
||||
changes, sessionState, state, _, err := s.client.GetEmailChanges(mailAccountId, session, s.ctx, s.logger, "", lastState, true, 0, 0)
|
||||
require.NoError(err)
|
||||
require.Equal(session.State, sessionState)
|
||||
require.NotEqual(lastState, state)
|
||||
@@ -192,7 +192,7 @@ func TestWs(t *testing.T) {
|
||||
require.Empty(changes.Updated)
|
||||
lastState = state
|
||||
|
||||
emailIds = append(emailIds, changes.Created...)
|
||||
emailIds = append(emailIds, structs.Map(changes.Created, func(e Email) string { return e.Id })...)
|
||||
}
|
||||
|
||||
{
|
||||
@@ -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, 0)
|
||||
changes, sessionState, state, _, err := s.client.GetEmailChanges(mailAccountId, session, s.ctx, s.logger, "", lastState, true, 0, 0)
|
||||
require.NoError(err)
|
||||
require.Equal(session.State, sessionState)
|
||||
require.NotEqual(lastState, state)
|
||||
|
||||
@@ -842,8 +842,12 @@ type SessionState string
|
||||
|
||||
type State string
|
||||
|
||||
const EmptyState = State("")
|
||||
|
||||
type Language string
|
||||
|
||||
const NoLanguage = Language("")
|
||||
|
||||
type SessionResponse struct {
|
||||
Capabilities SessionCapabilities `json:"capabilities"`
|
||||
|
||||
@@ -1350,7 +1354,7 @@ type MailboxChangesCommand struct {
|
||||
// If supplied by the client, the value MUST be a positive integer greater than 0.
|
||||
//
|
||||
// If a value outside of this range is given, the server MUST reject the call with an invalidArguments error.
|
||||
MaxChanges uint `json:"maxChanges,omitzero"`
|
||||
MaxChanges *uint `json:"maxChanges,omitzero"`
|
||||
}
|
||||
|
||||
type MailboxFilterElement interface {
|
||||
@@ -1859,7 +1863,7 @@ type EmailChangesCommand struct {
|
||||
// The server MAY choose to return fewer than this value but MUST NOT return more.
|
||||
// If not given by the client, the server may choose how many to return.
|
||||
// If supplied by the client, the value MUST be a positive integer greater than 0.
|
||||
MaxChanges uint `json:"maxChanges,omitzero"`
|
||||
MaxChanges *uint `json:"maxChanges,omitempty"`
|
||||
}
|
||||
|
||||
type EmailAddress struct {
|
||||
@@ -5307,6 +5311,47 @@ type ContactCardGetResponse struct {
|
||||
NotFound []any `json:"notFound"`
|
||||
}
|
||||
|
||||
type ContactCardChangesCommand struct {
|
||||
// The id of the account to use.
|
||||
AccountId string `json:"accountId"`
|
||||
|
||||
// The current state of the client.
|
||||
// This is the string that was returned as the "state" argument in the "ContactCard/get" response.
|
||||
// The server will return the changes that have occurred since this state.
|
||||
SinceState string `json:"sinceState,omitempty"`
|
||||
|
||||
// The maximum number of ids to return in the response.
|
||||
// The server MAY choose to return fewer than this value but MUST NOT return more.
|
||||
// If not given by the client, the server may choose how many to return.
|
||||
// If supplied by the client, the value MUST be a positive integer greater than 0.
|
||||
// If a value outside of this range is given, the server MUST reject the call with an `invalidArguments` error.
|
||||
MaxChanges *uint `json:"maxChanges,omitempty"`
|
||||
}
|
||||
|
||||
type ContactCardChangesResponse struct {
|
||||
// The id of the account used for the call.
|
||||
AccountId string `json:"accountId"`
|
||||
|
||||
// This is the "sinceState" argument echoed back; it's the state from which the server is returning changes.
|
||||
OldState State `json:"oldState"`
|
||||
|
||||
// This is the state the client will be in after applying the set of changes to the old state.
|
||||
NewState State `json:"newState"`
|
||||
|
||||
// If true, the client may call "ContactCard/changes" again with the "newState" returned to get further updates.
|
||||
// If false, "newState" is the current server state.
|
||||
HasMoreChanges bool `json:"hasMoreChanges"`
|
||||
|
||||
// An array of ids for records that have been created since the old state.
|
||||
Created []string `json:"created,omitempty"`
|
||||
|
||||
// An array of ids for records that have been updated since the old state.
|
||||
Updated []string `json:"updated,omitempty"`
|
||||
|
||||
// An array of ids for records that have been destroyed since the old state.
|
||||
Destroyed []string `json:"destroyed,omitempty"`
|
||||
}
|
||||
|
||||
type ContactCardUpdate map[string]any
|
||||
|
||||
type ContactCardSetCommand struct {
|
||||
@@ -5884,6 +5929,7 @@ const (
|
||||
CommandAddressBookGet Command = "AddressBook/get"
|
||||
CommandContactCardQuery Command = "ContactCard/query"
|
||||
CommandContactCardGet Command = "ContactCard/get"
|
||||
CommandContactCardChanges Command = "ContactCard/changes"
|
||||
CommandContactCardSet Command = "ContactCard/set"
|
||||
CommandCalendarEventParse Command = "CalendarEvent/parse"
|
||||
CommandCalendarGet Command = "Calendar/get"
|
||||
@@ -5916,6 +5962,7 @@ var CommandResponseTypeMap = map[Command]func() any{
|
||||
CommandAddressBookGet: func() any { return AddressBookGetResponse{} },
|
||||
CommandContactCardQuery: func() any { return ContactCardQueryResponse{} },
|
||||
CommandContactCardGet: func() any { return ContactCardGetResponse{} },
|
||||
CommandContactCardChanges: func() any { return ContactCardChangesResponse{} },
|
||||
CommandContactCardSet: func() any { return ContactCardSetResponse{} },
|
||||
CommandCalendarEventParse: func() any { return CalendarEventParseResponse{} },
|
||||
CommandCalendarGet: func() any { return CalendarGetResponse{} },
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/jscontact"
|
||||
c "github.com/opencloud-eu/opencloud/pkg/jscontact"
|
||||
)
|
||||
|
||||
@@ -697,9 +698,10 @@ func (e Exemplar) Mailboxes() []Mailbox {
|
||||
}
|
||||
|
||||
func (e Exemplar) MailboxChanges() MailboxChanges {
|
||||
a, _, _ := e.MailboxInbox()
|
||||
return MailboxChanges{
|
||||
NewState: "aesh2ahj",
|
||||
Created: []Email{e.Email()},
|
||||
Created: []Mailbox{a},
|
||||
Destroyed: []string{"baingow4"},
|
||||
}
|
||||
}
|
||||
@@ -1783,3 +1785,35 @@ func (e Exemplar) ContactCard() c.ContactCard {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (e Exemplar) ContactCardChanges() (ContactCardChanges, string, string) {
|
||||
c := e.ContactCard()
|
||||
return ContactCardChanges{
|
||||
OldState: "xai3iiraipoo",
|
||||
NewState: "ni7thah7eeY4",
|
||||
HasMoreChanges: true,
|
||||
Created: []jscontact.ContactCard{c},
|
||||
Destroyed: []string{"eaae", "bcba"},
|
||||
}, "A created ContactCard and two deleted ones", "created"
|
||||
}
|
||||
|
||||
func (e Exemplar) OtherContactCardChanges() (ContactCardChanges, string, string) {
|
||||
c := e.ContactCard()
|
||||
return ContactCardChanges{
|
||||
OldState: "xai3iiraipoo",
|
||||
NewState: "ni7thah7eeY4",
|
||||
HasMoreChanges: false,
|
||||
Updated: []jscontact.ContactCard{c},
|
||||
}, "An updated ContactCard", "updated"
|
||||
}
|
||||
|
||||
func (e Exemplar) EmailChanges() EmailChanges {
|
||||
emails := []Email{e.Email()}
|
||||
return EmailChanges{
|
||||
OldState: "xai3iiraipoo",
|
||||
NewState: "ni7thah7eeY4",
|
||||
HasMoreChanges: true,
|
||||
Created: emails,
|
||||
Destroyed: []string{"mmnan", "moxzz"},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,9 @@ tags:
|
||||
- name: vacation
|
||||
x-displayName: Vacation Responses
|
||||
description: APIs about vacation responses
|
||||
- name: changes
|
||||
x-displayName: Changes
|
||||
description: APIs for retrieving changes to objects
|
||||
x-tagGroups:
|
||||
- name: Bootstrapping
|
||||
tags:
|
||||
@@ -86,6 +89,9 @@ x-tagGroups:
|
||||
- name: Quotas
|
||||
tags:
|
||||
- quota
|
||||
- name: changes
|
||||
tags:
|
||||
- changes
|
||||
- name: Uncategorized
|
||||
tags:
|
||||
- untagged
|
||||
|
||||
@@ -14,10 +14,10 @@ func (g *Groupware) GetAccount(w http.ResponseWriter, r *http.Request) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
accountId, account, err := req.GetAccountForMail()
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
var body jmap.Account = account
|
||||
return etagResponse(single(accountId), body, req.session.State, AccountResponseObjectType, jmap.State(req.session.State), "")
|
||||
return req.respond(accountId, body, req.session.State, AccountResponseObjectType, "")
|
||||
})
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ func (g *Groupware) GetAccounts(w http.ResponseWriter, r *http.Request) {
|
||||
// sort on accountId to have a stable order that remains the same with every query
|
||||
slices.SortFunc(list, func(a, b AccountWithId) int { return strings.Compare(a.AccountId, b.AccountId) })
|
||||
var RBODY []AccountWithId = list
|
||||
return etagResponse(structs.Map(list, func(a AccountWithId) string { return a.AccountId }), RBODY, req.session.State, AccountResponseObjectType, jmap.State(req.session.State), "")
|
||||
return req.respondN(structs.Map(list, func(a AccountWithId) string { return a.AccountId }), RBODY, req.session.State, AccountResponseObjectType, "")
|
||||
})
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ func (g *Groupware) GetAccountsWithTheirIdentities(w http.ResponseWriter, r *htt
|
||||
allAccountIds := req.AllAccountIds()
|
||||
resp, sessionState, state, lang, err := g.jmap.GetIdentitiesForAllAccounts(allAccountIds, req.session, req.ctx, req.logger, req.language())
|
||||
if err != nil {
|
||||
return req.errorResponseFromJmap(allAccountIds, err)
|
||||
return req.jmapErrorN(allAccountIds, err, sessionState, lang)
|
||||
}
|
||||
list := make([]AccountWithIdAndIdentities, len(req.session.Accounts))
|
||||
i := 0
|
||||
@@ -66,7 +66,7 @@ func (g *Groupware) GetAccountsWithTheirIdentities(w http.ResponseWriter, r *htt
|
||||
// sort on accountId to have a stable order that remains the same with every query
|
||||
slices.SortFunc(list, func(a, b AccountWithIdAndIdentities) int { return strings.Compare(a.AccountId, b.AccountId) })
|
||||
var RBODY []AccountWithIdAndIdentities = list
|
||||
return etagResponse(structs.Map(list, func(a AccountWithIdAndIdentities) string { return a.AccountId }), RBODY, sessionState, AccountResponseObjectType, state, lang)
|
||||
return req.respondN(structs.Map(list, func(a AccountWithIdAndIdentities) string { return a.AccountId }), RBODY, sessionState, AccountResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -16,13 +16,13 @@ func (g *Groupware) GetBlobMeta(w http.ResponseWriter, r *http.Request) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
accountId, err := req.GetAccountIdForBlob()
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
l := req.logger.With().Str(logAccountId, accountId)
|
||||
|
||||
blobId, err := req.PathParam(UriParamBlobId)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
l = l.Str(UriParamBlobId, blobId)
|
||||
|
||||
@@ -30,12 +30,12 @@ func (g *Groupware) GetBlobMeta(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
res, sessionState, state, lang, jerr := g.jmap.GetBlobMetadata(accountId, req.session, req.ctx, logger, req.language(), blobId)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
if res == nil {
|
||||
return notFoundResponse(single(accountId), sessionState)
|
||||
return req.notFound(accountId, sessionState, BlobResponseObjectType, state)
|
||||
}
|
||||
return etagResponse(single(accountId), res, sessionState, BlobResponseObjectType, state, lang)
|
||||
return req.respond(accountId, res, sessionState, BlobResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -54,16 +54,16 @@ func (g *Groupware) UploadBlob(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
accountId, err := req.GetAccountIdForBlob()
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
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)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, req.session.State, lang)
|
||||
}
|
||||
|
||||
return response(single(accountId), resp, req.session.State, lang)
|
||||
return req.respondWithoutStatus(accountId, resp)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -18,10 +18,10 @@ func (g *Groupware) GetCalendars(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
calendars, sessionState, state, lang, jerr := g.jmap.GetCalendars(accountId, req.session, req.ctx, req.logger, req.language(), nil)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
return etagResponse(single(accountId), calendars, sessionState, CalendarResponseObjectType, state, lang)
|
||||
return req.respond(accountId, calendars, sessionState, CalendarResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -37,20 +37,20 @@ func (g *Groupware) GetCalendarById(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
calendarId, err := req.PathParam(UriParamCalendarId)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
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})
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
if len(calendars.NotFound) > 0 {
|
||||
return notFoundResponse(single(accountId), sessionState)
|
||||
return req.notFound(accountId, sessionState, CalendarResponseObjectType, state)
|
||||
} else {
|
||||
return etagResponse(single(accountId), calendars.Calendars[0], sessionState, CalendarResponseObjectType, state, lang)
|
||||
return req.respond(accountId, calendars.Calendars[0], sessionState, CalendarResponseObjectType, state)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -67,13 +67,13 @@ func (g *Groupware) GetEventsInCalendar(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
calendarId, err := req.PathParam(UriParamCalendarId)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
l = l.Str(UriParamCalendarId, log.SafeString(calendarId))
|
||||
|
||||
offset, ok, err := req.parseUIntParam(QueryParamOffset, 0)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
if ok {
|
||||
l = l.Uint(QueryParamOffset, offset)
|
||||
@@ -81,7 +81,7 @@ func (g *Groupware) GetEventsInCalendar(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
limit, ok, err := req.parseUIntParam(QueryParamLimit, g.defaults.contactLimit)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
if ok {
|
||||
l = l.Uint(QueryParamLimit, limit)
|
||||
@@ -95,13 +95,13 @@ func (g *Groupware) GetEventsInCalendar(w http.ResponseWriter, r *http.Request)
|
||||
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)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
if events, ok := eventsByAccountId[accountId]; ok {
|
||||
return etagResponse(single(accountId), events, sessionState, EventResponseObjectType, state, lang)
|
||||
return req.respond(accountId, events, sessionState, EventResponseObjectType, state)
|
||||
} else {
|
||||
return notFoundResponse(single(accountId), sessionState)
|
||||
return req.notFound(accountId, sessionState, EventResponseObjectType, state)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -118,15 +118,15 @@ func (g *Groupware) CreateCalendarEvent(w http.ResponseWriter, r *http.Request)
|
||||
var create jmap.CalendarEvent
|
||||
err := req.body(&create)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
|
||||
logger := log.From(l)
|
||||
created, sessionState, state, lang, jerr := g.jmap.CreateCalendarEvent(accountId, req.session, req.ctx, logger, req.language(), create)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
return etagResponse(single(accountId), created, sessionState, EventResponseObjectType, state, lang)
|
||||
return req.respond(accountId, created, sessionState, EventResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -140,33 +140,33 @@ func (g *Groupware) DeleteCalendarEvent(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
eventId, err := req.PathParam(UriParamEventId)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
l.Str(UriParamEventId, log.SafeString(eventId))
|
||||
|
||||
logger := log.From(l)
|
||||
|
||||
deleted, sessionState, state, _, jerr := g.jmap.DeleteCalendarEvent(accountId, []string{eventId}, req.session, req.ctx, logger, req.language())
|
||||
deleted, sessionState, state, lang, jerr := g.jmap.DeleteCalendarEvent(accountId, []string{eventId}, req.session, req.ctx, logger, req.language())
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
for _, e := range deleted {
|
||||
desc := e.Description
|
||||
if desc != "" {
|
||||
return errorResponseWithSessionState(single(accountId), apiError(
|
||||
return req.errorS(accountId, apiError(
|
||||
req.errorId(),
|
||||
ErrorFailedToDeleteContact,
|
||||
withDetail(e.Description),
|
||||
), sessionState)
|
||||
} else {
|
||||
return errorResponseWithSessionState(single(accountId), apiError(
|
||||
return req.errorS(accountId, apiError(
|
||||
req.errorId(),
|
||||
ErrorFailedToDeleteContact,
|
||||
), sessionState)
|
||||
}
|
||||
}
|
||||
return noContentResponseWithEtag(single(accountId), sessionState, EventResponseObjectType, state)
|
||||
return req.noContent(accountId, sessionState, EventResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -174,12 +174,12 @@ func (g *Groupware) ParseIcalBlob(w http.ResponseWriter, r *http.Request) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
accountId, err := req.GetAccountIdForBlob()
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
|
||||
blobId, err := req.PathParam(UriParamBlobId)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
|
||||
blobIds := strings.Split(blobId, ",")
|
||||
@@ -188,8 +188,8 @@ func (g *Groupware) ParseIcalBlob(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
resp, sessionState, state, lang, jerr := g.jmap.ParseICalendarBlob(accountId, req.session, req.ctx, logger, req.language(), blobIds)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
return etagResponse(single(accountId), resp, sessionState, EventResponseObjectType, state, lang)
|
||||
return req.respond(accountId, resp, sessionState, EventResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -51,11 +51,11 @@ func (g *Groupware) GetAddressbooks(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
addressbooks, sessionState, state, lang, jerr := g.jmap.GetAddressbooks(accountId, req.session, req.ctx, req.logger, req.language(), nil)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
var body jmap.AddressBooksResponse = addressbooks
|
||||
return etagResponse(single(accountId), body, sessionState, AddressBookResponseObjectType, state, lang)
|
||||
return req.respond(accountId, body, sessionState, AddressBookResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -71,20 +71,20 @@ func (g *Groupware) GetAddressbook(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
addressBookId, err := req.PathParam(UriParamAddressBookId)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
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})
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
if len(addressbooks.NotFound) > 0 {
|
||||
return notFoundResponse(single(accountId), sessionState)
|
||||
return req.notFound(accountId, sessionState, AddressBookResponseObjectType, state)
|
||||
} else {
|
||||
return etagResponse(single(accountId), addressbooks.AddressBooks[0], sessionState, AddressBookResponseObjectType, state, lang)
|
||||
return req.respond(accountId, addressbooks.AddressBooks[0], sessionState, AddressBookResponseObjectType, state)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -102,13 +102,13 @@ func (g *Groupware) GetContactsInAddressbook(w http.ResponseWriter, r *http.Requ
|
||||
|
||||
addressBookId, err := req.PathParam(UriParamAddressBookId)
|
||||
if err != nil {
|
||||
return errorResponseWithSessionState(accountIds, err, req.session.State)
|
||||
return req.errorN(accountIds, err)
|
||||
}
|
||||
l = l.Str(UriParamAddressBookId, log.SafeString(addressBookId))
|
||||
|
||||
offset, ok, err := req.parseUIntParam(QueryParamOffset, 0)
|
||||
if err != nil {
|
||||
return errorResponseWithSessionState(accountIds, err, req.session.State)
|
||||
return req.errorN(accountIds, err)
|
||||
}
|
||||
if ok {
|
||||
l = l.Uint(QueryParamOffset, offset)
|
||||
@@ -116,7 +116,7 @@ func (g *Groupware) GetContactsInAddressbook(w http.ResponseWriter, r *http.Requ
|
||||
|
||||
limit, ok, err := req.parseUIntParam(QueryParamLimit, g.defaults.contactLimit)
|
||||
if err != nil {
|
||||
return errorResponseWithSessionState(accountIds, err, req.session.State)
|
||||
return req.errorN(accountIds, err)
|
||||
}
|
||||
if ok {
|
||||
l = l.Uint(QueryParamLimit, limit)
|
||||
@@ -135,13 +135,13 @@ 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)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(accountIds, jerr)
|
||||
return req.jmapErrorN(accountIds, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
if contacts, ok := contactsByAccountId[accountId]; ok {
|
||||
return etagResponse(accountIds, contacts, sessionState, ContactResponseObjectType, state, lang)
|
||||
return req.respondN(accountIds, contacts, sessionState, ContactResponseObjectType, state)
|
||||
} else {
|
||||
return etagNotFoundResponse(accountIds, sessionState, ContactResponseObjectType, state, lang)
|
||||
return req.notFoundN(accountIds, sessionState, ContactResponseObjectType, state)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -157,24 +157,80 @@ func (g *Groupware) GetContactById(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
contactId, err := req.PathParam(UriParamContactId)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
l = l.Str(UriParamContactId, log.SafeString(contactId))
|
||||
|
||||
logger := log.From(l)
|
||||
contactsById, sessionState, state, lang, jerr := g.jmap.GetContactCardsById(accountId, req.session, req.ctx, logger, req.language(), []string{contactId})
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
if contact, ok := contactsById[contactId]; ok {
|
||||
return etagResponse(single(accountId), contact, sessionState, ContactResponseObjectType, state, lang)
|
||||
return req.respond(accountId, contact, sessionState, ContactResponseObjectType, state)
|
||||
} else {
|
||||
return etagNotFoundResponse(single(accountId), sessionState, ContactResponseObjectType, state, lang)
|
||||
return req.notFound(accountId, sessionState, ContactResponseObjectType, state)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (g *Groupware) GetAllContacts(w http.ResponseWriter, r *http.Request) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
ok, accountId, resp := req.needContactWithAccount()
|
||||
if !ok {
|
||||
return resp
|
||||
}
|
||||
|
||||
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{})
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
var body []jscontact.ContactCard = contacts
|
||||
|
||||
return req.respond(accountId, body, sessionState, ContactResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
// Get changes to Contacts since a given State
|
||||
// @api:tags contact,changes
|
||||
func (g *Groupware) GetContactsChanges(w http.ResponseWriter, r *http.Request) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
ok, accountId, resp := req.needContactWithAccount()
|
||||
if !ok {
|
||||
return resp
|
||||
}
|
||||
|
||||
l := req.logger.With()
|
||||
|
||||
var maxChanges uint = 0
|
||||
if v, ok, err := req.parseUIntParam(QueryParamMaxChanges, 0); err != nil {
|
||||
return req.error(accountId, err)
|
||||
} else if ok {
|
||||
maxChanges = v
|
||||
l = l.Uint(QueryParamMaxChanges, v)
|
||||
}
|
||||
|
||||
sinceState, err := req.HeaderParamDoc(HeaderParamSince, "Specifies the state identifier from which on to list mailbox changes")
|
||||
if err != nil {
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
l = l.Str(HeaderParamSince, log.SafeString(sinceState))
|
||||
|
||||
logger := log.From(l)
|
||||
changes, sessionState, state, lang, jerr := g.jmap.GetContactCardsSince(accountId, req.session, req.ctx, logger, req.language(), sinceState, maxChanges)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
var body jmap.ContactCardChanges = changes
|
||||
|
||||
return req.respond(accountId, body, sessionState, ContactResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
func (g *Groupware) CreateContact(w http.ResponseWriter, r *http.Request) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
ok, accountId, resp := req.needContactWithAccount()
|
||||
@@ -186,22 +242,22 @@ func (g *Groupware) CreateContact(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
addressBookId, err := req.PathParam(UriParamAddressBookId)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
l = l.Str(UriParamAddressBookId, log.SafeString(addressBookId))
|
||||
|
||||
var create jscontact.ContactCard
|
||||
err = req.bodydoc(&create, "The contact to create, which may not have its id attribute set")
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
|
||||
logger := log.From(l)
|
||||
created, sessionState, state, lang, jerr := g.jmap.CreateContactCard(accountId, req.session, req.ctx, logger, req.language(), create)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
return etagResponse(single(accountId), created, sessionState, ContactResponseObjectType, state, lang)
|
||||
return req.respond(accountId, created, sessionState, ContactResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -215,33 +271,33 @@ func (g *Groupware) DeleteContact(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
contactId, err := req.PathParam(UriParamContactId)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
l.Str(UriParamContactId, log.SafeString(contactId))
|
||||
|
||||
logger := log.From(l)
|
||||
|
||||
deleted, sessionState, state, _, jerr := g.jmap.DeleteContactCard(accountId, []string{contactId}, req.session, req.ctx, logger, req.language())
|
||||
deleted, sessionState, state, lang, jerr := g.jmap.DeleteContactCard(accountId, []string{contactId}, req.session, req.ctx, logger, req.language())
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
for _, e := range deleted {
|
||||
desc := e.Description
|
||||
if desc != "" {
|
||||
return errorResponseWithSessionState(single(accountId), apiError(
|
||||
return req.error(accountId, apiError(
|
||||
req.errorId(),
|
||||
ErrorFailedToDeleteContact,
|
||||
withDetail(e.Description),
|
||||
), sessionState)
|
||||
))
|
||||
} else {
|
||||
return errorResponseWithSessionState(single(accountId), apiError(
|
||||
return req.error(accountId, apiError(
|
||||
req.errorId(),
|
||||
ErrorFailedToDeleteContact,
|
||||
), sessionState)
|
||||
))
|
||||
}
|
||||
}
|
||||
return noContentResponseWithEtag(single(accountId), sessionState, ContactResponseObjectType, state)
|
||||
return req.noContent(accountId, sessionState, ContactResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -21,44 +21,41 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/services/groupware/pkg/metrics"
|
||||
)
|
||||
|
||||
// Get all the emails in a mailbox since a given state.
|
||||
//
|
||||
// Retrieve the list of all the emails that are in a given mailbox since a given state.
|
||||
//
|
||||
// The mailbox must be specified by its id, as part of the request URL path.
|
||||
//
|
||||
// A limit and an offset may be specified using the query parameters 'limit' and 'offset',
|
||||
// respectively.
|
||||
func (g *Groupware) GetAllEmailsInMailboxSince(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
maxChanges := uint(0)
|
||||
// Get the changes that occured in a given mailbox since a certain state.
|
||||
// @api:tags mailbox,changes
|
||||
func (g *Groupware) GetEmailChanges(w http.ResponseWriter, r *http.Request) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
l := req.logger.With()
|
||||
|
||||
accountId, err := req.GetAccountIdForMail()
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
l = l.Str(logAccountId, accountId)
|
||||
|
||||
mailboxId, err := req.PathParam(UriParamMailboxId)
|
||||
maxChanges, ok, err := req.parseUIntParam(QueryParamMaxChanges, 0)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
if ok {
|
||||
l = l.Uint(QueryParamMaxChanges, maxChanges)
|
||||
}
|
||||
|
||||
since, err := req.PathParamDoc(UriParamSince, "State identifier that indicates the coordinate from whence on to list mailbox changes")
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
sinceState := jmap.EmptyState
|
||||
if s := req.OptHeaderParamDoc(HeaderParamSince, "Optionally specifies the state identifier from which on to list email changes"); s != "" {
|
||||
l = l.Str(HeaderParamSince, log.SafeString(s))
|
||||
sinceState = jmap.State(s)
|
||||
}
|
||||
|
||||
logger := log.From(req.logger.With().Str(HeaderParamSince, log.SafeString(since)).Str(logAccountId, log.SafeString(accountId)))
|
||||
logger := log.From(l)
|
||||
|
||||
changes, sessionState, state, lang, jerr := g.jmap.GetMailboxChanges(accountId, req.session, req.ctx, logger, req.language(), mailboxId, since, true, g.config.maxBodyValueBytes, maxChanges)
|
||||
changes, sessionState, state, lang, jerr := g.jmap.GetEmailChanges(accountId, req.session, req.ctx, logger, req.language(), sinceState, true, g.config.maxBodyValueBytes, maxChanges)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
return etagResponse(single(accountId), changes, sessionState, EmailResponseObjectType, state, lang)
|
||||
return req.respond(accountId, changes, sessionState, MailboxResponseObjectType, state)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
// Get all the emails in a mailbox.
|
||||
@@ -75,18 +72,18 @@ func (g *Groupware) GetAllEmailsInMailbox(w http.ResponseWriter, r *http.Request
|
||||
|
||||
accountId, err := req.GetAccountIdForMail()
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
l = l.Str(logAccountId, accountId)
|
||||
|
||||
mailboxId, err := req.PathParam(UriParamMailboxId)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
|
||||
offset, ok, err := req.parseIntParam(QueryParamOffset, 0)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
if ok {
|
||||
l = l.Int(QueryParamOffset, offset)
|
||||
@@ -94,7 +91,7 @@ func (g *Groupware) GetAllEmailsInMailbox(w http.ResponseWriter, r *http.Request
|
||||
|
||||
limit, ok, err := req.parseUIntParam(QueryParamLimit, g.defaults.emailLimit)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
if ok {
|
||||
l = l.Uint(QueryParamLimit, limit)
|
||||
@@ -108,12 +105,12 @@ func (g *Groupware) GetAllEmailsInMailbox(w http.ResponseWriter, r *http.Request
|
||||
|
||||
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)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
sanitized, err := req.sanitizeEmails(emails.Emails)
|
||||
if err != nil {
|
||||
return errorResponseWithSessionState(single(accountId), err, sessionState)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
|
||||
safe := jmap.Emails{
|
||||
@@ -123,7 +120,7 @@ func (g *Groupware) GetAllEmailsInMailbox(w http.ResponseWriter, r *http.Request
|
||||
Offset: emails.Offset,
|
||||
}
|
||||
|
||||
return etagResponse(single(accountId), safe, sessionState, EmailResponseObjectType, state, lang)
|
||||
return req.respond(accountId, safe, sessionState, EmailResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -175,13 +172,13 @@ func (g *Groupware) GetEmailsById(w http.ResponseWriter, r *http.Request) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
accountId, err := req.GetAccountIdForMail()
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
l := req.logger.With().Str(logAccountId, log.SafeString(accountId))
|
||||
|
||||
id, err := req.PathParam(UriParamEmailId)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
ids := strings.Split(id, ",")
|
||||
if len(ids) < 1 {
|
||||
@@ -190,7 +187,7 @@ func (g *Groupware) GetEmailsById(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
markAsSeen, ok, err := req.parseBoolParam(QueryParamMarkAsSeen, false)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
if ok {
|
||||
l = l.Bool(QueryParamMarkAsSeen, markAsSeen)
|
||||
@@ -201,32 +198,32 @@ func (g *Groupware) GetEmailsById(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
emails, _, sessionState, state, lang, jerr := g.jmap.GetEmails(accountId, req.session, req.ctx, logger, req.language(), ids, true, g.config.maxBodyValueBytes, markAsSeen, true)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
if len(emails) < 1 {
|
||||
return notFoundResponse(single(accountId), sessionState)
|
||||
return req.notFound(accountId, sessionState, EmailResponseObjectType, state)
|
||||
} else {
|
||||
sanitized, err := req.sanitizeEmail(emails[0])
|
||||
if err != nil {
|
||||
return errorResponseWithSessionState(single(accountId), err, sessionState)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
return etagResponse(single(accountId), sanitized, sessionState, EmailResponseObjectType, state, lang)
|
||||
return req.respond(accountId, sanitized, sessionState, EmailResponseObjectType, state)
|
||||
}
|
||||
} 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)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
if len(emails) < 1 {
|
||||
return notFoundResponse(single(accountId), sessionState)
|
||||
return req.notFound(accountId, sessionState, EmailResponseObjectType, state)
|
||||
} else {
|
||||
sanitized, err := req.sanitizeEmails(emails)
|
||||
if err != nil {
|
||||
return errorResponseWithSessionState(single(accountId), err, sessionState)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
return etagResponse(single(accountId), sanitized, sessionState, EmailResponseObjectType, state, lang)
|
||||
return req.respond(accountId, sanitized, sessionState, EmailResponseObjectType, state)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -259,29 +256,29 @@ func (g *Groupware) GetEmailAttachments(w http.ResponseWriter, r *http.Request)
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
accountId, err := req.GetAccountIdForMail()
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
l := req.logger.With().Str(logAccountId, log.SafeString(accountId))
|
||||
|
||||
id, err := req.PathParam(UriParamEmailId)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
|
||||
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)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
if len(emails) < 1 {
|
||||
return notFoundResponse(single(accountId), sessionState)
|
||||
return req.notFound(accountId, sessionState, EmailResponseObjectType, state)
|
||||
}
|
||||
email, err := req.sanitizeEmail(emails[0])
|
||||
if err != nil {
|
||||
return errorResponseWithSessionState(single(accountId), err, sessionState)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
var body []jmap.EmailBodyPart = email.Attachments
|
||||
return etagResponse(single(accountId), body, sessionState, EmailResponseObjectType, state, lang)
|
||||
return req.respond(accountId, body, sessionState, EmailResponseObjectType, state)
|
||||
})
|
||||
} else {
|
||||
g.stream(w, r, func(req Request, w http.ResponseWriter) *Error {
|
||||
@@ -377,13 +374,13 @@ func (g *Groupware) getEmailsSince(w http.ResponseWriter, r *http.Request, since
|
||||
|
||||
accountId, err := req.GetAccountIdForMail()
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
l = l.Str(logAccountId, log.SafeString(accountId))
|
||||
|
||||
maxChanges, ok, err := req.parseUIntParam(QueryParamMaxChanges, 0)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
if ok {
|
||||
l = l.Uint(QueryParamMaxChanges, maxChanges)
|
||||
@@ -391,12 +388,12 @@ func (g *Groupware) getEmailsSince(w http.ResponseWriter, r *http.Request, since
|
||||
|
||||
logger := log.From(l)
|
||||
|
||||
changes, sessionState, state, lang, jerr := g.jmap.GetEmailsSince(accountId, req.session, req.ctx, logger, req.language(), since, true, g.config.maxBodyValueBytes, maxChanges)
|
||||
changes, sessionState, state, lang, jerr := g.jmap.GetEmailChanges(accountId, req.session, req.ctx, logger, req.language(), since, true, g.config.maxBodyValueBytes, maxChanges)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
return etagResponse(single(accountId), changes, sessionState, EmailResponseObjectType, state, lang)
|
||||
return req.respond(accountId, changes, sessionState, EmailResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -604,12 +601,12 @@ func (g *Groupware) GetEmails(w http.ResponseWriter, r *http.Request) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
accountId, err := req.GetAccountIdForMail()
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
|
||||
ok, filter, makesSnippets, offset, limit, logger, err := g.buildEmailFilter(req)
|
||||
if !ok {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
logger = log.From(req.logger.With().Str(logAccountId, log.SafeString(accountId)))
|
||||
|
||||
@@ -621,7 +618,7 @@ func (g *Groupware) GetEmails(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
resultsByAccount, sessionState, state, lang, jerr := g.jmap.QueryEmailsWithSnippets(single(accountId), filter, req.session, req.ctx, logger, req.language(), offset, limit, fetchBodies, g.config.maxBodyValueBytes)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
if results, ok := resultsByAccount[accountId]; ok {
|
||||
@@ -641,7 +638,7 @@ func (g *Groupware) GetEmails(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
sanitized, err := req.sanitizeEmail(result.Email)
|
||||
if err != nil {
|
||||
return errorResponseWithSessionState(single(accountId), err, sessionState)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
flattened[i] = EmailWithSnippets{
|
||||
Email: sanitized,
|
||||
@@ -649,14 +646,14 @@ func (g *Groupware) GetEmails(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
return etagResponse(single(accountId), EmailWithSnippetsSearchResults{
|
||||
return req.respond(accountId, EmailWithSnippetsSearchResults{
|
||||
Results: flattened,
|
||||
Total: results.Total,
|
||||
Limit: results.Limit,
|
||||
QueryState: results.QueryState,
|
||||
}, sessionState, EmailResponseObjectType, state, lang)
|
||||
}, sessionState, EmailResponseObjectType, state)
|
||||
} else {
|
||||
return notFoundResponse(single(accountId), sessionState)
|
||||
return req.notFound(accountId, sessionState, EmailResponseObjectType, state)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -668,7 +665,7 @@ func (g *Groupware) GetEmailsForAllAccounts(w http.ResponseWriter, r *http.Reque
|
||||
|
||||
ok, filter, makesSnippets, offset, limit, logger, err := g.buildEmailFilter(req)
|
||||
if !ok {
|
||||
return errorResponse(allAccountIds, err)
|
||||
return req.errorN(allAccountIds, err)
|
||||
}
|
||||
logger = log.From(req.logger.With().Array(logAccountId, log.SafeStringArray(allAccountIds)))
|
||||
|
||||
@@ -679,7 +676,7 @@ func (g *Groupware) GetEmailsForAllAccounts(w http.ResponseWriter, r *http.Reque
|
||||
if makesSnippets {
|
||||
resultsByAccountId, sessionState, state, lang, jerr := g.jmap.QueryEmailSnippets(allAccountIds, filter, req.session, req.ctx, logger, req.language(), offset, limit)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(allAccountIds, jerr)
|
||||
return req.jmapErrorN(allAccountIds, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
var totalOverAllAccounts uint = 0
|
||||
@@ -713,13 +710,13 @@ func (g *Groupware) GetEmailsForAllAccounts(w http.ResponseWriter, r *http.Reque
|
||||
QueryState: state,
|
||||
}
|
||||
|
||||
return etagResponse(allAccountIds, body, sessionState, EmailResponseObjectType, state, lang)
|
||||
return req.respondN(allAccountIds, body, sessionState, EmailResponseObjectType, state)
|
||||
} else {
|
||||
withThreads := true
|
||||
|
||||
resultsByAccountId, sessionState, state, lang, jerr := g.jmap.QueryEmailSummaries(allAccountIds, req.session, req.ctx, logger, req.language(), filter, limit, withThreads)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(allAccountIds, jerr)
|
||||
return req.jmapErrorN(allAccountIds, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
var totalAcrossAllAccounts uint = 0
|
||||
@@ -752,7 +749,7 @@ func (g *Groupware) GetEmailsForAllAccounts(w http.ResponseWriter, r *http.Reque
|
||||
QueryState: state,
|
||||
}
|
||||
|
||||
return etagResponse(allAccountIds, body, sessionState, EmailResponseObjectType, state, lang)
|
||||
return req.respondN(allAccountIds, body, sessionState, EmailResponseObjectType, state)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -763,9 +760,9 @@ var draftEmailAutoMailboxRolePrecedence = []string{
|
||||
}
|
||||
|
||||
func findDraftsMailboxId(j *jmap.Client, accountId string, req Request, logger *log.Logger) (string, Response) {
|
||||
mailboxIdsPerAccountIds, _, _, _, jerr := j.SearchMailboxIdsPerRole(single(accountId), req.session, req.ctx, logger, req.language(), draftEmailAutoMailboxRolePrecedence)
|
||||
mailboxIdsPerAccountIds, sessionState, _, lang, jerr := j.SearchMailboxIdsPerRole(single(accountId), req.session, req.ctx, logger, req.language(), draftEmailAutoMailboxRolePrecedence)
|
||||
if jerr != nil {
|
||||
return "", req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return "", req.jmapError(accountId, jerr, sessionState, lang)
|
||||
} else {
|
||||
for _, role := range draftEmailAutoMailboxRolePrecedence {
|
||||
if mailboxId, ok := mailboxIdsPerAccountIds[accountId][role]; ok {
|
||||
@@ -774,7 +771,7 @@ func findDraftsMailboxId(j *jmap.Client, accountId string, req Request, logger *
|
||||
}
|
||||
// couldn't find a Mailbox with the drafts role for that account,
|
||||
// we have to return an error... ?
|
||||
return "", errorResponse(single(accountId), apiError(req.errorId(), ErrorNoMailboxWithDraftRole))
|
||||
return "", req.error(accountId, apiError(req.errorId(), ErrorNoMailboxWithDraftRole))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -786,9 +783,9 @@ 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) {
|
||||
mailboxIdsPerAccountIds, _, _, _, jerr := j.SearchMailboxIdsPerRole(single(accountId), req.session, req.ctx, logger, req.language(), draftAndSentMailboxRoles)
|
||||
mailboxIdsPerAccountIds, sessionState, _, lang, jerr := j.SearchMailboxIdsPerRole(single(accountId), req.session, req.ctx, logger, req.language(), draftAndSentMailboxRoles)
|
||||
if jerr != nil {
|
||||
return "", "", req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return "", "", req.jmapError(accountId, jerr, sessionState, lang)
|
||||
} else {
|
||||
sentMailboxId := ""
|
||||
for _, role := range sentEmailAutoMailboxRolePrecedence {
|
||||
@@ -798,7 +795,7 @@ func findSentMailboxId(j *jmap.Client, accountId string, req Request, logger *lo
|
||||
}
|
||||
}
|
||||
if sentMailboxId == "" {
|
||||
return "", "", errorResponse(single(accountId), apiError(req.errorId(), ErrorNoMailboxWithSentRole))
|
||||
return "", "", req.error(accountId, apiError(req.errorId(), ErrorNoMailboxWithSentRole))
|
||||
}
|
||||
draftsMailboxId := ""
|
||||
for _, role := range draftEmailAutoMailboxRolePrecedence {
|
||||
@@ -808,7 +805,7 @@ func findSentMailboxId(j *jmap.Client, accountId string, req Request, logger *lo
|
||||
}
|
||||
}
|
||||
if draftsMailboxId == "" {
|
||||
return "", "", errorResponse(single(accountId), apiError(req.errorId(), ErrorNoMailboxWithDraftRole))
|
||||
return "", "", req.error(accountId, apiError(req.errorId(), ErrorNoMailboxWithDraftRole))
|
||||
}
|
||||
return draftsMailboxId, sentMailboxId, Response{}
|
||||
}
|
||||
@@ -820,14 +817,14 @@ func (g *Groupware) CreateEmail(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
accountId, gwerr := req.GetAccountIdForMail()
|
||||
if gwerr != nil {
|
||||
return errorResponse(single(accountId), gwerr)
|
||||
return req.error(accountId, gwerr)
|
||||
}
|
||||
logger = log.From(logger.With().Str(logAccountId, log.SafeString(accountId)))
|
||||
|
||||
var body jmap.EmailCreate
|
||||
err := req.body(&body)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
|
||||
if len(body.MailboxIds) < 1 {
|
||||
@@ -841,10 +838,10 @@ 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())
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
return etagResponse(single(accountId), created, sessionState, EmailResponseObjectType, state, lang)
|
||||
return req.respond(accountId, created, sessionState, EmailResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -854,12 +851,12 @@ func (g *Groupware) ReplaceEmail(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
accountId, gwerr := req.GetAccountIdForMail()
|
||||
if gwerr != nil {
|
||||
return errorResponse(single(accountId), gwerr)
|
||||
return req.error(accountId, gwerr)
|
||||
}
|
||||
|
||||
replaceId, err := req.PathParam(UriParamEmailId)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
|
||||
logger = log.From(logger.With().Str(logAccountId, log.SafeString(accountId)))
|
||||
@@ -867,7 +864,7 @@ func (g *Groupware) ReplaceEmail(w http.ResponseWriter, r *http.Request) {
|
||||
var body jmap.EmailCreate
|
||||
err = req.body(&body)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
|
||||
if len(body.MailboxIds) < 1 {
|
||||
@@ -881,10 +878,10 @@ 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())
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
return etagResponse(single(accountId), created, sessionState, EmailResponseObjectType, state, lang)
|
||||
return req.respond(accountId, created, sessionState, EmailResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -894,13 +891,13 @@ func (g *Groupware) UpdateEmail(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
accountId, gwerr := req.GetAccountIdForMail()
|
||||
if gwerr != nil {
|
||||
return errorResponse(single(accountId), gwerr)
|
||||
return req.error(accountId, gwerr)
|
||||
}
|
||||
l.Str(logAccountId, accountId)
|
||||
|
||||
emailId, err := req.PathParam(UriParamEmailId)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
l.Str(UriParamEmailId, log.SafeString(emailId))
|
||||
|
||||
@@ -909,7 +906,7 @@ func (g *Groupware) UpdateEmail(w http.ResponseWriter, r *http.Request) {
|
||||
var body map[string]any
|
||||
err = req.body(&body)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
|
||||
updates := map[string]jmap.EmailUpdate{
|
||||
@@ -918,20 +915,20 @@ func (g *Groupware) UpdateEmail(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
result, sessionState, state, lang, jerr := g.jmap.UpdateEmails(accountId, updates, req.session, req.ctx, logger, req.language())
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
if result == nil {
|
||||
return errorResponse(single(accountId), apiError(req.errorId(), ErrorApiInconsistency, withTitle("API Inconsistency: Missing Email Update Response",
|
||||
return req.error(accountId, apiError(req.errorId(), ErrorApiInconsistency, withTitle("API Inconsistency: Missing Email Update Response",
|
||||
"An internal API behaved unexpectedly: missing Email update response from JMAP endpoint")))
|
||||
}
|
||||
updatedEmail, ok := result[emailId]
|
||||
if !ok {
|
||||
return errorResponse(single(accountId), apiError(req.errorId(), ErrorApiInconsistency, withTitle("API Inconsistency: Wrong Email Update Response ID",
|
||||
return req.error(accountId, apiError(req.errorId(), ErrorApiInconsistency, withTitle("API Inconsistency: Wrong Email Update Response ID",
|
||||
"An internal API behaved unexpectedly: wrong Email update ID response from JMAP endpoint")))
|
||||
}
|
||||
|
||||
return etagResponse(single(accountId), updatedEmail, sessionState, EmailResponseObjectType, state, lang)
|
||||
return req.respond(accountId, updatedEmail, sessionState, EmailResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -950,13 +947,13 @@ func (g *Groupware) UpdateEmailKeywords(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
accountId, gwerr := req.GetAccountIdForMail()
|
||||
if gwerr != nil {
|
||||
return errorResponse(single(accountId), gwerr)
|
||||
return req.error(accountId, gwerr)
|
||||
}
|
||||
l.Str(logAccountId, accountId)
|
||||
|
||||
emailId, err := req.PathParam(UriParamEmailId)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
l.Str(UriParamEmailId, log.SafeString(emailId))
|
||||
|
||||
@@ -965,11 +962,11 @@ func (g *Groupware) UpdateEmailKeywords(w http.ResponseWriter, r *http.Request)
|
||||
var body emailKeywordUpdates
|
||||
err = req.body(&body)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
|
||||
if body.IsEmpty() {
|
||||
return noContentResponse(single(accountId), req.session.State)
|
||||
return req.noop(accountId)
|
||||
}
|
||||
|
||||
patch := jmap.EmailUpdate{}
|
||||
@@ -985,20 +982,20 @@ func (g *Groupware) UpdateEmailKeywords(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
result, sessionState, state, lang, jerr := g.jmap.UpdateEmails(accountId, patches, req.session, req.ctx, logger, req.language())
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
if result == nil {
|
||||
return errorResponse(single(accountId), apiError(req.errorId(), ErrorApiInconsistency, withTitle("API Inconsistency: Missing Email Update Response",
|
||||
return req.error(accountId, apiError(req.errorId(), ErrorApiInconsistency, withTitle("API Inconsistency: Missing Email Update Response",
|
||||
"An internal API behaved unexpectedly: missing Email update response from JMAP endpoint")))
|
||||
}
|
||||
updatedEmail, ok := result[emailId]
|
||||
if !ok {
|
||||
return errorResponse(single(accountId), apiError(req.errorId(), ErrorApiInconsistency, withTitle("API Inconsistency: Wrong Email Update Response ID",
|
||||
return req.error(accountId, apiError(req.errorId(), ErrorApiInconsistency, withTitle("API Inconsistency: Wrong Email Update Response ID",
|
||||
"An internal API behaved unexpectedly: wrong Email update ID response from JMAP endpoint")))
|
||||
}
|
||||
|
||||
return etagResponse(single(accountId), updatedEmail, sessionState, EmailResponseObjectType, state, lang)
|
||||
return req.respond(accountId, updatedEmail, sessionState, EmailResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1009,13 +1006,13 @@ func (g *Groupware) AddEmailKeywords(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
accountId, gwerr := req.GetAccountIdForMail()
|
||||
if gwerr != nil {
|
||||
return errorResponse(single(accountId), gwerr)
|
||||
return req.error(accountId, gwerr)
|
||||
}
|
||||
l.Str(logAccountId, accountId)
|
||||
|
||||
emailId, err := req.PathParam(UriParamEmailId)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
l.Str(UriParamEmailId, log.SafeString(emailId))
|
||||
|
||||
@@ -1024,11 +1021,11 @@ func (g *Groupware) AddEmailKeywords(w http.ResponseWriter, r *http.Request) {
|
||||
var body []string
|
||||
err = req.body(&body)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
|
||||
if len(body) < 1 {
|
||||
return noContentResponse(single(accountId), req.session.State)
|
||||
return req.noop(accountId)
|
||||
}
|
||||
|
||||
patch := jmap.EmailUpdate{}
|
||||
@@ -1041,23 +1038,23 @@ func (g *Groupware) AddEmailKeywords(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
result, sessionState, state, lang, jerr := g.jmap.UpdateEmails(accountId, patches, req.session, req.ctx, logger, req.language())
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
if result == nil {
|
||||
return errorResponse(single(accountId), apiError(req.errorId(), ErrorApiInconsistency, withTitle("API Inconsistency: Missing Email Update Response",
|
||||
return req.error(accountId, apiError(req.errorId(), ErrorApiInconsistency, withTitle("API Inconsistency: Missing Email Update Response",
|
||||
"An internal API behaved unexpectedly: missing Email update response from JMAP endpoint")))
|
||||
}
|
||||
updatedEmail, ok := result[emailId]
|
||||
if !ok {
|
||||
return errorResponse(single(accountId), apiError(req.errorId(), ErrorApiInconsistency, withTitle("API Inconsistency: Wrong Email Update Response ID",
|
||||
return req.error(accountId, apiError(req.errorId(), ErrorApiInconsistency, withTitle("API Inconsistency: Wrong Email Update Response ID",
|
||||
"An internal API behaved unexpectedly: wrong Email update ID response from JMAP endpoint")))
|
||||
}
|
||||
|
||||
if updatedEmail == nil {
|
||||
return noContentResponseWithEtag(single(accountId), sessionState, EmailResponseObjectType, state)
|
||||
return req.noContent(accountId, sessionState, EmailResponseObjectType, state)
|
||||
} else {
|
||||
return etagResponse(single(accountId), updatedEmail, sessionState, EmailResponseObjectType, state, lang)
|
||||
return req.respond(accountId, updatedEmail, sessionState, EmailResponseObjectType, state)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1069,13 +1066,13 @@ func (g *Groupware) RemoveEmailKeywords(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
accountId, err := req.GetAccountIdForMail()
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
l.Str(logAccountId, accountId)
|
||||
|
||||
emailId, err := req.PathParam(UriParamEmailId)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
l.Str(UriParamEmailId, log.SafeString(emailId))
|
||||
|
||||
@@ -1084,11 +1081,11 @@ func (g *Groupware) RemoveEmailKeywords(w http.ResponseWriter, r *http.Request)
|
||||
var body []string
|
||||
err = req.body(&body)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
|
||||
if len(body) < 1 {
|
||||
return noContentResponse(single(accountId), req.session.State)
|
||||
return req.noop(accountId)
|
||||
}
|
||||
|
||||
patch := jmap.EmailUpdate{}
|
||||
@@ -1101,23 +1098,23 @@ func (g *Groupware) RemoveEmailKeywords(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
result, sessionState, state, lang, jerr := g.jmap.UpdateEmails(accountId, patches, req.session, req.ctx, logger, req.language())
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
if result == nil {
|
||||
return errorResponse(single(accountId), apiError(req.errorId(), ErrorApiInconsistency, withTitle("API Inconsistency: Missing Email Update Response",
|
||||
return req.error(accountId, apiError(req.errorId(), ErrorApiInconsistency, withTitle("API Inconsistency: Missing Email Update Response",
|
||||
"An internal API behaved unexpectedly: missing Email update response from JMAP endpoint")))
|
||||
}
|
||||
updatedEmail, ok := result[emailId]
|
||||
if !ok {
|
||||
return errorResponse(single(accountId), apiError(req.errorId(), ErrorApiInconsistency, withTitle("API Inconsistency: Wrong Email Update Response ID",
|
||||
return req.error(accountId, apiError(req.errorId(), ErrorApiInconsistency, withTitle("API Inconsistency: Wrong Email Update Response ID",
|
||||
"An internal API behaved unexpectedly: wrong Email update ID response from JMAP endpoint")))
|
||||
}
|
||||
|
||||
if updatedEmail == nil {
|
||||
return noContentResponseWithEtag(single(accountId), sessionState, EmailResponseObjectType, state)
|
||||
return req.noContent(accountId, sessionState, EmailResponseObjectType, state)
|
||||
} else {
|
||||
return etagResponse(single(accountId), updatedEmail, sessionState, EmailResponseObjectType, state, lang)
|
||||
return req.respond(accountId, updatedEmail, sessionState, EmailResponseObjectType, state)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1129,39 +1126,39 @@ func (g *Groupware) DeleteEmail(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
accountId, gwerr := req.GetAccountIdForMail()
|
||||
if gwerr != nil {
|
||||
return errorResponse(single(accountId), gwerr)
|
||||
return req.error(accountId, gwerr)
|
||||
}
|
||||
l.Str(logAccountId, log.SafeString(accountId))
|
||||
|
||||
emailId, err := req.PathParam(UriParamEmailId)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
l.Str(UriParamEmailId, log.SafeString(emailId))
|
||||
|
||||
logger := log.From(l)
|
||||
|
||||
resp, sessionState, state, _, jerr := g.jmap.DeleteEmails(accountId, []string{emailId}, req.session, req.ctx, logger, req.language())
|
||||
resp, sessionState, state, lang, jerr := g.jmap.DeleteEmails(accountId, []string{emailId}, req.session, req.ctx, logger, req.language())
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
for _, e := range resp {
|
||||
desc := e.Description
|
||||
if desc != "" {
|
||||
return errorResponseWithSessionState(single(accountId), apiError(
|
||||
return req.error(accountId, apiError(
|
||||
req.errorId(),
|
||||
ErrorFailedToDeleteEmail,
|
||||
withDetail(e.Description),
|
||||
), sessionState)
|
||||
))
|
||||
} else {
|
||||
return errorResponseWithSessionState(single(accountId), apiError(
|
||||
return req.error(accountId, apiError(
|
||||
req.errorId(),
|
||||
ErrorFailedToDeleteEmail,
|
||||
), sessionState)
|
||||
))
|
||||
}
|
||||
}
|
||||
return noContentResponseWithEtag(single(accountId), sessionState, EmailResponseObjectType, state)
|
||||
return req.noContent(accountId, sessionState, EmailResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1176,23 +1173,23 @@ func (g *Groupware) DeleteEmails(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
accountId, gwerr := req.GetAccountIdForMail()
|
||||
if gwerr != nil {
|
||||
return errorResponse(single(accountId), gwerr)
|
||||
return req.error(accountId, gwerr)
|
||||
}
|
||||
l.Str(logAccountId, accountId)
|
||||
|
||||
var emailIds []string
|
||||
err := req.body(&emailIds)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
|
||||
l.Array("emailIds", log.SafeStringArray(emailIds))
|
||||
|
||||
logger := log.From(l)
|
||||
|
||||
resp, sessionState, state, _, jerr := g.jmap.DeleteEmails(accountId, emailIds, req.session, req.ctx, logger, req.language())
|
||||
resp, sessionState, state, lang, jerr := g.jmap.DeleteEmails(accountId, emailIds, req.session, req.ctx, logger, req.language())
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
if len(resp) > 0 {
|
||||
@@ -1200,13 +1197,13 @@ func (g *Groupware) DeleteEmails(w http.ResponseWriter, r *http.Request) {
|
||||
for emailId, e := range resp {
|
||||
meta[emailId] = e.Description
|
||||
}
|
||||
return errorResponseWithSessionState(single(accountId), apiError(
|
||||
return req.error(accountId, apiError(
|
||||
req.errorId(),
|
||||
ErrorFailedToDeleteEmail,
|
||||
withMeta(meta),
|
||||
), sessionState)
|
||||
))
|
||||
}
|
||||
return noContentResponseWithEtag(single(accountId), sessionState, EmailResponseObjectType, state)
|
||||
return req.noContent(accountId, sessionState, EmailResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1216,19 +1213,19 @@ func (g *Groupware) SendEmail(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
accountId, gwerr := req.GetAccountIdForMail()
|
||||
if gwerr != nil {
|
||||
return errorResponse(single(accountId), gwerr)
|
||||
return req.error(accountId, gwerr)
|
||||
}
|
||||
l.Str(logAccountId, accountId)
|
||||
|
||||
emailId, err := req.PathParam(UriParamEmailId)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
l.Str(UriParamEmailId, log.SafeString(emailId))
|
||||
|
||||
identityId, err := req.getMandatoryStringParam(QueryParamIdentityId)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
l.Str(QueryParamIdentityId, log.SafeString(identityId))
|
||||
|
||||
@@ -1261,10 +1258,10 @@ func (g *Groupware) SendEmail(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
resp, sessionState, state, lang, jerr := g.jmap.SubmitEmail(accountId, identityId, emailId, move, req.session, req.ctx, logger, req.language())
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
return etagResponse(single(accountId), resp, sessionState, EmailResponseObjectType, state, lang)
|
||||
return req.respond(accountId, resp, sessionState, EmailResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1330,21 +1327,21 @@ func (g *Groupware) RelatedToEmail(w http.ResponseWriter, r *http.Request) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
l := req.logger.With()
|
||||
|
||||
accountId, gwerr := req.GetAccountIdForMail()
|
||||
if gwerr != nil {
|
||||
return errorResponse(single(accountId), gwerr)
|
||||
accountId, err := req.GetAccountIdForMail()
|
||||
if err != nil {
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
l = l.Str(logAccountId, log.SafeString(accountId))
|
||||
|
||||
id, err := req.PathParam(UriParamEmailId)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
l = l.Str(logEmailId, log.SafeString(id))
|
||||
|
||||
limit, ok, err := req.parseUIntParam(QueryParamLimit, 10) // TODO configurable default limit
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
if ok {
|
||||
l = l.Uint("limit", limit)
|
||||
@@ -1352,7 +1349,7 @@ func (g *Groupware) RelatedToEmail(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
days, ok, err := req.parseUIntParam(QueryParamDays, 5) // TODO configurable default days
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
if ok {
|
||||
l = l.Uint("days", days)
|
||||
@@ -1365,13 +1362,13 @@ func (g *Groupware) RelatedToEmail(w http.ResponseWriter, r *http.Request) {
|
||||
emails, _, sessionState, state, lang, jerr := g.jmap.GetEmails(accountId, req.session, req.ctx, logger, req.language(), []string{id}, true, g.config.maxBodyValueBytes, false, false)
|
||||
getEmailsDuration := time.Since(getEmailsBefore)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
if len(emails) < 1 {
|
||||
req.observe(g.metrics.EmailByIdDuration.WithLabelValues(req.session.JmapEndpoint, metrics.Values.Result.NotFound), getEmailsDuration.Seconds())
|
||||
logger.Trace().Msg("failed to find any emails matching id") // the id is already in the log field
|
||||
return notFoundResponse(single(accountId), sessionState)
|
||||
return req.notFound(accountId, sessionState, EmailResponseObjectType, state)
|
||||
} else {
|
||||
req.observe(g.metrics.EmailByIdDuration.WithLabelValues(req.session.JmapEndpoint, metrics.Values.Result.Found), getEmailsDuration.Seconds())
|
||||
}
|
||||
@@ -1408,7 +1405,7 @@ func (g *Groupware) RelatedToEmail(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
g.job(logger, RelationTypeSameThread, func(jobId uint64, l *log.Logger) {
|
||||
before := time.Now()
|
||||
emails, _, _, _, jerr := g.jmap.EmailsInThread(accountId, email.ThreadId, req.session, bgctx, l, req.language(), false, g.config.maxBodyValueBytes)
|
||||
emails, _, _, lang, jerr := g.jmap.EmailsInThread(accountId, email.ThreadId, req.session, bgctx, l, req.language(), false, g.config.maxBodyValueBytes)
|
||||
duration := time.Since(before)
|
||||
if jerr != nil {
|
||||
_ = req.observeJmapError(jerr)
|
||||
@@ -1427,12 +1424,12 @@ func (g *Groupware) RelatedToEmail(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
sanitized, err := req.sanitizeEmail(email)
|
||||
if err != nil {
|
||||
return errorResponseWithSessionState(single(accountId), err, sessionState)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
return etagResponse(single(accountId), AboutEmailResponse{
|
||||
return req.respond(accountId, AboutEmailResponse{
|
||||
Email: sanitized,
|
||||
RequestId: reqId,
|
||||
}, sessionState, EmailResponseObjectType, state, lang)
|
||||
}, sessionState, EmailResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1630,7 +1627,7 @@ func (g *Groupware) GetLatestEmailsSummaryForAllAccounts(w http.ResponseWriter,
|
||||
|
||||
limit, ok, err := req.parseUIntParam(QueryParamLimit, 10) // TODO from configuration
|
||||
if err != nil {
|
||||
return errorResponse(allAccountIds, err)
|
||||
return req.errorN(allAccountIds, err)
|
||||
}
|
||||
if ok {
|
||||
l = l.Uint(QueryParamLimit, limit)
|
||||
@@ -1638,10 +1635,10 @@ func (g *Groupware) GetLatestEmailsSummaryForAllAccounts(w http.ResponseWriter,
|
||||
|
||||
offset, ok, err := req.parseUIntParam(QueryParamOffset, 0)
|
||||
if err != nil {
|
||||
return errorResponse(allAccountIds, err)
|
||||
return req.errorN(allAccountIds, err)
|
||||
}
|
||||
if offset > 0 {
|
||||
return notImplementedResponse()
|
||||
return req.notImplementedN(allAccountIds, EmailResponseObjectType)
|
||||
}
|
||||
if ok {
|
||||
l = l.Uint(QueryParamOffset, limit)
|
||||
@@ -1649,7 +1646,7 @@ func (g *Groupware) GetLatestEmailsSummaryForAllAccounts(w http.ResponseWriter,
|
||||
|
||||
seen, ok, err := req.parseBoolParam(QueryParamSeen, false)
|
||||
if err != nil {
|
||||
return errorResponse(allAccountIds, err)
|
||||
return req.errorN(allAccountIds, err)
|
||||
}
|
||||
if ok {
|
||||
l = l.Bool(QueryParamSeen, seen)
|
||||
@@ -1657,7 +1654,7 @@ func (g *Groupware) GetLatestEmailsSummaryForAllAccounts(w http.ResponseWriter,
|
||||
|
||||
undesirable, ok, err := req.parseBoolParam(QueryParamUndesirable, false)
|
||||
if err != nil {
|
||||
return errorResponse(allAccountIds, err)
|
||||
return req.errorN(allAccountIds, err)
|
||||
}
|
||||
if ok {
|
||||
l = l.Bool(QueryParamUndesirable, undesirable)
|
||||
@@ -1679,7 +1676,7 @@ func (g *Groupware) GetLatestEmailsSummaryForAllAccounts(w http.ResponseWriter,
|
||||
|
||||
emailsSummariesByAccount, sessionState, state, lang, jerr := g.jmap.QueryEmailSummaries(allAccountIds, req.session, req.ctx, logger, req.language(), filter, limit, true)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(allAccountIds, jerr)
|
||||
return req.jmapErrorN(allAccountIds, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
// sort in memory to respect the overall limit
|
||||
@@ -1703,12 +1700,12 @@ func (g *Groupware) GetLatestEmailsSummaryForAllAccounts(w http.ResponseWriter,
|
||||
summaries[i] = summarizeEmail(all[i].accountId, all[i].email)
|
||||
}
|
||||
|
||||
return etagResponse(allAccountIds, EmailSummaries{
|
||||
return req.respondN(allAccountIds, EmailSummaries{
|
||||
Emails: summaries,
|
||||
Total: total,
|
||||
Limit: limit,
|
||||
Offset: offset,
|
||||
}, sessionState, EmailResponseObjectType, state, lang)
|
||||
}, sessionState, EmailResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -15,14 +15,14 @@ func (g *Groupware) GetIdentities(w http.ResponseWriter, r *http.Request) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
accountId, err := req.GetAccountIdForMail()
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
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())
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
return etagResponse(single(accountId), res, sessionState, IdentityResponseObjectType, state, lang)
|
||||
return req.respond(accountId, res, sessionState, IdentityResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -30,22 +30,22 @@ func (g *Groupware) GetIdentityById(w http.ResponseWriter, r *http.Request) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
accountId, err := req.GetAccountIdForMail()
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
id, err := req.PathParam(UriParamIdentityId)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
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})
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
if len(res) < 1 {
|
||||
return notFoundResponse(single(accountId), sessionState)
|
||||
return req.notFound(accountId, sessionState, IdentityResponseObjectType, state)
|
||||
}
|
||||
var body jmap.Identity = res[0]
|
||||
return etagResponse(single(accountId), body, sessionState, IdentityResponseObjectType, state, lang)
|
||||
return req.respond(accountId, body, sessionState, IdentityResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -53,21 +53,21 @@ func (g *Groupware) AddIdentity(w http.ResponseWriter, r *http.Request) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
accountId, err := req.GetAccountIdForMail()
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
logger := log.From(req.logger.With().Str(logAccountId, accountId))
|
||||
|
||||
var identity jmap.Identity
|
||||
err = req.body(&identity)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
|
||||
created, sessionState, state, lang, jerr := g.jmap.CreateIdentity(accountId, req.session, req.ctx, logger, req.language(), identity)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
return etagResponse(single(accountId), created, sessionState, IdentityResponseObjectType, state, lang)
|
||||
return req.respond(accountId, created, sessionState, IdentityResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -75,21 +75,21 @@ func (g *Groupware) ModifyIdentity(w http.ResponseWriter, r *http.Request) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
accountId, err := req.GetAccountIdForMail()
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
logger := log.From(req.logger.With().Str(logAccountId, accountId))
|
||||
|
||||
var identity jmap.Identity
|
||||
err = req.body(&identity)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
|
||||
updated, sessionState, state, lang, jerr := g.jmap.UpdateIdentity(accountId, req.session, req.ctx, logger, req.language(), identity)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
return etagResponse(single(accountId), updated, sessionState, IdentityResponseObjectType, state, lang)
|
||||
return req.respond(accountId, updated, sessionState, IdentityResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -98,30 +98,30 @@ func (g *Groupware) DeleteIdentity(w http.ResponseWriter, r *http.Request) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
accountId, err := req.GetAccountIdForMail()
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
logger := log.From(req.logger.With().Str(logAccountId, accountId))
|
||||
|
||||
id, err := req.PathParam(UriParamIdentityId)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
ids := strings.Split(id, ",")
|
||||
if len(ids) < 1 {
|
||||
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, _, jerr := g.jmap.DeleteIdentity(accountId, req.session, req.ctx, logger, req.language(), ids)
|
||||
deletion, sessionState, state, lang, jerr := g.jmap.DeleteIdentity(accountId, req.session, req.ctx, logger, req.language(), ids)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
notDeletedIds := structs.Missing(ids, deletion)
|
||||
if len(notDeletedIds) == 0 {
|
||||
return noContentResponseWithEtag(single(accountId), sessionState, IdentityResponseObjectType, state)
|
||||
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 errorResponseWithSessionState(single(accountId), req.apiError(&ErrorFailedToDeleteSomeIdentities,
|
||||
return req.errorS(accountId, req.apiError(&ErrorFailedToDeleteSomeIdentities,
|
||||
withMeta(map[string]any{"ids": notDeletedIds})), sessionState)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -150,7 +150,7 @@ func (g *Groupware) Index(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
boot, sessionState, state, lang, err := g.jmap.GetBootstrap(accountIds, req.session, req.ctx, req.logger, req.language())
|
||||
if err != nil {
|
||||
return req.errorResponseFromJmap(accountIds, err)
|
||||
return req.jmapErrorN(accountIds, err, sessionState, lang)
|
||||
}
|
||||
|
||||
var body IndexResponse = IndexResponse{
|
||||
@@ -160,7 +160,7 @@ func (g *Groupware) Index(w http.ResponseWriter, r *http.Request) {
|
||||
Accounts: buildIndexAccounts(req.session, boot),
|
||||
PrimaryAccounts: buildIndexPrimaryAccounts(req.session),
|
||||
}
|
||||
return etagResponse(accountIds, body, sessionState, IndexResponseObjectType, state, lang)
|
||||
return req.respondN(accountIds, body, sessionState, IndexResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -21,23 +21,23 @@ func (g *Groupware) GetMailbox(w http.ResponseWriter, r *http.Request) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
accountId, err := req.GetAccountIdForMail()
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
|
||||
mailboxId, err := req.PathParam(UriParamMailboxId)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
|
||||
mailboxes, sessionState, state, lang, jerr := g.jmap.GetMailbox(accountId, req.session, req.ctx, req.logger, req.language(), []string{mailboxId})
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
if len(mailboxes.Mailboxes) == 1 {
|
||||
return etagResponse(single(accountId), mailboxes.Mailboxes[0], sessionState, MailboxResponseObjectType, state, lang)
|
||||
return req.respond(accountId, mailboxes.Mailboxes[0], sessionState, MailboxResponseObjectType, state)
|
||||
} else {
|
||||
return notFoundResponse(single(accountId), sessionState)
|
||||
return req.notFound(accountId, sessionState, MailboxResponseObjectType, state)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -69,12 +69,12 @@ func (g *Groupware) GetMailboxes(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
accountId, err := req.GetAccountIdForMail()
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
|
||||
subscribed, set, err := req.parseBoolParam(QueryParamMailboxSearchSubscribed, false)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
if set {
|
||||
filter.IsSubscribed = &subscribed
|
||||
@@ -86,23 +86,23 @@ func (g *Groupware) GetMailboxes(w http.ResponseWriter, r *http.Request) {
|
||||
if hasCriteria {
|
||||
mailboxesByAccountId, sessionState, state, lang, err := g.jmap.SearchMailboxes(single(accountId), req.session, req.ctx, logger, req.language(), filter)
|
||||
if err != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), err)
|
||||
return req.jmapError(accountId, err, sessionState, lang)
|
||||
}
|
||||
|
||||
if mailboxes, ok := mailboxesByAccountId[accountId]; ok {
|
||||
return etagResponse(single(accountId), sortMailboxSlice(mailboxes), sessionState, MailboxResponseObjectType, state, lang)
|
||||
return req.respond(accountId, sortMailboxSlice(mailboxes), sessionState, MailboxResponseObjectType, state)
|
||||
} else {
|
||||
return notFoundResponse(single(accountId), sessionState)
|
||||
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())
|
||||
if err != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), err)
|
||||
return req.jmapError(accountId, err, sessionState, lang)
|
||||
}
|
||||
if mailboxes, ok := mailboxesByAccountId[accountId]; ok {
|
||||
return etagResponse(single(accountId), sortMailboxSlice(mailboxes), sessionState, MailboxResponseObjectType, state, lang)
|
||||
return req.respond(accountId, sortMailboxSlice(mailboxes), sessionState, MailboxResponseObjectType, state)
|
||||
} else {
|
||||
return notFoundResponse(single(accountId), sessionState)
|
||||
return req.notFound(accountId, sessionState, MailboxResponseObjectType, state)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -113,7 +113,7 @@ func (g *Groupware) GetMailboxesForAllAccounts(w http.ResponseWriter, r *http.Re
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
accountIds := req.AllAccountIds()
|
||||
if len(accountIds) < 1 {
|
||||
return noContentResponse(nil, "") // when the user has no accounts
|
||||
return req.noopN(nil) // when the user has no accounts
|
||||
}
|
||||
logger := log.From(req.logger.With().Array(logAccountId, log.SafeStringArray(accountIds)))
|
||||
|
||||
@@ -126,7 +126,7 @@ func (g *Groupware) GetMailboxesForAllAccounts(w http.ResponseWriter, r *http.Re
|
||||
}
|
||||
|
||||
if subscribed, set, err := req.parseBoolParam(QueryParamMailboxSearchSubscribed, false); err != nil {
|
||||
return errorResponse(accountIds, err)
|
||||
return req.errorN(accountIds, err)
|
||||
} else if set {
|
||||
filter.IsSubscribed = &subscribed
|
||||
hasCriteria = true
|
||||
@@ -135,15 +135,15 @@ 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)
|
||||
if err != nil {
|
||||
return req.errorResponseFromJmap(accountIds, err)
|
||||
return req.jmapErrorN(accountIds, err, sessionState, lang)
|
||||
}
|
||||
return etagResponse(accountIds, sortMailboxesMap(mailboxesByAccountId), sessionState, MailboxResponseObjectType, state, 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())
|
||||
if err != nil {
|
||||
return req.errorResponseFromJmap(accountIds, err)
|
||||
return req.jmapErrorN(accountIds, err, sessionState, lang)
|
||||
}
|
||||
return etagResponse(accountIds, sortMailboxesMap(mailboxesByAccountId), sessionState, MailboxResponseObjectType, state, lang)
|
||||
return req.respondN(accountIds, sortMailboxesMap(mailboxesByAccountId), sessionState, MailboxResponseObjectType, state)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -153,12 +153,12 @@ func (g *Groupware) GetMailboxByRoleForAllAccounts(w http.ResponseWriter, r *htt
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
accountIds := req.AllAccountIds()
|
||||
if len(accountIds) < 1 {
|
||||
return noContentResponse(nil, "") // when the user has no accounts
|
||||
return req.noopN(accountIds) // when the user has no accounts
|
||||
}
|
||||
|
||||
role, err := req.PathParamDoc(UriParamRole, "Role of the mailboxes to retrieve across all accounts")
|
||||
if err != nil {
|
||||
return errorResponse(accountIds, err)
|
||||
return req.errorN(accountIds, err)
|
||||
}
|
||||
|
||||
logger := log.From(req.logger.With().Array(logAccountId, log.SafeStringArray(accountIds)).Str("role", role))
|
||||
@@ -169,50 +169,58 @@ func (g *Groupware) GetMailboxByRoleForAllAccounts(w http.ResponseWriter, r *htt
|
||||
|
||||
mailboxesByAccountId, sessionState, state, lang, jerr := g.jmap.SearchMailboxes(accountIds, req.session, req.ctx, logger, req.language(), filter)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(accountIds, jerr)
|
||||
return req.jmapErrorN(accountIds, jerr, sessionState, lang)
|
||||
}
|
||||
return etagResponse(accountIds, sortMailboxesMap(mailboxesByAccountId), sessionState, MailboxResponseObjectType, state, lang)
|
||||
return req.respondN(accountIds, sortMailboxesMap(mailboxesByAccountId), sessionState, MailboxResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
// Get the changes that occured in a given mailbox since a certain state.
|
||||
// @api:tags mailbox,changes
|
||||
func (g *Groupware) GetMailboxChanges(w http.ResponseWriter, r *http.Request) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
l := req.logger.With()
|
||||
|
||||
accountId, err := req.GetAccountIdForMail()
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
l = l.Str(logAccountId, accountId)
|
||||
|
||||
mailboxId, err := req.PathParam(UriParamMailboxId)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
}
|
||||
|
||||
maxChanges, ok, err := req.parseUIntParam(QueryParamMaxChanges, 0)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
if ok {
|
||||
l = l.Uint(QueryParamMaxChanges, maxChanges)
|
||||
}
|
||||
|
||||
sinceState, err := req.HeaderParamDoc(HeaderParamSince, "Specifies the state identifier from which on to list mailbox changes")
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
sinceState := req.OptHeaderParamDoc(HeaderParamSince, "Optionally specifies the state identifier from which on to list mailbox changes")
|
||||
if sinceState != "" {
|
||||
l = l.Str(HeaderParamSince, log.SafeString(sinceState))
|
||||
}
|
||||
l = l.Str(HeaderParamSince, log.SafeString(sinceState))
|
||||
|
||||
logger := log.From(l)
|
||||
|
||||
changes, sessionState, state, lang, jerr := g.jmap.GetMailboxChanges(accountId, req.session, req.ctx, logger, req.language(), mailboxId, sinceState, true, g.config.maxBodyValueBytes, maxChanges)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
// 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
|
||||
// Mailbox, at least in combination with Stalwart, as those are initial objects that
|
||||
// "always existed", even with the initial State, and this the Mailbox/changes operation
|
||||
// returns nothing.
|
||||
// For this reason, when the "since" state is empty, we respond with an error.
|
||||
if sinceState == "" {
|
||||
return req.error(accountId, req.apiError(&ErrorInvalidUserRequest, withTitle(
|
||||
"Mailbox changes without state is unsupported",
|
||||
"Requesting Mailbox changes without an initial state is an unsupported operation",
|
||||
)))
|
||||
}
|
||||
|
||||
return etagResponse(single(accountId), changes, sessionState, MailboxResponseObjectType, state, lang)
|
||||
changes, sessionState, state, lang, jerr := g.jmap.GetMailboxChanges(accountId, req.session, req.ctx, logger, req.language(), sinceState, maxChanges)
|
||||
if jerr != nil {
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
return req.respond(accountId, changes, sessionState, MailboxResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -226,7 +234,7 @@ func (g *Groupware) GetMailboxChangesForAllAccounts(w http.ResponseWriter, r *ht
|
||||
|
||||
sinceStateMap, ok, err := req.parseMapParam(QueryParamSince)
|
||||
if err != nil {
|
||||
return errorResponse(allAccountIds, err)
|
||||
return req.errorN(allAccountIds, err)
|
||||
}
|
||||
if ok {
|
||||
dict := zerolog.Dict()
|
||||
@@ -238,7 +246,7 @@ func (g *Groupware) GetMailboxChangesForAllAccounts(w http.ResponseWriter, r *ht
|
||||
|
||||
maxChanges, ok, err := req.parseUIntParam(QueryParamMaxChanges, 0)
|
||||
if err != nil {
|
||||
return errorResponse(allAccountIds, err)
|
||||
return req.errorN(allAccountIds, err)
|
||||
}
|
||||
if ok {
|
||||
l = l.Uint(QueryParamMaxChanges, maxChanges)
|
||||
@@ -246,12 +254,12 @@ func (g *Groupware) GetMailboxChangesForAllAccounts(w http.ResponseWriter, r *ht
|
||||
|
||||
logger := log.From(l)
|
||||
|
||||
changesByAccountId, sessionState, state, lang, jerr := g.jmap.GetMailboxChangesForMultipleAccounts(allAccountIds, req.session, req.ctx, logger, req.language(), sinceStateMap, true, g.config.maxBodyValueBytes, maxChanges)
|
||||
changesByAccountId, sessionState, state, lang, jerr := g.jmap.GetMailboxChangesForMultipleAccounts(allAccountIds, req.session, req.ctx, logger, req.language(), sinceStateMap, maxChanges)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(allAccountIds, jerr)
|
||||
return req.jmapErrorN(allAccountIds, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
return etagResponse(allAccountIds, changesByAccountId, sessionState, MailboxResponseObjectType, state, lang)
|
||||
return req.respondN(allAccountIds, changesByAccountId, sessionState, MailboxResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -266,10 +274,10 @@ func (g *Groupware) GetMailboxRoles(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
rolesByAccountId, sessionState, state, lang, jerr := g.jmap.GetMailboxRolesForMultipleAccounts(allAccountIds, req.session, req.ctx, logger, req.language())
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(allAccountIds, jerr)
|
||||
return req.jmapErrorN(allAccountIds, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
return etagResponse(allAccountIds, rolesByAccountId, sessionState, MailboxResponseObjectType, state, lang)
|
||||
return req.respondN(allAccountIds, rolesByAccountId, sessionState, MailboxResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -279,29 +287,29 @@ func (g *Groupware) UpdateMailbox(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
accountId, err := req.GetAccountIdForMail()
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
l = l.Str(logAccountId, accountId)
|
||||
|
||||
mailboxId, err := req.PathParamDoc(UriParamMailboxId, "the identifier of the mailbox to update")
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
l = l.Str(UriParamMailboxId, log.SafeString(mailboxId))
|
||||
|
||||
var body jmap.MailboxChange
|
||||
err = req.body(&body)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
logger := log.From(l)
|
||||
|
||||
updated, sessionState, state, lang, jerr := g.jmap.UpdateMailbox(accountId, req.session, req.ctx, logger, req.language(), mailboxId, "", body)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
return etagResponse(single(accountId), updated, sessionState, MailboxResponseObjectType, state, lang)
|
||||
return req.respond(accountId, updated, sessionState, MailboxResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -310,23 +318,23 @@ func (g *Groupware) CreateMailbox(w http.ResponseWriter, r *http.Request) {
|
||||
l := req.logger.With()
|
||||
accountId, err := req.GetAccountIdForMail()
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
l = l.Str(logAccountId, accountId)
|
||||
|
||||
var body jmap.MailboxChange
|
||||
err = req.body(&body)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
logger := log.From(l)
|
||||
|
||||
created, sessionState, state, lang, jerr := g.jmap.CreateMailbox(accountId, req.session, req.ctx, logger, req.language(), "", body)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
return etagResponse(single(accountId), created, sessionState, MailboxResponseObjectType, state, lang)
|
||||
return req.respond(accountId, created, sessionState, MailboxResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -340,28 +348,28 @@ func (g *Groupware) DeleteMailbox(w http.ResponseWriter, r *http.Request) {
|
||||
l := req.logger.With()
|
||||
accountId, err := req.GetAccountIdForMail()
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
l = l.Str(logAccountId, accountId)
|
||||
|
||||
mailboxIds, err := req.PathListParamDoc(UriParamMailboxId, "the identifier of the mailbox to delete")
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
l = l.Array(UriParamMailboxId, log.SafeStringArray(mailboxIds))
|
||||
|
||||
if len(mailboxIds) < 1 {
|
||||
return noContentResponse(single(accountId), req.session.State) // no mailbox identifiers were mentioned in the request
|
||||
return req.noop(accountId) // no mailbox identifiers were mentioned in the request
|
||||
}
|
||||
|
||||
logger := log.From(l)
|
||||
|
||||
deleted, sessionState, state, lang, jerr := g.jmap.DeleteMailboxes(accountId, req.session, req.ctx, logger, req.language(), "", mailboxIds)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
return etagResponse(single(accountId), deleted, sessionState, MailboxResponseObjectType, state, lang)
|
||||
return req.respond(accountId, deleted, sessionState, MailboxResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -16,19 +16,19 @@ func (g *Groupware) GetQuota(w http.ResponseWriter, r *http.Request) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
accountId, err := req.GetAccountIdForQuota()
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
logger := log.From(req.logger.With().Str(logAccountId, accountId))
|
||||
|
||||
res, sessionState, state, lang, jerr := g.jmap.GetQuotas(single(accountId), req.session, req.ctx, logger, req.language())
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
for _, v := range res {
|
||||
body := v.List
|
||||
return etagResponse(single(accountId), body, sessionState, QuotaResponseObjectType, state, lang)
|
||||
return req.respond(accountId, body, sessionState, QuotaResponseObjectType, state)
|
||||
}
|
||||
return notFoundResponse(single(accountId), sessionState)
|
||||
return req.notFound(accountId, sessionState, QuotaResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -45,13 +45,13 @@ func (g *Groupware) GetQuotaForAllAccounts(w http.ResponseWriter, r *http.Reques
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
accountIds := req.AllAccountIds()
|
||||
if len(accountIds) < 1 {
|
||||
return noContentResponse(accountIds, "") // user has no accounts
|
||||
return req.noopN(accountIds) // user has no accounts
|
||||
}
|
||||
logger := log.From(req.logger.With().Array(logAccountId, log.SafeStringArray(accountIds)))
|
||||
|
||||
res, sessionState, state, lang, jerr := g.jmap.GetQuotas(accountIds, req.session, req.ctx, logger, req.language())
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(accountIds, jerr)
|
||||
return req.jmapErrorN(accountIds, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
result := make(map[string]AccountQuota, len(res))
|
||||
@@ -61,6 +61,6 @@ func (g *Groupware) GetQuotaForAllAccounts(w http.ResponseWriter, r *http.Reques
|
||||
Quotas: accountQuotas.List,
|
||||
}
|
||||
}
|
||||
return etagResponse(accountIds, result, sessionState, QuotaResponseObjectType, state, lang)
|
||||
return req.respondN(accountIds, result, sessionState, QuotaResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ func (g *Groupware) GetTaskLists(w http.ResponseWriter, r *http.Request) {
|
||||
var _ string = accountId
|
||||
|
||||
var body []jmap.TaskList = AllTaskLists
|
||||
return etagResponse(single(accountId), body, req.session.State, TaskListResponseObjectType, TaskListsState, "")
|
||||
return req.respond(accountId, body, req.session.State, TaskListResponseObjectType, TaskListsState)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -31,15 +31,15 @@ func (g *Groupware) GetTaskListById(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
tasklistId, err := req.PathParam(UriParamTaskListId)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
// TODO replace with proper implementation
|
||||
for _, tasklist := range AllTaskLists {
|
||||
if tasklist.Id == tasklistId {
|
||||
return response(single(accountId), tasklist, req.session.State, "")
|
||||
return req.respond(accountId, tasklist, req.session.State, TaskListResponseObjectType, TaskListsState)
|
||||
}
|
||||
}
|
||||
return etagNotFoundResponse(single(accountId), req.session.State, TaskListResponseObjectType, TaskListsState, "")
|
||||
return req.etaggedNotFound(accountId, req.session.State, TaskListResponseObjectType, TaskListsState)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -54,13 +54,13 @@ func (g *Groupware) GetTasksInTaskList(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
tasklistId, err := req.PathParam(UriParamTaskListId)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
// TODO replace with proper implementation
|
||||
tasks, ok := TaskMapByTaskListId[tasklistId]
|
||||
if !ok {
|
||||
return notFoundResponse(single(accountId), req.session.State)
|
||||
return req.notFound(accountId, req.session.State, TaskResponseObjectType, TaskState)
|
||||
}
|
||||
return etagResponse(single(accountId), tasks, req.session.State, TaskResponseObjectType, TaskState, "")
|
||||
return req.respond(accountId, tasks, req.session.State, TaskResponseObjectType, TaskState)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -17,15 +17,15 @@ func (g *Groupware) GetVacation(w http.ResponseWriter, r *http.Request) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
accountId, err := req.GetAccountIdForVacationResponse()
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
logger := log.From(req.logger.With().Str(logAccountId, accountId))
|
||||
|
||||
res, sessionState, state, lang, jerr := g.jmap.GetVacationResponse(accountId, req.session, req.ctx, logger, req.language())
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
return etagResponse(single(accountId), res, sessionState, VacationResponseResponseObjectType, state, lang)
|
||||
return req.respond(accountId, res, sessionState, VacationResponseResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -37,21 +37,21 @@ func (g *Groupware) SetVacation(w http.ResponseWriter, r *http.Request) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
accountId, err := req.GetAccountIdForVacationResponse()
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
logger := log.From(req.logger.With().Str(logAccountId, accountId))
|
||||
|
||||
var body jmap.VacationResponsePayload
|
||||
err = req.body(&body)
|
||||
if err != nil {
|
||||
return errorResponse(single(accountId), err)
|
||||
return req.error(accountId, err)
|
||||
}
|
||||
|
||||
res, sessionState, state, lang, jerr := g.jmap.SetVacationResponse(accountId, body, req.session, req.ctx, logger, req.language())
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(single(accountId), jerr)
|
||||
return req.jmapError(accountId, jerr, sessionState, lang)
|
||||
}
|
||||
|
||||
return etagResponse(single(accountId), res, sessionState, VacationResponseResponseObjectType, state, lang)
|
||||
return req.respond(accountId, res, sessionState, VacationResponseResponseObjectType, state)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -651,6 +651,22 @@ func errorResponses(errors ...Error) ErrorResponse {
|
||||
return ErrorResponse{Errors: errors}
|
||||
}
|
||||
|
||||
func (r *Request) errorResponseFromJmap(accountIds []string, err jmap.Error) Response {
|
||||
return errorResponseWithSessionState(accountIds, r.apiErrorFromJmap(r.observeJmapError(err)), r.session.State)
|
||||
func (r *Request) error(accountId string, err *Error) Response {
|
||||
return errorResponse(single(accountId), err, r.session.State, jmap.NoLanguage)
|
||||
}
|
||||
|
||||
func (r *Request) errorS(accountId string, err *Error, sessionState jmap.SessionState) Response {
|
||||
return errorResponse(single(accountId), err, sessionState, jmap.NoLanguage)
|
||||
}
|
||||
|
||||
func (r *Request) errorN(accountIds []string, err *Error) Response {
|
||||
return errorResponse(accountIds, err, r.session.State, jmap.NoLanguage)
|
||||
}
|
||||
|
||||
func (r *Request) jmapError(accountId string, err jmap.Error, sessionState jmap.SessionState, lang jmap.Language) Response {
|
||||
return errorResponse(single(accountId), r.apiErrorFromJmap(r.observeJmapError(err)), sessionState, lang)
|
||||
}
|
||||
|
||||
func (r *Request) jmapErrorN(accountIds []string, err jmap.Error, sessionState jmap.SessionState, lang jmap.Language) Response {
|
||||
return errorResponse(accountIds, r.apiErrorFromJmap(r.observeJmapError(err)), sessionState, lang)
|
||||
}
|
||||
|
||||
@@ -223,7 +223,7 @@ func (r *Request) parameterError(param string, detail string) *Error {
|
||||
}
|
||||
|
||||
func (r *Request) parameterErrorResponse(accountIds []string, param string, detail string) Response {
|
||||
return errorResponse(accountIds, r.parameterError(param, detail))
|
||||
return r.errorN(accountIds, r.parameterError(param, detail))
|
||||
}
|
||||
|
||||
func (r *Request) getStringParam(param string, defaultValue string) (string, bool) {
|
||||
@@ -427,7 +427,7 @@ func (r *Request) observeJmapError(jerr jmap.Error) jmap.Error {
|
||||
func (r *Request) needTask(accountId string) (bool, Response) {
|
||||
if !IgnoreSessionCapabilityChecksForTasks {
|
||||
if r.session.Capabilities.Tasks == nil {
|
||||
return false, errorResponseWithSessionState(single(accountId), r.apiError(&ErrorMissingTasksSessionCapability), r.session.State)
|
||||
return false, errorResponse(single(accountId), r.apiError(&ErrorMissingTasksSessionCapability), r.session.State, jmap.Language(r.language()))
|
||||
}
|
||||
}
|
||||
return true, Response{}
|
||||
@@ -439,10 +439,10 @@ func (r *Request) needTaskForAccount(accountId string) (bool, Response) {
|
||||
}
|
||||
account, ok := r.session.Accounts[accountId]
|
||||
if !ok {
|
||||
return false, errorResponseWithSessionState(single(accountId), r.apiError(&ErrorAccountNotFound), r.session.State)
|
||||
return false, errorResponse(single(accountId), r.apiError(&ErrorAccountNotFound), r.session.State, jmap.NoLanguage)
|
||||
}
|
||||
if account.AccountCapabilities.Tasks == nil {
|
||||
return false, errorResponseWithSessionState(single(accountId), r.apiError(&ErrorMissingTasksAccountCapability), r.session.State)
|
||||
return false, errorResponse(single(accountId), r.apiError(&ErrorMissingTasksAccountCapability), r.session.State, jmap.NoLanguage)
|
||||
}
|
||||
return true, Response{}
|
||||
}
|
||||
@@ -450,7 +450,7 @@ func (r *Request) needTaskForAccount(accountId string) (bool, Response) {
|
||||
func (r *Request) needTaskWithAccount() (bool, string, Response) {
|
||||
accountId, err := r.GetAccountIdForTask()
|
||||
if err != nil {
|
||||
return false, "", errorResponse(single(accountId), err)
|
||||
return false, "", r.error(accountId, err)
|
||||
}
|
||||
if ok, resp := r.needTaskForAccount(accountId); !ok {
|
||||
return false, accountId, resp
|
||||
@@ -460,7 +460,7 @@ func (r *Request) needTaskWithAccount() (bool, string, Response) {
|
||||
|
||||
func (r *Request) needCalendar(accountId string) (bool, Response) {
|
||||
if r.session.Capabilities.Calendars == nil {
|
||||
return false, errorResponseWithSessionState(single(accountId), r.apiError(&ErrorMissingCalendarsSessionCapability), r.session.State)
|
||||
return false, errorResponse(single(accountId), r.apiError(&ErrorMissingCalendarsSessionCapability), r.session.State, jmap.NoLanguage)
|
||||
}
|
||||
return true, Response{}
|
||||
}
|
||||
@@ -471,10 +471,10 @@ func (r *Request) needCalendarForAccount(accountId string) (bool, Response) {
|
||||
}
|
||||
account, ok := r.session.Accounts[accountId]
|
||||
if !ok {
|
||||
return false, errorResponseWithSessionState(single(accountId), r.apiError(&ErrorAccountNotFound), r.session.State)
|
||||
return false, errorResponse(single(accountId), r.apiError(&ErrorAccountNotFound), r.session.State, jmap.NoLanguage)
|
||||
}
|
||||
if account.AccountCapabilities.Calendars == nil {
|
||||
return false, errorResponseWithSessionState(single(accountId), r.apiError(&ErrorMissingCalendarsAccountCapability), r.session.State)
|
||||
return false, errorResponse(single(accountId), r.apiError(&ErrorMissingCalendarsAccountCapability), r.session.State, jmap.NoLanguage)
|
||||
}
|
||||
return true, Response{}
|
||||
}
|
||||
@@ -482,7 +482,7 @@ func (r *Request) needCalendarForAccount(accountId string) (bool, Response) {
|
||||
func (r *Request) needCalendarWithAccount() (bool, string, Response) {
|
||||
accountId, err := r.GetAccountIdForCalendar()
|
||||
if err != nil {
|
||||
return false, "", errorResponse(single(accountId), err)
|
||||
return false, "", r.error(accountId, err)
|
||||
}
|
||||
if ok, resp := r.needCalendarForAccount(accountId); !ok {
|
||||
return false, accountId, resp
|
||||
@@ -492,7 +492,7 @@ func (r *Request) needCalendarWithAccount() (bool, string, Response) {
|
||||
|
||||
func (r *Request) needContact(accountId string) (bool, Response) {
|
||||
if r.session.Capabilities.Contacts == nil {
|
||||
return false, errorResponseWithSessionState(single(accountId), r.apiError(&ErrorMissingContactsSessionCapability), r.session.State)
|
||||
return false, errorResponse(single(accountId), r.apiError(&ErrorMissingContactsSessionCapability), r.session.State, jmap.NoLanguage)
|
||||
}
|
||||
return true, Response{}
|
||||
}
|
||||
@@ -503,10 +503,10 @@ func (r *Request) needContactForAccount(accountId string) (bool, Response) {
|
||||
}
|
||||
account, ok := r.session.Accounts[accountId]
|
||||
if !ok {
|
||||
return false, errorResponseWithSessionState(single(accountId), r.apiError(&ErrorAccountNotFound), r.session.State)
|
||||
return false, errorResponse(single(accountId), r.apiError(&ErrorAccountNotFound), r.session.State, jmap.NoLanguage)
|
||||
}
|
||||
if account.AccountCapabilities.Contacts == nil {
|
||||
return false, errorResponseWithSessionState(single(accountId), r.apiError(&ErrorMissingContactsAccountCapability), r.session.State)
|
||||
return false, errorResponse(single(accountId), r.apiError(&ErrorMissingContactsAccountCapability), r.session.State, jmap.NoLanguage)
|
||||
}
|
||||
return true, Response{}
|
||||
}
|
||||
@@ -514,7 +514,7 @@ func (r *Request) needContactForAccount(accountId string) (bool, Response) {
|
||||
func (r *Request) needContactWithAccount() (bool, string, Response) {
|
||||
accountId, err := r.GetAccountIdForContact()
|
||||
if err != nil {
|
||||
return false, "", errorResponse(single(accountId), err)
|
||||
return false, "", r.error(accountId, err)
|
||||
}
|
||||
if ok, resp := r.needContactForAccount(accountId); !ok {
|
||||
return false, accountId, resp
|
||||
@@ -565,7 +565,7 @@ func (r *Request) parseSort(s string, props []string) ([]SortCrit, *Error) {
|
||||
func mapSort[T any](accountIds []string, req *Request, defaultSort []T, props []string, mapper func(SortCrit) T) ([]T, bool, Response) {
|
||||
if sortSpec, ok := req.getStringParam(QueryParamSort, ""); ok && strings.TrimSpace(sortSpec) != "" {
|
||||
if sort, err := req.parseSort(sortSpec, props); err != nil {
|
||||
return nil, false, errorResponseWithSessionState(accountIds, err, req.session.State)
|
||||
return nil, false, errorResponse(accountIds, err, req.session.State, jmap.NoLanguage)
|
||||
} else {
|
||||
return structs.Map(sort, mapper), true, Response{}
|
||||
}
|
||||
|
||||
@@ -36,23 +36,14 @@ type Response struct {
|
||||
contentLanguage jmap.Language
|
||||
}
|
||||
|
||||
func errorResponse(accountIds []string, err *Error) Response {
|
||||
func errorResponse(accountIds []string, err *Error, sessionState jmap.SessionState, contentLanguage jmap.Language) Response {
|
||||
return Response{
|
||||
accountIds: accountIds,
|
||||
body: nil,
|
||||
err: err,
|
||||
etag: "",
|
||||
sessionState: "",
|
||||
}
|
||||
}
|
||||
|
||||
func errorResponseWithSessionState(accountIds []string, err *Error, sessionState jmap.SessionState) Response {
|
||||
return Response{
|
||||
accountIds: accountIds,
|
||||
body: nil,
|
||||
err: err,
|
||||
etag: "",
|
||||
sessionState: sessionState,
|
||||
accountIds: accountIds,
|
||||
body: nil,
|
||||
err: err,
|
||||
etag: "",
|
||||
sessionState: sessionState,
|
||||
contentLanguage: contentLanguage,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +58,11 @@ func response(accountIds []string, body any, sessionState jmap.SessionState, con
|
||||
}
|
||||
}
|
||||
|
||||
func etagResponse(accountIds []string, body any, sessionState jmap.SessionState, objectType ResponseObjectType, etag jmap.State, contentLanguage jmap.Language) Response {
|
||||
func (r *Request) respondWithoutStatus(accountId string, body any) Response {
|
||||
return response(single(accountId), body, r.session.State, jmap.Language(r.language()))
|
||||
}
|
||||
|
||||
func etaggedResponse(accountIds []string, body any, sessionState jmap.SessionState, objectType ResponseObjectType, etag jmap.State, contentLanguage jmap.Language) Response {
|
||||
return Response{
|
||||
accountIds: accountIds,
|
||||
body: body,
|
||||
@@ -79,6 +74,14 @@ func etagResponse(accountIds []string, body any, sessionState jmap.SessionState,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Request) respond(accountId string, body any, sessionState jmap.SessionState, objectType ResponseObjectType, etag jmap.State) Response {
|
||||
return etaggedResponse(single(accountId), body, sessionState, objectType, etag, jmap.Language(r.language()))
|
||||
}
|
||||
|
||||
func (r *Request) respondN(accountIds []string, body any, sessionState jmap.SessionState, objectType ResponseObjectType, etag jmap.State) Response {
|
||||
return etaggedResponse(accountIds, body, sessionState, objectType, etag, jmap.Language(r.language()))
|
||||
}
|
||||
|
||||
/*
|
||||
func etagOnlyResponse(body any, etag jmap.State, objectType ResponseObjectType, contentLanguage jmap.Language) Response {
|
||||
return Response{
|
||||
@@ -103,6 +106,14 @@ func noContentResponse(accountIds []string, sessionState jmap.SessionState) Resp
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Request) noop(accountId string) Response {
|
||||
return noContentResponse(single(accountId), r.session.State)
|
||||
}
|
||||
|
||||
func (r *Request) noopN(accountIds []string) Response {
|
||||
return noContentResponse(accountIds, r.session.State)
|
||||
}
|
||||
|
||||
func noContentResponseWithEtag(accountIds []string, sessionState jmap.SessionState, objectType ResponseObjectType, etag jmap.State) Response {
|
||||
return Response{
|
||||
accountIds: accountIds,
|
||||
@@ -115,6 +126,10 @@ func noContentResponseWithEtag(accountIds []string, sessionState jmap.SessionSta
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Request) noContent(accountId string, sessionState jmap.SessionState, objectType ResponseObjectType, etag jmap.State) Response {
|
||||
return noContentResponseWithEtag(single(accountId), sessionState, objectType, etag)
|
||||
}
|
||||
|
||||
/*
|
||||
func acceptedResponse(sessionState jmap.SessionState) Response {
|
||||
return Response{
|
||||
@@ -139,18 +154,27 @@ func timeoutResponse(sessionState jmap.SessionState) Response {
|
||||
}
|
||||
*/
|
||||
|
||||
func notFoundResponse(accountIds []string, sessionState jmap.SessionState) Response {
|
||||
func notFoundResponse(accountIds []string, sessionState jmap.SessionState, objectType ResponseObjectType, etag jmap.State) Response {
|
||||
return Response{
|
||||
accountIds: accountIds,
|
||||
body: nil,
|
||||
status: http.StatusNotFound,
|
||||
err: nil,
|
||||
etag: "",
|
||||
objectType: objectType,
|
||||
etag: etag,
|
||||
sessionState: sessionState,
|
||||
}
|
||||
}
|
||||
|
||||
func etagNotFoundResponse(accountIds []string, sessionState jmap.SessionState, objectType ResponseObjectType, etag jmap.State, contentLanguage jmap.Language) Response {
|
||||
func (r *Request) notFound(accountId string, sessionState jmap.SessionState, objectType ResponseObjectType, etag jmap.State) Response {
|
||||
return notFoundResponse(single(accountId), sessionState, objectType, etag)
|
||||
}
|
||||
|
||||
func (r *Request) notFoundN(accountIds []string, sessionState jmap.SessionState, objectType ResponseObjectType, etag jmap.State) Response {
|
||||
return notFoundResponse(accountIds, sessionState, objectType, etag)
|
||||
}
|
||||
|
||||
func etaggedNotFoundResponse(accountIds []string, sessionState jmap.SessionState, objectType ResponseObjectType, etag jmap.State, contentLanguage jmap.Language) Response {
|
||||
return Response{
|
||||
accountIds: accountIds,
|
||||
body: nil,
|
||||
@@ -163,10 +187,21 @@ func etagNotFoundResponse(accountIds []string, sessionState jmap.SessionState, o
|
||||
}
|
||||
}
|
||||
|
||||
func notImplementedResponse() Response {
|
||||
func (r *Request) etaggedNotFound(accountId string, sessionState jmap.SessionState, objectType ResponseObjectType, etag jmap.State) Response {
|
||||
return etaggedNotFoundResponse(single(accountId), sessionState, objectType, etag, jmap.Language(r.language()))
|
||||
}
|
||||
|
||||
func notImplementedResponse(accountIds []string, sessionState jmap.SessionState, objectType ResponseObjectType) Response {
|
||||
return Response{
|
||||
body: nil,
|
||||
status: http.StatusNotImplemented,
|
||||
err: nil,
|
||||
accountIds: accountIds,
|
||||
body: nil,
|
||||
status: http.StatusNotImplemented,
|
||||
err: nil,
|
||||
objectType: objectType,
|
||||
sessionState: sessionState,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Request) notImplementedN(accountIds []string, objectType ResponseObjectType) Response {
|
||||
return notImplementedResponse(accountIds, r.session.State, objectType)
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ const (
|
||||
UriParamContactId = "contactid" // Identifier of the contact
|
||||
UriParamEventId = "eventid" // Idenfitier of the event
|
||||
UriParamBlobName = "blobname"
|
||||
UriParamSince = "since"
|
||||
UriParamRole = "role"
|
||||
QueryParamMailboxSearchName = "name"
|
||||
QueryParamMailboxSearchRole = "role"
|
||||
@@ -102,8 +101,6 @@ func (g *Groupware) Route(r chi.Router) {
|
||||
r.Route("/{mailboxid}", func(r chi.Router) {
|
||||
r.Get("/", g.GetMailbox)
|
||||
r.Get("/emails", g.GetAllEmailsInMailbox)
|
||||
r.Get("/emails/since/{since}", g.GetAllEmailsInMailboxSince)
|
||||
r.Get("/changes", g.GetMailboxChanges)
|
||||
r.Patch("/", g.UpdateMailbox)
|
||||
r.Delete("/", g.DeleteMailbox)
|
||||
})
|
||||
@@ -148,6 +145,7 @@ func (g *Groupware) Route(r chi.Router) {
|
||||
})
|
||||
})
|
||||
r.Route("/contacts", func(r chi.Router) {
|
||||
r.Get("/", g.GetAllContacts)
|
||||
r.Post("/", g.CreateContact)
|
||||
r.Delete("/{contactid}", g.DeleteContact)
|
||||
r.Get("/{contactid}", g.GetContactById)
|
||||
@@ -170,6 +168,11 @@ func (g *Groupware) Route(r chi.Router) {
|
||||
r.Get("/tasks", g.GetTasksInTaskList)
|
||||
})
|
||||
})
|
||||
r.Route("/changes", func(r chi.Router) {
|
||||
r.Get("/contacts", g.GetContactsChanges)
|
||||
r.Get("/mailboxes", g.GetMailboxChanges)
|
||||
r.Get("/emails", g.GetEmailChanges)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user