mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-01-22 21:10:44 -05:00
groupware: add quota API + add support for Accept-Language and Content-Language
This commit is contained in:
@@ -9,7 +9,7 @@ import (
|
||||
)
|
||||
|
||||
type ApiClient interface {
|
||||
Command(ctx context.Context, logger *log.Logger, session *Session, request Request) ([]byte, Error)
|
||||
Command(ctx context.Context, logger *log.Logger, session *Session, request Request, acceptLanguage string) ([]byte, Language, Error)
|
||||
io.Closer
|
||||
}
|
||||
|
||||
@@ -33,8 +33,8 @@ type SessionClient interface {
|
||||
}
|
||||
|
||||
type BlobClient interface {
|
||||
UploadBinary(ctx context.Context, logger *log.Logger, session *Session, uploadUrl string, endpoint string, contentType string, content io.Reader) (UploadedBlob, Error)
|
||||
DownloadBinary(ctx context.Context, logger *log.Logger, session *Session, downloadUrl string, endpoint string) (*BlobDownload, Error)
|
||||
UploadBinary(ctx context.Context, logger *log.Logger, session *Session, uploadUrl string, endpoint string, contentType string, acceptLanguage string, content io.Reader) (UploadedBlob, Language, Error)
|
||||
DownloadBinary(ctx context.Context, logger *log.Logger, session *Session, downloadUrl string, endpoint string, acceptLanguage string) (*BlobDownload, Language, Error)
|
||||
io.Closer
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ type BlobResponse struct {
|
||||
State State `json:"state,omitempty"`
|
||||
}
|
||||
|
||||
func (j *Client) GetBlobMetadata(accountId string, session *Session, ctx context.Context, logger *log.Logger, id string) (BlobResponse, SessionState, Error) {
|
||||
func (j *Client) GetBlobMetadata(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, id string) (BlobResponse, SessionState, Language, Error) {
|
||||
cmd, jerr := j.request(session, logger,
|
||||
invocation(CommandBlobGet, BlobGetCommand{
|
||||
AccountId: accountId,
|
||||
@@ -24,10 +24,10 @@ func (j *Client) GetBlobMetadata(accountId string, session *Session, ctx context
|
||||
}, "0"),
|
||||
)
|
||||
if jerr != nil {
|
||||
return BlobResponse{}, "", jerr
|
||||
return BlobResponse{}, "", "", jerr
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, func(body *Response) (BlobResponse, Error) {
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (BlobResponse, Error) {
|
||||
var response BlobGetResponse
|
||||
err := retrieveResponseMatchParameters(logger, body, CommandBlobGet, "0", &response)
|
||||
if err != nil {
|
||||
@@ -51,14 +51,14 @@ type UploadedBlob struct {
|
||||
State State `json:"state"`
|
||||
}
|
||||
|
||||
func (j *Client) UploadBlobStream(accountId string, session *Session, ctx context.Context, logger *log.Logger, contentType string, body io.Reader) (UploadedBlob, Error) {
|
||||
func (j *Client) UploadBlobStream(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, contentType string, body io.Reader) (UploadedBlob, Language, Error) {
|
||||
logger = log.From(logger.With().Str(logEndpoint, session.UploadEndpoint))
|
||||
// TODO(pbleser-oc) use a library for proper URL template parsing
|
||||
uploadUrl := strings.ReplaceAll(session.UploadUrlTemplate, "{accountId}", accountId)
|
||||
return j.blob.UploadBinary(ctx, logger, session, uploadUrl, session.UploadEndpoint, contentType, body)
|
||||
return j.blob.UploadBinary(ctx, logger, session, uploadUrl, session.UploadEndpoint, contentType, acceptLanguage, body)
|
||||
}
|
||||
|
||||
func (j *Client) DownloadBlobStream(accountId string, blobId string, name string, typ string, session *Session, ctx context.Context, logger *log.Logger) (*BlobDownload, Error) {
|
||||
func (j *Client) DownloadBlobStream(accountId string, blobId string, name string, typ string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (*BlobDownload, Language, Error) {
|
||||
logger = log.From(logger.With().Str(logEndpoint, session.DownloadEndpoint))
|
||||
// TODO(pbleser-oc) use a library for proper URL template parsing
|
||||
downloadUrl := session.DownloadUrlTemplate
|
||||
@@ -67,10 +67,10 @@ func (j *Client) DownloadBlobStream(accountId string, blobId string, name string
|
||||
downloadUrl = strings.ReplaceAll(downloadUrl, "{name}", name)
|
||||
downloadUrl = strings.ReplaceAll(downloadUrl, "{type}", typ)
|
||||
logger = log.From(logger.With().Str(logDownloadUrl, downloadUrl).Str(logBlobId, blobId))
|
||||
return j.blob.DownloadBinary(ctx, logger, session, downloadUrl, session.DownloadEndpoint)
|
||||
return j.blob.DownloadBinary(ctx, logger, session, downloadUrl, session.DownloadEndpoint, acceptLanguage)
|
||||
}
|
||||
|
||||
func (j *Client) UploadBlob(accountId string, session *Session, ctx context.Context, logger *log.Logger, data []byte, contentType string) (UploadedBlob, SessionState, Error) {
|
||||
func (j *Client) UploadBlob(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, data []byte, contentType string) (UploadedBlob, SessionState, Language, Error) {
|
||||
encoded := base64.StdEncoding.EncodeToString(data)
|
||||
|
||||
upload := BlobUploadCommand{
|
||||
@@ -100,10 +100,10 @@ func (j *Client) UploadBlob(accountId string, session *Session, ctx context.Cont
|
||||
invocation(CommandBlobGet, getHash, "1"),
|
||||
)
|
||||
if jerr != nil {
|
||||
return UploadedBlob{}, "", jerr
|
||||
return UploadedBlob{}, "", "", jerr
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, func(body *Response) (UploadedBlob, Error) {
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (UploadedBlob, Error) {
|
||||
var uploadResponse BlobUploadResponse
|
||||
err := retrieveResponseMatchParameters(logger, body, CommandBlobUpload, "0", &uploadResponse)
|
||||
if err != nil {
|
||||
|
||||
@@ -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, ids []string, fetchBodies bool, maxBodyValueBytes uint) (Emails, SessionState, Error) {
|
||||
func (j *Client) GetEmails(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, ids []string, fetchBodies bool, maxBodyValueBytes uint) (Emails, SessionState, Language, Error) {
|
||||
logger = j.logger("GetEmails", session, logger)
|
||||
|
||||
get := EmailGetCommand{AccountId: accountId, Ids: ids, FetchAllBodyValues: fetchBodies}
|
||||
@@ -43,9 +43,9 @@ func (j *Client) GetEmails(accountId string, session *Session, ctx context.Conte
|
||||
cmd, err := j.request(session, logger, invocation(CommandEmailGet, get, "0"))
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Send()
|
||||
return Emails{}, "", simpleError(err, JmapErrorInvalidJmapRequestPayload)
|
||||
return Emails{}, "", "", simpleError(err, JmapErrorInvalidJmapRequestPayload)
|
||||
}
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, func(body *Response) (Emails, Error) {
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (Emails, Error) {
|
||||
var response EmailGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailGet, "0", &response)
|
||||
if err != nil {
|
||||
@@ -56,7 +56,7 @@ func (j *Client) GetEmails(accountId string, session *Session, ctx context.Conte
|
||||
}
|
||||
|
||||
// Retrieve all the Emails in a given Mailbox by its id.
|
||||
func (j *Client) GetAllEmailsInMailbox(accountId string, session *Session, ctx context.Context, logger *log.Logger, mailboxId string, offset uint, limit uint, fetchBodies bool, maxBodyValueBytes uint) (Emails, SessionState, Error) {
|
||||
func (j *Client) GetAllEmailsInMailbox(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, mailboxId string, offset uint, limit uint, fetchBodies bool, maxBodyValueBytes uint) (Emails, SessionState, Language, Error) {
|
||||
logger = j.loggerParams("GetAllEmailsInMailbox", session, logger, func(z zerolog.Context) zerolog.Context {
|
||||
return z.Bool(logFetchBodies, fetchBodies).Uint(logOffset, offset).Uint(logLimit, limit)
|
||||
})
|
||||
@@ -89,10 +89,10 @@ func (j *Client) GetAllEmailsInMailbox(accountId string, session *Session, ctx c
|
||||
invocation(CommandEmailGet, get, "1"),
|
||||
)
|
||||
if err != nil {
|
||||
return Emails{}, "", err
|
||||
return Emails{}, "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, func(body *Response) (Emails, Error) {
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (Emails, Error) {
|
||||
var queryResponse EmailQueryResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailQuery, "0", &queryResponse)
|
||||
if err != nil {
|
||||
@@ -116,7 +116,7 @@ func (j *Client) GetAllEmailsInMailbox(accountId string, session *Session, ctx c
|
||||
}
|
||||
|
||||
// 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, sinceState string, fetchBodies bool, maxBodyValueBytes uint, maxChanges uint) (MailboxChanges, SessionState, Error) {
|
||||
func (j *Client) GetEmailsSince(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, sinceState string, fetchBodies bool, maxBodyValueBytes uint, maxChanges uint) (MailboxChanges, SessionState, Language, Error) {
|
||||
logger = j.loggerParams("GetEmailsSince", session, logger, func(z zerolog.Context) zerolog.Context {
|
||||
return z.Bool(logFetchBodies, fetchBodies).Str(logSinceState, sinceState)
|
||||
})
|
||||
@@ -152,10 +152,10 @@ func (j *Client) GetEmailsSince(accountId string, session *Session, ctx context.
|
||||
invocation(CommandEmailGet, getUpdated, "2"),
|
||||
)
|
||||
if err != nil {
|
||||
return MailboxChanges{}, "", simpleError(err, JmapErrorInvalidJmapRequestPayload)
|
||||
return MailboxChanges{}, "", "", simpleError(err, JmapErrorInvalidJmapRequestPayload)
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, func(body *Response) (MailboxChanges, Error) {
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (MailboxChanges, Error) {
|
||||
var changesResponse EmailChangesResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailChanges, "0", &changesResponse)
|
||||
if err != nil {
|
||||
@@ -195,7 +195,7 @@ type EmailSnippetQueryResult struct {
|
||||
QueryState State `json:"queryState"`
|
||||
}
|
||||
|
||||
func (j *Client) QueryEmailSnippets(accountId string, filter EmailFilterElement, session *Session, ctx context.Context, logger *log.Logger, offset uint, limit uint) (EmailSnippetQueryResult, SessionState, Error) {
|
||||
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 {
|
||||
return z.Uint(logLimit, limit).Uint(logOffset, offset)
|
||||
})
|
||||
@@ -229,10 +229,10 @@ func (j *Client) QueryEmailSnippets(accountId string, filter EmailFilterElement,
|
||||
invocation(CommandSearchSnippetGet, snippet, "1"),
|
||||
)
|
||||
if err != nil {
|
||||
return EmailSnippetQueryResult{}, "", err
|
||||
return EmailSnippetQueryResult{}, "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, func(body *Response) (EmailSnippetQueryResult, Error) {
|
||||
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 {
|
||||
@@ -264,7 +264,7 @@ type EmailQueryResult struct {
|
||||
QueryState State `json:"queryState"`
|
||||
}
|
||||
|
||||
func (j *Client) QueryEmails(accountId string, filter EmailFilterElement, session *Session, ctx context.Context, logger *log.Logger, offset uint, limit uint, fetchBodies bool, maxBodyValueBytes uint) (EmailQueryResult, SessionState, Error) {
|
||||
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) {
|
||||
logger = j.loggerParams("QueryEmails", session, logger, func(z zerolog.Context) zerolog.Context {
|
||||
return z.Bool(logFetchBodies, fetchBodies)
|
||||
})
|
||||
@@ -299,10 +299,10 @@ func (j *Client) QueryEmails(accountId string, filter EmailFilterElement, sessio
|
||||
invocation(CommandEmailGet, mails, "1"),
|
||||
)
|
||||
if err != nil {
|
||||
return EmailQueryResult{}, "", err
|
||||
return EmailQueryResult{}, "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, func(body *Response) (EmailQueryResult, Error) {
|
||||
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 {
|
||||
@@ -339,7 +339,7 @@ type EmailQueryWithSnippetsResult struct {
|
||||
QueryState State `json:"queryState"`
|
||||
}
|
||||
|
||||
func (j *Client) QueryEmailsWithSnippets(accountId string, filter EmailFilterElement, session *Session, ctx context.Context, logger *log.Logger, offset uint, limit uint, fetchBodies bool, maxBodyValueBytes uint) (EmailQueryWithSnippetsResult, SessionState, Error) {
|
||||
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) {
|
||||
logger = j.loggerParams("QueryEmailsWithSnippets", session, logger, func(z zerolog.Context) zerolog.Context {
|
||||
return z.Bool(logFetchBodies, fetchBodies)
|
||||
})
|
||||
@@ -387,10 +387,10 @@ func (j *Client) QueryEmailsWithSnippets(accountId string, filter EmailFilterEle
|
||||
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Send()
|
||||
return EmailQueryWithSnippetsResult{}, "", simpleError(err, JmapErrorInvalidJmapRequestPayload)
|
||||
return EmailQueryWithSnippetsResult{}, "", "", simpleError(err, JmapErrorInvalidJmapRequestPayload)
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, func(body *Response) (EmailQueryWithSnippetsResult, Error) {
|
||||
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 {
|
||||
@@ -448,7 +448,7 @@ type UploadedEmail struct {
|
||||
Sha512 string `json:"sha:512"`
|
||||
}
|
||||
|
||||
func (j *Client) ImportEmail(accountId string, session *Session, ctx context.Context, logger *log.Logger, data []byte) (UploadedEmail, SessionState, Error) {
|
||||
func (j *Client) ImportEmail(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, data []byte) (UploadedEmail, SessionState, Language, Error) {
|
||||
encoded := base64.StdEncoding.EncodeToString(data)
|
||||
|
||||
upload := BlobUploadCommand{
|
||||
@@ -478,10 +478,10 @@ func (j *Client) ImportEmail(accountId string, session *Session, ctx context.Con
|
||||
invocation(CommandBlobGet, getHash, "1"),
|
||||
)
|
||||
if err != nil {
|
||||
return UploadedEmail{}, "", simpleError(err, JmapErrorInvalidJmapRequestPayload)
|
||||
return UploadedEmail{}, "", "", simpleError(err, JmapErrorInvalidJmapRequestPayload)
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, func(body *Response) (UploadedEmail, Error) {
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (UploadedEmail, Error) {
|
||||
var uploadResponse BlobUploadResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandBlobUpload, "0", &uploadResponse)
|
||||
if err != nil {
|
||||
@@ -526,7 +526,7 @@ type CreatedEmail struct {
|
||||
State State `json:"state"`
|
||||
}
|
||||
|
||||
func (j *Client) CreateEmail(accountId string, email EmailCreate, session *Session, ctx context.Context, logger *log.Logger) (CreatedEmail, SessionState, Error) {
|
||||
func (j *Client) CreateEmail(accountId string, email EmailCreate, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (CreatedEmail, SessionState, Language, Error) {
|
||||
cmd, err := j.request(session, logger,
|
||||
invocation(CommandEmailSubmissionSet, EmailSetCommand{
|
||||
AccountId: accountId,
|
||||
@@ -536,10 +536,10 @@ func (j *Client) CreateEmail(accountId string, email EmailCreate, session *Sessi
|
||||
}, "0"),
|
||||
)
|
||||
if err != nil {
|
||||
return CreatedEmail{}, "", err
|
||||
return CreatedEmail{}, "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, func(body *Response) (CreatedEmail, Error) {
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (CreatedEmail, Error) {
|
||||
var setResponse EmailSetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailSet, "0", &setResponse)
|
||||
if err != nil {
|
||||
@@ -584,7 +584,7 @@ type UpdatedEmails struct {
|
||||
// To create drafts, use the CreateEmail function instead.
|
||||
//
|
||||
// To delete mails, use the DeleteEmails function instead.
|
||||
func (j *Client) UpdateEmails(accountId string, updates map[string]EmailUpdate, session *Session, ctx context.Context, logger *log.Logger) (UpdatedEmails, SessionState, Error) {
|
||||
func (j *Client) UpdateEmails(accountId string, updates map[string]EmailUpdate, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (UpdatedEmails, SessionState, Language, Error) {
|
||||
cmd, err := j.request(session, logger,
|
||||
invocation(CommandEmailSet, EmailSetCommand{
|
||||
AccountId: accountId,
|
||||
@@ -592,10 +592,10 @@ func (j *Client) UpdateEmails(accountId string, updates map[string]EmailUpdate,
|
||||
}, "0"),
|
||||
)
|
||||
if err != nil {
|
||||
return UpdatedEmails{}, "", err
|
||||
return UpdatedEmails{}, "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, func(body *Response) (UpdatedEmails, Error) {
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (UpdatedEmails, Error) {
|
||||
var setResponse EmailSetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailSet, "0", &setResponse)
|
||||
if err != nil {
|
||||
@@ -616,7 +616,7 @@ type DeletedEmails struct {
|
||||
State State `json:"state"`
|
||||
}
|
||||
|
||||
func (j *Client) DeleteEmails(accountId string, destroy []string, session *Session, ctx context.Context, logger *log.Logger) (DeletedEmails, SessionState, Error) {
|
||||
func (j *Client) DeleteEmails(accountId string, destroy []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (DeletedEmails, SessionState, Language, Error) {
|
||||
cmd, err := j.request(session, logger,
|
||||
invocation(CommandEmailSet, EmailSetCommand{
|
||||
AccountId: accountId,
|
||||
@@ -624,10 +624,10 @@ func (j *Client) DeleteEmails(accountId string, destroy []string, session *Sessi
|
||||
}, "0"),
|
||||
)
|
||||
if err != nil {
|
||||
return DeletedEmails{}, "", err
|
||||
return DeletedEmails{}, "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, func(body *Response) (DeletedEmails, Error) {
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (DeletedEmails, Error) {
|
||||
var setResponse EmailSetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailSet, "0", &setResponse)
|
||||
if err != nil {
|
||||
@@ -666,7 +666,7 @@ type SubmittedEmail struct {
|
||||
MdnBlobIds []string `json:"mdnBlobIds,omitempty"`
|
||||
}
|
||||
|
||||
func (j *Client) SubmitEmail(accountId string, identityId string, emailId string, session *Session, ctx context.Context, logger *log.Logger, data []byte) (SubmittedEmail, SessionState, Error) {
|
||||
func (j *Client) SubmitEmail(accountId string, identityId string, emailId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, data []byte) (SubmittedEmail, SessionState, Language, Error) {
|
||||
set := EmailSubmissionSetCommand{
|
||||
AccountId: accountId,
|
||||
Create: map[string]EmailSubmissionCreate{
|
||||
@@ -696,10 +696,10 @@ func (j *Client) SubmitEmail(accountId string, identityId string, emailId string
|
||||
invocation(CommandEmailSubmissionGet, get, "1"),
|
||||
)
|
||||
if err != nil {
|
||||
return SubmittedEmail{}, "", err
|
||||
return SubmittedEmail{}, "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, func(body *Response) (SubmittedEmail, Error) {
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (SubmittedEmail, Error) {
|
||||
var submissionResponse EmailSubmissionSetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailSubmissionSet, "0", &submissionResponse)
|
||||
if err != nil {
|
||||
@@ -748,7 +748,7 @@ func (j *Client) SubmitEmail(accountId string, identityId string, emailId string
|
||||
})
|
||||
}
|
||||
|
||||
func (j *Client) EmailsInThread(accountId string, threadId string, session *Session, ctx context.Context, logger *log.Logger, fetchBodies bool, maxBodyValueBytes uint) ([]Email, SessionState, Error) {
|
||||
func (j *Client) EmailsInThread(accountId string, threadId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, fetchBodies bool, maxBodyValueBytes uint) ([]Email, SessionState, Language, Error) {
|
||||
logger = j.loggerParams("EmailsInThread", session, logger, func(z zerolog.Context) zerolog.Context {
|
||||
return z.Bool(logFetchBodies, fetchBodies).Str("threadId", log.SafeString(threadId))
|
||||
})
|
||||
@@ -770,10 +770,10 @@ func (j *Client) EmailsInThread(accountId string, threadId string, session *Sess
|
||||
}, "1"),
|
||||
)
|
||||
if err != nil {
|
||||
return []Email{}, "", err
|
||||
return []Email{}, "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, func(body *Response) ([]Email, Error) {
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) ([]Email, Error) {
|
||||
var emailsResponse EmailGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandEmailGet, "1", &emailsResponse)
|
||||
if err != nil {
|
||||
@@ -789,7 +789,7 @@ type EmailsSummary struct {
|
||||
State State `json:"state"`
|
||||
}
|
||||
|
||||
func (j *Client) QueryEmailSummaries(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, filter EmailFilterElement, limit uint) (map[string]EmailsSummary, SessionState, Error) {
|
||||
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) {
|
||||
logger = j.logger("QueryEmailSummaries", session, logger)
|
||||
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
@@ -815,10 +815,10 @@ func (j *Client) QueryEmailSummaries(accountIds []string, session *Session, ctx
|
||||
}
|
||||
cmd, err := j.request(session, logger, invocations...)
|
||||
if err != nil {
|
||||
return map[string]EmailsSummary{}, "", err
|
||||
return map[string]EmailsSummary{}, "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, func(body *Response) (map[string]EmailsSummary, Error) {
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (map[string]EmailsSummary, Error) {
|
||||
resp := map[string]EmailsSummary{}
|
||||
for _, accountId := range uniqueAccountIds {
|
||||
var response EmailGetResponse
|
||||
|
||||
@@ -14,13 +14,13 @@ type Identities struct {
|
||||
}
|
||||
|
||||
// https://jmap.io/spec-mail.html#identityget
|
||||
func (j *Client) GetIdentity(accountId string, session *Session, ctx context.Context, logger *log.Logger) (Identities, SessionState, Error) {
|
||||
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)
|
||||
cmd, err := j.request(session, logger, invocation(CommandIdentityGet, IdentityGetCommand{AccountId: accountId}, "0"))
|
||||
if err != nil {
|
||||
return Identities{}, "", err
|
||||
return Identities{}, "", "", err
|
||||
}
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, func(body *Response) (Identities, Error) {
|
||||
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 {
|
||||
@@ -39,7 +39,7 @@ type IdentitiesGetResponse struct {
|
||||
State State `json:"state"`
|
||||
}
|
||||
|
||||
func (j *Client) GetIdentities(accountIds []string, session *Session, ctx context.Context, logger *log.Logger) (IdentitiesGetResponse, SessionState, Error) {
|
||||
func (j *Client) GetIdentities(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)
|
||||
@@ -51,9 +51,9 @@ func (j *Client) GetIdentities(accountIds []string, session *Session, ctx contex
|
||||
|
||||
cmd, err := j.request(session, logger, calls...)
|
||||
if err != nil {
|
||||
return IdentitiesGetResponse{}, "", err
|
||||
return IdentitiesGetResponse{}, "", "", err
|
||||
}
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, func(body *Response) (IdentitiesGetResponse, Error) {
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (IdentitiesGetResponse, Error) {
|
||||
identities := make(map[string][]Identity, len(uniqueAccountIds))
|
||||
var lastState State
|
||||
notFound := []string{}
|
||||
@@ -84,7 +84,7 @@ type IdentitiesAndMailboxesGetResponse struct {
|
||||
Mailboxes []Mailbox `json:"mailboxes"`
|
||||
}
|
||||
|
||||
func (j *Client) GetIdentitiesAndMailboxes(mailboxAccountId string, accountIds []string, session *Session, ctx context.Context, logger *log.Logger) (IdentitiesAndMailboxesGetResponse, SessionState, Error) {
|
||||
func (j *Client) GetIdentitiesAndMailboxes(mailboxAccountId string, accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (IdentitiesAndMailboxesGetResponse, SessionState, Language, Error) {
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
|
||||
logger = j.logger("GetIdentitiesAndMailboxes", session, logger)
|
||||
@@ -97,9 +97,9 @@ func (j *Client) GetIdentitiesAndMailboxes(mailboxAccountId string, accountIds [
|
||||
|
||||
cmd, err := j.request(session, logger, calls...)
|
||||
if err != nil {
|
||||
return IdentitiesAndMailboxesGetResponse{}, "", err
|
||||
return IdentitiesAndMailboxesGetResponse{}, "", "", err
|
||||
}
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, func(body *Response) (IdentitiesAndMailboxesGetResponse, Error) {
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (IdentitiesAndMailboxesGetResponse, Error) {
|
||||
identities := make(map[string][]Identity, len(uniqueAccountIds))
|
||||
var lastState State
|
||||
notFound := []string{}
|
||||
|
||||
@@ -16,17 +16,17 @@ type MailboxesResponse struct {
|
||||
}
|
||||
|
||||
// https://jmap.io/spec-mail.html#mailboxget
|
||||
func (j *Client) GetMailbox(accountId string, session *Session, ctx context.Context, logger *log.Logger, ids []string) (MailboxesResponse, SessionState, Error) {
|
||||
func (j *Client) GetMailbox(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, ids []string) (MailboxesResponse, SessionState, Language, Error) {
|
||||
logger = j.logger("GetMailbox", session, logger)
|
||||
|
||||
cmd, err := j.request(session, logger,
|
||||
invocation(CommandMailboxGet, MailboxGetCommand{AccountId: accountId, Ids: ids}, "0"),
|
||||
)
|
||||
if err != nil {
|
||||
return MailboxesResponse{}, "", err
|
||||
return MailboxesResponse{}, "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, func(body *Response) (MailboxesResponse, Error) {
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (MailboxesResponse, Error) {
|
||||
var response MailboxGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandMailboxGet, "0", &response)
|
||||
if err != nil {
|
||||
@@ -45,13 +45,13 @@ type AllMailboxesResponse struct {
|
||||
State State `json:"state"`
|
||||
}
|
||||
|
||||
func (j *Client) GetAllMailboxes(accountIds []string, session *Session, ctx context.Context, logger *log.Logger) (map[string]AllMailboxesResponse, SessionState, Error) {
|
||||
func (j *Client) GetAllMailboxes(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (map[string]AllMailboxesResponse, SessionState, Language, Error) {
|
||||
logger = j.logger("GetAllMailboxes", session, logger)
|
||||
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
n := len(uniqueAccountIds)
|
||||
if n < 1 {
|
||||
return map[string]AllMailboxesResponse{}, "", nil
|
||||
return map[string]AllMailboxesResponse{}, "", "", nil
|
||||
}
|
||||
|
||||
invocations := make([]Invocation, n)
|
||||
@@ -61,10 +61,10 @@ func (j *Client) GetAllMailboxes(accountIds []string, session *Session, ctx cont
|
||||
|
||||
cmd, err := j.request(session, logger, invocations...)
|
||||
if err != nil {
|
||||
return map[string]AllMailboxesResponse{}, "", err
|
||||
return map[string]AllMailboxesResponse{}, "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, func(body *Response) (map[string]AllMailboxesResponse, Error) {
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (map[string]AllMailboxesResponse, Error) {
|
||||
resp := map[string]AllMailboxesResponse{}
|
||||
for _, accountId := range uniqueAccountIds {
|
||||
var response MailboxGetResponse
|
||||
@@ -89,7 +89,7 @@ type Mailboxes struct {
|
||||
State State `json:"state,omitempty"`
|
||||
}
|
||||
|
||||
func (j *Client) SearchMailboxes(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, filter MailboxFilterElement) (map[string]Mailboxes, SessionState, Error) {
|
||||
func (j *Client) SearchMailboxes(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, filter MailboxFilterElement) (map[string]Mailboxes, SessionState, Language, Error) {
|
||||
logger = j.logger("SearchMailboxes", session, logger)
|
||||
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
@@ -108,10 +108,10 @@ func (j *Client) SearchMailboxes(accountIds []string, session *Session, ctx cont
|
||||
}
|
||||
cmd, err := j.request(session, logger, invocations...)
|
||||
if err != nil {
|
||||
return map[string]Mailboxes{}, "", err
|
||||
return map[string]Mailboxes{}, "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, func(body *Response) (map[string]Mailboxes, Error) {
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (map[string]Mailboxes, Error) {
|
||||
resp := map[string]Mailboxes{}
|
||||
for _, accountId := range uniqueAccountIds {
|
||||
var response MailboxGetResponse
|
||||
@@ -136,7 +136,7 @@ type MailboxChanges struct {
|
||||
}
|
||||
|
||||
// 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, mailboxId string, sinceState string, fetchBodies bool, maxBodyValueBytes uint, maxChanges uint) (MailboxChanges, SessionState, Error) {
|
||||
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, Language, Error) {
|
||||
logger = j.loggerParams("GetMailboxChanges", session, logger, func(z zerolog.Context) zerolog.Context {
|
||||
return z.Bool(logFetchBodies, fetchBodies).Str(logSinceState, sinceState)
|
||||
})
|
||||
@@ -172,10 +172,10 @@ func (j *Client) GetMailboxChanges(accountId string, session *Session, ctx conte
|
||||
invocation(CommandEmailGet, getUpdated, "2"),
|
||||
)
|
||||
if err != nil {
|
||||
return MailboxChanges{}, "", err
|
||||
return MailboxChanges{}, "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, func(body *Response) (MailboxChanges, Error) {
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (MailboxChanges, Error) {
|
||||
var mailboxResponse MailboxChangesResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandMailboxChanges, "0", &mailboxResponse)
|
||||
if err != nil {
|
||||
@@ -208,7 +208,7 @@ 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, sinceStateMap map[string]string, fetchBodies bool, maxBodyValueBytes uint, maxChanges uint) (map[string]MailboxChanges, SessionState, Error) {
|
||||
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, Language, Error) {
|
||||
logger = j.loggerParams("GetMailboxChangesForMultipleAccounts", session, logger, func(z zerolog.Context) zerolog.Context {
|
||||
sinceStateLogDict := zerolog.Dict()
|
||||
for k, v := range sinceStateMap {
|
||||
@@ -220,7 +220,7 @@ func (j *Client) GetMailboxChangesForMultipleAccounts(accountIds []string, sessi
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
n := len(uniqueAccountIds)
|
||||
if n < 1 {
|
||||
return map[string]MailboxChanges{}, "", nil
|
||||
return map[string]MailboxChanges{}, "", "", nil
|
||||
}
|
||||
|
||||
invocations := make([]Invocation, n*3)
|
||||
@@ -262,10 +262,10 @@ func (j *Client) GetMailboxChangesForMultipleAccounts(accountIds []string, sessi
|
||||
|
||||
cmd, err := j.request(session, logger, invocations...)
|
||||
if err != nil {
|
||||
return map[string]MailboxChanges{}, "", err
|
||||
return map[string]MailboxChanges{}, "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, func(body *Response) (map[string]MailboxChanges, Error) {
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (map[string]MailboxChanges, Error) {
|
||||
resp := make(map[string]MailboxChanges, n)
|
||||
for _, accountId := range uniqueAccountIds {
|
||||
var mailboxResponse MailboxChangesResponse
|
||||
@@ -300,13 +300,13 @@ func (j *Client) GetMailboxChangesForMultipleAccounts(accountIds []string, sessi
|
||||
})
|
||||
}
|
||||
|
||||
func (j *Client) GetMailboxRolesForMultipleAccounts(accountIds []string, session *Session, ctx context.Context, logger *log.Logger) (map[string][]string, SessionState, Error) {
|
||||
func (j *Client) GetMailboxRolesForMultipleAccounts(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (map[string][]string, SessionState, Language, Error) {
|
||||
logger = j.logger("GetMailboxRolesForMultipleAccounts", session, logger)
|
||||
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
n := len(uniqueAccountIds)
|
||||
if n < 1 {
|
||||
return map[string][]string{}, "", nil
|
||||
return map[string][]string{}, "", "", nil
|
||||
}
|
||||
|
||||
t := true
|
||||
@@ -331,10 +331,10 @@ func (j *Client) GetMailboxRolesForMultipleAccounts(accountIds []string, session
|
||||
|
||||
cmd, err := j.request(session, logger, invocations...)
|
||||
if err != nil {
|
||||
return map[string][]string{}, "", err
|
||||
return map[string][]string{}, "", "", err
|
||||
}
|
||||
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, func(body *Response) (map[string][]string, Error) {
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (map[string][]string, Error) {
|
||||
resp := make(map[string][]string, n)
|
||||
for _, accountId := range uniqueAccountIds {
|
||||
var getResponse MailboxGetResponse
|
||||
|
||||
23
pkg/jmap/jmap_api_quota.go
Normal file
23
pkg/jmap/jmap_api_quota.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package jmap
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
)
|
||||
|
||||
func (j *Client) GetQuotas(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (QuotaGetResponse, SessionState, Language, Error) {
|
||||
logger = j.logger("GetQuotas", session, logger)
|
||||
cmd, err := j.request(session, logger, invocation(CommandQuotaGet, QuotaGetCommand{AccountId: accountId}, "0"))
|
||||
if err != nil {
|
||||
return QuotaGetResponse{}, "", "", err
|
||||
}
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (QuotaGetResponse, Error) {
|
||||
var response QuotaGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandQuotaGet, "0", &response)
|
||||
if err != nil {
|
||||
return QuotaGetResponse{}, err
|
||||
}
|
||||
return response, nil
|
||||
})
|
||||
}
|
||||
@@ -13,13 +13,13 @@ const (
|
||||
)
|
||||
|
||||
// https://jmap.io/spec-mail.html#vacationresponseget
|
||||
func (j *Client) GetVacationResponse(accountId string, session *Session, ctx context.Context, logger *log.Logger) (VacationResponseGetResponse, SessionState, Error) {
|
||||
func (j *Client) GetVacationResponse(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (VacationResponseGetResponse, SessionState, Language, Error) {
|
||||
logger = j.logger("GetVacationResponse", session, logger)
|
||||
cmd, err := j.request(session, logger, invocation(CommandVacationResponseGet, VacationResponseGetCommand{AccountId: accountId}, "0"))
|
||||
if err != nil {
|
||||
return VacationResponseGetResponse{}, "", err
|
||||
return VacationResponseGetResponse{}, "", "", err
|
||||
}
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, func(body *Response) (VacationResponseGetResponse, Error) {
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (VacationResponseGetResponse, Error) {
|
||||
var response VacationResponseGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandVacationResponseGet, "0", &response)
|
||||
if err != nil {
|
||||
@@ -58,7 +58,7 @@ type VacationResponseChange struct {
|
||||
ResponseState State `json:"state"`
|
||||
}
|
||||
|
||||
func (j *Client) SetVacationResponse(accountId string, vacation VacationResponsePayload, session *Session, ctx context.Context, logger *log.Logger) (VacationResponseChange, SessionState, Error) {
|
||||
func (j *Client) SetVacationResponse(accountId string, vacation VacationResponsePayload, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (VacationResponseChange, SessionState, Language, Error) {
|
||||
logger = j.logger("SetVacationResponse", session, logger)
|
||||
|
||||
cmd, err := j.request(session, logger,
|
||||
@@ -80,9 +80,9 @@ func (j *Client) SetVacationResponse(accountId string, vacation VacationResponse
|
||||
invocation(CommandVacationResponseGet, VacationResponseGetCommand{AccountId: accountId}, "1"),
|
||||
)
|
||||
if err != nil {
|
||||
return VacationResponseChange{}, "", err
|
||||
return VacationResponseChange{}, "", "", err
|
||||
}
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, func(body *Response) (VacationResponseChange, Error) {
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (VacationResponseChange, Error) {
|
||||
var setResponse VacationResponseSetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandVacationResponseSet, "0", &setResponse)
|
||||
if err != nil {
|
||||
|
||||
@@ -176,7 +176,7 @@ func (h *HttpJmapClient) GetSession(sessionUrl *url.URL, username string, logger
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (h *HttpJmapClient) Command(ctx context.Context, logger *log.Logger, session *Session, request Request) ([]byte, Error) {
|
||||
func (h *HttpJmapClient) Command(ctx context.Context, logger *log.Logger, session *Session, request Request, acceptLanguage string) ([]byte, Language, Error) {
|
||||
jmapUrl := session.JmapUrl.String()
|
||||
endpoint := session.JmapEndpoint
|
||||
logger = log.From(logger.With().Str(logEndpoint, endpoint))
|
||||
@@ -184,14 +184,21 @@ func (h *HttpJmapClient) Command(ctx context.Context, logger *log.Logger, sessio
|
||||
bodyBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msg("failed to marshall JSON payload")
|
||||
return nil, SimpleError{code: JmapErrorEncodingRequestBody, err: err}
|
||||
return nil, "", SimpleError{code: JmapErrorEncodingRequestBody, err: err}
|
||||
}
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, jmapUrl, bytes.NewBuffer(bodyBytes))
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msgf("failed to create POST request for %v", jmapUrl)
|
||||
return nil, SimpleError{code: JmapErrorCreatingRequest, err: err}
|
||||
return nil, "", SimpleError{code: JmapErrorCreatingRequest, err: err}
|
||||
}
|
||||
|
||||
// Some JMAP APIs use the Accept-Language header to determine which language to use to translate
|
||||
// texts in attributes.
|
||||
if acceptLanguage != "" {
|
||||
req.Header.Add("Accept-Language", acceptLanguage)
|
||||
}
|
||||
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
req.Header.Add("User-Agent", h.userAgent)
|
||||
h.auth(session.Username, logger, req)
|
||||
@@ -200,12 +207,13 @@ func (h *HttpJmapClient) Command(ctx context.Context, logger *log.Logger, sessio
|
||||
if err != nil {
|
||||
h.listener.OnFailedRequest(endpoint, err)
|
||||
logger.Error().Err(err).Msgf("failed to perform POST %v", jmapUrl)
|
||||
return nil, SimpleError{code: JmapErrorSendingRequest, err: err}
|
||||
return nil, "", SimpleError{code: JmapErrorSendingRequest, err: err}
|
||||
}
|
||||
language := Language(res.Header.Get("Content-Language"))
|
||||
if res.StatusCode < 200 || res.StatusCode > 299 {
|
||||
h.listener.OnFailedRequestWithStatus(endpoint, res.StatusCode)
|
||||
logger.Error().Str(logEndpoint, endpoint).Str(logHttpStatus, res.Status).Msg("HTTP response status code is not 2xx")
|
||||
return nil, SimpleError{code: JmapErrorServerResponse, err: err}
|
||||
return nil, language, SimpleError{code: JmapErrorServerResponse, err: err}
|
||||
}
|
||||
if res.Body != nil {
|
||||
defer func(Body io.ReadCloser) {
|
||||
@@ -221,34 +229,38 @@ func (h *HttpJmapClient) Command(ctx context.Context, logger *log.Logger, sessio
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msg("failed to read response body")
|
||||
h.listener.OnResponseBodyReadingError(endpoint, err)
|
||||
return nil, SimpleError{code: JmapErrorServerResponse, err: err}
|
||||
return nil, language, SimpleError{code: JmapErrorServerResponse, err: err}
|
||||
}
|
||||
|
||||
return body, nil
|
||||
return body, language, nil
|
||||
}
|
||||
|
||||
func (h *HttpJmapClient) UploadBinary(ctx context.Context, logger *log.Logger, session *Session, uploadUrl string, endpoint string, contentType string, body io.Reader) (UploadedBlob, Error) {
|
||||
func (h *HttpJmapClient) UploadBinary(ctx context.Context, logger *log.Logger, session *Session, uploadUrl string, endpoint string, contentType string, acceptLanguage string, body io.Reader) (UploadedBlob, Language, Error) {
|
||||
logger = log.From(logger.With().Str(logEndpoint, endpoint))
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, uploadUrl, body)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msgf("failed to create POST request for %v", uploadUrl)
|
||||
return UploadedBlob{}, SimpleError{code: JmapErrorCreatingRequest, err: err}
|
||||
return UploadedBlob{}, "", SimpleError{code: JmapErrorCreatingRequest, err: err}
|
||||
}
|
||||
req.Header.Add("Content-Type", contentType)
|
||||
req.Header.Add("User-Agent", h.userAgent)
|
||||
h.auth(session.Username, logger, req)
|
||||
if acceptLanguage != "" {
|
||||
req.Header.Add("Accept-Language", acceptLanguage)
|
||||
}
|
||||
|
||||
res, err := h.client.Do(req)
|
||||
if err != nil {
|
||||
h.listener.OnFailedRequest(endpoint, err)
|
||||
logger.Error().Err(err).Msgf("failed to perform POST %v", uploadUrl)
|
||||
return UploadedBlob{}, SimpleError{code: JmapErrorSendingRequest, err: err}
|
||||
return UploadedBlob{}, "", SimpleError{code: JmapErrorSendingRequest, err: err}
|
||||
}
|
||||
language := Language(res.Header.Get("Content-Language"))
|
||||
if res.StatusCode < 200 || res.StatusCode > 299 {
|
||||
h.listener.OnFailedRequestWithStatus(endpoint, res.StatusCode)
|
||||
logger.Error().Str(logHttpStatus, res.Status).Int(logHttpStatusCode, res.StatusCode).Msg("HTTP response status code is not 2xx")
|
||||
return UploadedBlob{}, SimpleError{code: JmapErrorServerResponse, err: err}
|
||||
return UploadedBlob{}, language, SimpleError{code: JmapErrorServerResponse, err: err}
|
||||
}
|
||||
if res.Body != nil {
|
||||
defer func(Body io.ReadCloser) {
|
||||
@@ -264,7 +276,7 @@ func (h *HttpJmapClient) UploadBinary(ctx context.Context, logger *log.Logger, s
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msg("failed to read response body")
|
||||
h.listener.OnResponseBodyReadingError(endpoint, err)
|
||||
return UploadedBlob{}, SimpleError{code: JmapErrorServerResponse, err: err}
|
||||
return UploadedBlob{}, language, SimpleError{code: JmapErrorServerResponse, err: err}
|
||||
}
|
||||
|
||||
var result UploadedBlob
|
||||
@@ -272,36 +284,40 @@ func (h *HttpJmapClient) UploadBinary(ctx context.Context, logger *log.Logger, s
|
||||
if err != nil {
|
||||
logger.Error().Str(logHttpUrl, uploadUrl).Err(err).Msg("failed to decode JSON payload from the upload response")
|
||||
h.listener.OnResponseBodyUnmarshallingError(endpoint, err)
|
||||
return UploadedBlob{}, SimpleError{code: JmapErrorDecodingResponseBody, err: err}
|
||||
return UploadedBlob{}, language, SimpleError{code: JmapErrorDecodingResponseBody, err: err}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
return result, language, nil
|
||||
}
|
||||
|
||||
func (h *HttpJmapClient) DownloadBinary(ctx context.Context, logger *log.Logger, session *Session, downloadUrl string, endpoint string) (*BlobDownload, Error) {
|
||||
func (h *HttpJmapClient) DownloadBinary(ctx context.Context, logger *log.Logger, session *Session, downloadUrl string, endpoint string, acceptLanguage string) (*BlobDownload, Language, Error) {
|
||||
logger = log.From(logger.With().Str(logEndpoint, endpoint))
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, downloadUrl, nil)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msgf("failed to create GET request for %v", downloadUrl)
|
||||
return nil, SimpleError{code: JmapErrorCreatingRequest, err: err}
|
||||
return nil, "", SimpleError{code: JmapErrorCreatingRequest, err: err}
|
||||
}
|
||||
req.Header.Add("User-Agent", h.userAgent)
|
||||
h.auth(session.Username, logger, req)
|
||||
if acceptLanguage != "" {
|
||||
req.Header.Add("Accept-Language", acceptLanguage)
|
||||
}
|
||||
|
||||
res, err := h.client.Do(req)
|
||||
if err != nil {
|
||||
h.listener.OnFailedRequest(endpoint, err)
|
||||
logger.Error().Err(err).Msgf("failed to perform GET %v", downloadUrl)
|
||||
return nil, SimpleError{code: JmapErrorSendingRequest, err: err}
|
||||
return nil, "", SimpleError{code: JmapErrorSendingRequest, err: err}
|
||||
}
|
||||
language := Language(res.Header.Get("Content-Language"))
|
||||
if res.StatusCode == http.StatusNotFound {
|
||||
return nil, nil
|
||||
return nil, language, nil
|
||||
}
|
||||
if res.StatusCode < 200 || res.StatusCode > 299 {
|
||||
h.listener.OnFailedRequestWithStatus(endpoint, res.StatusCode)
|
||||
logger.Error().Str(logHttpStatus, res.Status).Int(logHttpStatusCode, res.StatusCode).Msg("HTTP response status code is not 2xx")
|
||||
return nil, SimpleError{code: JmapErrorServerResponse, err: err}
|
||||
return nil, language, SimpleError{code: JmapErrorServerResponse, err: err}
|
||||
}
|
||||
h.listener.OnSuccessfulRequest(endpoint, res.StatusCode)
|
||||
|
||||
@@ -321,7 +337,7 @@ func (h *HttpJmapClient) DownloadBinary(ctx context.Context, logger *log.Logger,
|
||||
Type: res.Header.Get("Content-Type"),
|
||||
ContentDisposition: res.Header.Get("Content-Disposition"),
|
||||
CacheControl: res.Header.Get("Cache-Control"),
|
||||
}, nil
|
||||
}, language, nil
|
||||
}
|
||||
|
||||
type WebSocketPushEnable struct {
|
||||
|
||||
@@ -363,7 +363,7 @@ func TestWithStalwart(t *testing.T) {
|
||||
var inboxFolder string
|
||||
var inboxId string
|
||||
{
|
||||
respByAccountId, sessionState, err := j.GetAllMailboxes([]string{accountId}, session, ctx, logger)
|
||||
respByAccountId, sessionState, _, err := j.GetAllMailboxes([]string{accountId}, session, ctx, logger, "")
|
||||
require.NoError(err)
|
||||
require.Equal(session.State, sessionState)
|
||||
require.Len(respByAccountId, 1)
|
||||
@@ -440,7 +440,7 @@ func TestWithStalwart(t *testing.T) {
|
||||
|
||||
{
|
||||
{
|
||||
resp, sessionState, err := j.GetIdentity(accountId, session, ctx, logger)
|
||||
resp, sessionState, _, err := j.GetIdentity(accountId, session, ctx, logger, "")
|
||||
require.NoError(err)
|
||||
require.Equal(session.State, sessionState)
|
||||
require.Len(resp.Identities, 1)
|
||||
@@ -449,7 +449,7 @@ func TestWithStalwart(t *testing.T) {
|
||||
}
|
||||
|
||||
{
|
||||
respByAccountId, sessionState, err := j.GetAllMailboxes([]string{accountId}, session, ctx, logger)
|
||||
respByAccountId, sessionState, _, err := j.GetAllMailboxes([]string{accountId}, session, ctx, logger, "")
|
||||
require.NoError(err)
|
||||
require.Equal(session.State, sessionState)
|
||||
require.Len(respByAccountId, 1)
|
||||
@@ -465,7 +465,7 @@ func TestWithStalwart(t *testing.T) {
|
||||
}
|
||||
|
||||
{
|
||||
resp, sessionState, err := j.GetAllEmailsInMailbox(accountId, session, ctx, logger, inboxId, 0, 0, false, 0)
|
||||
resp, sessionState, _, err := j.GetAllEmailsInMailbox(accountId, session, ctx, logger, "", inboxId, 0, 0, false, 0)
|
||||
require.NoError(err)
|
||||
require.Equal(session.State, sessionState)
|
||||
|
||||
|
||||
@@ -865,6 +865,8 @@ type SessionState string
|
||||
|
||||
type State string
|
||||
|
||||
type Language string
|
||||
|
||||
type SessionResponse struct {
|
||||
Capabilities SessionCapabilities `json:"capabilities"`
|
||||
|
||||
@@ -4558,6 +4560,18 @@ type SendMDN struct {
|
||||
OnSuccessUpdateEmail map[string]PatchObject `json:"onSuccessUpdateEmail,omitempty"`
|
||||
}
|
||||
|
||||
type QuotaGetCommand struct {
|
||||
AccountId string `json:"accountId"`
|
||||
Ids []string `json:"ids,omitempty"`
|
||||
}
|
||||
|
||||
type QuotaGetResponse struct {
|
||||
AccountId string `json:"accountId"`
|
||||
State State `json:"state,omitempty"`
|
||||
List []Quota `json:"list,omitempty"`
|
||||
NotFound []string `json:"notFound,omitempty"`
|
||||
}
|
||||
|
||||
type ErrorResponse struct {
|
||||
Type string `json:"type"`
|
||||
Description string `json:"description,omitempty"`
|
||||
@@ -4582,6 +4596,7 @@ const (
|
||||
CommandVacationResponseGet Command = "VacationResponse/get"
|
||||
CommandVacationResponseSet Command = "VacationResponse/set"
|
||||
CommandSearchSnippetGet Command = "SearchSnippet/get"
|
||||
CommandQuotaGet Command = "Quota/get"
|
||||
)
|
||||
|
||||
var CommandResponseTypeMap = map[Command]func() any{
|
||||
@@ -4601,4 +4616,5 @@ var CommandResponseTypeMap = map[Command]func() any{
|
||||
CommandVacationResponseGet: func() any { return VacationResponseGetResponse{} },
|
||||
CommandVacationResponseSet: func() any { return VacationResponseSetResponse{} },
|
||||
CommandSearchSnippetGet: func() any { return SearchSnippetGetResponse{} },
|
||||
CommandQuotaGet: func() any { return QuotaGetResponse{} },
|
||||
}
|
||||
|
||||
@@ -117,10 +117,10 @@ func NewTestJmapBlobClient(t *testing.T) BlobClient {
|
||||
return &TestJmapBlobClient{t: t}
|
||||
}
|
||||
|
||||
func (t TestJmapBlobClient) UploadBinary(ctx context.Context, logger *log.Logger, session *Session, uploadUrl string, endpoint string, contentType string, body io.Reader) (UploadedBlob, Error) {
|
||||
func (t TestJmapBlobClient) UploadBinary(ctx context.Context, logger *log.Logger, session *Session, uploadUrl string, endpoint string, contentType string, acceptLanguage string, body io.Reader) (UploadedBlob, Language, Error) {
|
||||
bytes, err := io.ReadAll(body)
|
||||
if err != nil {
|
||||
return UploadedBlob{}, SimpleError{code: 0, err: err}
|
||||
return UploadedBlob{}, "", SimpleError{code: 0, err: err}
|
||||
}
|
||||
hasher := sha512.New()
|
||||
hasher.Write(bytes)
|
||||
@@ -129,17 +129,17 @@ func (t TestJmapBlobClient) UploadBinary(ctx context.Context, logger *log.Logger
|
||||
Size: len(bytes),
|
||||
Type: contentType,
|
||||
Sha512: base64.StdEncoding.EncodeToString(hasher.Sum(nil)),
|
||||
}, nil
|
||||
}, "", nil
|
||||
}
|
||||
|
||||
func (h *TestJmapBlobClient) DownloadBinary(ctx context.Context, logger *log.Logger, session *Session, downloadUrl string, endpoint string) (*BlobDownload, Error) {
|
||||
func (h *TestJmapBlobClient) DownloadBinary(ctx context.Context, logger *log.Logger, session *Session, downloadUrl string, endpoint string, acceptLanguage string) (*BlobDownload, Language, Error) {
|
||||
return &BlobDownload{
|
||||
Body: io.NopCloser(strings.NewReader("")),
|
||||
Size: -1,
|
||||
Type: "text/plain",
|
||||
ContentDisposition: "attachment; filename=\"file.txt\"",
|
||||
CacheControl: "",
|
||||
}, nil
|
||||
}, "", nil
|
||||
}
|
||||
|
||||
func (t TestJmapBlobClient) Close() error {
|
||||
@@ -164,24 +164,24 @@ func (t TestWsClientFactory) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func serveTestFile(t *testing.T, name string) ([]byte, Error) {
|
||||
func serveTestFile(t *testing.T, name string) ([]byte, Language, Error) {
|
||||
cwd, _ := os.Getwd()
|
||||
p := filepath.Join(cwd, "testdata", name)
|
||||
bytes, err := os.ReadFile(p)
|
||||
if err != nil {
|
||||
return bytes, SimpleError{code: 0, err: err}
|
||||
return bytes, "", SimpleError{code: 0, err: err}
|
||||
}
|
||||
// try to parse it first to avoid any deeper issues that are caused by the test tools
|
||||
var target map[string]any
|
||||
err = json.Unmarshal(bytes, &target)
|
||||
if err != nil {
|
||||
t.Errorf("failed to parse JSON test data file '%v': %v", p, err)
|
||||
return nil, SimpleError{code: 0, err: err}
|
||||
return nil, "", SimpleError{code: 0, err: err}
|
||||
}
|
||||
return bytes, nil
|
||||
return bytes, "", nil
|
||||
}
|
||||
|
||||
func (t *TestJmapApiClient) Command(ctx context.Context, logger *log.Logger, session *Session, request Request) ([]byte, Error) {
|
||||
func (t *TestJmapApiClient) Command(ctx context.Context, logger *log.Logger, session *Session, request Request, acceptLanguage string) ([]byte, Language, Error) {
|
||||
command := request.MethodCalls[0].Command
|
||||
switch command {
|
||||
case CommandMailboxGet:
|
||||
@@ -190,7 +190,7 @@ func (t *TestJmapApiClient) Command(ctx context.Context, logger *log.Logger, ses
|
||||
return serveTestFile(t.t, "mails1.json")
|
||||
default:
|
||||
require.Fail(t.t, "TestJmapApiClient: unsupported jmap command: %v", command)
|
||||
return nil, SimpleError{code: 0, err: fmt.Errorf("TestJmapApiClient: unsupported jmap command: %v", command)}
|
||||
return nil, "", SimpleError{code: 0, err: fmt.Errorf("TestJmapApiClient: unsupported jmap command: %v", command)}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,7 +231,7 @@ func TestRequests(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
foldersByAccountId, sessionState, err := client.GetAllMailboxes([]string{"a"}, &session, ctx, &logger)
|
||||
foldersByAccountId, sessionState, _, err := client.GetAllMailboxes([]string{"a"}, &session, ctx, &logger, "")
|
||||
require.NoError(err)
|
||||
require.Len(foldersByAccountId, 1)
|
||||
require.Contains(foldersByAccountId, "a")
|
||||
@@ -239,7 +239,7 @@ func TestRequests(t *testing.T) {
|
||||
require.Len(folders.Mailboxes, 5)
|
||||
require.NotEmpty(sessionState)
|
||||
|
||||
emails, sessionState, err := client.GetAllEmailsInMailbox("a", &session, ctx, &logger, "Inbox", 0, 0, true, 0)
|
||||
emails, sessionState, _, err := client.GetAllEmailsInMailbox("a", &session, ctx, &logger, "", "Inbox", 0, 0, true, 0)
|
||||
require.NoError(err)
|
||||
require.Len(emails.Emails, 3)
|
||||
require.NotEmpty(sessionState)
|
||||
|
||||
@@ -57,12 +57,13 @@ func command[T any](api ApiClient,
|
||||
session *Session,
|
||||
sessionOutdatedHandler func(session *Session, newState SessionState),
|
||||
request Request,
|
||||
mapper func(body *Response) (T, Error)) (T, SessionState, Error) {
|
||||
acceptLanguage string,
|
||||
mapper func(body *Response) (T, Error)) (T, SessionState, Language, Error) {
|
||||
|
||||
responseBody, jmapErr := api.Command(ctx, logger, session, request)
|
||||
responseBody, language, jmapErr := api.Command(ctx, logger, session, request, acceptLanguage)
|
||||
if jmapErr != nil {
|
||||
var zero T
|
||||
return zero, "", jmapErr
|
||||
return zero, "", language, jmapErr
|
||||
}
|
||||
|
||||
var response Response
|
||||
@@ -70,7 +71,7 @@ func command[T any](api ApiClient,
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msgf("failed to deserialize body JSON payload into a %T", response)
|
||||
var zero T
|
||||
return zero, "", SimpleError{code: JmapErrorDecodingResponseBody, err: err}
|
||||
return zero, "", language, SimpleError{code: JmapErrorDecodingResponseBody, err: err}
|
||||
}
|
||||
|
||||
if response.SessionState != session.State {
|
||||
@@ -117,21 +118,21 @@ func command[T any](api ApiClient,
|
||||
err = errors.New(msg)
|
||||
logger.Warn().Int("code", code).Str("type", errorParameters.Type).Msg(msg)
|
||||
var zero T
|
||||
return zero, response.SessionState, SimpleError{code: code, err: err}
|
||||
return zero, response.SessionState, language, SimpleError{code: code, err: err}
|
||||
} else {
|
||||
code := JmapErrorUnspecifiedType
|
||||
msg := fmt.Sprintf("found method level error in response '%v'", mr.Tag)
|
||||
err := errors.New(msg)
|
||||
logger.Warn().Int("code", code).Msg(msg)
|
||||
var zero T
|
||||
return zero, response.SessionState, SimpleError{code: code, err: err}
|
||||
return zero, response.SessionState, language, SimpleError{code: code, err: err}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result, jerr := mapper(&response)
|
||||
sessionState := response.SessionState
|
||||
return result, sessionState, jerr
|
||||
return result, sessionState, language, jerr
|
||||
}
|
||||
|
||||
func mapstructStringToTimeHook() mapstructure.DecodeHookFunc {
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
func TestDeserializeMailboxGetResponse(t *testing.T) {
|
||||
require := require.New(t)
|
||||
jsonBytes, jmapErr := serveTestFile(t, "mailboxes1.json")
|
||||
jsonBytes, _, jmapErr := serveTestFile(t, "mailboxes1.json")
|
||||
require.NoError(jmapErr)
|
||||
var data Response
|
||||
err := json.Unmarshal(jsonBytes, &data)
|
||||
@@ -66,7 +66,7 @@ func TestDeserializeMailboxGetResponse(t *testing.T) {
|
||||
|
||||
func TestDeserializeEmailGetResponse(t *testing.T) {
|
||||
require := require.New(t)
|
||||
jsonBytes, jmapErr := serveTestFile(t, "mails1.json")
|
||||
jsonBytes, _, jmapErr := serveTestFile(t, "mails1.json")
|
||||
require.NoError(jmapErr)
|
||||
var data Response
|
||||
err := json.Unmarshal(jsonBytes, &data)
|
||||
|
||||
@@ -35,6 +35,9 @@ tags:
|
||||
- name: task
|
||||
x-displayName: Tasks
|
||||
description: APIs about tasks
|
||||
- name: quota
|
||||
x-displayName: Quota
|
||||
description: APIs about quotas
|
||||
- name: vacation
|
||||
x-displayName: Vacation Responses
|
||||
description: APIs about vacation responses
|
||||
@@ -63,6 +66,9 @@ x-tagGroups:
|
||||
tags:
|
||||
- tasklist
|
||||
- task
|
||||
- name: Quotas
|
||||
tags:
|
||||
- quota
|
||||
components:
|
||||
securitySchemes:
|
||||
api:
|
||||
|
||||
@@ -32,7 +32,7 @@ func (g *Groupware) GetAccount(w http.ResponseWriter, r *http.Request) {
|
||||
if err != nil {
|
||||
return errorResponse(err)
|
||||
}
|
||||
return response(account, req.session.State)
|
||||
return response(account, req.session.State, "")
|
||||
})
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ type SwaggerGetAccountsResponse struct {
|
||||
// 500: ErrorResponse500
|
||||
func (g *Groupware) GetAccounts(w http.ResponseWriter, r *http.Request) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
return response(req.session.Accounts, req.session.State)
|
||||
return response(req.session.Accounts, req.session.State, "")
|
||||
})
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ func (g *Groupware) GetAccountBootstrap(w http.ResponseWriter, r *http.Request)
|
||||
logger := log.From(req.logger.With().Str(logAccountId, mailAccountId))
|
||||
accountIds := structs.Keys(req.session.Accounts)
|
||||
|
||||
resp, sessionState, jerr := g.jmap.GetIdentitiesAndMailboxes(mailAccountId, accountIds, req.session, req.ctx, logger)
|
||||
resp, sessionState, lang, jerr := g.jmap.GetIdentitiesAndMailboxes(mailAccountId, accountIds, req.session, req.ctx, logger, req.language())
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(jerr)
|
||||
}
|
||||
@@ -121,6 +121,6 @@ func (g *Groupware) GetAccountBootstrap(w http.ResponseWriter, r *http.Request)
|
||||
Mailboxes: map[string][]jmap.Mailbox{
|
||||
mailAccountId: resp.Mailboxes,
|
||||
},
|
||||
}, sessionState)
|
||||
}, sessionState, lang)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ func (g *Groupware) GetBlobMeta(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
logger := log.From(req.logger.With().Str(logAccountId, accountId))
|
||||
|
||||
res, sessionState, jerr := g.jmap.GetBlobMetadata(accountId, req.session, req.ctx, logger, blobId)
|
||||
res, sessionState, lang, jerr := g.jmap.GetBlobMetadata(accountId, req.session, req.ctx, logger, req.language(), blobId)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(jerr)
|
||||
}
|
||||
@@ -38,9 +38,9 @@ func (g *Groupware) GetBlobMeta(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
digest := blob.Digest()
|
||||
if digest != "" {
|
||||
return etagResponse(res, sessionState, jmap.State(digest))
|
||||
return etagResponse(res, sessionState, jmap.State(digest), lang)
|
||||
} else {
|
||||
return response(res, sessionState)
|
||||
return response(res, sessionState, lang)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -64,12 +64,12 @@ func (g *Groupware) UploadBlob(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
logger := log.From(req.logger.With().Str(logAccountId, accountId))
|
||||
|
||||
resp, jerr := g.jmap.UploadBlobStream(accountId, req.session, req.ctx, logger, contentType, body)
|
||||
resp, lang, jerr := g.jmap.UploadBlobStream(accountId, req.session, req.ctx, logger, contentType, req.language(), body)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(jerr)
|
||||
}
|
||||
|
||||
return etagOnlyResponse(resp, jmap.State(resp.Sha512))
|
||||
return etagOnlyResponse(resp, jmap.State(resp.Sha512), lang)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ func (g *Groupware) DownloadBlob(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
logger := log.From(req.logger.With().Str(logAccountId, accountId))
|
||||
|
||||
blob, jerr := g.jmap.DownloadBlobStream(accountId, blobId, name, typ, req.session, req.ctx, logger)
|
||||
blob, lang, jerr := g.jmap.DownloadBlobStream(accountId, blobId, name, typ, req.session, req.ctx, logger, req.language())
|
||||
if blob != nil && blob.Body != nil {
|
||||
defer func(Body io.ReadCloser) {
|
||||
err := Body.Close()
|
||||
@@ -118,6 +118,9 @@ func (g *Groupware) DownloadBlob(w http.ResponseWriter, r *http.Request) {
|
||||
if blob.Size >= 0 {
|
||||
w.Header().Add("Content-Size", strconv.Itoa(blob.Size))
|
||||
}
|
||||
if lang != "" {
|
||||
w.Header().Add("Content-Language", string(lang))
|
||||
}
|
||||
|
||||
_, err := io.Copy(w, blob.Body)
|
||||
if err != nil {
|
||||
|
||||
@@ -31,7 +31,7 @@ func (g *Groupware) GetCalendars(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
var _ string = accountId
|
||||
|
||||
return response(AllCalendars, req.session.State)
|
||||
return response(AllCalendars, req.session.State, "")
|
||||
})
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ func (g *Groupware) GetCalendarById(w http.ResponseWriter, r *http.Request) {
|
||||
// TODO replace with proper implementation
|
||||
for _, calendar := range AllCalendars {
|
||||
if calendar.Id == calendarId {
|
||||
return response(calendar, req.session.State)
|
||||
return response(calendar, req.session.State, "")
|
||||
}
|
||||
}
|
||||
return notFoundResponse(req.session.State)
|
||||
@@ -102,6 +102,6 @@ func (g *Groupware) GetEventsInCalendar(w http.ResponseWriter, r *http.Request)
|
||||
if !ok {
|
||||
return notFoundResponse(req.session.State)
|
||||
}
|
||||
return response(events, req.session.State)
|
||||
return response(events, req.session.State, "")
|
||||
})
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ func (g *Groupware) GetAddressbooks(w http.ResponseWriter, r *http.Request) {
|
||||
var _ string = accountId
|
||||
|
||||
// TODO replace with proper implementation
|
||||
return response(AllAddressBooks, req.session.State)
|
||||
return response(AllAddressBooks, req.session.State, "")
|
||||
})
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ func (g *Groupware) GetAddressbook(w http.ResponseWriter, r *http.Request) {
|
||||
// TODO replace with proper implementation
|
||||
for _, ab := range AllAddressBooks {
|
||||
if ab.Id == addressBookId {
|
||||
return response(ab, req.session.State)
|
||||
return response(ab, req.session.State, "")
|
||||
}
|
||||
}
|
||||
return notFoundResponse(req.session.State)
|
||||
@@ -104,6 +104,6 @@ func (g *Groupware) GetContactsInAddressbook(w http.ResponseWriter, r *http.Requ
|
||||
if !ok {
|
||||
return notFoundResponse(req.session.State)
|
||||
}
|
||||
return response(contactCards, req.session.State)
|
||||
return response(contactCards, req.session.State, "")
|
||||
})
|
||||
}
|
||||
|
||||
@@ -77,12 +77,12 @@ func (g *Groupware) GetAllEmailsInMailbox(w http.ResponseWriter, r *http.Request
|
||||
|
||||
logger := log.From(req.logger.With().Str(HeaderSince, since).Str(logAccountId, accountId))
|
||||
|
||||
emails, sessionState, jerr := g.jmap.GetMailboxChanges(accountId, req.session, req.ctx, logger, mailboxId, since, true, g.maxBodyValueBytes, maxChanges)
|
||||
emails, sessionState, lang, jerr := g.jmap.GetMailboxChanges(accountId, req.session, req.ctx, logger, req.language(), mailboxId, since, true, g.maxBodyValueBytes, maxChanges)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(jerr)
|
||||
}
|
||||
|
||||
return etagResponse(emails, sessionState, emails.State)
|
||||
return etagResponse(emails, sessionState, emails.State, lang)
|
||||
})
|
||||
} else {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
@@ -114,12 +114,12 @@ func (g *Groupware) GetAllEmailsInMailbox(w http.ResponseWriter, r *http.Request
|
||||
|
||||
logger := log.From(l)
|
||||
|
||||
emails, sessionState, jerr := g.jmap.GetAllEmailsInMailbox(accountId, req.session, req.ctx, logger, mailboxId, offset, limit, true, g.maxBodyValueBytes)
|
||||
emails, sessionState, lang, jerr := g.jmap.GetAllEmailsInMailbox(accountId, req.session, req.ctx, logger, req.language(), mailboxId, offset, limit, true, g.maxBodyValueBytes)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(jerr)
|
||||
}
|
||||
|
||||
return etagResponse(emails, sessionState, emails.State)
|
||||
return etagResponse(emails, sessionState, emails.State, lang)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -140,25 +140,25 @@ func (g *Groupware) GetEmailsById(w http.ResponseWriter, r *http.Request) {
|
||||
l := req.logger.With().Str(logAccountId, log.SafeString(accountId))
|
||||
if len(ids) == 1 {
|
||||
logger := log.From(l.Str("id", log.SafeString(id)))
|
||||
emails, sessionState, jerr := g.jmap.GetEmails(accountId, req.session, req.ctx, logger, ids, true, g.maxBodyValueBytes)
|
||||
emails, sessionState, lang, jerr := g.jmap.GetEmails(accountId, req.session, req.ctx, logger, req.language(), ids, true, g.maxBodyValueBytes)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(jerr)
|
||||
}
|
||||
if len(emails.Emails) < 1 {
|
||||
return notFoundResponse(sessionState)
|
||||
} else {
|
||||
return etagResponse(emails.Emails[0], sessionState, emails.State)
|
||||
return etagResponse(emails.Emails[0], sessionState, emails.State, lang)
|
||||
}
|
||||
} else {
|
||||
logger := log.From(l.Array("ids", log.SafeStringArray(ids)))
|
||||
emails, sessionState, jerr := g.jmap.GetEmails(accountId, req.session, req.ctx, logger, ids, true, g.maxBodyValueBytes)
|
||||
emails, sessionState, lang, jerr := g.jmap.GetEmails(accountId, req.session, req.ctx, logger, req.language(), ids, true, g.maxBodyValueBytes)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(jerr)
|
||||
}
|
||||
if len(emails.Emails) < 1 {
|
||||
return notFoundResponse(sessionState)
|
||||
} else {
|
||||
return etagResponse(emails.Emails, sessionState, emails.State)
|
||||
return etagResponse(emails.Emails, sessionState, emails.State, lang)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -196,7 +196,7 @@ func (g *Groupware) GetEmailAttachments(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
l := req.logger.With().Str(logAccountId, accountId)
|
||||
logger := log.From(l)
|
||||
emails, sessionState, jerr := g.jmap.GetEmails(accountId, req.session, req.ctx, logger, []string{id}, false, 0)
|
||||
emails, sessionState, lang, jerr := g.jmap.GetEmails(accountId, req.session, req.ctx, logger, req.language(), []string{id}, false, 0)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(jerr)
|
||||
}
|
||||
@@ -204,7 +204,7 @@ func (g *Groupware) GetEmailAttachments(w http.ResponseWriter, r *http.Request)
|
||||
return notFoundResponse(sessionState)
|
||||
}
|
||||
email := emails.Emails[0]
|
||||
return etagResponse(email.Attachments, sessionState, emails.State)
|
||||
return etagResponse(email.Attachments, sessionState, emails.State, lang)
|
||||
})
|
||||
} else {
|
||||
g.stream(w, r, func(req Request, w http.ResponseWriter) *Error {
|
||||
@@ -221,7 +221,7 @@ func (g *Groupware) GetEmailAttachments(w http.ResponseWriter, r *http.Request)
|
||||
l = contextAppender(l)
|
||||
logger := log.From(l)
|
||||
|
||||
emails, _, jerr := g.jmap.GetEmails(mailAccountId, req.session, req.ctx, logger, []string{id}, false, 0)
|
||||
emails, _, lang, jerr := g.jmap.GetEmails(mailAccountId, req.session, req.ctx, logger, req.language(), []string{id}, false, 0)
|
||||
if jerr != nil {
|
||||
return req.apiErrorFromJmap(req.observeJmapError(jerr))
|
||||
}
|
||||
@@ -241,7 +241,7 @@ func (g *Groupware) GetEmailAttachments(w http.ResponseWriter, r *http.Request)
|
||||
return nil
|
||||
}
|
||||
|
||||
blob, jerr := g.jmap.DownloadBlobStream(blobAccountId, attachment.BlobId, attachment.Name, attachment.Type, req.session, req.ctx, logger)
|
||||
blob, lang, jerr := g.jmap.DownloadBlobStream(blobAccountId, attachment.BlobId, attachment.Name, attachment.Type, req.session, req.ctx, logger, req.language())
|
||||
if blob != nil && blob.Body != nil {
|
||||
defer func(Body io.ReadCloser) {
|
||||
err := Body.Close()
|
||||
@@ -270,7 +270,9 @@ func (g *Groupware) GetEmailAttachments(w http.ResponseWriter, r *http.Request)
|
||||
if blob.Size >= 0 {
|
||||
w.Header().Add("Content-Size", strconv.Itoa(blob.Size))
|
||||
}
|
||||
|
||||
if lang != "" {
|
||||
w.Header().Add("Content-Language", string(lang))
|
||||
}
|
||||
_, err := io.Copy(w, blob.Body)
|
||||
if err != nil {
|
||||
return req.observedParameterError(ErrorStreamingResponse)
|
||||
@@ -300,12 +302,12 @@ func (g *Groupware) getEmailsSince(w http.ResponseWriter, r *http.Request, since
|
||||
|
||||
logger := log.From(l)
|
||||
|
||||
emails, sessionState, jerr := g.jmap.GetEmailsSince(accountId, req.session, req.ctx, logger, since, true, g.maxBodyValueBytes, maxChanges)
|
||||
emails, sessionState, lang, jerr := g.jmap.GetEmailsSince(accountId, req.session, req.ctx, logger, req.language(), since, true, g.maxBodyValueBytes, maxChanges)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(jerr)
|
||||
}
|
||||
|
||||
return etagResponse(emails, sessionState, emails.State)
|
||||
return etagResponse(emails, sessionState, emails.State, lang)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -497,7 +499,7 @@ func (g *Groupware) searchEmails(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
logger = log.From(logger.With().Str(logAccountId, accountId))
|
||||
|
||||
results, sessionState, jerr := g.jmap.QueryEmailsWithSnippets(accountId, filter, req.session, req.ctx, logger, offset, limit, fetchBodies, g.maxBodyValueBytes)
|
||||
results, sessionState, lang, jerr := g.jmap.QueryEmailsWithSnippets(accountId, filter, req.session, req.ctx, logger, req.language(), offset, limit, fetchBodies, g.maxBodyValueBytes)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(jerr)
|
||||
}
|
||||
@@ -522,7 +524,7 @@ func (g *Groupware) searchEmails(w http.ResponseWriter, r *http.Request) {
|
||||
Total: results.Total,
|
||||
Limit: results.Limit,
|
||||
QueryState: results.QueryState,
|
||||
}, sessionState, results.QueryState)
|
||||
}, sessionState, results.QueryState, lang)
|
||||
} else {
|
||||
accountId, err := req.GetAccountIdForMail()
|
||||
if err != nil {
|
||||
@@ -530,7 +532,7 @@ func (g *Groupware) searchEmails(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
logger = log.From(logger.With().Str(logAccountId, accountId))
|
||||
|
||||
results, sessionState, jerr := g.jmap.QueryEmailSnippets(accountId, filter, req.session, req.ctx, logger, offset, limit)
|
||||
results, sessionState, lang, jerr := g.jmap.QueryEmailSnippets(accountId, filter, req.session, req.ctx, logger, req.language(), offset, limit)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(jerr)
|
||||
}
|
||||
@@ -540,7 +542,7 @@ func (g *Groupware) searchEmails(w http.ResponseWriter, r *http.Request) {
|
||||
Total: results.Total,
|
||||
Limit: results.Limit,
|
||||
QueryState: results.QueryState,
|
||||
}, sessionState, results.QueryState)
|
||||
}, sessionState, results.QueryState, lang)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -608,12 +610,12 @@ func (g *Groupware) CreateEmail(w http.ResponseWriter, r *http.Request) {
|
||||
BodyValues: body.BodyValues,
|
||||
}
|
||||
|
||||
created, sessionState, jerr := g.jmap.CreateEmail(accountId, create, req.session, req.ctx, logger)
|
||||
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)
|
||||
return response(created.Email, sessionState, lang)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -642,7 +644,7 @@ func (g *Groupware) UpdateEmail(w http.ResponseWriter, r *http.Request) {
|
||||
emailId: body,
|
||||
}
|
||||
|
||||
result, sessionState, jerr := g.jmap.UpdateEmails(accountId, updates, req.session, req.ctx, logger)
|
||||
result, sessionState, lang, jerr := g.jmap.UpdateEmails(accountId, updates, req.session, req.ctx, logger, req.language())
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(jerr)
|
||||
}
|
||||
@@ -657,7 +659,7 @@ func (g *Groupware) UpdateEmail(w http.ResponseWriter, r *http.Request) {
|
||||
"An internal API behaved unexpectedly: wrong Email update ID response from JMAP endpoint")))
|
||||
}
|
||||
|
||||
return response(updatedEmail, sessionState)
|
||||
return response(updatedEmail, sessionState, lang)
|
||||
})
|
||||
|
||||
}
|
||||
@@ -677,7 +679,7 @@ func (g *Groupware) DeleteEmail(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
logger := log.From(l)
|
||||
|
||||
_, sessionState, jerr := g.jmap.DeleteEmails(accountId, []string{emailId}, req.session, req.ctx, logger)
|
||||
_, sessionState, _, jerr := g.jmap.DeleteEmails(accountId, []string{emailId}, req.session, req.ctx, logger, req.language())
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(jerr)
|
||||
}
|
||||
@@ -687,14 +689,16 @@ func (g *Groupware) DeleteEmail(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
type AboutEmailsEvent struct {
|
||||
Id string `json:"id"`
|
||||
Source string `json:"source"`
|
||||
Emails []jmap.Email `json:"emails"`
|
||||
Id string `json:"id"`
|
||||
Source string `json:"source"`
|
||||
Emails []jmap.Email `json:"emails"`
|
||||
Language jmap.Language `json:"lang"`
|
||||
}
|
||||
|
||||
type AboutEmailResponse struct {
|
||||
Email jmap.Email `json:"email"`
|
||||
RequestId string `json:"requestId"`
|
||||
Email jmap.Email `json:"email"`
|
||||
RequestId string `json:"requestId"`
|
||||
Language jmap.Language `json:"lang"`
|
||||
}
|
||||
|
||||
func relatedEmails(email jmap.Email, beacon time.Time, days uint) jmap.EmailFilterElement {
|
||||
@@ -766,7 +770,7 @@ func (g *Groupware) RelatedToEmail(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
reqId := req.GetRequestId()
|
||||
getEmailsBefore := time.Now()
|
||||
emails, sessionState, jerr := g.jmap.GetEmails(accountId, req.session, req.ctx, logger, []string{id}, true, g.maxBodyValueBytes)
|
||||
emails, sessionState, lang, jerr := g.jmap.GetEmails(accountId, req.session, req.ctx, logger, req.language(), []string{id}, true, g.maxBodyValueBytes)
|
||||
getEmailsDuration := time.Since(getEmailsBefore)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(jerr)
|
||||
@@ -791,7 +795,7 @@ func (g *Groupware) RelatedToEmail(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
g.job(logger, RelationTypeSameSender, func(jobId uint64, l *log.Logger) {
|
||||
before := time.Now()
|
||||
results, _, jerr := g.jmap.QueryEmails(accountId, filter, req.session, bgctx, l, 0, limit, false, g.maxBodyValueBytes)
|
||||
results, _, lang, jerr := g.jmap.QueryEmails(accountId, filter, req.session, bgctx, l, req.language(), 0, limit, false, g.maxBodyValueBytes)
|
||||
duration := time.Since(before)
|
||||
if jerr != nil {
|
||||
req.observeJmapError(jerr)
|
||||
@@ -801,14 +805,14 @@ func (g *Groupware) RelatedToEmail(w http.ResponseWriter, r *http.Request) {
|
||||
related := filterEmails(results.Emails, email)
|
||||
l.Trace().Msgf("'%v' found %v other emails", RelationTypeSameSender, len(related))
|
||||
if len(related) > 0 {
|
||||
req.push(RelationEntityEmail, AboutEmailsEvent{Id: reqId, Emails: related, Source: RelationTypeSameSender})
|
||||
req.push(RelationEntityEmail, AboutEmailsEvent{Id: reqId, Emails: related, Source: RelationTypeSameSender, Language: lang})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
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, false, g.maxBodyValueBytes)
|
||||
emails, _, _, jerr := g.jmap.EmailsInThread(accountId, email.ThreadId, req.session, bgctx, l, req.language(), false, g.maxBodyValueBytes)
|
||||
duration := time.Since(before)
|
||||
if jerr != nil {
|
||||
req.observeJmapError(jerr)
|
||||
@@ -818,7 +822,7 @@ func (g *Groupware) RelatedToEmail(w http.ResponseWriter, r *http.Request) {
|
||||
related := filterEmails(emails, email)
|
||||
l.Trace().Msgf("'%v' found %v other emails", RelationTypeSameThread, len(related))
|
||||
if len(related) > 0 {
|
||||
req.push(RelationEntityEmail, AboutEmailsEvent{Id: reqId, Emails: related, Source: RelationTypeSameThread})
|
||||
req.push(RelationEntityEmail, AboutEmailsEvent{Id: reqId, Emails: related, Source: RelationTypeSameThread, Language: lang})
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -826,7 +830,7 @@ func (g *Groupware) RelatedToEmail(w http.ResponseWriter, r *http.Request) {
|
||||
return etagResponse(AboutEmailResponse{
|
||||
Email: email,
|
||||
RequestId: reqId,
|
||||
}, sessionState, emails.State)
|
||||
}, sessionState, emails.State, lang)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1113,7 +1117,7 @@ func (g *Groupware) GetLatestEmailsSummaryForAllAccounts(w http.ResponseWriter,
|
||||
|
||||
logger := log.From(l)
|
||||
|
||||
emailsSummariesByAccount, sessionState, jerr := g.jmap.QueryEmailSummaries(allAccountIds, req.session, req.ctx, logger, filter, limit)
|
||||
emailsSummariesByAccount, sessionState, lang, jerr := g.jmap.QueryEmailSummaries(allAccountIds, req.session, req.ctx, logger, req.language(), filter, limit)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(jerr)
|
||||
}
|
||||
@@ -1141,7 +1145,7 @@ func (g *Groupware) GetLatestEmailsSummaryForAllAccounts(w http.ResponseWriter,
|
||||
summaries[i] = summarizeEmail(all[i].accountId, all[i].email)
|
||||
}
|
||||
|
||||
return response(summaries, sessionState)
|
||||
return response(summaries, sessionState, lang)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -32,10 +32,10 @@ func (g *Groupware) GetIdentities(w http.ResponseWriter, r *http.Request) {
|
||||
return errorResponse(err)
|
||||
}
|
||||
logger := log.From(req.logger.With().Str(logAccountId, accountId))
|
||||
res, sessionState, jerr := g.jmap.GetIdentity(accountId, req.session, req.ctx, logger)
|
||||
res, sessionState, lang, jerr := g.jmap.GetIdentity(accountId, req.session, req.ctx, logger, req.language())
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(jerr)
|
||||
}
|
||||
return etagResponse(res, sessionState, res.State)
|
||||
return etagResponse(res, sessionState, res.State, lang)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ func (g *Groupware) Index(w http.ResponseWriter, r *http.Request) {
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
accountIds := structs.Keys(req.session.Accounts)
|
||||
|
||||
identitiesResponse, sessionState, err := g.jmap.GetIdentities(accountIds, req.session, req.ctx, req.logger)
|
||||
identitiesResponse, sessionState, lang, err := g.jmap.GetIdentities(accountIds, req.session, req.ctx, req.logger, req.language())
|
||||
if err != nil {
|
||||
return req.errorResponseFromJmap(err)
|
||||
}
|
||||
@@ -163,7 +163,7 @@ func (g *Groupware) Index(w http.ResponseWriter, r *http.Request) {
|
||||
Limits: buildIndexLimits(req.session),
|
||||
Accounts: buildIndexAccount(req.session, identitiesResponse.Identities),
|
||||
PrimaryAccounts: buildIndexPrimaryAccounts(req.session),
|
||||
}, sessionState)
|
||||
}, sessionState, lang)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -41,13 +41,13 @@ func (g *Groupware) GetMailbox(w http.ResponseWriter, r *http.Request) {
|
||||
return errorResponse(err)
|
||||
}
|
||||
|
||||
mailboxes, sessionState, jerr := g.jmap.GetMailbox(accountId, req.session, req.ctx, req.logger, []string{mailboxId})
|
||||
mailboxes, sessionState, lang, jerr := g.jmap.GetMailbox(accountId, req.session, req.ctx, req.logger, req.language(), []string{mailboxId})
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(jerr)
|
||||
}
|
||||
|
||||
if len(mailboxes.Mailboxes) == 1 {
|
||||
return etagResponse(mailboxes.Mailboxes[0], sessionState, mailboxes.State)
|
||||
return etagResponse(mailboxes.Mailboxes[0], sessionState, mailboxes.State, lang)
|
||||
} else {
|
||||
return notFoundResponse(sessionState)
|
||||
}
|
||||
@@ -123,25 +123,25 @@ func (g *Groupware) GetMailboxes(w http.ResponseWriter, r *http.Request) {
|
||||
logger := log.From(req.logger.With().Str(logAccountId, accountId))
|
||||
|
||||
if hasCriteria {
|
||||
mailboxesByAccountId, sessionState, err := g.jmap.SearchMailboxes([]string{accountId}, req.session, req.ctx, logger, filter)
|
||||
mailboxesByAccountId, sessionState, lang, err := g.jmap.SearchMailboxes([]string{accountId}, req.session, req.ctx, logger, req.language(), filter)
|
||||
if err != nil {
|
||||
return req.errorResponseFromJmap(err)
|
||||
}
|
||||
|
||||
mailboxes, ok := mailboxesByAccountId[accountId]
|
||||
if ok {
|
||||
return etagResponse(mailboxes.Mailboxes, sessionState, mailboxes.State)
|
||||
return etagResponse(mailboxes.Mailboxes, sessionState, mailboxes.State, lang)
|
||||
} else {
|
||||
return notFoundResponse(sessionState)
|
||||
}
|
||||
} else {
|
||||
mailboxesByAccountId, sessionState, err := g.jmap.GetAllMailboxes([]string{accountId}, req.session, req.ctx, logger)
|
||||
mailboxesByAccountId, sessionState, lang, err := g.jmap.GetAllMailboxes([]string{accountId}, req.session, req.ctx, logger, req.language())
|
||||
if err != nil {
|
||||
return req.errorResponseFromJmap(err)
|
||||
}
|
||||
mailboxes, ok := mailboxesByAccountId[accountId]
|
||||
if ok {
|
||||
return etagResponse(mailboxes.Mailboxes, sessionState, mailboxes.State)
|
||||
return etagResponse(mailboxes.Mailboxes, sessionState, mailboxes.State, lang)
|
||||
} else {
|
||||
return notFoundResponse(sessionState)
|
||||
}
|
||||
@@ -193,17 +193,17 @@ func (g *Groupware) GetMailboxesForAllAccounts(w http.ResponseWriter, r *http.Re
|
||||
logger := log.From(req.logger.With().Array(logAccountId, log.SafeStringArray(accountIds)))
|
||||
|
||||
if hasCriteria {
|
||||
mailboxesByAccountId, sessionState, err := g.jmap.SearchMailboxes(accountIds, req.session, req.ctx, logger, filter)
|
||||
mailboxesByAccountId, sessionState, lang, err := g.jmap.SearchMailboxes(accountIds, req.session, req.ctx, logger, req.language(), filter)
|
||||
if err != nil {
|
||||
return req.errorResponseFromJmap(err)
|
||||
}
|
||||
return response(mailboxesByAccountId, sessionState)
|
||||
return response(mailboxesByAccountId, sessionState, lang)
|
||||
} else {
|
||||
mailboxesByAccountId, sessionState, err := g.jmap.GetAllMailboxes(accountIds, req.session, req.ctx, logger)
|
||||
mailboxesByAccountId, sessionState, lang, err := g.jmap.GetAllMailboxes(accountIds, req.session, req.ctx, logger, req.language())
|
||||
if err != nil {
|
||||
return req.errorResponseFromJmap(err)
|
||||
}
|
||||
return response(mailboxesByAccountId, sessionState)
|
||||
return response(mailboxesByAccountId, sessionState, lang)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -221,11 +221,11 @@ func (g *Groupware) GetMailboxByRoleForAllAccounts(w http.ResponseWriter, r *htt
|
||||
Role: role,
|
||||
}
|
||||
|
||||
mailboxesByAccountId, sessionState, err := g.jmap.SearchMailboxes(accountIds, req.session, req.ctx, logger, filter)
|
||||
mailboxesByAccountId, sessionState, lang, err := g.jmap.SearchMailboxes(accountIds, req.session, req.ctx, logger, req.language(), filter)
|
||||
if err != nil {
|
||||
return req.errorResponseFromJmap(err)
|
||||
}
|
||||
return response(mailboxesByAccountId, sessionState)
|
||||
return response(mailboxesByAccountId, sessionState, lang)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -267,12 +267,12 @@ func (g *Groupware) GetMailboxChanges(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
logger := log.From(l)
|
||||
|
||||
changes, sessionState, jerr := g.jmap.GetMailboxChanges(accountId, req.session, req.ctx, logger, mailboxId, sinceState, true, g.maxBodyValueBytes, maxChanges)
|
||||
changes, sessionState, lang, jerr := g.jmap.GetMailboxChanges(accountId, req.session, req.ctx, logger, req.language(), mailboxId, sinceState, true, g.maxBodyValueBytes, maxChanges)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(jerr)
|
||||
}
|
||||
|
||||
return etagResponse(changes, sessionState, changes.State)
|
||||
return etagResponse(changes, sessionState, changes.State, lang)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -320,12 +320,12 @@ func (g *Groupware) GetMailboxChangesForAllAccounts(w http.ResponseWriter, r *ht
|
||||
|
||||
logger := log.From(l)
|
||||
|
||||
changesByAccountId, sessionState, jerr := g.jmap.GetMailboxChangesForMultipleAccounts(allAccountIds, req.session, req.ctx, logger, sinceStateMap, true, g.maxBodyValueBytes, maxChanges)
|
||||
changesByAccountId, sessionState, lang, jerr := g.jmap.GetMailboxChangesForMultipleAccounts(allAccountIds, req.session, req.ctx, logger, req.language(), sinceStateMap, true, g.maxBodyValueBytes, maxChanges)
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(jerr)
|
||||
}
|
||||
|
||||
return response(changesByAccountId, sessionState)
|
||||
return response(changesByAccountId, sessionState, lang)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -336,11 +336,11 @@ func (g *Groupware) GetMailboxRoles(w http.ResponseWriter, r *http.Request) {
|
||||
l.Array(logAccountId, log.SafeStringArray(allAccountIds))
|
||||
logger := log.From(l)
|
||||
|
||||
rolesByAccountId, sessionState, jerr := g.jmap.GetMailboxRolesForMultipleAccounts(allAccountIds, req.session, req.ctx, logger)
|
||||
rolesByAccountId, sessionState, lang, jerr := g.jmap.GetMailboxRolesForMultipleAccounts(allAccountIds, req.session, req.ctx, logger, req.language())
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(jerr)
|
||||
}
|
||||
|
||||
return response(rolesByAccountId, sessionState)
|
||||
return response(rolesByAccountId, sessionState, lang)
|
||||
})
|
||||
}
|
||||
|
||||
39
services/groupware/pkg/groupware/groupware_api_quota.go
Normal file
39
services/groupware/pkg/groupware/groupware_api_quota.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package groupware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/jmap"
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
)
|
||||
|
||||
// When the request succeeds.
|
||||
// swagger:response GetQuotaResponse200
|
||||
type SwaggerGetQuotaResponse200 struct {
|
||||
// in: body
|
||||
Body []jmap.Quota
|
||||
}
|
||||
|
||||
// swagger:route GET /groupware/accounts/{account}/quota quota getquota
|
||||
// Get quota limits.
|
||||
//
|
||||
// responses:
|
||||
//
|
||||
// 200: GetQuotaResponse200
|
||||
// 400: ErrorResponse400
|
||||
// 500: ErrorResponse500
|
||||
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(err)
|
||||
}
|
||||
logger := log.From(req.logger.With().Str(logAccountId, accountId))
|
||||
|
||||
res, sessionState, lang, jerr := g.jmap.GetQuotas(accountId, req.session, req.ctx, logger, req.language())
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(jerr)
|
||||
}
|
||||
return etagResponse(res.List, sessionState, res.State, lang)
|
||||
})
|
||||
}
|
||||
@@ -31,7 +31,7 @@ func (g *Groupware) GetTaskLists(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
var _ string = accountId
|
||||
|
||||
return response(AllTaskLists, req.session.State)
|
||||
return response(AllTaskLists, req.session.State, "")
|
||||
})
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ func (g *Groupware) GetTaskListById(w http.ResponseWriter, r *http.Request) {
|
||||
// TODO replace with proper implementation
|
||||
for _, tasklist := range AllTaskLists {
|
||||
if tasklist.Id == tasklistId {
|
||||
return response(tasklist, req.session.State)
|
||||
return response(tasklist, req.session.State, "")
|
||||
}
|
||||
}
|
||||
return notFoundResponse(req.session.State)
|
||||
@@ -102,6 +102,6 @@ func (g *Groupware) GetTasksInTaskList(w http.ResponseWriter, r *http.Request) {
|
||||
if !ok {
|
||||
return notFoundResponse(req.session.State)
|
||||
}
|
||||
return response(tasks, req.session.State)
|
||||
return response(tasks, req.session.State, "")
|
||||
})
|
||||
}
|
||||
|
||||
@@ -37,11 +37,11 @@ func (g *Groupware) GetVacation(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
logger := log.From(req.logger.With().Str(logAccountId, accountId))
|
||||
|
||||
res, sessionState, jerr := g.jmap.GetVacationResponse(accountId, req.session, req.ctx, logger)
|
||||
res, sessionState, lang, jerr := g.jmap.GetVacationResponse(accountId, req.session, req.ctx, logger, req.language())
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(jerr)
|
||||
}
|
||||
return etagResponse(res, sessionState, res.State)
|
||||
return etagResponse(res, sessionState, res.State, lang)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -79,11 +79,11 @@ func (g *Groupware) SetVacation(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
logger := log.From(req.logger.With().Str(logAccountId, accountId))
|
||||
|
||||
res, sessionState, jerr := g.jmap.SetVacationResponse(accountId, body, req.session, req.ctx, logger)
|
||||
res, sessionState, lang, jerr := g.jmap.SetVacationResponse(accountId, body, req.session, req.ctx, logger, req.language())
|
||||
if jerr != nil {
|
||||
return req.errorResponseFromJmap(jerr)
|
||||
}
|
||||
|
||||
return etagResponse(res, sessionState, res.ResponseState)
|
||||
return etagResponse(res, sessionState, res.ResponseState, lang)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -575,6 +575,10 @@ func (g *Groupware) sendResponse(w http.ResponseWriter, r *http.Request, respons
|
||||
w.Header().Add("Session-State", string(sessionState))
|
||||
}
|
||||
|
||||
if response.contentLanguage != "" {
|
||||
w.Header().Add("Content-Language", string(response.contentLanguage))
|
||||
}
|
||||
|
||||
notModified := false
|
||||
if etag != "" {
|
||||
challenge := r.Header.Get("if-none-match")
|
||||
|
||||
@@ -65,8 +65,8 @@ var (
|
||||
errNoPrimaryAccountForTask = errors.New("no primary account for task")
|
||||
errNoPrimaryAccountForCalendar = errors.New("no primary account for calendar")
|
||||
errNoPrimaryAccountForContact = errors.New("no primary account for contact")
|
||||
errNoPrimaryAccountForQuota = errors.New("no primary account for quota")
|
||||
// errNoPrimaryAccountForSieve = errors.New("no primary account for sieve")
|
||||
// errNoPrimaryAccountForQuota = errors.New("no primary account for quota")
|
||||
// errNoPrimaryAccountForWebsocket = errors.New("no primary account for websocket")
|
||||
)
|
||||
|
||||
@@ -109,6 +109,10 @@ func (r Request) GetAccountIdForVacationResponse() (string, *Error) {
|
||||
return r.getAccountId(r.session.PrimaryAccounts.VacationResponse, errNoPrimaryAccountForVacationResponse)
|
||||
}
|
||||
|
||||
func (r Request) GetAccountIdForQuota() (string, *Error) {
|
||||
return r.getAccountId(r.session.PrimaryAccounts.Quota, errNoPrimaryAccountForQuota)
|
||||
}
|
||||
|
||||
func (r Request) GetAccountIdForSubmission() (string, *Error) {
|
||||
return r.getAccountId(r.session.PrimaryAccounts.Blob, errNoPrimaryAccountForSubmission)
|
||||
}
|
||||
@@ -280,6 +284,10 @@ func (r Request) body(target any) *Error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r Request) language() string {
|
||||
return r.r.Header.Get("Accept-Language")
|
||||
}
|
||||
|
||||
func (r Request) observe(obs prometheus.Observer, value float64) {
|
||||
metrics.WithExemplar(obs, value, r.GetRequestId(), r.GetTraceId())
|
||||
}
|
||||
|
||||
@@ -7,11 +7,12 @@ import (
|
||||
)
|
||||
|
||||
type Response struct {
|
||||
body any
|
||||
status int
|
||||
err *Error
|
||||
etag jmap.State
|
||||
sessionState jmap.SessionState
|
||||
body any
|
||||
status int
|
||||
err *Error
|
||||
etag jmap.State
|
||||
sessionState jmap.SessionState
|
||||
contentLanguage jmap.Language
|
||||
}
|
||||
|
||||
func errorResponse(err *Error) Response {
|
||||
@@ -32,30 +33,33 @@ func errorResponseWithSessionState(err *Error, sessionState jmap.SessionState) R
|
||||
}
|
||||
}
|
||||
|
||||
func response(body any, sessionState jmap.SessionState) Response {
|
||||
func response(body any, sessionState jmap.SessionState, contentLanguage jmap.Language) Response {
|
||||
return Response{
|
||||
body: body,
|
||||
err: nil,
|
||||
etag: jmap.State(sessionState),
|
||||
sessionState: sessionState,
|
||||
body: body,
|
||||
err: nil,
|
||||
etag: jmap.State(sessionState),
|
||||
sessionState: sessionState,
|
||||
contentLanguage: contentLanguage,
|
||||
}
|
||||
}
|
||||
|
||||
func etagResponse(body any, sessionState jmap.SessionState, etag jmap.State) Response {
|
||||
func etagResponse(body any, sessionState jmap.SessionState, etag jmap.State, contentLanguage jmap.Language) Response {
|
||||
return Response{
|
||||
body: body,
|
||||
err: nil,
|
||||
etag: etag,
|
||||
sessionState: sessionState,
|
||||
body: body,
|
||||
err: nil,
|
||||
etag: etag,
|
||||
sessionState: sessionState,
|
||||
contentLanguage: contentLanguage,
|
||||
}
|
||||
}
|
||||
|
||||
func etagOnlyResponse(body any, etag jmap.State) Response {
|
||||
func etagOnlyResponse(body any, etag jmap.State, contentLanguage jmap.Language) Response {
|
||||
return Response{
|
||||
body: body,
|
||||
err: nil,
|
||||
etag: etag,
|
||||
sessionState: "",
|
||||
body: body,
|
||||
err: nil,
|
||||
etag: etag,
|
||||
sessionState: "",
|
||||
contentLanguage: contentLanguage,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -72,6 +72,7 @@ func (g *Groupware) Route(r chi.Router) {
|
||||
r.Get("/identities", g.GetIdentities)
|
||||
r.Get("/vacation", g.GetVacation)
|
||||
r.Put("/vacation", g.SetVacation)
|
||||
r.Get("/quota", g.GetQuota)
|
||||
r.Route("/mailboxes", func(r chi.Router) {
|
||||
r.Get("/", g.GetMailboxes) // ?name=&role=&subcribed=
|
||||
r.Get("/{mailbox}", g.GetMailbox)
|
||||
|
||||
Reference in New Issue
Block a user