mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-02-12 23:19:08 -06:00
groupware:
* made several email related operations multi-account: QueryEmailSnippets, QueryEmails, QueryEmailsWithSnippets * add GetIdentitiesForAllAccounts * add GetEmailsForAllAccounts * jmap: add CreateIdentity, UpdateIdentity; groupware: add GetIdentityById, AddIdentity, ModifyIdentity * add temporary workaround until Calendars, Tasks, Contacts are implemented in Stalwart when determining the default account for those: use the mail one in the mean time
This commit is contained in:
@@ -187,71 +187,125 @@ func (j *Client) GetEmailsSince(accountId string, session *Session, ctx context.
|
||||
})
|
||||
}
|
||||
|
||||
type EmailSnippetQueryResult struct {
|
||||
Snippets []SearchSnippet `json:"snippets,omitempty"`
|
||||
Total uint `json:"total"`
|
||||
Limit uint `json:"limit,omitzero"`
|
||||
Position uint `json:"position,omitzero"`
|
||||
QueryState State `json:"queryState"`
|
||||
type SearchSnippetWithMeta struct {
|
||||
ReceivedAt time.Time `json:"receivedAt,omitzero"`
|
||||
EmailId string `json:"emailId,omitempty"`
|
||||
SearchSnippet
|
||||
}
|
||||
|
||||
func (j *Client) QueryEmailSnippets(accountId string, filter EmailFilterElement, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, offset uint, limit uint) (EmailSnippetQueryResult, SessionState, Language, Error) {
|
||||
logger = j.loggerParams("QueryEmails", session, logger, func(z zerolog.Context) zerolog.Context {
|
||||
type EmailSnippetQueryResult struct {
|
||||
Snippets []SearchSnippetWithMeta `json:"snippets,omitempty"`
|
||||
Total uint `json:"total"`
|
||||
Limit uint `json:"limit,omitzero"`
|
||||
Position uint `json:"position,omitzero"`
|
||||
QueryState State `json:"queryState"`
|
||||
}
|
||||
|
||||
func (j *Client) QueryEmailSnippets(accountIds []string, filter EmailFilterElement, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, offset uint, limit uint) (map[string]EmailSnippetQueryResult, SessionState, Language, Error) {
|
||||
logger = j.loggerParams("QueryEmailSnippets", session, logger, func(z zerolog.Context) zerolog.Context {
|
||||
return z.Uint(logLimit, limit).Uint(logOffset, offset)
|
||||
})
|
||||
|
||||
query := EmailQueryCommand{
|
||||
AccountId: accountId,
|
||||
Filter: filter,
|
||||
Sort: []EmailComparator{{Property: emailSortByReceivedAt, IsAscending: false}},
|
||||
CollapseThreads: true,
|
||||
CalculateTotal: true,
|
||||
}
|
||||
if offset > 0 {
|
||||
query.Position = offset
|
||||
}
|
||||
if limit > 0 {
|
||||
query.Limit = limit
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
invocations := make([]Invocation, len(uniqueAccountIds)*3)
|
||||
for i, accountId := range uniqueAccountIds {
|
||||
query := EmailQueryCommand{
|
||||
AccountId: accountId,
|
||||
Filter: filter,
|
||||
Sort: []EmailComparator{{Property: emailSortByReceivedAt, IsAscending: false}},
|
||||
CollapseThreads: true,
|
||||
CalculateTotal: true,
|
||||
}
|
||||
if offset > 0 {
|
||||
query.Position = offset
|
||||
}
|
||||
if limit > 0 {
|
||||
query.Limit = limit
|
||||
}
|
||||
|
||||
mails := EmailGetRefCommand{
|
||||
AccountId: accountId,
|
||||
IdsRef: &ResultReference{
|
||||
ResultOf: mcid(accountId, "0"),
|
||||
Name: CommandEmailQuery,
|
||||
Path: "/ids/*",
|
||||
},
|
||||
FetchAllBodyValues: false,
|
||||
MaxBodyValueBytes: 0,
|
||||
Properties: []string{"id", "receivedAt", "sentAt"},
|
||||
}
|
||||
|
||||
snippet := SearchSnippetGetRefCommand{
|
||||
AccountId: accountId,
|
||||
Filter: filter,
|
||||
EmailIdRef: &ResultReference{
|
||||
ResultOf: mcid(accountId, "0"),
|
||||
Name: CommandEmailQuery,
|
||||
Path: "/ids/*",
|
||||
},
|
||||
}
|
||||
|
||||
invocations[i*3+0] = invocation(CommandEmailQuery, query, mcid(accountId, "0"))
|
||||
invocations[i*3+1] = invocation(CommandEmailGet, mails, mcid(accountId, "1"))
|
||||
invocations[i*3+2] = invocation(CommandSearchSnippetGet, snippet, mcid(accountId, "2"))
|
||||
}
|
||||
|
||||
snippet := SearchSnippetGetRefCommand{
|
||||
AccountId: accountId,
|
||||
Filter: filter,
|
||||
EmailIdRef: &ResultReference{
|
||||
ResultOf: "0",
|
||||
Name: CommandEmailQuery,
|
||||
Path: "/ids/*",
|
||||
},
|
||||
}
|
||||
|
||||
cmd, err := j.request(session, logger,
|
||||
invocation(CommandEmailQuery, query, "0"),
|
||||
invocation(CommandSearchSnippetGet, snippet, "1"),
|
||||
)
|
||||
cmd, err := j.request(session, logger, invocations...)
|
||||
if err != nil {
|
||||
return EmailSnippetQueryResult{}, "", "", err
|
||||
return nil, "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (EmailSnippetQueryResult, Error) {
|
||||
var queryResponse EmailQueryResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailQuery, "0", &queryResponse)
|
||||
if err != nil {
|
||||
return EmailSnippetQueryResult{}, err
|
||||
}
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (map[string]EmailSnippetQueryResult, Error) {
|
||||
results := make(map[string]EmailSnippetQueryResult, len(uniqueAccountIds))
|
||||
for _, accountId := range uniqueAccountIds {
|
||||
var queryResponse EmailQueryResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailQuery, mcid(accountId, "0"), &queryResponse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var snippetResponse SearchSnippetGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandSearchSnippetGet, "1", &snippetResponse)
|
||||
if err != nil {
|
||||
return EmailSnippetQueryResult{}, err
|
||||
}
|
||||
var mailResponse EmailGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailGet, mcid(accountId, "1"), &mailResponse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return EmailSnippetQueryResult{
|
||||
Snippets: snippetResponse.List,
|
||||
Total: queryResponse.Total,
|
||||
Limit: queryResponse.Limit,
|
||||
Position: queryResponse.Position,
|
||||
QueryState: queryResponse.QueryState,
|
||||
}, nil
|
||||
var snippetResponse SearchSnippetGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandSearchSnippetGet, mcid(accountId, "2"), &snippetResponse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mailResponseById := structs.Index(mailResponse.List, func(e Email) string { return e.Id })
|
||||
|
||||
snippets := make([]SearchSnippetWithMeta, len(queryResponse.Ids))
|
||||
if len(queryResponse.Ids) > len(snippetResponse.List) {
|
||||
// TODO how do we handle this, if there are more email IDs than snippets?
|
||||
}
|
||||
|
||||
i := 0
|
||||
for _, id := range queryResponse.Ids {
|
||||
if mail, ok := mailResponseById[id]; ok {
|
||||
snippets[i] = SearchSnippetWithMeta{
|
||||
EmailId: id,
|
||||
ReceivedAt: mail.ReceivedAt,
|
||||
SearchSnippet: snippetResponse.List[i],
|
||||
}
|
||||
} else {
|
||||
// TODO how do we handle this, if there is no email result for that id?
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
results[accountId] = EmailSnippetQueryResult{
|
||||
Snippets: snippets,
|
||||
Total: queryResponse.Total,
|
||||
Limit: queryResponse.Limit,
|
||||
Position: queryResponse.Position,
|
||||
QueryState: queryResponse.QueryState,
|
||||
}
|
||||
}
|
||||
return results, nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -263,64 +317,72 @@ type EmailQueryResult struct {
|
||||
QueryState State `json:"queryState"`
|
||||
}
|
||||
|
||||
func (j *Client) QueryEmails(accountId string, filter EmailFilterElement, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, offset uint, limit uint, fetchBodies bool, maxBodyValueBytes uint) (EmailQueryResult, SessionState, Language, Error) {
|
||||
func (j *Client) QueryEmails(accountIds []string, filter EmailFilterElement, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, offset uint, limit uint, fetchBodies bool, maxBodyValueBytes uint) (map[string]EmailQueryResult, SessionState, Language, Error) {
|
||||
logger = j.loggerParams("QueryEmails", session, logger, func(z zerolog.Context) zerolog.Context {
|
||||
return z.Bool(logFetchBodies, fetchBodies)
|
||||
})
|
||||
|
||||
query := EmailQueryCommand{
|
||||
AccountId: accountId,
|
||||
Filter: filter,
|
||||
Sort: []EmailComparator{{Property: emailSortByReceivedAt, IsAscending: false}},
|
||||
CollapseThreads: true,
|
||||
CalculateTotal: true,
|
||||
}
|
||||
if offset > 0 {
|
||||
query.Position = offset
|
||||
}
|
||||
if limit > 0 {
|
||||
query.Limit = limit
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
invocations := make([]Invocation, len(uniqueAccountIds)*2)
|
||||
for i, accountId := range uniqueAccountIds {
|
||||
query := EmailQueryCommand{
|
||||
AccountId: accountId,
|
||||
Filter: filter,
|
||||
Sort: []EmailComparator{{Property: emailSortByReceivedAt, IsAscending: false}},
|
||||
CollapseThreads: true,
|
||||
CalculateTotal: true,
|
||||
}
|
||||
if offset > 0 {
|
||||
query.Position = offset
|
||||
}
|
||||
if limit > 0 {
|
||||
query.Limit = limit
|
||||
}
|
||||
|
||||
mails := EmailGetRefCommand{
|
||||
AccountId: accountId,
|
||||
IdsRef: &ResultReference{
|
||||
ResultOf: mcid(accountId, "0"),
|
||||
Name: CommandEmailQuery,
|
||||
Path: "/ids/*",
|
||||
},
|
||||
FetchAllBodyValues: fetchBodies,
|
||||
MaxBodyValueBytes: maxBodyValueBytes,
|
||||
}
|
||||
|
||||
invocations[i*2+0] = invocation(CommandEmailQuery, query, mcid(accountId, "0"))
|
||||
invocations[i*2+1] = invocation(CommandEmailGet, mails, mcid(accountId, "1"))
|
||||
}
|
||||
|
||||
mails := EmailGetRefCommand{
|
||||
AccountId: accountId,
|
||||
IdsRef: &ResultReference{
|
||||
ResultOf: "0",
|
||||
Name: CommandEmailQuery,
|
||||
Path: "/ids/*",
|
||||
},
|
||||
FetchAllBodyValues: fetchBodies,
|
||||
MaxBodyValueBytes: maxBodyValueBytes,
|
||||
}
|
||||
|
||||
cmd, err := j.request(session, logger,
|
||||
invocation(CommandEmailQuery, query, "0"),
|
||||
invocation(CommandEmailGet, mails, "1"),
|
||||
)
|
||||
cmd, err := j.request(session, logger, invocations...)
|
||||
if err != nil {
|
||||
return EmailQueryResult{}, "", "", err
|
||||
return nil, "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (EmailQueryResult, Error) {
|
||||
var queryResponse EmailQueryResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailQuery, "0", &queryResponse)
|
||||
if err != nil {
|
||||
return EmailQueryResult{}, err
|
||||
}
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (map[string]EmailQueryResult, Error) {
|
||||
results := make(map[string]EmailQueryResult, len(uniqueAccountIds))
|
||||
for _, accountId := range uniqueAccountIds {
|
||||
var queryResponse EmailQueryResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailQuery, mcid(accountId, "0"), &queryResponse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var emailsResponse EmailGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailGet, "1", &emailsResponse)
|
||||
if err != nil {
|
||||
return EmailQueryResult{}, err
|
||||
}
|
||||
var emailsResponse EmailGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailGet, mcid(accountId, "1"), &emailsResponse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return EmailQueryResult{
|
||||
Emails: emailsResponse.List,
|
||||
Total: queryResponse.Total,
|
||||
Limit: queryResponse.Limit,
|
||||
Position: queryResponse.Position,
|
||||
QueryState: queryResponse.QueryState,
|
||||
}, nil
|
||||
results[accountId] = EmailQueryResult{
|
||||
Emails: emailsResponse.List,
|
||||
Total: queryResponse.Total,
|
||||
Limit: queryResponse.Limit,
|
||||
Position: queryResponse.Position,
|
||||
QueryState: queryResponse.QueryState,
|
||||
}
|
||||
}
|
||||
return results, nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -337,104 +399,110 @@ type EmailQueryWithSnippetsResult struct {
|
||||
QueryState State `json:"queryState"`
|
||||
}
|
||||
|
||||
func (j *Client) QueryEmailsWithSnippets(accountId string, filter EmailFilterElement, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, offset uint, limit uint, fetchBodies bool, maxBodyValueBytes uint) (EmailQueryWithSnippetsResult, SessionState, Language, Error) {
|
||||
func (j *Client) QueryEmailsWithSnippets(accountIds []string, filter EmailFilterElement, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, offset uint, limit uint, fetchBodies bool, maxBodyValueBytes uint) (map[string]EmailQueryWithSnippetsResult, SessionState, Language, Error) {
|
||||
logger = j.loggerParams("QueryEmailsWithSnippets", session, logger, func(z zerolog.Context) zerolog.Context {
|
||||
return z.Bool(logFetchBodies, fetchBodies)
|
||||
})
|
||||
|
||||
query := EmailQueryCommand{
|
||||
AccountId: accountId,
|
||||
Filter: filter,
|
||||
Sort: []EmailComparator{{Property: emailSortByReceivedAt, IsAscending: false}},
|
||||
CollapseThreads: false,
|
||||
CalculateTotal: true,
|
||||
}
|
||||
if offset > 0 {
|
||||
query.Position = offset
|
||||
}
|
||||
if limit > 0 {
|
||||
query.Limit = limit
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
invocations := make([]Invocation, len(uniqueAccountIds)*3)
|
||||
for i, accountId := range uniqueAccountIds {
|
||||
query := EmailQueryCommand{
|
||||
AccountId: accountId,
|
||||
Filter: filter,
|
||||
Sort: []EmailComparator{{Property: emailSortByReceivedAt, IsAscending: false}},
|
||||
CollapseThreads: false,
|
||||
CalculateTotal: true,
|
||||
}
|
||||
if offset > 0 {
|
||||
query.Position = offset
|
||||
}
|
||||
if limit > 0 {
|
||||
query.Limit = limit
|
||||
}
|
||||
|
||||
snippet := SearchSnippetGetRefCommand{
|
||||
AccountId: accountId,
|
||||
Filter: filter,
|
||||
EmailIdRef: &ResultReference{
|
||||
ResultOf: mcid(accountId, "0"),
|
||||
Name: CommandEmailQuery,
|
||||
Path: "/ids/*",
|
||||
},
|
||||
}
|
||||
|
||||
mails := EmailGetRefCommand{
|
||||
AccountId: accountId,
|
||||
IdsRef: &ResultReference{
|
||||
ResultOf: mcid(accountId, "0"),
|
||||
Name: CommandEmailQuery,
|
||||
Path: "/ids/*",
|
||||
},
|
||||
FetchAllBodyValues: fetchBodies,
|
||||
MaxBodyValueBytes: maxBodyValueBytes,
|
||||
}
|
||||
invocations[i*3+0] = invocation(CommandEmailQuery, query, mcid(accountId, "0"))
|
||||
invocations[i*3+1] = invocation(CommandSearchSnippetGet, snippet, mcid(accountId, "1"))
|
||||
invocations[i*3+2] = invocation(CommandEmailGet, mails, mcid(accountId, "2"))
|
||||
}
|
||||
|
||||
snippet := SearchSnippetGetRefCommand{
|
||||
AccountId: accountId,
|
||||
Filter: filter,
|
||||
EmailIdRef: &ResultReference{
|
||||
ResultOf: "0",
|
||||
Name: CommandEmailQuery,
|
||||
Path: "/ids/*",
|
||||
},
|
||||
}
|
||||
|
||||
mails := EmailGetRefCommand{
|
||||
AccountId: accountId,
|
||||
IdsRef: &ResultReference{
|
||||
ResultOf: "0",
|
||||
Name: CommandEmailQuery,
|
||||
Path: "/ids/*",
|
||||
},
|
||||
FetchAllBodyValues: fetchBodies,
|
||||
MaxBodyValueBytes: maxBodyValueBytes,
|
||||
}
|
||||
|
||||
cmd, err := j.request(session, logger,
|
||||
invocation(CommandEmailQuery, query, "0"),
|
||||
invocation(CommandSearchSnippetGet, snippet, "1"),
|
||||
invocation(CommandEmailGet, mails, "2"),
|
||||
)
|
||||
|
||||
cmd, err := j.request(session, logger, invocations...)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Send()
|
||||
return EmailQueryWithSnippetsResult{}, "", "", simpleError(err, JmapErrorInvalidJmapRequestPayload)
|
||||
return nil, "", "", simpleError(err, JmapErrorInvalidJmapRequestPayload)
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (EmailQueryWithSnippetsResult, Error) {
|
||||
var queryResponse EmailQueryResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailQuery, "0", &queryResponse)
|
||||
if err != nil {
|
||||
return EmailQueryWithSnippetsResult{}, err
|
||||
}
|
||||
|
||||
var snippetResponse SearchSnippetGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandSearchSnippetGet, "1", &snippetResponse)
|
||||
if err != nil {
|
||||
return EmailQueryWithSnippetsResult{}, err
|
||||
}
|
||||
|
||||
var emailsResponse EmailGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailGet, "2", &emailsResponse)
|
||||
if err != nil {
|
||||
return EmailQueryWithSnippetsResult{}, err
|
||||
}
|
||||
|
||||
snippetsById := map[string][]SearchSnippet{}
|
||||
for _, snippet := range snippetResponse.List {
|
||||
list, ok := snippetsById[snippet.EmailId]
|
||||
if !ok {
|
||||
list = []SearchSnippet{}
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (map[string]EmailQueryWithSnippetsResult, Error) {
|
||||
result := make(map[string]EmailQueryWithSnippetsResult, len(uniqueAccountIds))
|
||||
for _, accountId := range uniqueAccountIds {
|
||||
var queryResponse EmailQueryResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailQuery, mcid(accountId, "0"), &queryResponse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
snippetsById[snippet.EmailId] = append(list, snippet)
|
||||
}
|
||||
|
||||
results := []EmailWithSnippets{}
|
||||
for _, email := range emailsResponse.List {
|
||||
snippets, ok := snippetsById[email.Id]
|
||||
if !ok {
|
||||
snippets = []SearchSnippet{}
|
||||
var snippetResponse SearchSnippetGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandSearchSnippetGet, mcid(accountId, "1"), &snippetResponse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
results = append(results, EmailWithSnippets{
|
||||
Email: email,
|
||||
Snippets: snippets,
|
||||
})
|
||||
}
|
||||
|
||||
return EmailQueryWithSnippetsResult{
|
||||
Results: results,
|
||||
Total: queryResponse.Total,
|
||||
Limit: queryResponse.Limit,
|
||||
Position: queryResponse.Position,
|
||||
QueryState: queryResponse.QueryState,
|
||||
}, nil
|
||||
var emailsResponse EmailGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailGet, mcid(accountId, "2"), &emailsResponse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
snippetsById := map[string][]SearchSnippet{}
|
||||
for _, snippet := range snippetResponse.List {
|
||||
list, ok := snippetsById[snippet.EmailId]
|
||||
if !ok {
|
||||
list = []SearchSnippet{}
|
||||
}
|
||||
snippetsById[snippet.EmailId] = append(list, snippet)
|
||||
}
|
||||
|
||||
results := []EmailWithSnippets{}
|
||||
for _, email := range emailsResponse.List {
|
||||
snippets, ok := snippetsById[email.Id]
|
||||
if !ok {
|
||||
snippets = []SearchSnippet{}
|
||||
}
|
||||
results = append(results, EmailWithSnippets{
|
||||
Email: email,
|
||||
Snippets: snippets,
|
||||
})
|
||||
}
|
||||
|
||||
result[accountId] = EmailQueryWithSnippetsResult{
|
||||
Results: results,
|
||||
Total: queryResponse.Total,
|
||||
Limit: queryResponse.Limit,
|
||||
Position: queryResponse.Position,
|
||||
QueryState: queryResponse.QueryState,
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -13,9 +13,8 @@ type Identities struct {
|
||||
State State `json:"state"`
|
||||
}
|
||||
|
||||
// https://jmap.io/spec-mail.html#identityget
|
||||
func (j *Client) GetIdentity(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (Identities, SessionState, Language, Error) {
|
||||
logger = j.logger("GetIdentity", session, logger)
|
||||
func (j *Client) GetAllIdentities(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (Identities, SessionState, Language, Error) {
|
||||
logger = j.logger("GetAllIdentities", session, logger)
|
||||
cmd, err := j.request(session, logger, invocation(CommandIdentityGet, IdentityGetCommand{AccountId: accountId}, "0"))
|
||||
if err != nil {
|
||||
return Identities{}, "", "", err
|
||||
@@ -33,16 +32,35 @@ func (j *Client) GetIdentity(accountId string, session *Session, ctx context.Con
|
||||
})
|
||||
}
|
||||
|
||||
func (j *Client) GetIdentities(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, identityIds []string) (Identities, SessionState, Language, Error) {
|
||||
logger = j.logger("GetIdentities", session, logger)
|
||||
cmd, err := j.request(session, logger, invocation(CommandIdentityGet, IdentityGetCommand{AccountId: accountId, Ids: identityIds}, "0"))
|
||||
if err != nil {
|
||||
return Identities{}, "", "", err
|
||||
}
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (Identities, Error) {
|
||||
var response IdentityGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandIdentityGet, "0", &response)
|
||||
if err != nil {
|
||||
return Identities{}, err
|
||||
}
|
||||
return Identities{
|
||||
Identities: response.List,
|
||||
State: response.State,
|
||||
}, nil
|
||||
})
|
||||
}
|
||||
|
||||
type IdentitiesGetResponse struct {
|
||||
Identities map[string][]Identity `json:"identities,omitempty"`
|
||||
NotFound []string `json:"notFound,omitempty"`
|
||||
State State `json:"state"`
|
||||
}
|
||||
|
||||
func (j *Client) GetIdentities(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (IdentitiesGetResponse, SessionState, Language, Error) {
|
||||
func (j *Client) GetIdentitiesForAllAccounts(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (IdentitiesGetResponse, SessionState, Language, Error) {
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
|
||||
logger = j.logger("GetIdentities", session, logger)
|
||||
logger = j.logger("GetIdentitiesForAllAccounts", session, logger)
|
||||
|
||||
calls := make([]Invocation, len(uniqueAccountIds))
|
||||
for i, accountId := range uniqueAccountIds {
|
||||
@@ -129,3 +147,55 @@ func (j *Client) GetIdentitiesAndMailboxes(mailboxAccountId string, accountIds [
|
||||
}, nil
|
||||
})
|
||||
}
|
||||
|
||||
func (j *Client) CreateIdentity(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, identity Identity) (State, SessionState, Language, Error) {
|
||||
logger = j.logger("CreateIdentity", session, logger)
|
||||
cmd, err := j.request(session, logger, invocation(CommandIdentitySet, IdentitySetCommand{
|
||||
AccountId: accountId,
|
||||
Create: map[string]Identity{
|
||||
"c": identity,
|
||||
},
|
||||
}, "0"))
|
||||
if err != nil {
|
||||
return "", "", "", err
|
||||
}
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (State, Error) {
|
||||
var response IdentitySetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandIdentitySet, "0", &response)
|
||||
if err != nil {
|
||||
return response.NewState, err
|
||||
}
|
||||
setErr, notok := response.NotCreated["c"]
|
||||
if notok {
|
||||
logger.Error().Msgf("%T.NotCreated returned an error %v", response, setErr)
|
||||
return "", setErrorError(setErr, IdentityType)
|
||||
}
|
||||
return response.NewState, nil
|
||||
})
|
||||
}
|
||||
|
||||
func (j *Client) UpdateIdentity(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, identity Identity) (State, SessionState, Language, Error) {
|
||||
logger = j.logger("UpdateIdentity", session, logger)
|
||||
cmd, err := j.request(session, logger, invocation(CommandIdentitySet, IdentitySetCommand{
|
||||
AccountId: accountId,
|
||||
Update: map[string]PatchObject{
|
||||
"c": identity.AsPatch(),
|
||||
},
|
||||
}, "0"))
|
||||
if err != nil {
|
||||
return "", "", "", err
|
||||
}
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (State, Error) {
|
||||
var response IdentitySetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandIdentitySet, "0", &response)
|
||||
if err != nil {
|
||||
return response.NewState, err
|
||||
}
|
||||
setErr, notok := response.NotCreated["c"]
|
||||
if notok {
|
||||
logger.Error().Msgf("%T.NotCreated returned an error %v", response, setErr)
|
||||
return "", setErrorError(setErr, IdentityType)
|
||||
}
|
||||
return response.NewState, nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -724,7 +724,7 @@ func TestEmails(t *testing.T) {
|
||||
|
||||
{
|
||||
{
|
||||
resp, sessionState, _, err := s.client.GetIdentity(accountId, s.session, s.ctx, s.logger, "")
|
||||
resp, sessionState, _, err := s.client.GetAllIdentities(accountId, s.session, s.ctx, s.logger, "")
|
||||
require.NoError(err)
|
||||
require.Equal(s.session.State, sessionState)
|
||||
require.Len(resp.Identities, 1)
|
||||
|
||||
@@ -3025,9 +3025,29 @@ type IdentityGetCommand struct {
|
||||
Ids []string `json:"ids,omitempty"`
|
||||
}
|
||||
|
||||
type IdentitySetCommand struct {
|
||||
AccountId string `json:"accountId"`
|
||||
IfInState string `json:"ifInState,omitempty"`
|
||||
Create map[string]Identity `json:"create,omitempty"`
|
||||
Update map[string]PatchObject `json:"update,omitempty"`
|
||||
Destroy []string `json:"destroy,omitempty"`
|
||||
}
|
||||
|
||||
type IdentitySetResponse struct {
|
||||
AccountId string `json:"accountId"`
|
||||
OldState State `json:"oldState,omitempty"`
|
||||
NewState State `json:"newState,omitempty"`
|
||||
Created map[string]Identity `json:"created,omitempty"`
|
||||
Updated map[string]Identity `json:"updated,omitempty"`
|
||||
Destroyed []string `json:"destroyed,omitempty"`
|
||||
NotCreated map[string]SetError `json:"notCreated,omitempty"`
|
||||
NotUpdated map[string]SetError `json:"notUpdated,omitempty"`
|
||||
NotDestroyed map[string]SetError `json:"notDestroyed,omitempty"`
|
||||
}
|
||||
|
||||
type Identity struct {
|
||||
// The id of the Identity.
|
||||
Id string `json:"id"`
|
||||
Id string `json:"id,omitempty"`
|
||||
|
||||
// The “From” name the client SHOULD use when creating a new Email from this Identity.
|
||||
Name string `json:"name,omitempty"`
|
||||
@@ -3043,13 +3063,13 @@ type Identity struct {
|
||||
ReplyTo string `json:"replyTo,omitempty"`
|
||||
|
||||
// The Bcc value the client SHOULD set when creating a new Email from this Identity.
|
||||
Bcc []EmailAddress `json:"bcc,omitempty"`
|
||||
Bcc *[]EmailAddress `json:"bcc,omitempty"`
|
||||
|
||||
// A signature the client SHOULD insert into new plaintext messages that will be sent from
|
||||
// this Identity.
|
||||
//
|
||||
// Clients MAY ignore this and/or combine this with a client-specific signature preference.
|
||||
TextSignature string `json:"textSignature,omitempty"`
|
||||
TextSignature *string `json:"textSignature,omitempty"`
|
||||
|
||||
// A signature the client SHOULD insert into new HTML messages that will be sent from this
|
||||
// Identity.
|
||||
@@ -3057,7 +3077,7 @@ type Identity struct {
|
||||
// This text MUST be an HTML snippet to be inserted into the <body></body> section of the HTML.
|
||||
//
|
||||
// Clients MAY ignore this and/or combine this with a client-specific signature preference.
|
||||
HtmlSignature string `json:"htmlSignature,omitempty"`
|
||||
HtmlSignature *string `json:"htmlSignature,omitempty"`
|
||||
|
||||
// Is the user allowed to delete this Identity?
|
||||
//
|
||||
@@ -3065,7 +3085,30 @@ type Identity struct {
|
||||
//
|
||||
// Attempts to destroy an Identity with mayDelete: false will be rejected with a standard
|
||||
// forbidden SetError.
|
||||
MayDelete bool `json:"mayDelete"`
|
||||
MayDelete bool `json:"mayDelete,omitzero"`
|
||||
}
|
||||
|
||||
func (i Identity) AsPatch() PatchObject {
|
||||
p := PatchObject{}
|
||||
if i.Name != "" {
|
||||
p["name"] = i.Name
|
||||
}
|
||||
if i.Email != "" {
|
||||
p["email"] = i.Email
|
||||
}
|
||||
if i.ReplyTo != "" {
|
||||
p["replyTo"] = i.ReplyTo
|
||||
}
|
||||
if i.Bcc != nil {
|
||||
p["bcc"] = i.Bcc
|
||||
}
|
||||
if i.TextSignature != nil {
|
||||
p["textSignature"] = i.TextSignature
|
||||
}
|
||||
if i.HtmlSignature != nil {
|
||||
p["htmlSignature"] = i.HtmlSignature
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
type IdentityGetResponse struct {
|
||||
@@ -4639,6 +4682,7 @@ const (
|
||||
CommandMailboxQuery Command = "Mailbox/query"
|
||||
CommandMailboxChanges Command = "Mailbox/changes"
|
||||
CommandIdentityGet Command = "Identity/get"
|
||||
CommandIdentitySet Command = "Identity/set"
|
||||
CommandVacationResponseGet Command = "VacationResponse/get"
|
||||
CommandVacationResponseSet Command = "VacationResponse/set"
|
||||
CommandSearchSnippetGet Command = "SearchSnippet/get"
|
||||
@@ -4660,6 +4704,7 @@ var CommandResponseTypeMap = map[Command]func() any{
|
||||
CommandEmailSubmissionSet: func() any { return EmailSubmissionSetResponse{} },
|
||||
CommandThreadGet: func() any { return ThreadGetResponse{} },
|
||||
CommandIdentityGet: func() any { return IdentityGetResponse{} },
|
||||
CommandIdentitySet: func() any { return IdentitySetResponse{} },
|
||||
CommandVacationResponseGet: func() any { return VacationResponseGetResponse{} },
|
||||
CommandVacationResponseSet: func() any { return VacationResponseSetResponse{} },
|
||||
CommandSearchSnippetGet: func() any { return SearchSnippetGetResponse{} },
|
||||
|
||||
@@ -66,3 +66,18 @@ func Map[E any, R any](source []E, indexer func(E) R) []R {
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func MapN[E any, R any](source []E, indexer func(E) *R) []R {
|
||||
if source == nil {
|
||||
var zero []R
|
||||
return zero
|
||||
}
|
||||
result := []R{}
|
||||
for _, e := range source {
|
||||
opt := indexer(e)
|
||||
if opt != nil {
|
||||
result = append(result, *opt)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user