chore: fix gocyclo issues
This commit is contained in:
parent
b330fbd1a5
commit
60814b97e2
|
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue