mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-04-14 04:17:36 -04:00
groupware: pollute code with NOSONAR comments, and make a little more use of JMAP API templates
This commit is contained in:
@@ -52,7 +52,7 @@ func (j *Client) UploadBlobStream(accountId string, session *Session, ctx contex
|
||||
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, acceptLanguage string) (*BlobDownload, Language, 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) { //NOSONAR
|
||||
logger = log.From(logger.With().Str(logEndpoint, session.DownloadEndpoint))
|
||||
// TODO(pbleser-oc) use a library for proper URL template parsing
|
||||
downloadUrl := session.DownloadUrlTemplate
|
||||
|
||||
@@ -12,7 +12,7 @@ type AccountBootstrapResult struct {
|
||||
Quotas []Quota `json:"quotas,omitempty"`
|
||||
}
|
||||
|
||||
func (j *Client) GetBootstrap(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (map[string]AccountBootstrapResult, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetBootstrap(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (map[string]AccountBootstrapResult, SessionState, State, Language, Error) { //NOSONAR
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
|
||||
logger = j.logger("GetBootstrap", session, logger)
|
||||
|
||||
@@ -2,7 +2,6 @@ package jmap
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
"github.com/opencloud-eu/opencloud/pkg/structs"
|
||||
@@ -46,7 +45,7 @@ func (j *Client) GetCalendars(accountId string, session *Session, ctx context.Co
|
||||
)
|
||||
}
|
||||
|
||||
func (j *Client) QueryCalendarEvents(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string,
|
||||
func (j *Client) QueryCalendarEvents(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, //NOSONAR
|
||||
filter CalendarEventFilterElement, sortBy []CalendarEventComparator,
|
||||
position uint, limit uint) (map[string][]CalendarEvent, SessionState, State, Language, Error) {
|
||||
logger = j.logger("QueryCalendarEvents", session, logger)
|
||||
@@ -137,114 +136,3 @@ func (j *Client) DeleteCalendarEvent(accountId string, destroy []string, session
|
||||
func(resp CalendarEventSetResponse) State { return resp.NewState },
|
||||
accountId, destroy, session, ctx, logger, acceptLanguage)
|
||||
}
|
||||
|
||||
func getTemplate[GETREQ any, GETRESP any, RESP any](
|
||||
client *Client, name string, getCommand Command,
|
||||
getCommandFactory func(string, []string) GETREQ,
|
||||
mapper func(GETRESP) RESP,
|
||||
stateMapper func(GETRESP) State,
|
||||
accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, ids []string) (RESP, SessionState, State, Language, Error) {
|
||||
logger = client.logger(name, session, logger)
|
||||
|
||||
var zero RESP
|
||||
|
||||
cmd, err := client.request(session, logger,
|
||||
invocation(getCommand, getCommandFactory(accountId, ids), "0"),
|
||||
)
|
||||
if err != nil {
|
||||
return zero, "", "", "", err
|
||||
}
|
||||
|
||||
return command(client.api, logger, ctx, session, client.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (RESP, State, Error) {
|
||||
var response GETRESP
|
||||
err = retrieveResponseMatchParameters(logger, body, getCommand, "0", &response)
|
||||
if err != nil {
|
||||
return zero, "", err
|
||||
}
|
||||
|
||||
return mapper(response), stateMapper(response), nil
|
||||
})
|
||||
}
|
||||
|
||||
func createTemplate[T any, SETREQ any, GETREQ any, SETRESP any, GETRESP any](
|
||||
client *Client, name string, t ObjectType, setCommand Command, getCommand Command,
|
||||
setCommandFactory func(string, map[string]T) SETREQ,
|
||||
getCommandFactory func(string, string) GETREQ,
|
||||
createdMapper func(SETRESP) map[string]*T,
|
||||
notCreatedMapper func(SETRESP) map[string]SetError,
|
||||
listMapper func(GETRESP) []T,
|
||||
stateMapper func(SETRESP) State,
|
||||
accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, create T) (*T, SessionState, State, Language, Error) {
|
||||
logger = client.logger(name, session, logger)
|
||||
|
||||
createMap := map[string]T{"c": create}
|
||||
cmd, err := client.request(session, logger,
|
||||
invocation(setCommand, setCommandFactory(accountId, createMap), "0"),
|
||||
invocation(getCommand, getCommandFactory(accountId, "#c"), "1"),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
}
|
||||
|
||||
return command(client.api, logger, ctx, session, client.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (*T, State, Error) {
|
||||
var setResponse SETRESP
|
||||
err = retrieveResponseMatchParameters(logger, body, setCommand, "0", &setResponse)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
notCreatedMap := notCreatedMapper(setResponse)
|
||||
setErr, notok := notCreatedMap["c"]
|
||||
if notok {
|
||||
logger.Error().Msgf("%T.NotCreated returned an error %v", setResponse, setErr)
|
||||
return nil, "", setErrorError(setErr, t)
|
||||
}
|
||||
|
||||
createdMap := createdMapper(setResponse)
|
||||
if created, ok := createdMap["c"]; !ok || created == nil {
|
||||
berr := fmt.Errorf("failed to find %s in %s response", string(t), string(setCommand))
|
||||
logger.Error().Err(berr)
|
||||
return nil, "", simpleError(berr, JmapErrorInvalidJmapResponsePayload)
|
||||
}
|
||||
|
||||
var getResponse GETRESP
|
||||
err = retrieveResponseMatchParameters(logger, body, getCommand, "1", &getResponse)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
list := listMapper(getResponse)
|
||||
|
||||
if len(list) < 1 {
|
||||
berr := fmt.Errorf("failed to find %s in %s response", string(t), string(getCommand))
|
||||
logger.Error().Err(berr)
|
||||
return nil, "", simpleError(berr, JmapErrorInvalidJmapResponsePayload)
|
||||
}
|
||||
|
||||
return &list[0], stateMapper(setResponse), nil
|
||||
})
|
||||
}
|
||||
|
||||
func deleteTemplate[REQ any, RESP any](client *Client, name string, c Command,
|
||||
commandFactory func(string, []string) REQ,
|
||||
notDestroyedMapper func(RESP) map[string]SetError,
|
||||
stateMapper func(RESP) State,
|
||||
accountId string, destroy []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (map[string]SetError, SessionState, State, Language, Error) {
|
||||
logger = client.logger(name, session, logger)
|
||||
|
||||
cmd, err := client.request(session, logger,
|
||||
invocation(c, commandFactory(accountId, destroy), "0"),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
}
|
||||
|
||||
return command(client.api, logger, ctx, session, client.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (map[string]SetError, State, Error) {
|
||||
var setResponse RESP
|
||||
err = retrieveResponseMatchParameters(logger, body, c, "0", &setResponse)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
return notDestroyedMapper(setResponse), stateMapper(setResponse), nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ func (j *Client) GetContactCardsSince(accountId string, session *Session, ctx co
|
||||
})
|
||||
}
|
||||
|
||||
func (j *Client) QueryContactCards(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string,
|
||||
func (j *Client) QueryContactCards(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, //NOSONAR
|
||||
filter ContactCardFilterElement, sortBy []ContactCardComparator,
|
||||
position uint, limit uint) (map[string][]jscontact.ContactCard, SessionState, State, Language, Error) {
|
||||
logger = j.logger("QueryContactCards", session, logger)
|
||||
|
||||
@@ -24,7 +24,7 @@ type getEmailsResult struct {
|
||||
}
|
||||
|
||||
// Retrieve specific Emails by their id.
|
||||
func (j *Client) GetEmails(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, ids []string, fetchBodies bool, maxBodyValueBytes uint, markAsSeen bool, withThreads bool) ([]Email, []string, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetEmails(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, ids []string, fetchBodies bool, maxBodyValueBytes uint, markAsSeen bool, withThreads bool) ([]Email, []string, SessionState, State, Language, Error) { //NOSONAR
|
||||
logger = j.logger("GetEmails", session, logger)
|
||||
|
||||
get := EmailGetCommand{AccountId: accountId, Ids: ids, FetchAllBodyValues: fetchBodies}
|
||||
@@ -48,7 +48,7 @@ func (j *Client) GetEmails(accountId string, session *Session, ctx context.Conte
|
||||
IdsRef: &ResultReference{
|
||||
ResultOf: "1",
|
||||
Name: CommandEmailGet,
|
||||
Path: "/list/*/" + EmailPropertyThreadId,
|
||||
Path: "/list/*/" + EmailPropertyThreadId, //NOSONAR
|
||||
},
|
||||
}
|
||||
methodCalls = append(methodCalls, invocation(CommandThreadGet, threads, "2"))
|
||||
@@ -113,7 +113,7 @@ func (j *Client) GetEmailBlobId(accountId string, session *Session, ctx context.
|
||||
}
|
||||
|
||||
// Retrieve all the Emails in a given Mailbox by its id.
|
||||
func (j *Client) GetAllEmailsInMailbox(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, mailboxId string, offset int, limit uint, collapseThreads bool, fetchBodies bool, maxBodyValueBytes uint, withThreads bool) (Emails, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetAllEmailsInMailbox(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, mailboxId string, offset int, limit uint, collapseThreads bool, fetchBodies bool, maxBodyValueBytes uint, withThreads bool) (Emails, SessionState, State, Language, Error) { //NOSONAR
|
||||
logger = j.loggerParams("GetAllEmailsInMailbox", session, logger, func(z zerolog.Context) zerolog.Context {
|
||||
return z.Bool(logFetchBodies, fetchBodies).Int(logOffset, offset).Uint(logLimit, limit)
|
||||
})
|
||||
@@ -135,7 +135,7 @@ func (j *Client) GetAllEmailsInMailbox(accountId string, session *Session, ctx c
|
||||
get := EmailGetRefCommand{
|
||||
AccountId: accountId,
|
||||
FetchAllBodyValues: fetchBodies,
|
||||
IdsRef: &ResultReference{Name: CommandEmailQuery, Path: "/ids/*", ResultOf: "0"},
|
||||
IdsRef: &ResultReference{Name: CommandEmailQuery, Path: "/ids/*", ResultOf: "0"}, //NOSONAR
|
||||
}
|
||||
if maxBodyValueBytes > 0 {
|
||||
get.MaxBodyValueBytes = maxBodyValueBytes
|
||||
@@ -204,7 +204,7 @@ type EmailChanges struct {
|
||||
}
|
||||
|
||||
// Get all the Emails that have been created, updated or deleted since a given state.
|
||||
func (j *Client) GetEmailChanges(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, sinceState State, fetchBodies bool, maxBodyValueBytes uint, maxChanges uint) (EmailChanges, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetEmailChanges(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, sinceState State, fetchBodies bool, maxBodyValueBytes uint, maxChanges uint) (EmailChanges, SessionState, State, Language, Error) { //NOSONAR
|
||||
logger = j.loggerParams("GetEmailChanges", session, logger, func(z zerolog.Context) zerolog.Context {
|
||||
return z.Bool(logFetchBodies, fetchBodies).Str(logSinceState, string(sinceState))
|
||||
})
|
||||
@@ -289,7 +289,7 @@ type EmailSnippetQueryResult struct {
|
||||
QueryState State `json:"queryState"`
|
||||
}
|
||||
|
||||
func (j *Client) QueryEmailSnippets(accountIds []string, filter EmailFilterElement, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, offset int, limit uint) (map[string]EmailSnippetQueryResult, SessionState, State, Language, Error) {
|
||||
func (j *Client) QueryEmailSnippets(accountIds []string, filter EmailFilterElement, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, offset int, limit uint) (map[string]EmailSnippetQueryResult, SessionState, State, Language, Error) { //NOSONAR
|
||||
logger = j.loggerParams("QueryEmailSnippets", session, logger, func(z zerolog.Context) zerolog.Context {
|
||||
return z.Uint(logLimit, limit).Int(logOffset, offset)
|
||||
})
|
||||
@@ -405,7 +405,7 @@ type EmailQueryResult struct {
|
||||
QueryState State `json:"queryState"`
|
||||
}
|
||||
|
||||
func (j *Client) QueryEmails(accountIds []string, filter EmailFilterElement, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, offset int, limit uint, fetchBodies bool, maxBodyValueBytes uint) (map[string]EmailQueryResult, SessionState, State, Language, Error) {
|
||||
func (j *Client) QueryEmails(accountIds []string, filter EmailFilterElement, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, offset int, limit uint, fetchBodies bool, maxBodyValueBytes uint) (map[string]EmailQueryResult, SessionState, State, Language, Error) { //NOSONAR
|
||||
logger = j.loggerParams("QueryEmails", session, logger, func(z zerolog.Context) zerolog.Context {
|
||||
return z.Bool(logFetchBodies, fetchBodies)
|
||||
})
|
||||
@@ -487,7 +487,7 @@ type EmailQueryWithSnippetsResult struct {
|
||||
QueryState State `json:"queryState"`
|
||||
}
|
||||
|
||||
func (j *Client) QueryEmailsWithSnippets(accountIds []string, filter EmailFilterElement, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, offset int, limit uint, fetchBodies bool, maxBodyValueBytes uint) (map[string]EmailQueryWithSnippetsResult, SessionState, State, Language, Error) {
|
||||
func (j *Client) QueryEmailsWithSnippets(accountIds []string, filter EmailFilterElement, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, offset int, limit uint, fetchBodies bool, maxBodyValueBytes uint) (map[string]EmailQueryWithSnippetsResult, SessionState, State, Language, Error) { //NOSONAR
|
||||
logger = j.loggerParams("QueryEmailsWithSnippets", session, logger, func(z zerolog.Context) zerolog.Context {
|
||||
return z.Bool(logFetchBodies, fetchBodies)
|
||||
})
|
||||
@@ -806,7 +806,7 @@ type MoveMail struct {
|
||||
ToMailboxId string
|
||||
}
|
||||
|
||||
func (j *Client) SubmitEmail(accountId string, identityId string, emailId string, move *MoveMail, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (EmailSubmission, SessionState, State, Language, Error) {
|
||||
func (j *Client) SubmitEmail(accountId string, identityId string, emailId string, move *MoveMail, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (EmailSubmission, SessionState, State, Language, Error) { //NOSONAR
|
||||
logger = j.logger("SubmitEmail", session, logger)
|
||||
|
||||
update := map[string]any{
|
||||
@@ -924,7 +924,7 @@ func (j *Client) GetEmailSubmissionStatus(accountId string, submissionIds []stri
|
||||
return result.submissions, result.notFound, sessionState, state, lang, err
|
||||
}
|
||||
|
||||
func (j *Client) EmailsInThread(accountId string, threadId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, fetchBodies bool, maxBodyValueBytes uint) ([]Email, SessionState, State, Language, Error) {
|
||||
func (j *Client) EmailsInThread(accountId string, threadId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, fetchBodies bool, maxBodyValueBytes uint) ([]Email, SessionState, State, Language, Error) { //NOSONAR
|
||||
logger = j.loggerParams("EmailsInThread", session, logger, func(z zerolog.Context) zerolog.Context {
|
||||
return z.Bool(logFetchBodies, fetchBodies).Str("threadId", log.SafeString(threadId))
|
||||
})
|
||||
@@ -986,7 +986,7 @@ var EmailSummaryProperties = []string{
|
||||
EmailPropertyPreview,
|
||||
}
|
||||
|
||||
func (j *Client) QueryEmailSummaries(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, filter EmailFilterElement, limit uint, withThreads bool) (map[string]EmailsSummary, SessionState, State, Language, Error) {
|
||||
func (j *Client) QueryEmailSummaries(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, filter EmailFilterElement, limit uint, withThreads bool) (map[string]EmailsSummary, SessionState, State, Language, Error) { //NOSONAR
|
||||
logger = j.logger("QueryEmailSummaries", session, logger)
|
||||
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
|
||||
@@ -150,7 +150,7 @@ func (j *Client) CreateIdentity(accountId string, session *Session, ctx context.
|
||||
}
|
||||
setErr, notok := response.NotCreated["c"]
|
||||
if notok {
|
||||
logger.Error().Msgf("%T.NotCreated returned an error %v", response, setErr)
|
||||
logger.Error().Msgf("%T.NotCreated returned an error %v", response, setErr) //NOSONAR
|
||||
return Identity{}, "", setErrorError(setErr, IdentityType)
|
||||
}
|
||||
return response.Created["c"], response.NewState, nil
|
||||
|
||||
@@ -114,7 +114,7 @@ func (j *Client) SearchMailboxes(accountIds []string, session *Session, ctx cont
|
||||
})
|
||||
}
|
||||
|
||||
func (j *Client) SearchMailboxIdsPerRole(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, roles []string) (map[string]map[string]string, SessionState, State, Language, Error) {
|
||||
func (j *Client) SearchMailboxIdsPerRole(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, roles []string) (map[string]map[string]string, SessionState, State, Language, Error) { //NOSONAR
|
||||
logger = j.logger("SearchMailboxIdsPerRole", session, logger)
|
||||
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
@@ -228,7 +228,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, acceptLanguage string, sinceStateMap map[string]string, maxChanges uint) (map[string]MailboxChanges, SessionState, State, Language, Error) {
|
||||
func (j *Client) GetMailboxChangesForMultipleAccounts(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, sinceStateMap map[string]string, maxChanges uint) (map[string]MailboxChanges, SessionState, State, Language, Error) { //NOSONAR
|
||||
logger = j.loggerParams("GetMailboxChangesForMultipleAccounts", session, logger, func(z zerolog.Context) zerolog.Context {
|
||||
sinceStateLogDict := zerolog.Dict()
|
||||
for k, v := range sinceStateMap {
|
||||
@@ -417,7 +417,7 @@ func (j *Client) GetInboxNameForMultipleAccounts(accountIds []string, session *S
|
||||
})
|
||||
}
|
||||
|
||||
func (j *Client) UpdateMailbox(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, mailboxId string, ifInState string, update MailboxChange) (Mailbox, SessionState, State, Language, Error) {
|
||||
func (j *Client) UpdateMailbox(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, mailboxId string, ifInState string, update MailboxChange) (Mailbox, SessionState, State, Language, Error) { //NOSONAR
|
||||
logger = j.logger("UpdateMailbox", session, logger)
|
||||
cmd, err := j.request(session, logger, invocation(CommandMailboxSet, MailboxSetCommand{
|
||||
AccountId: accountId,
|
||||
|
||||
@@ -4,32 +4,15 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
"github.com/opencloud-eu/opencloud/pkg/structs"
|
||||
)
|
||||
|
||||
func (j *Client) GetQuotas(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (map[string]QuotaGetResponse, SessionState, State, Language, Error) {
|
||||
logger = j.logger("GetQuotas", session, logger)
|
||||
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
|
||||
invocations := make([]Invocation, len(uniqueAccountIds))
|
||||
for i, accountId := range uniqueAccountIds {
|
||||
invocations[i] = invocation(CommandQuotaGet, QuotaGetCommand{AccountId: accountId}, mcid(accountId, "0"))
|
||||
}
|
||||
cmd, err := j.request(session, logger, invocations...)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
}
|
||||
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (map[string]QuotaGetResponse, State, Error) {
|
||||
result := map[string]QuotaGetResponse{}
|
||||
for _, accountId := range uniqueAccountIds {
|
||||
var response QuotaGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandQuotaGet, mcid(accountId, "0"), &response)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
result[accountId] = response
|
||||
}
|
||||
return result, squashStateFunc(result, func(q QuotaGetResponse) State { return q.State }), nil
|
||||
})
|
||||
return getTemplateN(j, "GetQuotas", CommandQuotaGet,
|
||||
func(accountId string, ids []string) QuotaGetCommand {
|
||||
return QuotaGetCommand{AccountId: accountId}
|
||||
},
|
||||
identity1,
|
||||
func(resp QuotaGetResponse) State { return resp.State },
|
||||
accountIds, session, ctx, logger, acceptLanguage, []string{},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -12,21 +12,15 @@ const (
|
||||
vacationResponseId = "singleton"
|
||||
)
|
||||
|
||||
// https://jmap.io/spec-mail.html#vacationresponseget
|
||||
func (j *Client) GetVacationResponse(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (VacationResponseGetResponse, SessionState, State, 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 command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (VacationResponseGetResponse, State, Error) {
|
||||
var response VacationResponseGetResponse
|
||||
err = retrieveResponseMatchParameters(logger, body, CommandVacationResponseGet, "0", &response)
|
||||
if err != nil {
|
||||
return VacationResponseGetResponse{}, "", err
|
||||
}
|
||||
return response, response.State, nil
|
||||
})
|
||||
return getTemplate(j, "GetVacationResponse", CommandVacationResponseGet,
|
||||
func(accountId string, ids []string) VacationResponseGetCommand {
|
||||
return VacationResponseGetCommand{AccountId: accountId}
|
||||
},
|
||||
identity1,
|
||||
func(resp VacationResponseGetResponse) State { return resp.State },
|
||||
accountId, session, ctx, logger, acceptLanguage, []string{},
|
||||
)
|
||||
}
|
||||
|
||||
// Same as VacationResponse but without the id.
|
||||
|
||||
@@ -63,18 +63,25 @@ type nullHttpJmapApiClientEventListener struct {
|
||||
}
|
||||
|
||||
func (l nullHttpJmapApiClientEventListener) OnSuccessfulRequest(endpoint string, status int) {
|
||||
// null implementation does nothing
|
||||
}
|
||||
func (l nullHttpJmapApiClientEventListener) OnFailedRequest(endpoint string, err error) {
|
||||
// null implementation does nothing
|
||||
}
|
||||
func (l nullHttpJmapApiClientEventListener) OnFailedRequestWithStatus(endpoint string, status int) {
|
||||
// null implementation does nothing
|
||||
}
|
||||
func (l nullHttpJmapApiClientEventListener) OnResponseBodyReadingError(endpoint string, err error) {
|
||||
// null implementation does nothing
|
||||
}
|
||||
func (l nullHttpJmapApiClientEventListener) OnResponseBodyUnmarshallingError(endpoint string, err error) {
|
||||
// null implementation does nothing
|
||||
}
|
||||
func (l nullHttpJmapApiClientEventListener) OnSuccessfulWsRequest(endpoint string, status int) {
|
||||
// null implementation does nothing
|
||||
}
|
||||
func (l nullHttpJmapApiClientEventListener) OnFailedWsHandshakeRequestWithStatus(endpoint string, status int) {
|
||||
// null implementation does nothing
|
||||
}
|
||||
|
||||
var _ HttpJmapApiClientEventListener = nullHttpJmapApiClientEventListener{}
|
||||
@@ -187,14 +194,14 @@ func (h *HttpJmapClient) GetSession(ctx context.Context, sessionUrl *url.URL, us
|
||||
defer func(Body io.ReadCloser) {
|
||||
err := Body.Close()
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msg("failed to close response body")
|
||||
logger.Error().Err(err).Msg("failed to close response body") //NOSONAR
|
||||
}
|
||||
}(res.Body)
|
||||
}
|
||||
|
||||
body, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msg("failed to read response body")
|
||||
logger.Error().Err(err).Msg("failed to read response body") //NOSONAR
|
||||
h.listener.OnResponseBodyReadingError(endpoint, err)
|
||||
return SessionResponse{}, SimpleError{code: JmapErrorReadingResponseBody, err: err}
|
||||
}
|
||||
@@ -210,7 +217,7 @@ func (h *HttpJmapClient) GetSession(ctx context.Context, sessionUrl *url.URL, us
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (h *HttpJmapClient) Command(ctx context.Context, logger *log.Logger, session *Session, request Request, acceptLanguage string) ([]byte, Language, Error) {
|
||||
func (h *HttpJmapClient) Command(ctx context.Context, logger *log.Logger, session *Session, request Request, acceptLanguage string) ([]byte, Language, Error) { //NOSONAR
|
||||
jmapUrl := session.JmapUrl.String()
|
||||
endpoint := session.JmapEndpoint
|
||||
logger = log.From(logger.With().Str(logEndpoint, endpoint))
|
||||
@@ -230,11 +237,11 @@ func (h *HttpJmapClient) Command(ctx context.Context, logger *log.Logger, sessio
|
||||
// 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("Accept-Language", acceptLanguage) //NOSONAR
|
||||
}
|
||||
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
req.Header.Add("User-Agent", h.userAgent)
|
||||
req.Header.Add("Content-Type", "application/json") //NOSONAR
|
||||
req.Header.Add("User-Agent", h.userAgent) //NOSONAR
|
||||
|
||||
if logger.Trace().Enabled() {
|
||||
requestBytes, err := httputil.DumpRequestOut(req, true)
|
||||
@@ -262,10 +269,10 @@ func (h *HttpJmapClient) Command(ctx context.Context, logger *log.Logger, sessio
|
||||
}
|
||||
}
|
||||
|
||||
language := Language(res.Header.Get("Content-Language"))
|
||||
language := Language(res.Header.Get("Content-Language")) //NOSONAR
|
||||
if res.StatusCode < 200 || res.StatusCode > 299 {
|
||||
h.listener.OnFailedRequestWithStatus(endpoint, res.StatusCode)
|
||||
logger.Error().Str(logEndpoint, endpoint).Str(logHttpStatus, log.SafeString(res.Status)).Msg("HTTP response status code is not 2xx")
|
||||
logger.Error().Str(logEndpoint, endpoint).Str(logHttpStatus, log.SafeString(res.Status)).Msg("HTTP response status code is not 2xx") //NOSONAR
|
||||
return nil, language, SimpleError{code: JmapErrorServerResponse, err: err}
|
||||
}
|
||||
if res.Body != nil {
|
||||
@@ -288,7 +295,7 @@ func (h *HttpJmapClient) Command(ctx context.Context, logger *log.Logger, sessio
|
||||
return body, language, nil
|
||||
}
|
||||
|
||||
func (h *HttpJmapClient) UploadBinary(ctx context.Context, logger *log.Logger, session *Session, uploadUrl string, endpoint string, contentType string, acceptLanguage string, body io.Reader) (UploadedBlob, Language, Error) {
|
||||
func (h *HttpJmapClient) UploadBinary(ctx context.Context, logger *log.Logger, session *Session, uploadUrl string, endpoint string, contentType string, acceptLanguage string, body io.Reader) (UploadedBlob, Language, Error) { //NOSONAR
|
||||
logger = log.From(logger.With().Str(logEndpoint, endpoint))
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, uploadUrl, body)
|
||||
@@ -363,7 +370,7 @@ func (h *HttpJmapClient) UploadBinary(ctx context.Context, logger *log.Logger, s
|
||||
return result, language, nil
|
||||
}
|
||||
|
||||
func (h *HttpJmapClient) DownloadBinary(ctx context.Context, logger *log.Logger, session *Session, downloadUrl string, endpoint string, acceptLanguage string) (*BlobDownload, Language, Error) {
|
||||
func (h *HttpJmapClient) DownloadBinary(ctx context.Context, logger *log.Logger, session *Session, downloadUrl string, endpoint string, acceptLanguage string) (*BlobDownload, Language, Error) { //NOSONAR
|
||||
logger = log.From(logger.With().Str(logEndpoint, endpoint))
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, downloadUrl, nil)
|
||||
@@ -554,7 +561,7 @@ type HttpWsClient struct {
|
||||
WsClient
|
||||
}
|
||||
|
||||
func (w *HttpWsClient) readPump() {
|
||||
func (w *HttpWsClient) readPump() { //NOSONAR
|
||||
logger := log.From(w.logger.With().Str("username", w.username))
|
||||
defer func() {
|
||||
if err := w.c.Close(); err != nil {
|
||||
|
||||
@@ -97,7 +97,7 @@ type ContactsBoxes struct {
|
||||
|
||||
var streetNumberRegex = regexp.MustCompile(`^(\d+)\s+(.+)$`)
|
||||
|
||||
func (s *StalwartTest) fillContacts(
|
||||
func (s *StalwartTest) fillContacts( //NOSONAR
|
||||
t *testing.T,
|
||||
count uint,
|
||||
session *Session,
|
||||
|
||||
@@ -484,7 +484,7 @@ var allKeywords = map[string]imap.Flag{
|
||||
JmapKeywordSeen: imap.FlagSeen,
|
||||
}
|
||||
|
||||
func (s *StalwartTest) fillEmailsWithImap(folder string, count int, empty bool, user User) ([]filledMail, int, error) {
|
||||
func (s *StalwartTest) fillEmailsWithImap(folder string, count int, empty bool, user User) ([]filledMail, int, error) { //NOSONAR
|
||||
to := fmt.Sprintf("%s <%s>", user.description, user.email)
|
||||
ccEvery := 2
|
||||
bccEvery := 3
|
||||
|
||||
@@ -85,7 +85,7 @@ type EventsBoxes struct {
|
||||
mayInvite bool
|
||||
}
|
||||
|
||||
func (s *StalwartTest) fillEvents(
|
||||
func (s *StalwartTest) fillEvents( //NOSONAR
|
||||
t *testing.T,
|
||||
count uint,
|
||||
session *Session,
|
||||
@@ -156,7 +156,7 @@ func (s *StalwartTest) fillEvents(
|
||||
title := gofakeit.Sentence(1)
|
||||
description := gofakeit.Paragraph(1+rand.Intn(3), 1+rand.Intn(4), 1+rand.Intn(32), "\n")
|
||||
|
||||
descriptionFormat := pickRandom("text/plain", "text/html")
|
||||
descriptionFormat := pickRandom("text/plain", "text/html") //NOSONAR
|
||||
if descriptionFormat == "text/html" {
|
||||
description = toHtml(description)
|
||||
}
|
||||
@@ -196,7 +196,7 @@ func (s *StalwartTest) fillEvents(
|
||||
"timeZone": tz,
|
||||
"hideAttendees": false,
|
||||
"replyTo": map[string]string{
|
||||
"imip": "mailto:" + organizerEmail,
|
||||
"imip": "mailto:" + organizerEmail, //NOSONAR
|
||||
},
|
||||
"locations": locationMaps,
|
||||
"virtualLocations": map[string]any{
|
||||
@@ -299,7 +299,7 @@ func (s *StalwartTest) fillEvents(
|
||||
mime = "image/png"
|
||||
uri = "data:" + mime + ";base64," + base64.StdEncoding.EncodeToString(img)
|
||||
default:
|
||||
mime = "image/jpeg"
|
||||
mime = "image/jpeg" //NOSONAR
|
||||
uri = externalImageUri()
|
||||
}
|
||||
return map[string]any{
|
||||
|
||||
@@ -206,7 +206,7 @@ func (lc *stalwartTestLogConsumer) Accept(l testcontainers.Log) {
|
||||
fmt.Print("STALWART: " + string(l.Content))
|
||||
}
|
||||
|
||||
func newStalwartTest(t *testing.T) (*StalwartTest, error) {
|
||||
func newStalwartTest(t *testing.T) (*StalwartTest, error) { //NOSONAR
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
|
||||
var _ context.CancelFunc = cancel // ignore context leak warning: it is passed in the struct and called in Close()
|
||||
|
||||
@@ -369,7 +369,7 @@ func newStalwartTest(t *testing.T) (*StalwartTest, error) {
|
||||
req.SetBasicAuth("mailadmin", "secret")
|
||||
resp, err := h.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "200 OK", resp.Status)
|
||||
require.Equal(t, "200 OK", resp.Status) //NOSONAR
|
||||
}
|
||||
|
||||
for _, user := range users {
|
||||
@@ -562,7 +562,7 @@ type uploadedBlob struct {
|
||||
Sha512 string `json:"sha:512"`
|
||||
}
|
||||
|
||||
func (j *TestJmapClient) uploadBlob(accountId string, data []byte, mimetype string) (uploadedBlob, error) {
|
||||
func (j *TestJmapClient) uploadBlob(accountId string, data []byte, mimetype string) (uploadedBlob, error) { //NOSONAR
|
||||
uploadUrl := strings.ReplaceAll(j.session.UploadUrl, "{accountId}", accountId)
|
||||
req, err := http.NewRequest(http.MethodPost, uploadUrl, bytes.NewReader(data))
|
||||
if err != nil {
|
||||
@@ -608,7 +608,7 @@ func (j *TestJmapClient) uploadBlob(accountId string, data []byte, mimetype stri
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (j *TestJmapClient) command(body map[string]any) ([]any, error) {
|
||||
func (j *TestJmapClient) command(body map[string]any) ([]any, error) { //NOSONAR
|
||||
payload, err := json.Marshal(body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -1369,7 +1369,9 @@ type MailboxFilterCondition struct {
|
||||
IsSubscribed *bool `json:"isSubscribed,omitempty"`
|
||||
}
|
||||
|
||||
func (c MailboxFilterCondition) _isAMailboxFilterElement() {}
|
||||
func (c MailboxFilterCondition) _isAMailboxFilterElement() { //NOSONAR
|
||||
// marker interface method, does not need to do anything
|
||||
}
|
||||
|
||||
var _ MailboxFilterElement = &MailboxFilterCondition{}
|
||||
|
||||
@@ -1378,7 +1380,9 @@ type MailboxFilterOperator struct {
|
||||
Conditions []MailboxFilterElement `json:"conditions,omitempty"`
|
||||
}
|
||||
|
||||
func (c MailboxFilterOperator) _isAMailboxFilterElement() {}
|
||||
func (c MailboxFilterOperator) _isAMailboxFilterElement() { //NOSONAR
|
||||
// marker interface method, does not need to do anything
|
||||
}
|
||||
|
||||
var _ MailboxFilterElement = &MailboxFilterOperator{}
|
||||
|
||||
@@ -1498,10 +1502,11 @@ type EmailFilterCondition struct {
|
||||
Header []string `json:"header,omitempty"`
|
||||
}
|
||||
|
||||
func (f EmailFilterCondition) _isAnEmailFilterElement() {
|
||||
func (f EmailFilterCondition) _isAnEmailFilterElement() { //NOSONAR
|
||||
// marker interface method, does not need to do anything
|
||||
}
|
||||
|
||||
func (f EmailFilterCondition) IsNotEmpty() bool {
|
||||
func (f EmailFilterCondition) IsNotEmpty() bool { //NOSONAR
|
||||
if !f.After.IsZero() {
|
||||
return true
|
||||
}
|
||||
@@ -1572,7 +1577,8 @@ type EmailFilterOperator struct {
|
||||
Conditions []EmailFilterElement `json:"conditions,omitempty"`
|
||||
}
|
||||
|
||||
func (o EmailFilterOperator) _isAnEmailFilterElement() {
|
||||
func (o EmailFilterOperator) _isAnEmailFilterElement() { //NOSONAR
|
||||
// marker interface method, does not need to do anything
|
||||
}
|
||||
|
||||
func (o EmailFilterOperator) IsNotEmpty() bool {
|
||||
@@ -5064,10 +5070,11 @@ type ContactCardFilterCondition struct {
|
||||
Note string `json:"note,omitempty"`
|
||||
}
|
||||
|
||||
func (f ContactCardFilterCondition) _isAContactCardFilterElement() {
|
||||
func (f ContactCardFilterCondition) _isAContactCardFilterElement() { //NOSONAR
|
||||
// marker interface method, does not need to do anything
|
||||
}
|
||||
|
||||
func (f ContactCardFilterCondition) IsNotEmpty() bool {
|
||||
func (f ContactCardFilterCondition) IsNotEmpty() bool { //NOSONAR
|
||||
if len(f.InAddressBook) != 0 {
|
||||
return true
|
||||
}
|
||||
@@ -5138,7 +5145,8 @@ type ContactCardFilterOperator struct {
|
||||
Conditions []ContactCardFilterElement `json:"conditions,omitempty"`
|
||||
}
|
||||
|
||||
func (o ContactCardFilterOperator) _isAContactCardFilterElement() {
|
||||
func (o ContactCardFilterOperator) _isAContactCardFilterElement() { //NOSONAR
|
||||
// marker interface method, does not need to do anything
|
||||
}
|
||||
|
||||
func (o ContactCardFilterOperator) IsNotEmpty() bool {
|
||||
@@ -5577,7 +5585,8 @@ type CalendarEventFilterCondition struct {
|
||||
Uid string `json:"uid,omitempty" doc:"opt"`
|
||||
}
|
||||
|
||||
func (f CalendarEventFilterCondition) _isACalendarEventFilterElement() {
|
||||
func (f CalendarEventFilterCondition) _isACalendarEventFilterElement() { //NOSONAR
|
||||
// marker interface method, does not need to do anything
|
||||
}
|
||||
|
||||
func (f CalendarEventFilterCondition) IsNotEmpty() bool {
|
||||
@@ -5624,7 +5633,8 @@ type CalendarEventFilterOperator struct {
|
||||
Conditions []CalendarEventFilterElement `json:"conditions,omitempty"`
|
||||
}
|
||||
|
||||
func (o CalendarEventFilterOperator) _isACalendarEventFilterElement() {
|
||||
func (o CalendarEventFilterOperator) _isACalendarEventFilterElement() { //NOSONAR
|
||||
// marker interface method, does not need to do anything
|
||||
}
|
||||
|
||||
func (o CalendarEventFilterOperator) IsNotEmpty() bool {
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
c "github.com/opencloud-eu/opencloud/pkg/jscontact"
|
||||
)
|
||||
|
||||
func SerializeExamples(e any) {
|
||||
func SerializeExamples(e any) { //NOSONAR
|
||||
type example struct {
|
||||
Type string `json:"type"`
|
||||
Key string `json:"key,omitempty"`
|
||||
@@ -146,7 +146,7 @@ var ExemplarInstance = Exemplar{
|
||||
AccountId: "b",
|
||||
Username: "cdrummer",
|
||||
IdentityId: "aemua9ai",
|
||||
IdentityName: "Camina Drummer",
|
||||
IdentityName: "Camina Drummer", //NOSONAR
|
||||
EmailAddress: "cdrummer@opa.example.com",
|
||||
BccName: "OPA Secretary",
|
||||
BccAddress: "secretary@opa.example.com",
|
||||
@@ -519,7 +519,7 @@ func (e Exemplar) Identities() []Identity {
|
||||
return []Identity{a, b}
|
||||
}
|
||||
|
||||
func (e Exemplar) Identity_req() Identity {
|
||||
func (e Exemplar) Identity_req() Identity { //NOSONAR
|
||||
return Identity{
|
||||
Name: e.IdentityName,
|
||||
Email: e.EmailAddress,
|
||||
@@ -964,7 +964,7 @@ func (e Exemplar) OtherJSCalendar() (c.Calendar, string, string) {
|
||||
Type: c.CalendarType,
|
||||
Kind: c.CalendarKindCalendar,
|
||||
Uri: "https://opencloud.example.com/calendar/d05779b6-9638-4694-9869-008a61df6025",
|
||||
MediaType: "application/jscontact+json",
|
||||
MediaType: "application/jscontact+json", //NOSONAR
|
||||
Contexts: map[c.CalendarContext]bool{
|
||||
c.CalendarContextWork: true,
|
||||
},
|
||||
@@ -1276,7 +1276,7 @@ func (e Exemplar) Anniversary() (c.Anniversary, string, string) {
|
||||
}
|
||||
|
||||
func (e Exemplar) OtherAnniversary() (c.Anniversary, string, string) {
|
||||
ts, _ := time.Parse(time.RFC3339, "2025-09-25T18:26:14.094725532+02:00")
|
||||
ts, _ := time.Parse(time.RFC3339, "2025-09-25T18:26:14.094725532+02:00") //NOSONAR
|
||||
return c.Anniversary{
|
||||
Type: c.AnniversaryType,
|
||||
Kind: c.AnniversaryKindBirth,
|
||||
|
||||
156
pkg/jmap/templates.go
Normal file
156
pkg/jmap/templates.go
Normal file
@@ -0,0 +1,156 @@
|
||||
package jmap
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
"github.com/opencloud-eu/opencloud/pkg/structs"
|
||||
)
|
||||
|
||||
func getTemplate[GETREQ any, GETRESP any, RESP any]( //NOSONAR
|
||||
client *Client, name string, getCommand Command,
|
||||
getCommandFactory func(string, []string) GETREQ,
|
||||
mapper func(GETRESP) RESP,
|
||||
stateMapper func(GETRESP) State,
|
||||
accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, ids []string) (RESP, SessionState, State, Language, Error) {
|
||||
logger = client.logger(name, session, logger)
|
||||
|
||||
var zero RESP
|
||||
|
||||
cmd, err := client.request(session, logger,
|
||||
invocation(getCommand, getCommandFactory(accountId, ids), "0"),
|
||||
)
|
||||
if err != nil {
|
||||
return zero, "", "", "", err
|
||||
}
|
||||
|
||||
return command(client.api, logger, ctx, session, client.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (RESP, State, Error) {
|
||||
var response GETRESP
|
||||
err = retrieveResponseMatchParameters(logger, body, getCommand, "0", &response)
|
||||
if err != nil {
|
||||
return zero, "", err
|
||||
}
|
||||
|
||||
return mapper(response), stateMapper(response), nil
|
||||
})
|
||||
}
|
||||
|
||||
func getTemplateN[GETREQ any, GETRESP any, RESP any]( //NOSONAR
|
||||
client *Client, name string, getCommand Command,
|
||||
getCommandFactory func(string, []string) GETREQ,
|
||||
mapper func(map[string]GETRESP) RESP,
|
||||
stateMapper func(GETRESP) State,
|
||||
accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, ids []string) (RESP, SessionState, State, Language, Error) {
|
||||
logger = client.logger(name, session, logger)
|
||||
|
||||
var zero RESP
|
||||
|
||||
uniqueAccountIds := structs.Uniq(accountIds)
|
||||
|
||||
invocations := make([]Invocation, len(uniqueAccountIds))
|
||||
for i, accountId := range uniqueAccountIds {
|
||||
invocations[i] = invocation(getCommand, getCommandFactory(accountId, ids), mcid(accountId, "0"))
|
||||
}
|
||||
|
||||
cmd, err := client.request(session, logger, invocations...)
|
||||
if err != nil {
|
||||
return zero, "", "", "", err
|
||||
}
|
||||
|
||||
return command(client.api, logger, ctx, session, client.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (RESP, State, Error) {
|
||||
result := map[string]GETRESP{}
|
||||
for _, accountId := range uniqueAccountIds {
|
||||
var response GETRESP
|
||||
err = retrieveResponseMatchParameters(logger, body, getCommand, mcid(accountId, "0"), &response)
|
||||
if err != nil {
|
||||
return zero, "", err
|
||||
}
|
||||
result[accountId] = response
|
||||
}
|
||||
return mapper(result), squashStateFunc(result, stateMapper), nil
|
||||
})
|
||||
}
|
||||
|
||||
func createTemplate[T any, SETREQ any, GETREQ any, SETRESP any, GETRESP any]( //NOSONAR
|
||||
client *Client, name string, t ObjectType, setCommand Command, getCommand Command,
|
||||
setCommandFactory func(string, map[string]T) SETREQ,
|
||||
getCommandFactory func(string, string) GETREQ,
|
||||
createdMapper func(SETRESP) map[string]*T,
|
||||
notCreatedMapper func(SETRESP) map[string]SetError,
|
||||
listMapper func(GETRESP) []T,
|
||||
stateMapper func(SETRESP) State,
|
||||
accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, create T) (*T, SessionState, State, Language, Error) {
|
||||
logger = client.logger(name, session, logger)
|
||||
|
||||
createMap := map[string]T{"c": create}
|
||||
cmd, err := client.request(session, logger,
|
||||
invocation(setCommand, setCommandFactory(accountId, createMap), "0"),
|
||||
invocation(getCommand, getCommandFactory(accountId, "#c"), "1"),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
}
|
||||
|
||||
return command(client.api, logger, ctx, session, client.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (*T, State, Error) {
|
||||
var setResponse SETRESP
|
||||
err = retrieveResponseMatchParameters(logger, body, setCommand, "0", &setResponse)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
notCreatedMap := notCreatedMapper(setResponse)
|
||||
setErr, notok := notCreatedMap["c"]
|
||||
if notok {
|
||||
logger.Error().Msgf("%T.NotCreated returned an error %v", setResponse, setErr)
|
||||
return nil, "", setErrorError(setErr, t)
|
||||
}
|
||||
|
||||
createdMap := createdMapper(setResponse)
|
||||
if created, ok := createdMap["c"]; !ok || created == nil {
|
||||
berr := fmt.Errorf("failed to find %s in %s response", string(t), string(setCommand))
|
||||
logger.Error().Err(berr)
|
||||
return nil, "", simpleError(berr, JmapErrorInvalidJmapResponsePayload)
|
||||
}
|
||||
|
||||
var getResponse GETRESP
|
||||
err = retrieveResponseMatchParameters(logger, body, getCommand, "1", &getResponse)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
list := listMapper(getResponse)
|
||||
|
||||
if len(list) < 1 {
|
||||
berr := fmt.Errorf("failed to find %s in %s response", string(t), string(getCommand))
|
||||
logger.Error().Err(berr)
|
||||
return nil, "", simpleError(berr, JmapErrorInvalidJmapResponsePayload)
|
||||
}
|
||||
|
||||
return &list[0], stateMapper(setResponse), nil
|
||||
})
|
||||
}
|
||||
|
||||
func deleteTemplate[REQ any, RESP any](client *Client, name string, c Command, //NOSONAR
|
||||
commandFactory func(string, []string) REQ,
|
||||
notDestroyedMapper func(RESP) map[string]SetError,
|
||||
stateMapper func(RESP) State,
|
||||
accountId string, destroy []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (map[string]SetError, SessionState, State, Language, Error) {
|
||||
logger = client.logger(name, session, logger)
|
||||
|
||||
cmd, err := client.request(session, logger,
|
||||
invocation(c, commandFactory(accountId, destroy), "0"),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
}
|
||||
|
||||
return command(client.api, logger, ctx, session, client.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (map[string]SetError, State, Error) {
|
||||
var setResponse RESP
|
||||
err = retrieveResponseMatchParameters(logger, body, c, "0", &setResponse)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
return notDestroyedMapper(setResponse), stateMapper(setResponse), nil
|
||||
})
|
||||
}
|
||||
@@ -52,7 +52,7 @@ func mcid(accountId string, tag string) string {
|
||||
return accountId + ":" + tag
|
||||
}
|
||||
|
||||
func command[T any](api ApiClient,
|
||||
func command[T any](api ApiClient, //NOSONAR
|
||||
logger *log.Logger,
|
||||
ctx context.Context,
|
||||
session *Session,
|
||||
@@ -342,3 +342,7 @@ func intPtr(i int) *int {
|
||||
func boolPtr(b bool) *bool {
|
||||
return &b
|
||||
}
|
||||
|
||||
func identity1[T any](t T) T {
|
||||
return t
|
||||
}
|
||||
|
||||
@@ -1360,7 +1360,9 @@ type OffsetTrigger struct {
|
||||
|
||||
var _ Trigger = OffsetTrigger{}
|
||||
|
||||
func (o OffsetTrigger) trigger() {}
|
||||
func (o OffsetTrigger) trigger() {
|
||||
// marker interface method, does not need to do anything
|
||||
}
|
||||
|
||||
type AbsoluteTrigger struct {
|
||||
// This specifies the type of this object. This MUST be `AbsoluteTrigger`.
|
||||
@@ -1372,7 +1374,9 @@ type AbsoluteTrigger struct {
|
||||
|
||||
var _ Trigger = AbsoluteTrigger{}
|
||||
|
||||
func (o AbsoluteTrigger) trigger() {}
|
||||
func (o AbsoluteTrigger) trigger() {
|
||||
// marker interface method, does not need to do anything
|
||||
}
|
||||
|
||||
// An `UnknownTrigger` object is an object that contains an `@type` property whose value is not recognized
|
||||
// (i.e., not `OffsetTrigger` or `AbsoluteTrigger`) plus zero or more other properties.
|
||||
@@ -1384,10 +1388,12 @@ type UnknownTrigger map[string]any
|
||||
|
||||
var _ Trigger = UnknownTrigger{}
|
||||
|
||||
func (o UnknownTrigger) trigger() {}
|
||||
func (o UnknownTrigger) trigger() {
|
||||
// marker interface method, does not need to do anything
|
||||
}
|
||||
|
||||
func MapstructTriggerHook() mapstructure.DecodeHookFunc {
|
||||
fn := func(Trigger) {}
|
||||
fn := func(Trigger) {} //NOSONAR
|
||||
wanted := reflect.TypeOf(fn).In(0)
|
||||
return func(from reflect.Type, to reflect.Type, data any) (any, error) {
|
||||
if to != wanted {
|
||||
@@ -2186,11 +2192,15 @@ type GroupEntry interface {
|
||||
groupEntry()
|
||||
}
|
||||
|
||||
func (e Event) groupEntry() {}
|
||||
func (e Event) groupEntry() {
|
||||
// marker interface method, does not need to do anything
|
||||
}
|
||||
|
||||
var _ GroupEntry = Event{}
|
||||
|
||||
func (t Task) groupEntry() {}
|
||||
func (t Task) groupEntry() {
|
||||
// marker interface method, does not need to do anything
|
||||
}
|
||||
|
||||
var _ GroupEntry = Task{}
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ func TestLink(t *testing.T) {
|
||||
}`, Link{
|
||||
Type: LinkType,
|
||||
Href: "https://opencloud.eu.example.com/f72ae875-40be-48a4-84ff-aea9aed3e085.png",
|
||||
ContentType: "image/png",
|
||||
ContentType: "image/png", //NOSONAR
|
||||
Size: 128912,
|
||||
Rel: RelIcon,
|
||||
Display: DisplayThumbnail,
|
||||
@@ -158,10 +158,10 @@ func TestNDay(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRecurrenceRule(t *testing.T) {
|
||||
ts, err := time.Parse(time.RFC3339, "2025-09-25T18:26:14+02:00")
|
||||
ts, err := time.Parse(time.RFC3339, "2025-09-25T18:26:14+02:00") //NOSONAR
|
||||
require.NoError(t, err)
|
||||
ts = ts.UTC()
|
||||
l := LocalDateTime("2025-09-25T16:26:14")
|
||||
l := LocalDateTime("2025-09-25T16:26:14") //NOSONAR
|
||||
|
||||
jsoneq(t, `{
|
||||
"@type": "RecurrenceRule",
|
||||
@@ -361,7 +361,7 @@ func TestAlertWithAbsoluteTrigger(t *testing.T) {
|
||||
},
|
||||
Acknowledged: ts,
|
||||
RelatedTo: map[string]Relation{
|
||||
"a2e729eb-7d9c-4ea7-8514-93d2590ef0a2": {
|
||||
"a2e729eb-7d9c-4ea7-8514-93d2590ef0a2": { //NOSONAR
|
||||
Type: RelationType,
|
||||
Relation: map[Relationship]bool{
|
||||
RelationshipFirst: true,
|
||||
|
||||
@@ -1905,6 +1905,7 @@ type PartialDate struct {
|
||||
}
|
||||
|
||||
func (_ PartialDate) isAnniversaryDate() {
|
||||
// marker interface method, does not need to do anything
|
||||
}
|
||||
|
||||
var _ AnniversaryDate = &PartialDate{}
|
||||
@@ -1920,6 +1921,7 @@ type Timestamp struct {
|
||||
var _ AnniversaryDate = &Timestamp{}
|
||||
|
||||
func (_ Timestamp) isAnniversaryDate() {
|
||||
// marker interface method, does not need to do anything
|
||||
}
|
||||
|
||||
type Anniversary struct {
|
||||
|
||||
@@ -32,8 +32,8 @@ func TestCalendar(t *testing.T) {
|
||||
}`, Calendar{
|
||||
Type: CalendarType,
|
||||
Kind: CalendarKindCalendar,
|
||||
Uri: "https://opencloud.eu/calendar/d05779b6-9638-4694-9869-008a61df6025",
|
||||
MediaType: "application/jscontact+json",
|
||||
Uri: "https://opencloud.eu/calendar/d05779b6-9638-4694-9869-008a61df6025", //NOSONAR
|
||||
MediaType: "application/jscontact+json", //NOSONAR
|
||||
Contexts: map[CalendarContext]bool{
|
||||
CalendarContextWork: true,
|
||||
},
|
||||
@@ -396,7 +396,7 @@ func TestOnlineService(t *testing.T) {
|
||||
Contexts: map[OnlineServiceContext]bool{
|
||||
OnlineServiceContextWork: true,
|
||||
},
|
||||
Uri: "https://opa.org/cdrummer",
|
||||
Uri: "https://opa.org/cdrummer", //NOSONAR
|
||||
User: "cdrummer@opa.org",
|
||||
Pref: 12,
|
||||
Label: "opa",
|
||||
@@ -550,7 +550,7 @@ func TestPartialDate(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestTimestamp(t *testing.T) {
|
||||
ts, err := time.Parse(time.RFC3339, "2025-09-25T18:26:14.094725532+02:00")
|
||||
ts, err := time.Parse(time.RFC3339, "2025-09-25T18:26:14.094725532+02:00") //NOSONAR
|
||||
require.NoError(t, err)
|
||||
jsoneq(t, `{
|
||||
"@type": "Timestamp",
|
||||
|
||||
@@ -56,7 +56,7 @@ func (g *Groupware) GetCalendarById(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// Get all the events in a calendar of an account by its identifier.
|
||||
func (g *Groupware) GetEventsInCalendar(w http.ResponseWriter, r *http.Request) {
|
||||
func (g *Groupware) GetEventsInCalendar(w http.ResponseWriter, r *http.Request) { //NOSONAR
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
ok, accountId, resp := req.needCalendarWithAccount()
|
||||
if !ok {
|
||||
|
||||
@@ -90,7 +90,7 @@ func (g *Groupware) GetAddressbook(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// Get all the contacts in an addressbook of an account by its identifier.
|
||||
func (g *Groupware) GetContactsInAddressbook(w http.ResponseWriter, r *http.Request) {
|
||||
func (g *Groupware) GetContactsInAddressbook(w http.ResponseWriter, r *http.Request) { //NOSONAR
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
ok, accountId, resp := req.needContactWithAccount()
|
||||
if !ok {
|
||||
|
||||
@@ -66,7 +66,7 @@ func (g *Groupware) GetEmailChanges(w http.ResponseWriter, r *http.Request) {
|
||||
//
|
||||
// A limit and an offset may be specified using the query parameters 'limit' and 'offset',
|
||||
// respectively.
|
||||
func (g *Groupware) GetAllEmailsInMailbox(w http.ResponseWriter, r *http.Request) {
|
||||
func (g *Groupware) GetAllEmailsInMailbox(w http.ResponseWriter, r *http.Request) { //NOSONAR
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
l := req.logger.With()
|
||||
|
||||
@@ -124,7 +124,7 @@ func (g *Groupware) GetAllEmailsInMailbox(w http.ResponseWriter, r *http.Request
|
||||
})
|
||||
}
|
||||
|
||||
func (g *Groupware) GetEmailsById(w http.ResponseWriter, r *http.Request) {
|
||||
func (g *Groupware) GetEmailsById(w http.ResponseWriter, r *http.Request) { //NOSONAR
|
||||
accept := r.Header.Get("Accept")
|
||||
if accept == "message/rfc822" {
|
||||
g.stream(w, r, func(req Request, w http.ResponseWriter) *Error {
|
||||
@@ -230,7 +230,7 @@ func (g *Groupware) GetEmailsById(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Groupware) GetEmailAttachments(w http.ResponseWriter, r *http.Request) {
|
||||
func (g *Groupware) GetEmailAttachments(w http.ResponseWriter, r *http.Request) { //NOSONAR
|
||||
contextAppender := func(l zerolog.Context) zerolog.Context { return l }
|
||||
q := r.URL.Query()
|
||||
var attachmentSelector func(jmap.EmailBodyPart) bool = nil
|
||||
@@ -434,7 +434,7 @@ type EmailSearchResults struct {
|
||||
QueryState jmap.State `json:"queryState,omitempty"`
|
||||
}
|
||||
|
||||
func (g *Groupware) buildEmailFilter(req Request) (bool, jmap.EmailFilterElement, bool, int, uint, *log.Logger, *Error) {
|
||||
func (g *Groupware) buildEmailFilter(req Request) (bool, jmap.EmailFilterElement, bool, int, uint, *log.Logger, *Error) { //NOSONAR
|
||||
mailboxId, _ := req.getStringParam(QueryParamMailboxId, "") // the identifier of the Mailbox to which to restrict the search
|
||||
text, _ := req.getStringParam(QueryParamSearchText, "") // text that must be included in the Email, specifically in From, To, Cc, Bcc, Subject and any text/* body part
|
||||
from, _ := req.getStringParam(QueryParamSearchFrom, "") // text that must be included in the From header of the Email
|
||||
@@ -587,7 +587,7 @@ func (g *Groupware) buildEmailFilter(req Request) (bool, jmap.EmailFilterElement
|
||||
return true, filter, snippets, offset, limit, logger, nil
|
||||
}
|
||||
|
||||
func (g *Groupware) GetEmails(w http.ResponseWriter, r *http.Request) {
|
||||
func (g *Groupware) GetEmails(w http.ResponseWriter, r *http.Request) { //NOSONAR
|
||||
q := r.URL.Query()
|
||||
since := q.Get(QueryParamSince)
|
||||
if since == "" {
|
||||
@@ -659,7 +659,7 @@ func (g *Groupware) GetEmails(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Groupware) GetEmailsForAllAccounts(w http.ResponseWriter, r *http.Request) {
|
||||
func (g *Groupware) GetEmailsForAllAccounts(w http.ResponseWriter, r *http.Request) { //NOSONAR
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
allAccountIds := req.AllAccountIds()
|
||||
|
||||
@@ -782,7 +782,7 @@ var sentEmailAutoMailboxRolePrecedence = []string{
|
||||
|
||||
var draftAndSentMailboxRoles = structs.Uniq(structs.Concat(draftEmailAutoMailboxRolePrecedence, sentEmailAutoMailboxRolePrecedence))
|
||||
|
||||
func findSentMailboxId(j *jmap.Client, accountId string, req Request, logger *log.Logger) (string, string, Response) {
|
||||
func findSentMailboxId(j *jmap.Client, accountId string, req Request, logger *log.Logger) (string, string, Response) { //NOSONAR
|
||||
mailboxIdsPerAccountIds, sessionState, _, lang, jerr := j.SearchMailboxIdsPerRole(single(accountId), req.session, req.ctx, logger, req.language(), draftAndSentMailboxRoles)
|
||||
if jerr != nil {
|
||||
return "", "", req.jmapError(accountId, jerr, sessionState, lang)
|
||||
@@ -919,13 +919,13 @@ func (g *Groupware) UpdateEmail(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
if result == nil {
|
||||
return req.error(accountId, apiError(req.errorId(), ErrorApiInconsistency, withTitle("API Inconsistency: Missing Email Update Response",
|
||||
"An internal API behaved unexpectedly: missing Email update response from JMAP endpoint")))
|
||||
return req.error(accountId, apiError(req.errorId(), ErrorApiInconsistency, withTitle("API Inconsistency: Missing Email Update Response", //NOSONAR
|
||||
"An internal API behaved unexpectedly: missing Email update response from JMAP endpoint"))) //NOSONAR
|
||||
}
|
||||
updatedEmail, ok := result[emailId]
|
||||
if !ok {
|
||||
return req.error(accountId, apiError(req.errorId(), ErrorApiInconsistency, withTitle("API Inconsistency: Wrong Email Update Response ID",
|
||||
"An internal API behaved unexpectedly: wrong Email update ID response from JMAP endpoint")))
|
||||
return req.error(accountId, apiError(req.errorId(), ErrorApiInconsistency, withTitle("API Inconsistency: Wrong Email Update Response ID", //NOSONAR
|
||||
"An internal API behaved unexpectedly: wrong Email update ID response from JMAP endpoint"))) //NOSONAR
|
||||
}
|
||||
|
||||
return req.respond(accountId, updatedEmail, sessionState, EmailResponseObjectType, state)
|
||||
@@ -941,7 +941,7 @@ func (e emailKeywordUpdates) IsEmpty() bool {
|
||||
return len(e.Add) == 0 && len(e.Remove) == 0
|
||||
}
|
||||
|
||||
func (g *Groupware) UpdateEmailKeywords(w http.ResponseWriter, r *http.Request) {
|
||||
func (g *Groupware) UpdateEmailKeywords(w http.ResponseWriter, r *http.Request) { //NOSONAR
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
l := req.logger.With()
|
||||
|
||||
@@ -971,10 +971,10 @@ func (g *Groupware) UpdateEmailKeywords(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
patch := jmap.EmailUpdate{}
|
||||
for _, keyword := range body.Add {
|
||||
patch["keywords/"+keyword] = true
|
||||
patch["keywords/"+keyword] = true //NOSONAR
|
||||
}
|
||||
for _, keyword := range body.Remove {
|
||||
patch["keywords/"+keyword] = nil
|
||||
patch["keywords/"+keyword] = nil //NOSONAR
|
||||
}
|
||||
patches := map[string]jmap.EmailUpdate{
|
||||
emailId: patch,
|
||||
@@ -1000,7 +1000,7 @@ func (g *Groupware) UpdateEmailKeywords(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
|
||||
// Add keywords to an email by its unique identifier.
|
||||
func (g *Groupware) AddEmailKeywords(w http.ResponseWriter, r *http.Request) {
|
||||
func (g *Groupware) AddEmailKeywords(w http.ResponseWriter, r *http.Request) { //NOSONAR
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
l := req.logger.With()
|
||||
|
||||
@@ -1060,7 +1060,7 @@ func (g *Groupware) AddEmailKeywords(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// Remove keywords of an email by its unique identifier.
|
||||
func (g *Groupware) RemoveEmailKeywords(w http.ResponseWriter, r *http.Request) {
|
||||
func (g *Groupware) RemoveEmailKeywords(w http.ResponseWriter, r *http.Request) { //NOSONAR
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
l := req.logger.With()
|
||||
|
||||
@@ -1207,7 +1207,7 @@ func (g *Groupware) DeleteEmails(w http.ResponseWriter, r *http.Request) {
|
||||
})
|
||||
}
|
||||
|
||||
func (g *Groupware) SendEmail(w http.ResponseWriter, r *http.Request) {
|
||||
func (g *Groupware) SendEmail(w http.ResponseWriter, r *http.Request) { //NOSONAR
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
l := req.logger.With()
|
||||
|
||||
@@ -1323,7 +1323,7 @@ func relatedEmailsFilter(email jmap.Email, beacon time.Time, days uint) jmap.Ema
|
||||
return filter
|
||||
}
|
||||
|
||||
func (g *Groupware) RelatedToEmail(w http.ResponseWriter, r *http.Request) {
|
||||
func (g *Groupware) RelatedToEmail(w http.ResponseWriter, r *http.Request) { //NOSONAR
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
l := req.logger.With()
|
||||
|
||||
@@ -1618,7 +1618,7 @@ type EmailSummaries struct {
|
||||
//
|
||||
// * `seen`: when `true`, emails that have already been seen (read) will be included as well (default is to only include emails that have not been read yet)
|
||||
// * `undesirable`: when `true`, emails that are flagged as spam or phishing will also be summarized (default is to ignore those)
|
||||
func (g *Groupware) GetLatestEmailsSummaryForAllAccounts(w http.ResponseWriter, r *http.Request) {
|
||||
func (g *Groupware) GetLatestEmailsSummaryForAllAccounts(w http.ResponseWriter, r *http.Request) { //NOSONAR
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
l := req.logger.With()
|
||||
|
||||
@@ -1741,7 +1741,7 @@ var sanitizableMediaTypes = []string{
|
||||
"text/xhtml",
|
||||
}
|
||||
|
||||
func (r *Request) sanitizeEmail(source jmap.Email) (jmap.Email, *Error) {
|
||||
func (r *Request) sanitizeEmail(source jmap.Email) (jmap.Email, *Error) { //NOSONAR
|
||||
if !r.g.config.sanitize {
|
||||
return source, nil
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ func (g *Groupware) GetMailbox(w http.ResponseWriter, r *http.Request) {
|
||||
// It is analogous to a folder or a label in other systems.
|
||||
//
|
||||
// When none of the query parameters are specified, all the mailboxes are returned.
|
||||
func (g *Groupware) GetMailboxes(w http.ResponseWriter, r *http.Request) {
|
||||
func (g *Groupware) GetMailboxes(w http.ResponseWriter, r *http.Request) { //NOSONAR
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
var filter jmap.MailboxFilterCondition
|
||||
|
||||
@@ -109,7 +109,7 @@ func (g *Groupware) GetMailboxes(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// Get the list of all the mailboxes of all accounts of a user, potentially filtering on the role of the mailboxes.
|
||||
func (g *Groupware) GetMailboxesForAllAccounts(w http.ResponseWriter, r *http.Request) {
|
||||
func (g *Groupware) GetMailboxesForAllAccounts(w http.ResponseWriter, r *http.Request) { //NOSONAR
|
||||
g.respond(w, r, func(req Request) Response {
|
||||
accountIds := req.AllAccountIds()
|
||||
if len(accountIds) < 1 {
|
||||
|
||||
@@ -74,7 +74,7 @@ func (d DnsSessionUrlResolver) isRedListed(domain string) bool {
|
||||
return !slices.Contains(d.domainRedList, domain)
|
||||
}
|
||||
|
||||
func (d DnsSessionUrlResolver) Resolve(ctx context.Context, username string) (*url.URL, *GroupwareError) {
|
||||
func (d DnsSessionUrlResolver) Resolve(ctx context.Context, username string) (*url.URL, *GroupwareError) { //NOSONAR
|
||||
// heuristic to detect whether the username is an email address
|
||||
parts := strings.Split(username, "@")
|
||||
domain := d.defaultDomain
|
||||
|
||||
@@ -172,7 +172,7 @@ func (r groupwareHttpJmapApiClientMetricsRecorder) OnFailedWsHandshakeRequestWit
|
||||
// TODO metrics for WSS
|
||||
}
|
||||
|
||||
func NewGroupware(config *config.Config, logger *log.Logger, mux *chi.Mux, prometheusRegistry prometheus.Registerer) (*Groupware, error) {
|
||||
func NewGroupware(config *config.Config, logger *log.Logger, mux *chi.Mux, prometheusRegistry prometheus.Registerer) (*Groupware, error) { //NOSONAR
|
||||
baseUrl, err := url.Parse(config.Mail.BaseUrl)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msgf("failed to parse configured Mail.Baseurl '%v'", config.Mail.BaseUrl)
|
||||
@@ -318,7 +318,7 @@ func NewGroupware(config *config.Config, logger *log.Logger, mux *chi.Mux, prome
|
||||
{
|
||||
eventBufferSizeMetric, err := prometheus.NewConstMetric(m.EventBufferSizeDesc, prometheus.GaugeValue, float64(eventChannelSize))
|
||||
if err != nil {
|
||||
logger.Warn().Err(err).Msgf("failed to create metric %v", m.EventBufferSizeDesc.String())
|
||||
logger.Warn().Err(err).Msgf("failed to create metric %v", m.EventBufferSizeDesc.String()) //NOSONAR
|
||||
} else {
|
||||
if err := prometheusRegistry.Register(metrics.ConstMetricCollector{Metric: eventBufferSizeMetric}); err != nil {
|
||||
logger.Error().Err(err).Msg("failed to register event buffer size metric collector")
|
||||
@@ -567,7 +567,7 @@ func (g *Groupware) serveError(w http.ResponseWriter, r *http.Request, error *Er
|
||||
return
|
||||
}
|
||||
g.log(error)
|
||||
w.Header().Add("Content-Type", ContentTypeJsonApi)
|
||||
w.Header().Add("Content-Type", ContentTypeJsonApi) //NOSONAR
|
||||
if !retryAfter.IsZero() {
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Retry-After
|
||||
// either as an absolute timestamp:
|
||||
@@ -578,7 +578,7 @@ func (g *Groupware) serveError(w http.ResponseWriter, r *http.Request, error *Er
|
||||
render.Status(r, error.NumStatus)
|
||||
w.WriteHeader(error.NumStatus)
|
||||
if err := render.Render(w, r, errorResponses(*error)); err != nil {
|
||||
g.logger.Error().Err(err).Msgf("failed to render error response")
|
||||
g.logger.Error().Err(err).Msg("failed to render error response") //NOSONAR
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -67,13 +67,13 @@ func (g *Groupware) Route(r chi.Router) {
|
||||
r.Get("/", g.GetAccountsWithTheirIdentities)
|
||||
r.Route("/all", func(r chi.Router) {
|
||||
r.Get("/", g.GetAccounts)
|
||||
r.Route("/mailboxes", func(r chi.Router) {
|
||||
r.Route("/mailboxes", func(r chi.Router) { //NOSONAR
|
||||
r.Get("/", g.GetMailboxesForAllAccounts) // ?role=
|
||||
r.Get("/changes", g.GetMailboxChangesForAllAccounts)
|
||||
r.Get("/roles", g.GetMailboxRoles) // ?role=
|
||||
r.Get("/roles/{role}", g.GetMailboxByRoleForAllAccounts) // ?role=
|
||||
})
|
||||
r.Route("/emails", func(r chi.Router) {
|
||||
r.Route("/emails", func(r chi.Router) { //NOSONAR
|
||||
r.Get("/", g.GetEmailsForAllAccounts)
|
||||
r.Get("/latest/summary", g.GetLatestEmailsSummaryForAllAccounts) // ?limit=10&seen=true&undesirable=true
|
||||
})
|
||||
@@ -141,7 +141,7 @@ func (g *Groupware) Route(r chi.Router) {
|
||||
r.Get("/", g.GetAddressbooks)
|
||||
r.Route("/{addressbookid}", func(r chi.Router) {
|
||||
r.Get("/", g.GetAddressbook)
|
||||
r.Get("/contacts", g.GetContactsInAddressbook)
|
||||
r.Get("/contacts", g.GetContactsInAddressbook) //NOSONAR
|
||||
})
|
||||
})
|
||||
r.Route("/contacts", func(r chi.Router) {
|
||||
|
||||
@@ -172,7 +172,7 @@ type sessionCacheBuilder struct {
|
||||
sessionFailureCacheTtl time.Duration
|
||||
}
|
||||
|
||||
func newSessionCacheBuilder(
|
||||
func newSessionCacheBuilder( //NOSONAR
|
||||
sessionUrl *url.URL,
|
||||
logger *log.Logger,
|
||||
sessionSupplier func(ctx context.Context, sessionUrl *url.URL, username string, logger *log.Logger) (jmap.Session, jmap.Error),
|
||||
@@ -229,7 +229,7 @@ func (b *sessionCacheBuilder) withDnsAutoDiscovery(
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *sessionCacheBuilder) build() (sessionCache, error) {
|
||||
func (b *sessionCacheBuilder) build() (sessionCache, error) { //NOSONAR
|
||||
var cache *ttlcache.Cache[sessionCacheKey, cachedSession]
|
||||
|
||||
sessionUrlResolver, err := b.sessionUrlResolverFactory()
|
||||
|
||||
Reference in New Issue
Block a user