Skip to content

Commit 92cd1b9

Browse files
pmigkosmoz
andauthored
fix: only return licensed application if feature is active (#611)
Signed-off-by: Philip Miglinci <pmig@glasskube.com> Co-authored-by: Jakob Steiner <kosmoz@users.noreply.github.com>
1 parent cf293fc commit 92cd1b9

File tree

3 files changed

+111
-7
lines changed

3 files changed

+111
-7
lines changed

internal/db/applications.go

+69-6
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"errors"
66
"fmt"
77

8+
"github.com/glasskube/distr/internal/util"
9+
810
"github.com/glasskube/distr/internal/apierrors"
911
internalctx "github.com/glasskube/distr/internal/context"
1012
"github.com/glasskube/distr/internal/types"
@@ -20,9 +22,20 @@ const (
2022
coalesce((
2123
SELECT array_agg(row(av.id, av.created_at, av.archived_at, av.name, av.application_id,
2224
av.chart_type, av.chart_name, av.chart_url, av.chart_version) ORDER BY av.created_at ASC)
23-
FROM applicationversion av
25+
FROM ApplicationVersion av
2426
WHERE av.application_id = a.id
25-
), array[]::record[]) as versions `
27+
), array[]::record[]) AS versions `
28+
29+
applicationWithLicensedVersionsOutputExpr = applicationOutputExpr + `,
30+
coalesce((
31+
SELECT array_agg(row(av.id, av.created_at, av.archived_at, av.name, av.application_id,
32+
av.chart_type, av.chart_name, av.chart_url, av.chart_version) ORDER BY av.created_at ASC)
33+
FROM ApplicationVersion av
34+
WHERE av.application_id = a.id and
35+
((av.id IN
36+
(SELECT application_version_id FROM ApplicationLicense_ApplicationVersion WHERE application_license_id = al.id)
37+
OR (SELECT NOT EXISTS (SELECT FROM ApplicationLicense_ApplicationVersion WHERE application_license_id = al.id)))
38+
)), array[]::record[]) AS versions `
2639
)
2740

2841
func CreateApplication(ctx context.Context, application *types.Application, orgID uuid.UUID) error {
@@ -88,22 +101,51 @@ func GetApplicationsByOrgID(ctx context.Context, orgID uuid.UUID) ([]types.Appli
88101
}
89102
}
90103

104+
func appendMissingVersions(application types.Application,
105+
versions []types.ApplicationVersion) types.Application {
106+
107+
for _, version := range versions {
108+
found := false
109+
for _, existingVersion := range application.Versions {
110+
if version.ID == existingVersion.ID {
111+
found = true
112+
break
113+
}
114+
}
115+
if !found {
116+
application.Versions = append(application.Versions, version)
117+
}
118+
}
119+
return application
120+
}
121+
122+
func mergeApplications(applications []types.Application) []types.Application {
123+
applicationMap := make(map[uuid.UUID]types.Application)
124+
for _, application := range applications {
125+
if existingApplication, ok := applicationMap[application.ID]; ok {
126+
applicationMap[application.ID] = appendMissingVersions(existingApplication, application.Versions)
127+
} else {
128+
applicationMap[application.ID] = application
129+
}
130+
}
131+
return util.GetValues(applicationMap)
132+
}
133+
91134
func GetApplicationsWithLicenseOwnerID(ctx context.Context, id uuid.UUID) ([]types.Application, error) {
92135
db := internalctx.GetDb(ctx)
93-
// TODO: Only include versions from at least one license
94136
if rows, err := db.Query(ctx, `
95-
SELECT DISTINCT `+applicationWithVersionsOutputExpr+`
137+
SELECT DISTINCT `+applicationWithLicensedVersionsOutputExpr+`
96138
FROM ApplicationLicense al
97139
LEFT JOIN Application a ON al.application_id = a.id
98-
WHERE al.owner_useraccount_id = @id
140+
WHERE al.owner_useraccount_id = @id AND (al.expires_at IS NULL OR al.expires_at > now())
99141
ORDER BY a.name
100142
`, pgx.NamedArgs{"id": id}); err != nil {
101143
return nil, fmt.Errorf("failed to query applications: %w", err)
102144
} else if applications, err :=
103145
pgx.CollectRows(rows, pgx.RowToStructByName[types.Application]); err != nil {
104146
return nil, fmt.Errorf("failed to get applications: %w", err)
105147
} else {
106-
return applications, nil
148+
return mergeApplications(applications), nil
107149
}
108150
}
109151

@@ -126,6 +168,27 @@ func GetApplication(ctx context.Context, id, orgID uuid.UUID) (*types.Applicatio
126168
}
127169
}
128170

