Repository navigation
Expand file tree
/
Copy pathfeatures.go
More file actions
192 lines (173 loc) · 7.02 KB
/
Copy pathfeatures.go
File metadata and controls
192 lines (173 loc) · 7.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
package handler
import (
"context"
"net/http"
"reflect"
"strings"
"github.com/content-services/content-sources-backend/pkg/api"
"github.com/content-services/content-sources-backend/pkg/clients/feature_service_client"
"github.com/content-services/content-sources-backend/pkg/config"
ce "github.com/content-services/content-sources-backend/pkg/errors"
"github.com/content-services/content-sources-backend/pkg/rbac"
"github.com/content-services/content-sources-backend/pkg/utils"
"github.com/labstack/echo/v4"
"github.com/redhatinsights/platform-go-middlewares/v2/identity"
"github.com/rs/zerolog/log"
)
type FeaturesHandler struct {
FeatureServiceClient feature_service_client.FeatureServiceClient
}
func RegisterFeaturesRoutes(engine *echo.Group, fsClient *feature_service_client.FeatureServiceClient) {
if fsClient == nil {
panic("fsClient is nil")
}
fh := FeaturesHandler{FeatureServiceClient: *fsClient}
addRepoRoute(engine, http.MethodGet, "/features/", fh.listFeatures, rbac.RbacVerbRead)
}
// ListFeatures godoc
// @Summary List Features within the application, whether they are enabled, and whether the requesting user can use them
// @ID listFeatures
// @Description Get features enables retrieving information about the features within an application, regardless of their current status (enabled or disabled) and the user's access to them.
// @Tags features
// @Accept json
// @Produce json
// @Success 200 {object} api.FeatureSet
// @Router /features/ [get]
func (fh *FeaturesHandler) listFeatures(c echo.Context) error {
set := make(api.FeatureSet)
elem := reflect.ValueOf(config.Get().Features)
for i := 0; i < elem.NumField(); i++ {
name := strings.ToLower(elem.Type().Field(i).Name)
value := elem.Field(i).Interface()
feature, valid := value.(config.Feature)
if !valid {
continue
}
accessible := false
if supportsLightwellEntitlements(name) {
accessible = lightwellLensFeatureAccessible(c.Request().Context(), feature, fh.FeatureServiceClient)
} else {
accessible = config.FeatureAccessible(c.Request().Context(), feature)
}
set[name] = api.Feature{
Enabled: feature.Enabled,
Accessible: accessible,
}
}
return c.JSON(http.StatusOK, set)
}
func supportsLightwellEntitlements(featureName string) bool {
return featureName == "lightwelllens" || featureName == "lightwellstoreuploads"
}
func lightwellLensFeatureAccessible(
ctx context.Context, feature config.Feature, fsClient feature_service_client.FeatureServiceClient,
) bool {
if !feature.Enabled {
return false
}
if config.FeatureAccessible(ctx, feature) {
return true
}
entitledFeatures := config.Get().Features.LightwellLensInternalEntitledFeatures
if entitledFeatures == nil {
return false
}
xrhid := identity.GetIdentity(ctx)
if fsClient == nil || xrhid.Identity.OrgID == "" {
return false
}
features, err := fsClient.GetEntitledFeatures(ctx, xrhid.Identity.OrgID)
if err != nil {
log.Logger.Error().Err(err).Msg("error getting entitled features")
return false
}
return utils.ContainsAny(features, *entitledFeatures)
}
func CheckSnapshotAccessible(ctx context.Context) (err error) {
if !config.Get().Features.Snapshots.Enabled {
return ce.NewErrorResponse(http.StatusBadRequest, "Snapshotting Feature is disabled.", "")
} else if config.FeatureAccessible(ctx, config.Get().Features.Snapshots) {
return nil
} else {
return ce.NewErrorResponse(http.StatusBadRequest, "Cannot manage repository snapshots",
"Neither the user nor the account is allowed.")
}
}
func CheckAdminTaskAccessible(ctx context.Context) (err error) {
if !config.Get().Features.AdminTasks.Enabled {
return ce.NewErrorResponse(http.StatusBadRequest, "Cannot manage admin tasks",
"Admin tasks feature is disabled.")
} else if config.FeatureAccessible(ctx, config.Get().Features.AdminTasks) {
return nil
} else {
return ce.NewErrorResponse(http.StatusBadRequest, "Cannot manage admin tasks",
"Neither the user nor account is allowed.")
}
}
func CheckAdminPartnerRepositoriesAccessible(ctx context.Context) (err error) {
if !config.Get().Features.AdminPartnerRepositories.Enabled {
return ce.NewErrorResponse(http.StatusBadRequest, "Cannot administer partner repositories",
"Administration of Partner repositories feature is disabled.")
} else if config.FeatureAccessible(ctx, config.Get().Features.AdminPartnerRepositories) {
return nil
} else {
return ce.NewErrorResponse(http.StatusBadRequest, "Cannot administer partner repositories",
"Neither the user nor account is allowed.")
}
}
func CheckLightwellNotificationsAccessible(ctx context.Context) (err error) {
if !config.Get().Features.LightwellNotifications.Enabled {
return ce.NewErrorResponse(http.StatusBadRequest, "Cannot manage lightwell notification preferences",
"Lightwell notifications feature is disabled.")
} else if config.FeatureAccessible(ctx, config.Get().Features.LightwellNotifications) {
return nil
} else {
return ce.NewErrorResponse(http.StatusBadRequest, "Cannot manage lightwell notification preferences",
"Neither the user nor account is allowed.")
}
}
func CheckAdminNotificationsAccessible(ctx context.Context) (err error) {
if !config.Get().Features.AdminNotifications.Enabled {
return ce.NewErrorResponse(http.StatusBadRequest, "Cannot send test notifications",
"Admin notifications feature is disabled.")
} else if config.FeatureAccessible(ctx, config.Get().Features.AdminNotifications) {
return nil
} else {
return ce.NewErrorResponse(http.StatusBadRequest, "Cannot send test notifications",
"Neither the user nor account is allowed.")
}
}
func CheckLightwellBeaconAccessible(ctx context.Context) (err error) {
if !config.Get().Features.LightwellBeacon.Enabled {
return ce.NewErrorResponse(http.StatusBadRequest, "Cannot access Lightwell Beacon",
"Lightwell Beacon is disabled.")
} else if config.FeatureAccessible(ctx, config.Get().Features.LightwellBeacon) {
return nil
} else {
return ce.NewErrorResponse(http.StatusBadRequest, "Cannot access Lightwell Beacon",
"Neither the user nor account is allowed.")
}
}
func CheckLightwellTermsEnabled(ctx context.Context) (err error) {
if !config.Get().Features.LightwellTerms.Enabled {
return ce.NewErrorResponse(http.StatusBadRequest, "Cannot check Lightwell terms",
"Lightwell Terms feature is disabled.")
} else if config.FeatureAccessible(ctx, config.Get().Features.LightwellTerms) {
return nil
} else {
return ce.NewErrorResponse(http.StatusBadRequest, "Cannot check Lightwell terms",
"Neither the user nor account is allowed.")
}
}
func CheckLightwellLensAccessible(ctx context.Context, fsClient feature_service_client.FeatureServiceClient) (err error) {
feature := config.Get().Features.LightwellLens
if !feature.Enabled {
return ce.NewErrorResponse(http.StatusBadRequest, "Cannot access Lightwell Lens",
"Lightwell Lens is disabled.")
}
if lightwellLensFeatureAccessible(ctx, feature, fsClient) {
return nil
}
return ce.NewErrorResponse(http.StatusBadRequest, "Cannot access Lightwell Lens",
"Neither the user nor account is allowed.")
}