mirror of
https://github.com/fleetdm/fleet
synced 2026-05-23 08:58:41 +00:00
add support for in house apps and vpp apps (#35671)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #35534 # Checklist for submitter If some of the following don't apply, delete the relevant line. - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. - [x] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements) ## Testing - [x] Added/updated automated tests - [x] QA'd all new/changed functionality manually For unreleased bug fixes in a release candidate, one of: - [x] Confirmed that the fix is not expected to adversely impact load test results
This commit is contained in:
parent
04e7a308d4
commit
67a954661c
13 changed files with 219 additions and 22 deletions
|
|
@ -17,9 +17,7 @@ func (svc *Service) updateInHouseAppInstaller(ctx context.Context, payload *flee
|
|||
return nil, ctxerr.Wrap(ctx, err, "getting existing installer")
|
||||
}
|
||||
|
||||
if payload.SelfService == nil && payload.InstallerFile == nil && payload.PreInstallQuery == nil &&
|
||||
payload.InstallScript == nil && payload.PostInstallScript == nil && payload.UninstallScript == nil &&
|
||||
payload.LabelsIncludeAny == nil && payload.LabelsExcludeAny == nil {
|
||||
if payload.IsNoopPayload(software) {
|
||||
return existingInstaller, nil // no payload, noop
|
||||
}
|
||||
|
||||
|
|
@ -41,13 +39,14 @@ func (svc *Service) updateInHouseAppInstaller(ctx context.Context, payload *flee
|
|||
selfService = *payload.SelfService
|
||||
}
|
||||
activity := fleet.ActivityTypeEditedSoftware{
|
||||
SoftwareTitle: existingInstaller.SoftwareTitle,
|
||||
TeamName: teamName,
|
||||
TeamID: actTeamID,
|
||||
SoftwarePackage: &existingInstaller.Name,
|
||||
SoftwareTitleID: payload.TitleID,
|
||||
SoftwareIconURL: existingInstaller.IconUrl,
|
||||
SelfService: selfService,
|
||||
SoftwareTitle: existingInstaller.SoftwareTitle,
|
||||
TeamName: teamName,
|
||||
TeamID: actTeamID,
|
||||
SoftwarePackage: &existingInstaller.Name,
|
||||
SoftwareTitleID: payload.TitleID,
|
||||
SoftwareIconURL: existingInstaller.IconUrl,
|
||||
SelfService: selfService,
|
||||
SoftwareDisplayName: payload.DisplayName,
|
||||
}
|
||||
|
||||
var payloadForNewInstallerFile *fleet.UploadSoftwareInstallerPayload
|
||||
|
|
|
|||
|
|
@ -360,9 +360,7 @@ func (svc *Service) UpdateSoftwareInstaller(ctx context.Context, payload *fleet.
|
|||
return nil, ctxerr.Wrap(ctx, err, "getting existing installer")
|
||||
}
|
||||
|
||||
if payload.SelfService == nil && payload.InstallerFile == nil && payload.PreInstallQuery == nil &&
|
||||
payload.InstallScript == nil && payload.PostInstallScript == nil && payload.UninstallScript == nil &&
|
||||
payload.LabelsIncludeAny == nil && payload.LabelsExcludeAny == nil && software.DisplayName == payload.DisplayName {
|
||||
if payload.IsNoopPayload(software) {
|
||||
return existingInstaller, nil // no payload, noop
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -599,7 +599,7 @@ func getVPPAppsMetadata(ctx context.Context, ids []fleet.VPPAppTeam) ([]*fleet.V
|
|||
return apps, nil
|
||||
}
|
||||
|
||||
func (svc *Service) UpdateAppStoreApp(ctx context.Context, titleID uint, teamID *uint, selfService bool, labelsIncludeAny, labelsExcludeAny, categories []string) (*fleet.VPPAppStoreApp, error) {
|
||||
func (svc *Service) UpdateAppStoreApp(ctx context.Context, titleID uint, teamID *uint, selfService bool, labelsIncludeAny, labelsExcludeAny, categories []string, displayName string) (*fleet.VPPAppStoreApp, error) {
|
||||
if err := svc.authz.Authorize(ctx, &fleet.VPPApp{TeamID: teamID}, fleet.ActionWrite); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -634,6 +634,7 @@ func (svc *Service) UpdateAppStoreApp(ctx context.Context, titleID uint, teamID
|
|||
},
|
||||
SelfService: selfService,
|
||||
ValidatedLabels: validatedLabels,
|
||||
DisplayName: displayName,
|
||||
},
|
||||
TeamID: teamID,
|
||||
TitleID: titleID,
|
||||
|
|
|
|||
|
|
@ -248,6 +248,13 @@ WHERE
|
|||
dest.Categories = categories
|
||||
}
|
||||
|
||||
displayName, err := ds.getSoftwareTitleDisplayName(ctx, tmID, titleID)
|
||||
if err != nil && !fleet.IsNotFound(err) {
|
||||
return nil, ctxerr.Wrap(ctx, err, "get in house app display name")
|
||||
}
|
||||
|
||||
dest.DisplayName = displayName
|
||||
|
||||
if teamID != nil {
|
||||
icon, err := ds.GetSoftwareTitleIcon(ctx, *teamID, titleID)
|
||||
if err != nil && !fleet.IsNotFound(err) {
|
||||
|
|
@ -295,6 +302,10 @@ func (ds *Datastore) SaveInHouseAppUpdates(ctx context.Context, payload *fleet.U
|
|||
}
|
||||
}
|
||||
|
||||
if err := updateSoftwareTitleDisplayName(ctx, tx, payload.TeamID, payload.TitleID, payload.DisplayName); err != nil {
|
||||
return ctxerr.Wrap(ctx, err, "update in house app display name")
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -930,6 +930,13 @@ WHERE
|
|||
dest.Categories = categories
|
||||
}
|
||||
|
||||
displayName, err := ds.getSoftwareTitleDisplayName(ctx, tmID, titleID)
|
||||
if err != nil && !fleet.IsNotFound(err) {
|
||||
return nil, ctxerr.Wrap(ctx, err, "get software title display name")
|
||||
}
|
||||
|
||||
dest.DisplayName = displayName
|
||||
|
||||
if teamID != nil {
|
||||
policies, err := ds.getPoliciesBySoftwareTitleIDs(ctx, []uint{titleID}, *teamID)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -84,6 +84,18 @@ WHERE
|
|||
}
|
||||
app.Categories = categories
|
||||
|
||||
var tmID uint
|
||||
if teamID != nil {
|
||||
tmID = *teamID
|
||||
}
|
||||
|
||||
displayName, err := ds.getSoftwareTitleDisplayName(ctx, tmID, titleID)
|
||||
if err != nil && !fleet.IsNotFound(err) {
|
||||
return nil, ctxerr.Wrap(ctx, err, "get display name for app store app")
|
||||
}
|
||||
|
||||
app.DisplayName = displayName
|
||||
|
||||
if teamID != nil {
|
||||
policies, err := ds.getPoliciesBySoftwareTitleIDs(ctx, []uint{titleID}, *teamID)
|
||||
if err != nil {
|
||||
|
|
@ -98,6 +110,7 @@ WHERE
|
|||
if icon != nil {
|
||||
app.IconURL = ptr.String(icon.IconUrl())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return &app, nil
|
||||
|
|
|
|||
|
|
@ -717,7 +717,7 @@ type Service interface {
|
|||
|
||||
// AddAppStoreApp persists a VPP app onto a team and returns the resulting title ID
|
||||
AddAppStoreApp(ctx context.Context, teamID *uint, appTeam VPPAppTeam) (uint, error)
|
||||
UpdateAppStoreApp(ctx context.Context, titleID uint, teamID *uint, selfService bool, labelsIncludeAny, labelsExcludeAny, categories []string) (*VPPAppStoreApp, error)
|
||||
UpdateAppStoreApp(ctx context.Context, titleID uint, teamID *uint, selfService bool, labelsIncludeAny, labelsExcludeAny, categories []string, displayName string) (*VPPAppStoreApp, error)
|
||||
|
||||
// GetInHouseAppManifest returns a manifest XML file that points at the download URL for the given in-house app.
|
||||
GetInHouseAppManifest(ctx context.Context, titleID uint, teamID *uint) ([]byte, error)
|
||||
|
|
|
|||
|
|
@ -130,6 +130,9 @@ type SoftwareInstaller struct {
|
|||
Categories []string `json:"categories"`
|
||||
|
||||
BundleIdentifier string `json:"-" db:"bundle_identifier"`
|
||||
|
||||
// DisplayName is an end-user friendly name.
|
||||
DisplayName string `json:"display_name"`
|
||||
}
|
||||
|
||||
// SoftwarePackageResponse is the response type used when applying software by batch.
|
||||
|
|
@ -567,6 +570,12 @@ type UpdateSoftwareInstallerPayload struct {
|
|||
DisplayName string
|
||||
}
|
||||
|
||||
func (u *UpdateSoftwareInstallerPayload) IsNoopPayload(existing *SoftwareTitle) bool {
|
||||
return u.SelfService == nil && u.InstallerFile == nil && u.PreInstallQuery == nil &&
|
||||
u.InstallScript == nil && u.PostInstallScript == nil && u.UninstallScript == nil &&
|
||||
u.LabelsIncludeAny == nil && u.LabelsExcludeAny == nil && u.DisplayName == existing.DisplayName
|
||||
}
|
||||
|
||||
// DownloadSoftwareInstallerPayload is the payload for downloading a software installer.
|
||||
type DownloadSoftwareInstallerPayload struct {
|
||||
Filename string
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ type VPPAppTeam struct {
|
|||
// automatically created when a VPP app is added to Fleet. This field should be set after VPP
|
||||
// app creation if AddAutoInstallPolicy is true.
|
||||
AddedAutomaticInstallPolicy *Policy `json:"-"`
|
||||
DisplayName string `json:"-"`
|
||||
DisplayName string `json:"display_name"`
|
||||
}
|
||||
|
||||
// VPPApp represents a VPP (Volume Purchase Program) application,
|
||||
|
|
@ -102,7 +102,8 @@ type VPPAppStoreApp struct {
|
|||
AddedAt time.Time `db:"added_at" json:"created_at"`
|
||||
// Categories is the list of categories to which this software belongs: e.g. "Productivity",
|
||||
// "Browsers", etc.
|
||||
Categories []string `json:"categories"`
|
||||
Categories []string `json:"categories"`
|
||||
DisplayName string `json:"display_name"`
|
||||
}
|
||||
|
||||
// VPPAppStatusSummary represents aggregated status metrics for a VPP app.
|
||||
|
|
|
|||
|
|
@ -456,7 +456,7 @@ type GetAppStoreAppsFunc func(ctx context.Context, teamID *uint) ([]*fleet.VPPAp
|
|||
|
||||
type AddAppStoreAppFunc func(ctx context.Context, teamID *uint, appTeam fleet.VPPAppTeam) (uint, error)
|
||||
|
||||
type UpdateAppStoreAppFunc func(ctx context.Context, titleID uint, teamID *uint, selfService bool, labelsIncludeAny []string, labelsExcludeAny []string, categories []string) (*fleet.VPPAppStoreApp, error)
|
||||
type UpdateAppStoreAppFunc func(ctx context.Context, titleID uint, teamID *uint, selfService bool, labelsIncludeAny []string, labelsExcludeAny []string, categories []string, displayName string) (*fleet.VPPAppStoreApp, error)
|
||||
|
||||
type GetInHouseAppManifestFunc func(ctx context.Context, titleID uint, teamID *uint) ([]byte, error)
|
||||
|
||||
|
|
@ -3640,11 +3640,11 @@ func (s *Service) AddAppStoreApp(ctx context.Context, teamID *uint, appTeam flee
|
|||
return s.AddAppStoreAppFunc(ctx, teamID, appTeam)
|
||||
}
|
||||
|
||||
func (s *Service) UpdateAppStoreApp(ctx context.Context, titleID uint, teamID *uint, selfService bool, labelsIncludeAny []string, labelsExcludeAny []string, categories []string) (*fleet.VPPAppStoreApp, error) {
|
||||
func (s *Service) UpdateAppStoreApp(ctx context.Context, titleID uint, teamID *uint, selfService bool, labelsIncludeAny []string, labelsExcludeAny []string, categories []string, displayName string) (*fleet.VPPAppStoreApp, error) {
|
||||
s.mu.Lock()
|
||||
s.UpdateAppStoreAppFuncInvoked = true
|
||||
s.mu.Unlock()
|
||||
return s.UpdateAppStoreAppFunc(ctx, titleID, teamID, selfService, labelsIncludeAny, labelsExcludeAny, categories)
|
||||
return s.UpdateAppStoreAppFunc(ctx, titleID, teamID, selfService, labelsIncludeAny, labelsExcludeAny, categories, displayName)
|
||||
}
|
||||
|
||||
func (s *Service) GetInHouseAppManifest(ctx context.Context, titleID uint, teamID *uint) ([]byte, error) {
|
||||
|
|
|
|||
|
|
@ -1,18 +1,22 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/fleetdm/fleet/v4/server/datastore/mysql"
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
"github.com/fleetdm/fleet/v4/server/ptr"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func (s *integrationMDMTestSuite) TestSoftwareTitleDisplayNames() {
|
||||
t := s.T()
|
||||
ctx := context.Background()
|
||||
|
||||
// Create a team
|
||||
var newTeamResp teamResponse
|
||||
|
|
@ -155,4 +159,148 @@ func (s *integrationMDMTestSuite) TestSoftwareTitleDisplayNames() {
|
|||
require.Equal(t, getDeviceSw.Software[0].Name, "ruby")
|
||||
s.Assert().Empty(getDeviceSw.Software[0].DisplayName)
|
||||
|
||||
// Test display names with app store apps
|
||||
includeAnyApp := fleet.VPPApp{
|
||||
VPPAppTeam: fleet.VPPAppTeam{
|
||||
VPPAppID: fleet.VPPAppID{
|
||||
AdamID: "1",
|
||||
Platform: fleet.MacOSPlatform,
|
||||
},
|
||||
},
|
||||
Name: "App 1",
|
||||
BundleIdentifier: "a-1",
|
||||
IconURL: "https://example.com/images/1",
|
||||
LatestVersion: "1.0.0",
|
||||
}
|
||||
|
||||
var addAppResp addAppStoreAppResponse
|
||||
addAppReq := &addAppStoreAppRequest{
|
||||
TeamID: &team.ID,
|
||||
AppStoreID: includeAnyApp.AdamID,
|
||||
SelfService: true,
|
||||
}
|
||||
|
||||
// Now add it for real
|
||||
s.DoJSON("POST", "/api/latest/fleet/software/app_store_apps", addAppReq, http.StatusOK, &addAppResp)
|
||||
|
||||
macOSTitleID := addAppResp.TitleID
|
||||
|
||||
updateAppReq := &updateAppStoreAppRequest{TeamID: &team.ID, SelfService: false, DisplayName: "MacOSAppStoreAppUpdated1"}
|
||||
var updateAppResp updateAppStoreAppResponse
|
||||
s.DoJSON("PATCH", fmt.Sprintf("/api/latest/fleet/software/titles/%d/app_store_app", macOSTitleID), updateAppReq, http.StatusOK, &updateAppResp)
|
||||
|
||||
s.Assert().Equal(updateAppReq.DisplayName, updateAppResp.AppStoreApp.DisplayName)
|
||||
|
||||
stResp = getSoftwareTitleResponse{}
|
||||
s.DoJSON("GET", fmt.Sprintf("/api/latest/fleet/software/titles/%d", macOSTitleID), getSoftwareTitleRequest{}, http.StatusOK, &stResp, "team_id", fmt.Sprint(team.ID))
|
||||
s.Assert().Equal(updateAppReq.DisplayName, stResp.SoftwareTitle.DisplayName)
|
||||
|
||||
// List software titles has display name
|
||||
s.DoJSON("GET", "/api/latest/fleet/software/titles", listSoftwareTitlesRequest{}, http.StatusOK, &resp, "team_id", fmt.Sprint(team.ID), "query", includeAnyApp.Name)
|
||||
for _, a := range resp.SoftwareTitles {
|
||||
if a.ID == macOSTitleID {
|
||||
s.Assert().Equal(updateAppReq.DisplayName, a.DisplayName)
|
||||
}
|
||||
}
|
||||
|
||||
updateAppReq = &updateAppStoreAppRequest{TeamID: &team.ID, SelfService: false, DisplayName: "MacOSAppStoreAppUpdated2"}
|
||||
s.DoJSON("PATCH", fmt.Sprintf("/api/latest/fleet/software/titles/%d/app_store_app", macOSTitleID), updateAppReq, http.StatusOK, &updateAppResp)
|
||||
|
||||
s.Assert().Equal(updateAppReq.DisplayName, updateAppResp.AppStoreApp.DisplayName)
|
||||
|
||||
stResp = getSoftwareTitleResponse{}
|
||||
s.DoJSON("GET", fmt.Sprintf("/api/latest/fleet/software/titles/%d", macOSTitleID), getSoftwareTitleRequest{}, http.StatusOK, &stResp, "team_id", fmt.Sprint(team.ID))
|
||||
s.Assert().Equal(updateAppReq.DisplayName, stResp.SoftwareTitle.DisplayName)
|
||||
|
||||
// List software titles has display name
|
||||
s.DoJSON("GET", "/api/latest/fleet/software/titles", listSoftwareTitlesRequest{}, http.StatusOK, &resp, "team_id", fmt.Sprint(team.ID), "query", includeAnyApp.Name)
|
||||
for _, a := range resp.SoftwareTitles {
|
||||
if a.ID == macOSTitleID {
|
||||
s.Assert().Equal(updateAppReq.DisplayName, a.DisplayName)
|
||||
}
|
||||
}
|
||||
|
||||
updateAppReq = &updateAppStoreAppRequest{TeamID: &team.ID, SelfService: false, DisplayName: ""}
|
||||
s.DoJSON("PATCH", fmt.Sprintf("/api/latest/fleet/software/titles/%d/app_store_app", macOSTitleID), updateAppReq, http.StatusOK, &updateAppResp)
|
||||
|
||||
s.Assert().Equal(updateAppReq.DisplayName, updateAppResp.AppStoreApp.DisplayName)
|
||||
|
||||
stResp = getSoftwareTitleResponse{}
|
||||
s.DoJSON("GET", fmt.Sprintf("/api/latest/fleet/software/titles/%d", macOSTitleID), getSoftwareTitleRequest{}, http.StatusOK, &stResp, "team_id", fmt.Sprint(team.ID))
|
||||
s.Assert().Empty(stResp.SoftwareTitle.DisplayName)
|
||||
|
||||
// List software titles has display name
|
||||
s.DoJSON("GET", "/api/latest/fleet/software/titles", listSoftwareTitlesRequest{}, http.StatusOK, &resp, "team_id", fmt.Sprint(team.ID), "query", includeAnyApp.Name)
|
||||
for _, a := range resp.SoftwareTitles {
|
||||
if a.ID == macOSTitleID {
|
||||
s.Assert().Empty(a.DisplayName)
|
||||
}
|
||||
}
|
||||
|
||||
// Test display names with in-house apps
|
||||
// Upload in-house app for iOS, with the label as "exclude any"
|
||||
s.uploadSoftwareInstaller(t, &fleet.UploadSoftwareInstallerPayload{Filename: "ipa_test.ipa", TeamID: &team.ID}, http.StatusOK, "")
|
||||
|
||||
// Get title ID
|
||||
mysql.ExecAdhocSQL(t, s.ds, func(q sqlx.ExtContext) error {
|
||||
return sqlx.GetContext(ctx, q, &titleID, "SELECT title_id FROM in_house_apps WHERE filename = 'ipa_test.ipa'")
|
||||
})
|
||||
|
||||
s.updateSoftwareInstaller(t, &fleet.UpdateSoftwareInstallerPayload{
|
||||
TitleID: titleID,
|
||||
TeamID: &team.ID,
|
||||
DisplayName: "InHouseAppUpdate",
|
||||
}, http.StatusOK, "")
|
||||
|
||||
// Entity has display name
|
||||
s.DoJSON("GET", fmt.Sprintf("/api/latest/fleet/software/titles/%d", titleID), getSoftwareTitleRequest{}, http.StatusOK, &stResp, "team_id", fmt.Sprint(team.ID))
|
||||
s.Assert().Equal("InHouseAppUpdate", stResp.SoftwareTitle.DisplayName)
|
||||
|
||||
// List software titles has display name
|
||||
s.DoJSON("GET", "/api/latest/fleet/software/titles", listSoftwareTitlesRequest{}, http.StatusOK, &resp, "team_id", fmt.Sprint(team.ID))
|
||||
|
||||
for _, t := range resp.SoftwareTitles {
|
||||
if t.ID == titleID {
|
||||
s.Assert().Equal("InHouseAppUpdate", t.DisplayName)
|
||||
}
|
||||
}
|
||||
|
||||
s.updateSoftwareInstaller(t, &fleet.UpdateSoftwareInstallerPayload{
|
||||
TitleID: titleID,
|
||||
TeamID: &team.ID,
|
||||
DisplayName: "InHouseAppUpdate2",
|
||||
}, http.StatusOK, "")
|
||||
|
||||
// Entity has display name
|
||||
s.DoJSON("GET", fmt.Sprintf("/api/latest/fleet/software/titles/%d", titleID), getSoftwareTitleRequest{}, http.StatusOK, &stResp, "team_id", fmt.Sprint(team.ID))
|
||||
s.Assert().Equal("InHouseAppUpdate2", stResp.SoftwareTitle.DisplayName)
|
||||
|
||||
// List software titles has display name
|
||||
s.DoJSON("GET", "/api/latest/fleet/software/titles", listSoftwareTitlesRequest{}, http.StatusOK, &resp, "team_id", fmt.Sprint(team.ID))
|
||||
|
||||
for _, t := range resp.SoftwareTitles {
|
||||
if t.ID == titleID {
|
||||
s.Assert().Equal("InHouseAppUpdate2", t.DisplayName)
|
||||
}
|
||||
}
|
||||
|
||||
s.updateSoftwareInstaller(t, &fleet.UpdateSoftwareInstallerPayload{
|
||||
TitleID: titleID,
|
||||
TeamID: &team.ID,
|
||||
DisplayName: "",
|
||||
}, http.StatusOK, "")
|
||||
|
||||
// Entity has display name
|
||||
s.DoJSON("GET", fmt.Sprintf("/api/latest/fleet/software/titles/%d", titleID), getSoftwareTitleRequest{}, http.StatusOK, &stResp, "team_id", fmt.Sprint(team.ID))
|
||||
s.Assert().Empty(stResp.SoftwareTitle.DisplayName)
|
||||
|
||||
// List software titles has display name
|
||||
s.DoJSON("GET", "/api/latest/fleet/software/titles", listSoftwareTitlesRequest{}, http.StatusOK, &resp, "team_id", fmt.Sprint(team.ID))
|
||||
|
||||
for _, t := range resp.SoftwareTitles {
|
||||
if t.ID == titleID {
|
||||
s.Assert().Empty(t.DisplayName)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -832,5 +832,14 @@ func (ts *withServer) updateSoftwareInstaller(
|
|||
if expectedError != "" {
|
||||
errMsg := extractServerErrorText(r.Body)
|
||||
require.Contains(t, errMsg, expectedError)
|
||||
return
|
||||
}
|
||||
|
||||
bodyBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
|
||||
var resp getSoftwareInstallerResponse
|
||||
require.NoError(t, json.Unmarshal(bodyBytes, &resp))
|
||||
|
||||
assert.Equal(t, payload.DisplayName, resp.SoftwareInstaller.DisplayName)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@ type updateAppStoreAppRequest struct {
|
|||
LabelsIncludeAny []string `json:"labels_include_any"`
|
||||
LabelsExcludeAny []string `json:"labels_exclude_any"`
|
||||
Categories []string `json:"categories"`
|
||||
DisplayName string `json:"display_name"`
|
||||
}
|
||||
|
||||
type updateAppStoreAppResponse struct {
|
||||
|
|
@ -115,7 +116,7 @@ func (r updateAppStoreAppResponse) Error() error { return r.Err }
|
|||
func updateAppStoreAppEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (fleet.Errorer, error) {
|
||||
req := request.(*updateAppStoreAppRequest)
|
||||
|
||||
updatedApp, err := svc.UpdateAppStoreApp(ctx, req.TitleID, req.TeamID, req.SelfService, req.LabelsIncludeAny, req.LabelsExcludeAny, req.Categories)
|
||||
updatedApp, err := svc.UpdateAppStoreApp(ctx, req.TitleID, req.TeamID, req.SelfService, req.LabelsIncludeAny, req.LabelsExcludeAny, req.Categories, req.DisplayName)
|
||||
if err != nil {
|
||||
return updateAppStoreAppResponse{Err: err}, nil
|
||||
}
|
||||
|
|
@ -123,7 +124,7 @@ func updateAppStoreAppEndpoint(ctx context.Context, request interface{}, svc fle
|
|||
return updateAppStoreAppResponse{AppStoreApp: updatedApp}, nil
|
||||
}
|
||||
|
||||
func (svc *Service) UpdateAppStoreApp(ctx context.Context, titleID uint, teamID *uint, selfService bool, labelsIncludeAny, labelsExcludeAny, categories []string) (*fleet.VPPAppStoreApp, error) {
|
||||
func (svc *Service) UpdateAppStoreApp(ctx context.Context, titleID uint, teamID *uint, selfService bool, labelsIncludeAny, labelsExcludeAny, categories []string, displayName string) (*fleet.VPPAppStoreApp, error) {
|
||||
// skipauth: No authorization check needed due to implementation returning
|
||||
// only license error.
|
||||
svc.authz.SkipAuthorization(ctx)
|
||||
|
|
|
|||
Loading…
Reference in a new issue