From 96ee4e6db13e42b9326a8165b77c67ff0efb583d Mon Sep 17 00:00:00 2001
From: Pascal Bleser
Date: Tue, 24 Mar 2026 10:55:42 +0100
Subject: [PATCH] groupware: pollute code with NOSONAR comments, and make a
little more use of JMAP API templates
---
pkg/jmap/api_blob.go | 2 +-
pkg/jmap/api_bootstrap.go | 2 +-
pkg/jmap/api_calendar.go | 114 +------------
pkg/jmap/api_contact.go | 2 +-
pkg/jmap/api_email.go | 22 +--
pkg/jmap/api_identity.go | 2 +-
pkg/jmap/api_mailbox.go | 6 +-
pkg/jmap/api_quota.go | 33 +---
pkg/jmap/api_vacation.go | 22 +--
pkg/jmap/http.go | 29 ++--
pkg/jmap/integration_contact_test.go | 2 +-
pkg/jmap/integration_email_test.go | 2 +-
pkg/jmap/integration_event_test.go | 8 +-
pkg/jmap/integration_test.go | 8 +-
pkg/jmap/model.go | 30 ++--
pkg/jmap/model_examples.go | 10 +-
pkg/jmap/templates.go | 156 ++++++++++++++++++
pkg/jmap/tools.go | 6 +-
pkg/jscalendar/model.go | 22 ++-
pkg/jscalendar/model_test.go | 8 +-
pkg/jscontact/model.go | 2 +
pkg/jscontact/model_test.go | 8 +-
.../groupware/pkg/groupware/api_calendars.go | 2 +-
.../groupware/pkg/groupware/api_contacts.go | 2 +-
.../groupware/pkg/groupware/api_emails.go | 40 ++---
.../groupware/pkg/groupware/api_mailbox.go | 4 +-
services/groupware/pkg/groupware/dns.go | 2 +-
services/groupware/pkg/groupware/framework.go | 8 +-
services/groupware/pkg/groupware/route.go | 6 +-
services/groupware/pkg/groupware/session.go | 4 +-
30 files changed, 309 insertions(+), 255 deletions(-)
create mode 100644 pkg/jmap/templates.go
diff --git a/pkg/jmap/api_blob.go b/pkg/jmap/api_blob.go
index bb0b0a6751..c6ab466cb7 100644
--- a/pkg/jmap/api_blob.go
+++ b/pkg/jmap/api_blob.go
@@ -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
diff --git a/pkg/jmap/api_bootstrap.go b/pkg/jmap/api_bootstrap.go
index 2635bf273a..532a8a4001 100644
--- a/pkg/jmap/api_bootstrap.go
+++ b/pkg/jmap/api_bootstrap.go
@@ -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)
diff --git a/pkg/jmap/api_calendar.go b/pkg/jmap/api_calendar.go
index 1e78dcb9a2..083fa6e986 100644
--- a/pkg/jmap/api_calendar.go
+++ b/pkg/jmap/api_calendar.go
@@ -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
- })
-}
diff --git a/pkg/jmap/api_contact.go b/pkg/jmap/api_contact.go
index 790fbcb24d..7bdbd9a58a 100644
--- a/pkg/jmap/api_contact.go
+++ b/pkg/jmap/api_contact.go
@@ -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)
diff --git a/pkg/jmap/api_email.go b/pkg/jmap/api_email.go
index e6cffd3ef5..558977f4a9 100644
--- a/pkg/jmap/api_email.go
+++ b/pkg/jmap/api_email.go
@@ -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)
diff --git a/pkg/jmap/api_identity.go b/pkg/jmap/api_identity.go
index 3eabf7abf5..86dbbcc696 100644
--- a/pkg/jmap/api_identity.go
+++ b/pkg/jmap/api_identity.go
@@ -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
diff --git a/pkg/jmap/api_mailbox.go b/pkg/jmap/api_mailbox.go
index 0c0b2b643e..efe2d481d5 100644
--- a/pkg/jmap/api_mailbox.go
+++ b/pkg/jmap/api_mailbox.go
@@ -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,
diff --git a/pkg/jmap/api_quota.go b/pkg/jmap/api_quota.go
index 3b82a13bd9..d67fa79bfb 100644
--- a/pkg/jmap/api_quota.go
+++ b/pkg/jmap/api_quota.go
@@ -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{},
+ )
}
diff --git a/pkg/jmap/api_vacation.go b/pkg/jmap/api_vacation.go
index ef553e5de8..f2a4f9d9b1 100644
--- a/pkg/jmap/api_vacation.go
+++ b/pkg/jmap/api_vacation.go
@@ -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.
diff --git a/pkg/jmap/http.go b/pkg/jmap/http.go
index 3561cd3bbc..bd6eda438c 100644
--- a/pkg/jmap/http.go
+++ b/pkg/jmap/http.go
@@ -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 {
diff --git a/pkg/jmap/integration_contact_test.go b/pkg/jmap/integration_contact_test.go
index decdbf3e8f..33c636e273 100644
--- a/pkg/jmap/integration_contact_test.go
+++ b/pkg/jmap/integration_contact_test.go
@@ -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,
diff --git a/pkg/jmap/integration_email_test.go b/pkg/jmap/integration_email_test.go
index 433eb5cf3a..1a8c992703 100644
--- a/pkg/jmap/integration_email_test.go
+++ b/pkg/jmap/integration_email_test.go
@@ -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
diff --git a/pkg/jmap/integration_event_test.go b/pkg/jmap/integration_event_test.go
index a4d1ee76b5..c3c5585f03 100644
--- a/pkg/jmap/integration_event_test.go
+++ b/pkg/jmap/integration_event_test.go
@@ -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{
diff --git a/pkg/jmap/integration_test.go b/pkg/jmap/integration_test.go
index eebbc61144..c4ccbe899b 100644
--- a/pkg/jmap/integration_test.go
+++ b/pkg/jmap/integration_test.go
@@ -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
diff --git a/pkg/jmap/model.go b/pkg/jmap/model.go
index 6ed66897c4..1a08029229 100644
--- a/pkg/jmap/model.go
+++ b/pkg/jmap/model.go
@@ -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 {
diff --git a/pkg/jmap/model_examples.go b/pkg/jmap/model_examples.go
index 933b1441b3..c1982c30a6 100644
--- a/pkg/jmap/model_examples.go
+++ b/pkg/jmap/model_examples.go
@@ -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,
diff --git a/pkg/jmap/templates.go b/pkg/jmap/templates.go
new file mode 100644
index 0000000000..f327ca8efe
--- /dev/null
+++ b/pkg/jmap/templates.go
@@ -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
+ })
+}
diff --git a/pkg/jmap/tools.go b/pkg/jmap/tools.go
index c6f2f836e7..bbba0c7ce0 100644
--- a/pkg/jmap/tools.go
+++ b/pkg/jmap/tools.go
@@ -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
+}
diff --git a/pkg/jscalendar/model.go b/pkg/jscalendar/model.go
index 7c26a5edf5..3cb12bde3a 100644
--- a/pkg/jscalendar/model.go
+++ b/pkg/jscalendar/model.go
@@ -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{}
diff --git a/pkg/jscalendar/model_test.go b/pkg/jscalendar/model_test.go
index e54c3e5a44..d21403dfe9 100644
--- a/pkg/jscalendar/model_test.go
+++ b/pkg/jscalendar/model_test.go
@@ -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,
diff --git a/pkg/jscontact/model.go b/pkg/jscontact/model.go
index 8e1be8a3b7..17cf4d5492 100644
--- a/pkg/jscontact/model.go
+++ b/pkg/jscontact/model.go
@@ -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 {
diff --git a/pkg/jscontact/model_test.go b/pkg/jscontact/model_test.go
index 684bf69556..f70eeabb7c 100644
--- a/pkg/jscontact/model_test.go
+++ b/pkg/jscontact/model_test.go
@@ -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",
diff --git a/services/groupware/pkg/groupware/api_calendars.go b/services/groupware/pkg/groupware/api_calendars.go
index 21c62919d4..91d8ca2336 100644
--- a/services/groupware/pkg/groupware/api_calendars.go
+++ b/services/groupware/pkg/groupware/api_calendars.go
@@ -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 {
diff --git a/services/groupware/pkg/groupware/api_contacts.go b/services/groupware/pkg/groupware/api_contacts.go
index 28e9081642..973e3a8de3 100644
--- a/services/groupware/pkg/groupware/api_contacts.go
+++ b/services/groupware/pkg/groupware/api_contacts.go
@@ -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 {
diff --git a/services/groupware/pkg/groupware/api_emails.go b/services/groupware/pkg/groupware/api_emails.go
index 57a44ce40b..e91afe8803 100644
--- a/services/groupware/pkg/groupware/api_emails.go
+++ b/services/groupware/pkg/groupware/api_emails.go
@@ -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
}
diff --git a/services/groupware/pkg/groupware/api_mailbox.go b/services/groupware/pkg/groupware/api_mailbox.go
index c571d9e855..8baa9abbcb 100644
--- a/services/groupware/pkg/groupware/api_mailbox.go
+++ b/services/groupware/pkg/groupware/api_mailbox.go
@@ -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 {
diff --git a/services/groupware/pkg/groupware/dns.go b/services/groupware/pkg/groupware/dns.go
index 2ca67df8e4..c05c7b7a66 100644
--- a/services/groupware/pkg/groupware/dns.go
+++ b/services/groupware/pkg/groupware/dns.go
@@ -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
diff --git a/services/groupware/pkg/groupware/framework.go b/services/groupware/pkg/groupware/framework.go
index 9b384955a4..1869759098 100644
--- a/services/groupware/pkg/groupware/framework.go
+++ b/services/groupware/pkg/groupware/framework.go
@@ -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
}
}
diff --git a/services/groupware/pkg/groupware/route.go b/services/groupware/pkg/groupware/route.go
index f1e2c25117..91a41e71be 100644
--- a/services/groupware/pkg/groupware/route.go
+++ b/services/groupware/pkg/groupware/route.go
@@ -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) {
diff --git a/services/groupware/pkg/groupware/session.go b/services/groupware/pkg/groupware/session.go
index 2ef0aaa86b..3feac3a763 100644
--- a/services/groupware/pkg/groupware/session.go
+++ b/services/groupware/pkg/groupware/session.go
@@ -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()