mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-01-22 12:59:23 -05:00
groupware: add threadSize in email-by-id response
This commit is contained in:
@@ -32,7 +32,7 @@ type Emails struct {
|
||||
}
|
||||
|
||||
// Retrieve specific Emails by their id.
|
||||
func (j *Client) GetEmails(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, ids []string, fetchBodies bool, maxBodyValueBytes uint, markAsSeen bool) (Emails, SessionState, Language, Error) {
|
||||
func (j *Client) GetEmails(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, ids []string, fetchBodies bool, maxBodyValueBytes uint, markAsSeen bool, withThreads bool) (Emails, SessionState, Language, Error) {
|
||||
logger = j.logger("GetEmails", session, logger)
|
||||
|
||||
get := EmailGetCommand{AccountId: accountId, Ids: ids, FetchAllBodyValues: fetchBodies}
|
||||
@@ -50,6 +50,17 @@ func (j *Client) GetEmails(accountId string, session *Session, ctx context.Conte
|
||||
mark := EmailSetCommand{AccountId: accountId, Update: updates}
|
||||
methodCalls = []Invocation{invocation(CommandEmailSet, mark, "0"), invokeGet}
|
||||
}
|
||||
if withThreads {
|
||||
threads := ThreadGetRefCommand{
|
||||
AccountId: accountId,
|
||||
IdsRef: &ResultReference{
|
||||
ResultOf: "1",
|
||||
Name: CommandEmailGet,
|
||||
Path: "/list/*/" + EmailPropertyThreadId,
|
||||
},
|
||||
}
|
||||
methodCalls = append(methodCalls, invocation(CommandThreadGet, threads, "2"))
|
||||
}
|
||||
|
||||
cmd, err := j.request(session, logger, methodCalls...)
|
||||
if err != nil {
|
||||
@@ -73,6 +84,14 @@ func (j *Client) GetEmails(accountId string, session *Session, ctx context.Conte
|
||||
if err != nil {
|
||||
return Emails{}, err
|
||||
}
|
||||
if withThreads {
|
||||
var threads ThreadGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandThreadGet, "2", &threads)
|
||||
if err != nil {
|
||||
return Emails{}, err
|
||||
}
|
||||
setThreadSize(&threads, response.List)
|
||||
}
|
||||
return Emails{Emails: response.List, State: response.State}, nil
|
||||
})
|
||||
}
|
||||
@@ -636,14 +655,19 @@ type CreatedEmail struct {
|
||||
State State `json:"state"`
|
||||
}
|
||||
|
||||
func (j *Client) CreateEmail(accountId string, email EmailCreate, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (CreatedEmail, SessionState, Language, Error) {
|
||||
func (j *Client) CreateEmail(accountId string, email EmailCreate, replaceId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (CreatedEmail, SessionState, Language, Error) {
|
||||
set := EmailSetCommand{
|
||||
AccountId: accountId,
|
||||
Create: map[string]EmailCreate{
|
||||
"c": email,
|
||||
},
|
||||
}
|
||||
if replaceId != "" {
|
||||
set.Destroy = []string{replaceId}
|
||||
}
|
||||
|
||||
cmd, err := j.request(session, logger,
|
||||
invocation(CommandEmailSubmissionSet, EmailSetCommand{
|
||||
AccountId: accountId,
|
||||
Create: map[string]EmailCreate{
|
||||
"c": email,
|
||||
},
|
||||
}, "0"),
|
||||
invocation(CommandEmailSet, set, "0"),
|
||||
)
|
||||
if err != nil {
|
||||
return CreatedEmail{}, "", "", err
|
||||
@@ -899,16 +923,6 @@ type EmailsSummary struct {
|
||||
State State `json:"state"`
|
||||
}
|
||||
|
||||
type EmailWithThread struct {
|
||||
Email
|
||||
ThreadSize int `json:"threadSize,omitzero"`
|
||||
}
|
||||
|
||||
type EmailsWithThreadSummary struct {
|
||||
Emails []EmailWithThread `json:"emails"`
|
||||
State State `json:"state"`
|
||||
}
|
||||
|
||||
var EmailSummaryProperties = []string{
|
||||
EmailPropertyId,
|
||||
EmailPropertyThreadId,
|
||||
@@ -928,21 +942,26 @@ var EmailSummaryProperties = []string{
|
||||
EmailPropertyPreview,
|
||||
}
|
||||
|
||||
func (j *Client) QueryEmailSummaries(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, filter EmailFilterElement, limit uint) (map[string]EmailsSummary, SessionState, Language, Error) {
|
||||
func (j *Client) QueryEmailSummaries(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, filter EmailFilterElement, limit uint, withThreads bool) (map[string]EmailsSummary, SessionState, Language, Error) {
|
||||
logger = j.logger("QueryEmailSummaries", session, logger)
|
||||
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
|
||||
invocations := make([]Invocation, len(uniqueAccountIds)*2)
|
||||
factor := 2
|
||||
if withThreads {
|
||||
factor++
|
||||
}
|
||||
|
||||
invocations := make([]Invocation, len(uniqueAccountIds)*factor)
|
||||
for i, accountId := range uniqueAccountIds {
|
||||
invocations[i*2+0] = invocation(CommandEmailQuery, EmailQueryCommand{
|
||||
invocations[i*factor+0] = invocation(CommandEmailQuery, EmailQueryCommand{
|
||||
AccountId: accountId,
|
||||
Filter: filter,
|
||||
Sort: []EmailComparator{{Property: emailSortByReceivedAt, IsAscending: false}},
|
||||
Limit: limit,
|
||||
//CalculateTotal: false,
|
||||
}, mcid(accountId, "0"))
|
||||
invocations[i*2+1] = invocation(CommandEmailGet, EmailGetRefCommand{
|
||||
invocations[i*factor+1] = invocation(CommandEmailGet, EmailGetRefCommand{
|
||||
AccountId: accountId,
|
||||
IdsRef: &ResultReference{
|
||||
Name: CommandEmailQuery,
|
||||
@@ -951,6 +970,16 @@ func (j *Client) QueryEmailSummaries(accountIds []string, session *Session, ctx
|
||||
},
|
||||
Properties: EmailSummaryProperties,
|
||||
}, mcid(accountId, "1"))
|
||||
if withThreads {
|
||||
invocations[i*factor+2] = invocation(CommandThreadGet, ThreadGetRefCommand{
|
||||
AccountId: accountId,
|
||||
IdsRef: &ResultReference{
|
||||
Name: CommandEmailGet,
|
||||
Path: "/list/*/" + EmailPropertyThreadId,
|
||||
ResultOf: mcid(accountId, "1"),
|
||||
},
|
||||
}, mcid(accountId, "2"))
|
||||
}
|
||||
}
|
||||
cmd, err := j.request(session, logger, invocations...)
|
||||
if err != nil {
|
||||
@@ -968,87 +997,31 @@ func (j *Client) QueryEmailSummaries(accountIds []string, session *Session, ctx
|
||||
if len(response.NotFound) > 0 {
|
||||
// TODO what to do when there are not-found emails here? potentially nothing, they could have been deleted between query and get?
|
||||
}
|
||||
if withThreads {
|
||||
var thread ThreadGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandThreadGet, mcid(accountId, "2"), &thread)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
setThreadSize(&thread, response.List)
|
||||
}
|
||||
|
||||
resp[accountId] = EmailsSummary{Emails: response.List, State: response.State}
|
||||
}
|
||||
return resp, nil
|
||||
})
|
||||
}
|
||||
|
||||
func (j *Client) QueryEmailSummariesWithThreadCount(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, filter EmailFilterElement, limit uint) (map[string]EmailsWithThreadSummary, SessionState, Language, Error) {
|
||||
logger = j.logger("QueryEmailSummariesWithThreadCount", session, logger)
|
||||
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
|
||||
invocations := make([]Invocation, len(uniqueAccountIds)*3)
|
||||
for i, accountId := range uniqueAccountIds {
|
||||
invocations[i*3+0] = invocation(CommandEmailQuery, EmailQueryCommand{
|
||||
AccountId: accountId,
|
||||
Filter: filter,
|
||||
Sort: []EmailComparator{{Property: emailSortByReceivedAt, IsAscending: false}},
|
||||
Limit: limit,
|
||||
//CalculateTotal: false,
|
||||
}, mcid(accountId, "0"))
|
||||
invocations[i*3+1] = invocation(CommandEmailGet, EmailGetRefCommand{
|
||||
AccountId: accountId,
|
||||
IdsRef: &ResultReference{
|
||||
Name: CommandEmailQuery,
|
||||
Path: "/ids/*",
|
||||
ResultOf: mcid(accountId, "0"),
|
||||
},
|
||||
Properties: EmailSummaryProperties,
|
||||
}, mcid(accountId, "1"))
|
||||
invocations[i*3+2] = invocation(CommandThreadGet, ThreadGetRefCommand{
|
||||
AccountId: accountId,
|
||||
IdsRef: &ResultReference{
|
||||
Name: CommandEmailGet,
|
||||
Path: "/list/*/" + EmailPropertyThreadId,
|
||||
ResultOf: mcid(accountId, "1"),
|
||||
},
|
||||
}, mcid(accountId, "2"))
|
||||
func setThreadSize(threads *ThreadGetResponse, emails []Email) {
|
||||
threadSizeById := make(map[string]int, len(threads.List))
|
||||
for _, thread := range threads.List {
|
||||
threadSizeById[thread.Id] = len(thread.EmailIds)
|
||||
}
|
||||
cmd, err := j.request(session, logger, invocations...)
|
||||
if err != nil {
|
||||
return nil, "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (map[string]EmailsWithThreadSummary, Error) {
|
||||
resp := map[string]EmailsWithThreadSummary{}
|
||||
for _, accountId := range uniqueAccountIds {
|
||||
var response EmailGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailGet, mcid(accountId, "1"), &response)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var thread ThreadGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandThreadGet, mcid(accountId, "2"), &thread)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
threadSizeById := make(map[string]int, len(thread.List))
|
||||
for _, thread := range thread.List {
|
||||
threadSizeById[thread.Id] = len(thread.EmailIds)
|
||||
}
|
||||
|
||||
if len(response.NotFound) > 0 {
|
||||
// TODO what to do when there are not-found emails here? potentially nothing, they could have been deleted between query and get?
|
||||
}
|
||||
|
||||
list := make([]EmailWithThread, len(response.List))
|
||||
for i, email := range response.List {
|
||||
ts, ok := threadSizeById[email.ThreadId]
|
||||
if !ok {
|
||||
ts = 1
|
||||
}
|
||||
list[i] = EmailWithThread{
|
||||
Email: email,
|
||||
ThreadSize: ts,
|
||||
}
|
||||
}
|
||||
|
||||
resp[accountId] = EmailsWithThreadSummary{Emails: list, State: response.State}
|
||||
for i := range len(emails) {
|
||||
ts, ok := threadSizeById[emails[i].ThreadId]
|
||||
if !ok {
|
||||
ts = 1
|
||||
}
|
||||
return resp, nil
|
||||
})
|
||||
emails[i].ThreadSize = ts
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2065,6 +2065,10 @@ type Email struct {
|
||||
// example: $threadId
|
||||
ThreadId string `json:"threadId,omitempty"`
|
||||
|
||||
// The number of emails (this one included) that are in the thread this email is in.
|
||||
// Note that this is not part of the JMAP specification, and is only calculated when requested.
|
||||
ThreadSize int `json:"threadSize,omitzero"`
|
||||
|
||||
// The set of Mailbox ids this Email belongs to.
|
||||
//
|
||||
// An Email in the mail store MUST belong to one or more Mailboxes at all times (until it is destroyed).
|
||||
@@ -2179,7 +2183,7 @@ type Email struct {
|
||||
// This is the full MIME structure of the message body, without recursing into message/rfc822 or message/global parts.
|
||||
//
|
||||
// Note that EmailBodyParts may have subParts if they are of type multipart/*.
|
||||
BodyStructure EmailBodyPart `json:"bodyStructure,omitzero"`
|
||||
BodyStructure *EmailBodyPart `json:"bodyStructure,omitzero"`
|
||||
|
||||
// This is a map of partId to an EmailBodyValue object for none, some, or all text/* parts.
|
||||
//
|
||||
@@ -2812,12 +2816,6 @@ type MailboxQueryResponse struct {
|
||||
Limit int `json:"limit,omitzero"`
|
||||
}
|
||||
|
||||
type EmailBodyStructure struct {
|
||||
Type string `json:"type"`
|
||||
PartId string `json:"partId"`
|
||||
Other map[string]any `mapstructure:",remain"`
|
||||
}
|
||||
|
||||
type EmailCreate struct {
|
||||
// The set of Mailbox ids this Email belongs to.
|
||||
//
|
||||
@@ -2866,7 +2864,7 @@ type EmailCreate struct {
|
||||
// This is the full MIME structure of the message body, without recursing into message/rfc822 or message/global parts.
|
||||
//
|
||||
// Note that EmailBodyParts may have subParts if they are of type multipart/*.
|
||||
BodyStructure EmailBodyStructure `json:"bodyStructure"`
|
||||
BodyStructure *EmailBodyPart `json:"bodyStructure,omitempty"`
|
||||
|
||||
// This is a map of partId to an EmailBodyValue object for none, some, or all text/* parts.
|
||||
BodyValues map[string]EmailBodyValue `json:"bodyValues,omitempty"`
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"maps"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -207,23 +206,6 @@ func retrieveResponseMatchParameters[T any](logger *log.Logger, data *Response,
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e EmailBodyStructure) MarshalJSON() ([]byte, error) {
|
||||
m := map[string]any{}
|
||||
maps.Copy(m, e.Other) // do this first to avoid overwriting type and partId
|
||||
m["type"] = e.Type
|
||||
m["partId"] = e.PartId
|
||||
return json.Marshal(m)
|
||||
}
|
||||
|
||||
func (e *EmailBodyStructure) UnmarshalJSON(bs []byte) error {
|
||||
m := map[string]any{}
|
||||
err := json.Unmarshal(bs, &m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return decodeMap(m, e)
|
||||
}
|
||||
|
||||
func (i *Invocation) MarshalJSON() ([]byte, error) {
|
||||
// JMAP requests have a slightly unusual structure since they are not a JSON object
|
||||
// but, instead, a three-element array composed of
|
||||
|
||||
@@ -88,53 +88,6 @@ func TestDeserializeEmailGetResponse(t *testing.T) {
|
||||
require.Equal("cbejozsk1fgcviw7thwzsvtgmf1ep0a3izjoimj02jmtsunpeuwmsaya1yma", email.BlobId)
|
||||
}
|
||||
|
||||
func TestUnmarshallingUnknown(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
const text = `{
|
||||
"subject": "aaa",
|
||||
"bodyStructure": {
|
||||
"type": "a",
|
||||
"partId": "b",
|
||||
"header:x": "yz",
|
||||
"header:a": "bc"
|
||||
}
|
||||
}`
|
||||
|
||||
var target EmailCreate
|
||||
err := json.Unmarshal([]byte(text), &target)
|
||||
|
||||
require.NoError(err)
|
||||
require.Equal("aaa", target.Subject)
|
||||
bs := target.BodyStructure
|
||||
require.Equal("a", bs.Type)
|
||||
require.Equal("b", bs.PartId)
|
||||
require.Contains(bs.Other, "header:x")
|
||||
require.Equal(bs.Other["header:x"], "yz")
|
||||
require.Contains(bs.Other, "header:a")
|
||||
require.Equal(bs.Other["header:a"], "bc")
|
||||
}
|
||||
|
||||
func TestMarshallingUnknown(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
source := EmailCreate{
|
||||
Subject: "aaa",
|
||||
BodyStructure: EmailBodyStructure{
|
||||
Type: "a",
|
||||
PartId: "b",
|
||||
Other: map[string]any{
|
||||
"header:x": "yz",
|
||||
"header:a": "bc",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
result, err := json.Marshal(source)
|
||||
require.NoError(err)
|
||||
require.Equal(`{"subject":"aaa","bodyStructure":{"header:a":"bc","header:x":"yz","partId":"b","type":"a"}}`, string(result))
|
||||
}
|
||||
|
||||
func TestUnmarshallingError(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
|
||||
@@ -204,7 +204,7 @@ func (g *Groupware) GetEmailsById(w http.ResponseWriter, r *http.Request) {
|
||||
if len(ids) == 1 {
|
||||
logger := log.From(l.Str("id", log.SafeString(id)))
|
||||
|
||||
emails, sessionState, lang, jerr := g.jmap.GetEmails(accountId, req.session, req.ctx, logger, req.language(), ids, true, g.maxBodyValueBytes, markAsSeen)
|
||||
emails, sessionState, lang, jerr := g.jmap.GetEmails(accountId, req.session, req.ctx, logger, req.language(), ids, true, g.maxBodyValueBytes, markAsSeen, true)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(jerr)
|
||||
}
|
||||
@@ -220,7 +220,7 @@ func (g *Groupware) GetEmailsById(w http.ResponseWriter, r *http.Request) {
|
||||
} else {
|
||||
logger := log.From(l.Array("ids", log.SafeStringArray(ids)))
|
||||
|
||||
emails, sessionState, lang, jerr := g.jmap.GetEmails(accountId, req.session, req.ctx, logger, req.language(), ids, true, g.maxBodyValueBytes, markAsSeen)
|
||||
emails, sessionState, lang, jerr := g.jmap.GetEmails(accountId, req.session, req.ctx, logger, req.language(), ids, true, g.maxBodyValueBytes, markAsSeen, false)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(jerr)
|
||||
}
|
||||
@@ -270,7 +270,7 @@ func (g *Groupware) GetEmailAttachments(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
l := req.logger.With().Str(logAccountId, log.SafeString(accountId))
|
||||
logger := log.From(l)
|
||||
emails, sessionState, lang, jerr := g.jmap.GetEmails(accountId, req.session, req.ctx, logger, req.language(), []string{id}, false, 0, false)
|
||||
emails, sessionState, 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(jerr)
|
||||
}
|
||||
@@ -298,7 +298,7 @@ func (g *Groupware) GetEmailAttachments(w http.ResponseWriter, r *http.Request)
|
||||
l = contextAppender(l)
|
||||
logger := log.From(l)
|
||||
|
||||
emails, _, lang, jerr := g.jmap.GetEmails(mailAccountId, req.session, req.ctx, logger, req.language(), []string{id}, false, 0, false)
|
||||
emails, _, lang, jerr := g.jmap.GetEmails(mailAccountId, req.session, req.ctx, logger, req.language(), []string{id}, false, 0, false, false)
|
||||
if jerr != nil {
|
||||
return req.apiErrorFromJmap(req.observeJmapError(jerr))
|
||||
}
|
||||
@@ -869,6 +869,7 @@ func (g *Groupware) GetEmailsForAllAccounts(w http.ResponseWriter, r *http.Reque
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
type EmailCreation struct {
|
||||
MailboxIds []string `json:"mailboxIds,omitempty"`
|
||||
Keywords []string `json:"keywords,omitempty"`
|
||||
@@ -879,6 +880,7 @@ type EmailCreation struct {
|
||||
BodyStructure jmap.EmailBodyStructure `json:"bodyStructure"`
|
||||
BodyValues map[string]jmap.EmailBodyValue `json:"bodyValues,omitempty"`
|
||||
}
|
||||
*/
|
||||
|
||||
func (g *Groupware) CreateEmail(w http.ResponseWriter, r *http.Request) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
@@ -890,25 +892,15 @@ func (g *Groupware) CreateEmail(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
logger = log.From(logger.With().Str(logAccountId, log.SafeString(accountId)))
|
||||
|
||||
var body EmailCreation
|
||||
var body jmap.Email
|
||||
err := req.body(&body)
|
||||
if err != nil {
|
||||
return errorResponse(err)
|
||||
}
|
||||
|
||||
mailboxIdsMap := map[string]bool{}
|
||||
for _, mailboxId := range body.MailboxIds {
|
||||
mailboxIdsMap[mailboxId] = true
|
||||
}
|
||||
|
||||
keywordsMap := map[string]bool{}
|
||||
for _, keyword := range body.Keywords {
|
||||
keywordsMap[keyword] = true
|
||||
}
|
||||
|
||||
create := jmap.EmailCreate{
|
||||
MailboxIds: mailboxIdsMap,
|
||||
Keywords: keywordsMap,
|
||||
MailboxIds: body.MailboxIds,
|
||||
Keywords: body.Keywords,
|
||||
From: body.From,
|
||||
Subject: body.Subject,
|
||||
ReceivedAt: body.ReceivedAt,
|
||||
@@ -917,7 +909,46 @@ func (g *Groupware) CreateEmail(w http.ResponseWriter, r *http.Request) {
|
||||
BodyValues: body.BodyValues,
|
||||
}
|
||||
|
||||
created, sessionState, lang, jerr := g.jmap.CreateEmail(accountId, create, req.session, req.ctx, logger, req.language())
|
||||
created, sessionState, lang, jerr := g.jmap.CreateEmail(accountId, create, "", req.session, req.ctx, logger, req.language())
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(jerr)
|
||||
}
|
||||
|
||||
return response(created.Email, sessionState, lang)
|
||||
})
|
||||
}
|
||||
|
||||
func (g *Groupware) ReplaceEmail(w http.ResponseWriter, r *http.Request) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
logger := req.logger
|
||||
|
||||
accountId, gwerr := req.GetAccountIdForMail()
|
||||
if gwerr != nil {
|
||||
return errorResponse(gwerr)
|
||||
}
|
||||
|
||||
replaceId := chi.URLParam(r, UriParamEmailId)
|
||||
|
||||
logger = log.From(logger.With().Str(logAccountId, log.SafeString(accountId)))
|
||||
|
||||
var body jmap.Email
|
||||
err := req.body(&body)
|
||||
if err != nil {
|
||||
return errorResponse(err)
|
||||
}
|
||||
|
||||
create := jmap.EmailCreate{
|
||||
MailboxIds: body.MailboxIds,
|
||||
Keywords: body.Keywords,
|
||||
From: body.From,
|
||||
Subject: body.Subject,
|
||||
ReceivedAt: body.ReceivedAt,
|
||||
SentAt: body.SentAt,
|
||||
BodyStructure: body.BodyStructure,
|
||||
BodyValues: body.BodyValues,
|
||||
}
|
||||
|
||||
created, sessionState, lang, jerr := g.jmap.CreateEmail(accountId, create, replaceId, req.session, req.ctx, logger, req.language())
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(jerr)
|
||||
}
|
||||
@@ -1361,7 +1392,7 @@ func (g *Groupware) RelatedToEmail(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
reqId := req.GetRequestId()
|
||||
getEmailsBefore := time.Now()
|
||||
emails, sessionState, lang, jerr := g.jmap.GetEmails(accountId, req.session, req.ctx, logger, req.language(), []string{id}, true, g.maxBodyValueBytes, false)
|
||||
emails, sessionState, lang, jerr := g.jmap.GetEmails(accountId, req.session, req.ctx, logger, req.language(), []string{id}, true, g.maxBodyValueBytes, false, false)
|
||||
getEmailsDuration := time.Since(getEmailsBefore)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(jerr)
|
||||
@@ -1610,7 +1641,7 @@ type EmailSummary struct {
|
||||
Preview string `json:"preview,omitempty"`
|
||||
}
|
||||
|
||||
func summarizeEmail(accountId string, email jmap.EmailWithThread) EmailSummary {
|
||||
func summarizeEmail(accountId string, email jmap.Email) EmailSummary {
|
||||
return EmailSummary{
|
||||
AccountId: accountId,
|
||||
Id: email.Id,
|
||||
@@ -1635,7 +1666,7 @@ func summarizeEmail(accountId string, email jmap.EmailWithThread) EmailSummary {
|
||||
|
||||
type emailWithAccountId struct {
|
||||
accountId string
|
||||
email jmap.EmailWithThread
|
||||
email jmap.Email
|
||||
}
|
||||
|
||||
// When the request succeeds.
|
||||
@@ -1728,8 +1759,7 @@ func (g *Groupware) GetLatestEmailsSummaryForAllAccounts(w http.ResponseWriter,
|
||||
|
||||
logger := log.From(l)
|
||||
|
||||
// emailsSummariesByAccount, sessionState, lang, jerr := g.jmap.QueryEmailSummaries(allAccountIds, req.session, req.ctx, logger, req.language(), filter, limit)
|
||||
emailsSummariesByAccount, sessionState, lang, jerr := g.jmap.QueryEmailSummariesWithThreadCount(allAccountIds, req.session, req.ctx, logger, req.language(), filter, limit)
|
||||
emailsSummariesByAccount, sessionState, lang, jerr := g.jmap.QueryEmailSummaries(allAccountIds, req.session, req.ctx, logger, req.language(), filter, limit, true)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(jerr)
|
||||
}
|
||||
|
||||
@@ -290,6 +290,7 @@ func (r Request) body(target any) *Error {
|
||||
|
||||
err := json.NewDecoder(body).Decode(target)
|
||||
if err != nil {
|
||||
r.logger.Warn().Msgf("failed to deserialize the request body: %s", err.Error())
|
||||
return r.observedParameterError(ErrorInvalidRequestBody, withSource(&ErrorSource{Pointer: "/"})) // we don't get any details here
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -97,7 +97,7 @@ func (g *Groupware) Route(r chi.Router) {
|
||||
r.Post("/", g.CreateEmail)
|
||||
r.Delete("/", g.DeleteEmails)
|
||||
r.Get("/{emailid}", g.GetEmailsById) // Accept:message/rfc822
|
||||
// r.Put("/{emailid}", g.ReplaceEmail) // TODO
|
||||
r.Put("/{emailid}", g.ReplaceEmail)
|
||||
r.Patch("/{emailid}", g.UpdateEmail)
|
||||
r.Patch("/{emailid}/keywords", g.UpdateEmailKeywords)
|
||||
r.Post("/{emailid}/keywords", g.AddEmailKeywords)
|
||||
|
||||
Reference in New Issue
Block a user