171+
func GetApplicationWithLicenseOwnerID(ctx context.Context, oID uuid.UUID, id uuid.UUID) (*types.Application, error) {
172+
db := internalctx.GetDb(ctx)
173+
if rows, err := db.Query(ctx, `
174+
SELECT DISTINCT `+applicationWithLicensedVersionsOutputExpr+`
175+
FROM ApplicationLicense al
176+
LEFT JOIN Application a ON al.application_id = a.id
177+
WHERE al.owner_useraccount_id = @ownerID AND a.id = @id AND (al.expires_at IS NULL OR al.expires_at > now())
178+
ORDER BY a.name
179+
`, pgx.NamedArgs{"ownerID": oID, "id": id}); err != nil {
180+
return nil, fmt.Errorf("failed to query applications: %w", err)
181+
} else if applications, err :=
182+
pgx.CollectRows(rows, pgx.RowToStructByName[types.Application]); err != nil {
183+
if errors.Is(err, pgx.ErrNoRows) {
184+
return nil, apierrors.ErrNotFound
185+
}
186+
return nil, fmt.Errorf("failed to get application: %w", err)
187+
} else {
188+
return &mergeApplications(applications)[0], nil
189+
}
190+
}
191+
129192
func GetApplicationForApplicationVersionID(ctx context.Context, id, orgID uuid.UUID) (*types.Application, error) {
130193
db := internalctx.GetDb(ctx)
131194
if rows, err := db.Query(ctx, `

internal/handlers/applications.go

+34-1
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,40 @@ func getApplications(w http.ResponseWriter, r *http.Request) {
140140
}
141141

142142
func getApplication(w http.ResponseWriter, r *http.Request) {
143-
RespondJSON(w, internalctx.GetApplication(r.Context()))
143+
ctx := r.Context()
144+
auth := auth.Authentication.Require(ctx)
145+
log := internalctx.GetLogger(ctx)
146+
147+
org, err := db.GetOrganizationByID(ctx, *auth.CurrentOrgID())
148+
if err != nil {
149+
log.Error("failed to get org", zap.Error(err))
150+
sentry.GetHubFromContext(ctx).CaptureException(err)
151+
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
152+
return
153+
}
154+
155+
if org.HasFeature(types.FeatureLicensing) && *auth.CurrentUserRole() == types.UserRoleCustomer {
156+
157+
if applicationID, err := uuid.Parse(r.PathValue("applicationId")); err != nil {
158+
http.NotFound(w, r)
159+
return
160+
} else {
161+
application, err := db.GetApplicationWithLicenseOwnerID(ctx, auth.CurrentUserID(), applicationID)
162+
if errors.Is(err, apierrors.ErrNotFound) {
163+
http.NotFound(w, r)
164+
} else if err != nil {
165+
log.Error("failed to get application", zap.Error(err))
166+
sentry.GetHubFromContext(ctx).CaptureException(err)
167+
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
168+
} else {
169+
RespondJSON(w, application)
170+
}
171+
}
172+
173+
} else {
174+
RespondJSON(w, internalctx.GetApplication(r.Context()))
175+
}
176+
144177
}
145178

146179
func getApplicationVersion(w http.ResponseWriter, r *http.Request) {

internal/util/maps.go

+8
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,11 @@ func MergeIntoRecursive(dst, src map[string]any) error {
5757
}
5858
return nil
5959
}
60+
61+
func GetValues[K comparable, V any](src map[K]V) []V {
62+
values := make([]V, 0, len(src))
63+
for _, value := range src {
64+
values = append(values, value)
65+
}
66+
return values
67+
}

0 commit comments

Comments
 (0)