chore: fix gocyclo issues

This commit is contained in:
jamesread 2025-10-11 00:52:18 +01:00
parent b330fbd1a5
commit 60814b97e2
3 changed files with 120 additions and 74 deletions

View File

@ -321,40 +321,50 @@ func (api *oliveTinAPI) GetActionBinding(ctx ctx.Context, req *connect.Request[a
func (api *oliveTinAPI) GetDashboard(ctx ctx.Context, req *connect.Request[apiv1.GetDashboardRequest]) (*connect.Response[apiv1.GetDashboardResponse], error) { func (api *oliveTinAPI) GetDashboard(ctx ctx.Context, req *connect.Request[apiv1.GetDashboardRequest]) (*connect.Response[apiv1.GetDashboardResponse], error) {
user := acl.UserFromContext(ctx, api.cfg) user := acl.UserFromContext(ctx, api.cfg)
if user.IsGuest() && api.cfg.AuthRequireGuestsToLogin { if err := api.checkDashboardAccess(user); err != nil {
return nil, connect.NewError(connect.CodePermissionDenied, fmt.Errorf("guests are not allowed to access the dashboard")) return nil, err
} }
dashboardRenderRequest := &DashboardRenderRequest{ dashboardRenderRequest := api.createDashboardRenderRequest(user)
if api.isDefaultDashboard(req.Msg.Title) {
return api.buildDefaultDashboardResponse(dashboardRenderRequest)
}
return api.buildCustomDashboardResponse(dashboardRenderRequest, req.Msg.Title)
}
func (api *oliveTinAPI) checkDashboardAccess(user *acl.AuthenticatedUser) error {
if user.IsGuest() && api.cfg.AuthRequireGuestsToLogin {
return connect.NewError(connect.CodePermissionDenied, fmt.Errorf("guests are not allowed to access the dashboard"))
}
return nil
}
func (api *oliveTinAPI) createDashboardRenderRequest(user *acl.AuthenticatedUser) *DashboardRenderRequest {
return &DashboardRenderRequest{
AuthenticatedUser: user, AuthenticatedUser: user,
cfg: api.cfg, cfg: api.cfg,
ex: api.executor, ex: api.executor,
} }
}
if req.Msg.Title == "default" || req.Msg.Title == "" || req.Msg.Title == "Actions" { func (api *oliveTinAPI) isDefaultDashboard(title string) bool {
db := buildDefaultDashboard(dashboardRenderRequest) return title == "default" || title == "" || title == "Actions"
res := &apiv1.GetDashboardResponse{ }
Dashboard: db,
}
return connect.NewResponse(res), nil
}
func (api *oliveTinAPI) buildDefaultDashboardResponse(rr *DashboardRenderRequest) (*connect.Response[apiv1.GetDashboardResponse], error) {
db := buildDefaultDashboard(rr)
res := &apiv1.GetDashboardResponse{ res := &apiv1.GetDashboardResponse{
Dashboard: renderDashboard(dashboardRenderRequest, req.Msg.Title), Dashboard: db,
} }
return connect.NewResponse(res), nil
}
/* func (api *oliveTinAPI) buildCustomDashboardResponse(rr *DashboardRenderRequest, title string) (*connect.Response[apiv1.GetDashboardResponse], error) {
if len(res.Actions) == 0 { res := &apiv1.GetDashboardResponse{
log.WithFields(log.Fields{ Dashboard: renderDashboard(rr, title),
"username": user.Username, }
"usergroupLine": user.UsergroupLine,
"provider": user.Provider,
"acls": user.Acls,
"availableActions": len(api.cfg.Actions),
}).Warn("Zero actions found for user")
}
*/
return connect.NewResponse(res), nil return connect.NewResponse(res), nil
} }
@ -595,31 +605,31 @@ func (api *oliveTinAPI) Init(ctx ctx.Context, req *connect.Request[apiv1.InitReq
func (api *oliveTinAPI) buildRootDashboards(user *acl.AuthenticatedUser, dashboards []*config.DashboardComponent) []string { func (api *oliveTinAPI) buildRootDashboards(user *acl.AuthenticatedUser, dashboards []*config.DashboardComponent) []string {
var rootDashboards []string var rootDashboards []string
dashboardRenderRequest := api.createDashboardRenderRequest(user)
dashboardRenderRequest := &DashboardRenderRequest{ api.addDefaultDashboardIfNeeded(&rootDashboards, dashboardRenderRequest)
AuthenticatedUser: user, api.addCustomDashboards(&rootDashboards, dashboards, dashboardRenderRequest)
cfg: api.cfg,
ex: api.executor,
}
defaultDashboard := buildDefaultDashboard(dashboardRenderRequest) return rootDashboards
}
func (api *oliveTinAPI) addDefaultDashboardIfNeeded(rootDashboards *[]string, rr *DashboardRenderRequest) {
defaultDashboard := buildDefaultDashboard(rr)
if defaultDashboard != nil && len(defaultDashboard.Contents) > 0 { if defaultDashboard != nil && len(defaultDashboard.Contents) > 0 {
log.Infof("defaultDashboard: %+v", defaultDashboard.Contents) log.Infof("defaultDashboard: %+v", defaultDashboard.Contents)
rootDashboards = append(rootDashboards, "Actions") *rootDashboards = append(*rootDashboards, "Actions")
} }
}
func (api *oliveTinAPI) addCustomDashboards(rootDashboards *[]string, dashboards []*config.DashboardComponent, rr *DashboardRenderRequest) {
for _, dashboard := range dashboards { for _, dashboard := range dashboards {
// We have to build the dashboard response instead of just looping over config.dashboards, // We have to build the dashboard response instead of just looping over config.dashboards,
// because we need to check if the user has access to the dashboard // because we need to check if the user has access to the dashboard
db := renderDashboard(dashboardRenderRequest, dashboard.Title) db := renderDashboard(rr, dashboard.Title)
if db != nil { if db != nil {
rootDashboards = append(rootDashboards, dashboard.Title) *rootDashboards = append(*rootDashboards, dashboard.Title)
} }
} }
return rootDashboards
} }
func buildPublicOAuth2ProvidersList(cfg *config.Config) []*apiv1.OAuth2Provider { func buildPublicOAuth2ProvidersList(cfg *config.Config) []*apiv1.OAuth2Provider {
@ -720,7 +730,7 @@ func (api *oliveTinAPI) GetEntity(ctx ctx.Context, req *connect.Request[apiv1.Ge
log.Infof("msg: %+v", req.Msg) log.Infof("msg: %+v", req.Msg)
if instances == nil || len(instances) == 0 { if len(instances) == 0 {
return nil, connect.NewError(connect.CodeNotFound, fmt.Errorf("entity type %s not found", req.Msg.Type)) return nil, connect.NewError(connect.CodeNotFound, fmt.Errorf("entity type %s not found", req.Msg.Type))
} }

View File

@ -14,32 +14,44 @@ func renderDashboard(rr *DashboardRenderRequest, dashboardTitle string) *apiv1.D
return buildDefaultDashboard(rr) return buildDefaultDashboard(rr)
} }
return findAndRenderDashboard(rr, dashboardTitle)
}
func findAndRenderDashboard(rr *DashboardRenderRequest, dashboardTitle string) *apiv1.Dashboard {
for _, dashboard := range rr.cfg.Dashboards { for _, dashboard := range rr.cfg.Dashboards {
if dashboard.Title != dashboardTitle { if dashboard.Title != dashboardTitle {
continue continue
} }
if len(dashboard.Contents) == 0 { if len(dashboard.Contents) == 0 {
log.WithFields(log.Fields{ logEmptyDashboard(dashboard.Title, rr.AuthenticatedUser.Username)
"dashboard": dashboard.Title,
"username": rr.AuthenticatedUser.Username,
}).Debugf("Dashboard has no readable contents, so it will not be visible in the web ui")
return nil return nil
} }
return &apiv1.Dashboard{ return buildDashboardFromConfig(dashboard, rr)
Title: dashboard.Title,
Contents: sortActions(removeNulls(getDashboardComponentContents(dashboard, rr))),
}
} }
return nil return nil
} }
func logEmptyDashboard(dashboardTitle, username string) {
log.WithFields(log.Fields{
"dashboard": dashboardTitle,
"username": username,
}).Debugf("Dashboard has no readable contents, so it will not be visible in the web ui")
}
func buildDashboardFromConfig(dashboard *config.DashboardComponent, rr *DashboardRenderRequest) *apiv1.Dashboard {
return &apiv1.Dashboard{
Title: dashboard.Title,
Contents: sortActions(removeNulls(getDashboardComponentContents(dashboard, rr))),
}
}
//gocyclo:ignore //gocyclo:ignore
func buildDefaultDashboard(rr *DashboardRenderRequest) *apiv1.Dashboard { func buildDefaultDashboard(rr *DashboardRenderRequest) *apiv1.Dashboard {
db := &apiv1.Dashboard{ db := &apiv1.Dashboard{
Title: "Default", Title: "Actions",
Contents: make([]*apiv1.DashboardComponent, 0), Contents: make([]*apiv1.DashboardComponent, 0),
} }
@ -112,28 +124,40 @@ func removeNulls(components []*apiv1.DashboardComponent) []*apiv1.DashboardCompo
func getDashboardComponentContents(dashboard *config.DashboardComponent, rr *DashboardRenderRequest) []*apiv1.DashboardComponent { func getDashboardComponentContents(dashboard *config.DashboardComponent, rr *DashboardRenderRequest) []*apiv1.DashboardComponent {
ret := make([]*apiv1.DashboardComponent, 0) ret := make([]*apiv1.DashboardComponent, 0)
rootFieldset := createRootFieldset()
rootFieldset := &apiv1.DashboardComponent{ for _, subitem := range dashboard.Contents {
processDashboardSubitem(subitem, rr, &ret, rootFieldset)
}
return appendRootFieldsetIfNeeded(ret, rootFieldset)
}
func createRootFieldset() *apiv1.DashboardComponent {
return &apiv1.DashboardComponent{
Type: "fieldset", Type: "fieldset",
Title: "Actions", Title: "Actions",
Contents: make([]*apiv1.DashboardComponent, 0), Contents: make([]*apiv1.DashboardComponent, 0),
} }
}
for _, subitem := range dashboard.Contents { func processDashboardSubitem(subitem *config.DashboardComponent, rr *DashboardRenderRequest, ret *[]*apiv1.DashboardComponent, rootFieldset *apiv1.DashboardComponent) {
if subitem.Type == "fieldset" && subitem.Entity != "" { if subitem.Type != "fieldset" {
ret = append(ret, buildEntityFieldsets(subitem.Entity, subitem, rr)...) rootFieldset.Contents = append(rootFieldset.Contents, buildDashboardComponentSimple(subitem, rr))
} else if subitem.Type == "fieldset" { return
// Handle regular fieldsets by creating them directly
ret = append(ret, buildDashboardComponentSimple(subitem, rr))
} else {
rootFieldset.Contents = append(rootFieldset.Contents, buildDashboardComponentSimple(subitem, rr))
}
} }
if subitem.Entity != "" {
*ret = append(*ret, buildEntityFieldsets(subitem.Entity, subitem, rr)...)
} else {
*ret = append(*ret, buildDashboardComponentSimple(subitem, rr))
}
}
func appendRootFieldsetIfNeeded(ret []*apiv1.DashboardComponent, rootFieldset *apiv1.DashboardComponent) []*apiv1.DashboardComponent {
if len(rootFieldset.Contents) > 0 { if len(rootFieldset.Contents) > 0 {
ret = append(ret, rootFieldset) ret = append(ret, rootFieldset)
} }
return ret return ret
} }

View File

@ -7,8 +7,9 @@ import (
config "github.com/OliveTin/OliveTin/internal/config" config "github.com/OliveTin/OliveTin/internal/config"
"github.com/OliveTin/OliveTin/internal/entities" "github.com/OliveTin/OliveTin/internal/entities"
"github.com/stretchr/testify/assert"
"testing" "testing"
"github.com/stretchr/testify/assert"
) )
func TestSanitizeUnsafe(t *testing.T) { func TestSanitizeUnsafe(t *testing.T) {
@ -254,9 +255,9 @@ func TestTypeSafetyCheckRawStringMultiline(t *testing.T) {
func TestTypeSafetyCheckUnicodeIdentifier(t *testing.T) { func TestTypeSafetyCheckUnicodeIdentifier(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
field string field string
value string value string
expectsError bool expectsError bool
}{ }{
{"Valid unicode identifier", "name", "hello_world", false}, {"Valid unicode identifier", "name", "hello_world", false},
@ -273,24 +274,35 @@ func TestTypeSafetyCheckUnicodeIdentifier(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
err := TypeSafetyCheck(tt.field, tt.value, "unicode_identifier") err := TypeSafetyCheck(tt.field, tt.value, "unicode_identifier")
validateTypeSafetyResult(t, tt.value, tt.expectsError, err)
if tt.expectsError {
if err == nil {
t.Errorf("Expected error for value '%s', but got none", tt.value)
} else {
t.Logf("Received expected error for value '%s': %v", tt.value, err)
}
} else {
if err != nil {
t.Errorf("Expected no error for value '%s', but got: %v", tt.value, err)
} else {
t.Logf("No error for valid value '%s' as expected", tt.value)
}
}
}) })
} }
} }
func validateTypeSafetyResult(t *testing.T, value string, expectsError bool, err error) {
if expectsError {
assertErrorExpected(t, value, err)
} else {
assertNoErrorExpected(t, value, err)
}
}
func assertErrorExpected(t *testing.T, value string, err error) {
if err == nil {
t.Errorf("Expected error for value '%s', but got none", value)
} else {
t.Logf("Received expected error for value '%s': %v", value, err)
}
}
func assertNoErrorExpected(t *testing.T, value string, err error) {
if err != nil {
t.Errorf("Expected no error for value '%s', but got: %v", value, err)
} else {
t.Logf("No error for valid value '%s' as expected", value)
}
}
func TestTypeSafetyCheckAsciiIdentifier(t *testing.T) { func TestTypeSafetyCheckAsciiIdentifier(t *testing.T) {
tests := []struct { tests := []struct {
name string name string