mirror of https://github.com/portainer/portainer
feat(demo): remove demo mode EE-6769 (#11841)
parent
fbbf550730
commit
2b01136d03
|
@ -34,7 +34,6 @@ func (*Service) ParseFlags(version string) (*portainer.CLIFlags, error) {
|
|||
TunnelPort: kingpin.Flag("tunnel-port", "Port to serve the tunnel server").Default(defaultTunnelServerPort).String(),
|
||||
Assets: kingpin.Flag("assets", "Path to the assets").Default(defaultAssetsDirectory).Short('a').String(),
|
||||
Data: kingpin.Flag("data", "Path to the folder where the data is stored").Default(defaultDataDirectory).Short('d').String(),
|
||||
DemoEnvironment: kingpin.Flag("demo", "Demo environment").Bool(),
|
||||
EndpointURL: kingpin.Flag("host", "Environment URL").Short('H').String(),
|
||||
FeatureFlags: kingpin.Flag("feat", "List of feature flags").Strings(),
|
||||
EnableEdgeComputeFeatures: kingpin.Flag("edge-compute", "Enable Edge Compute features").Bool(),
|
||||
|
|
|
@ -20,7 +20,6 @@ import (
|
|||
"github.com/portainer/portainer/api/datastore"
|
||||
"github.com/portainer/portainer/api/datastore/migrator"
|
||||
"github.com/portainer/portainer/api/datastore/postinit"
|
||||
"github.com/portainer/portainer/api/demo"
|
||||
"github.com/portainer/portainer/api/docker"
|
||||
dockerclient "github.com/portainer/portainer/api/docker/client"
|
||||
"github.com/portainer/portainer/api/exec"
|
||||
|
@ -509,14 +508,6 @@ func buildServer(flags *portainer.CLIFlags) portainer.Server {
|
|||
|
||||
applicationStatus := initStatus(instanceID)
|
||||
|
||||
demoService := demo.NewService()
|
||||
if *flags.DemoEnvironment {
|
||||
err := demoService.Init(dataStore, cryptoService)
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("failed initializing demo environment")
|
||||
}
|
||||
}
|
||||
|
||||
// channel to control when the admin user is created
|
||||
adminCreationDone := make(chan struct{}, 1)
|
||||
|
||||
|
@ -631,7 +622,6 @@ func buildServer(flags *portainer.CLIFlags) portainer.Server {
|
|||
ShutdownCtx: shutdownCtx,
|
||||
ShutdownTrigger: shutdownTrigger,
|
||||
StackDeployer: stackDeployer,
|
||||
DemoService: demoService,
|
||||
UpgradeService: upgradeService,
|
||||
AdminCreationDone: adminCreationDone,
|
||||
PendingActionsService: pendingActionsService,
|
||||
|
|
118
api/demo/demo.go
118
api/demo/demo.go
|
@ -1,118 +0,0 @@
|
|||
package demo
|
||||
|
||||
import (
|
||||
portainer "github.com/portainer/portainer/api"
|
||||
"github.com/portainer/portainer/api/dataservices"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type EnvironmentDetails struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
Users []portainer.UserID `json:"users"`
|
||||
Environments []portainer.EndpointID `json:"environments"`
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
details EnvironmentDetails
|
||||
}
|
||||
|
||||
func NewService() *Service {
|
||||
return &Service{}
|
||||
}
|
||||
|
||||
func (service *Service) Details() EnvironmentDetails {
|
||||
return service.details
|
||||
}
|
||||
|
||||
func (service *Service) Init(store dataservices.DataStore, cryptoService portainer.CryptoService) error {
|
||||
log.Info().Msg("starting demo environment")
|
||||
|
||||
isClean, err := isCleanStore(store)
|
||||
if err != nil {
|
||||
return errors.WithMessage(err, "failed checking if store is clean")
|
||||
}
|
||||
|
||||
if !isClean {
|
||||
return errors.New(" Demo environment can only be initialized on a clean database")
|
||||
}
|
||||
|
||||
id, err := initDemoUser(store, cryptoService)
|
||||
if err != nil {
|
||||
return errors.WithMessage(err, "failed creating demo user")
|
||||
}
|
||||
|
||||
endpointIds, err := initDemoEndpoints(store)
|
||||
if err != nil {
|
||||
return errors.WithMessage(err, "failed creating demo endpoint")
|
||||
}
|
||||
|
||||
err = initDemoSettings(store)
|
||||
if err != nil {
|
||||
return errors.WithMessage(err, "failed updating demo settings")
|
||||
}
|
||||
|
||||
service.details = EnvironmentDetails{
|
||||
Enabled: true,
|
||||
Users: []portainer.UserID{id},
|
||||
// endpoints 2,3 are created after deployment of portainer
|
||||
Environments: endpointIds,
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func isCleanStore(store dataservices.DataStore) (bool, error) {
|
||||
endpoints, err := store.Endpoint().Endpoints()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if len(endpoints) > 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
users, err := store.User().ReadAll()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if len(users) > 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (service *Service) IsDemo() bool {
|
||||
return service.details.Enabled
|
||||
}
|
||||
|
||||
func (service *Service) IsDemoEnvironment(environmentID portainer.EndpointID) bool {
|
||||
if !service.IsDemo() {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, demoEndpointID := range service.details.Environments {
|
||||
if environmentID == demoEndpointID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (service *Service) IsDemoUser(userID portainer.UserID) bool {
|
||||
if !service.IsDemo() {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, demoUserID := range service.details.Users {
|
||||
if userID == demoUserID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
|
@ -1,88 +0,0 @@
|
|||
package demo
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
portainer "github.com/portainer/portainer/api"
|
||||
"github.com/portainer/portainer/api/dataservices"
|
||||
)
|
||||
|
||||
func initDemoUser(
|
||||
store dataservices.DataStore,
|
||||
cryptoService portainer.CryptoService,
|
||||
) (portainer.UserID, error) {
|
||||
|
||||
password, err := cryptoService.Hash("tryportainer")
|
||||
if err != nil {
|
||||
return 0, errors.WithMessage(err, "failed creating password hash")
|
||||
}
|
||||
|
||||
admin := &portainer.User{
|
||||
Username: "admin",
|
||||
Password: password,
|
||||
Role: portainer.AdministratorRole,
|
||||
}
|
||||
|
||||
err = store.User().Create(admin)
|
||||
return admin.ID, errors.WithMessage(err, "failed creating user")
|
||||
}
|
||||
|
||||
func initDemoEndpoints(store dataservices.DataStore) ([]portainer.EndpointID, error) {
|
||||
localEndpointId, err := initDemoLocalEndpoint(store)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// second and third endpoints are going to be created with docker-compose as a part of the demo environment set up.
|
||||
// ref: https://github.com/portainer/portainer-demo/blob/master/docker-compose.yml
|
||||
return []portainer.EndpointID{localEndpointId, localEndpointId + 1, localEndpointId + 2}, nil
|
||||
}
|
||||
|
||||
func initDemoLocalEndpoint(store dataservices.DataStore) (portainer.EndpointID, error) {
|
||||
id := portainer.EndpointID(store.Endpoint().GetNextIdentifier())
|
||||
localEndpoint := &portainer.Endpoint{
|
||||
ID: id,
|
||||
Name: "local",
|
||||
URL: "unix:///var/run/docker.sock",
|
||||
PublicURL: "demo.portainer.io",
|
||||
Type: portainer.DockerEnvironment,
|
||||
GroupID: portainer.EndpointGroupID(1),
|
||||
TLSConfig: portainer.TLSConfiguration{
|
||||
TLS: false,
|
||||
},
|
||||
AuthorizedUsers: []portainer.UserID{},
|
||||
AuthorizedTeams: []portainer.TeamID{},
|
||||
UserAccessPolicies: portainer.UserAccessPolicies{},
|
||||
TeamAccessPolicies: portainer.TeamAccessPolicies{},
|
||||
TagIDs: []portainer.TagID{},
|
||||
Status: portainer.EndpointStatusUp,
|
||||
Snapshots: []portainer.DockerSnapshot{},
|
||||
Kubernetes: portainer.KubernetesDefault(),
|
||||
}
|
||||
|
||||
err := store.Endpoint().Create(localEndpoint)
|
||||
if err != nil {
|
||||
return id, errors.WithMessage(err, "failed creating local endpoint")
|
||||
}
|
||||
|
||||
err = store.Snapshot().Create(&portainer.Snapshot{EndpointID: id})
|
||||
if err != nil {
|
||||
return id, errors.WithMessage(err, "failed creating snapshot")
|
||||
}
|
||||
|
||||
return id, errors.WithMessage(err, "failed creating local endpoint")
|
||||
}
|
||||
|
||||
func initDemoSettings(
|
||||
store dataservices.DataStore,
|
||||
) error {
|
||||
settings, err := store.Settings().Settings()
|
||||
if err != nil {
|
||||
return errors.WithMessage(err, "failed fetching settings")
|
||||
}
|
||||
|
||||
settings.EnableTelemetry = false
|
||||
settings.LogoURL = ""
|
||||
|
||||
err = store.Settings().UpdateSettings(settings)
|
||||
return errors.WithMessage(err, "failed updating settings")
|
||||
}
|
|
@ -9,6 +9,4 @@ var (
|
|||
ErrUnauthorized = errors.New("Unauthorized")
|
||||
// ErrResourceAccessDenied Access denied to resource error
|
||||
ErrResourceAccessDenied = errors.New("Access denied to resource")
|
||||
// ErrNotAvailableInDemo feature is not allowed in demo
|
||||
ErrNotAvailableInDemo = errors.New("This feature is not available in the demo version of Portainer")
|
||||
)
|
||||
|
|
|
@ -16,7 +16,6 @@ import (
|
|||
|
||||
"github.com/portainer/portainer/api/adminmonitor"
|
||||
"github.com/portainer/portainer/api/crypto"
|
||||
"github.com/portainer/portainer/api/demo"
|
||||
"github.com/portainer/portainer/api/http/offlinegate"
|
||||
"github.com/portainer/portainer/api/internal/testhelpers"
|
||||
|
||||
|
@ -55,8 +54,7 @@ func Test_backupHandlerWithoutPassword_shouldCreateATarballArchive(t *testing.T)
|
|||
gate,
|
||||
"./test_assets/handler_test",
|
||||
func() {},
|
||||
adminMonitor,
|
||||
&demo.Service{}).backup(w, r)
|
||||
adminMonitor).backup(w, r)
|
||||
assert.Nil(t, handlerErr, "Handler should not fail")
|
||||
|
||||
response := w.Result()
|
||||
|
@ -99,8 +97,7 @@ func Test_backupHandlerWithPassword_shouldCreateEncryptedATarballArchive(t *test
|
|||
gate,
|
||||
"./test_assets/handler_test",
|
||||
func() {},
|
||||
adminMonitor,
|
||||
&demo.Service{}).backup(w, r)
|
||||
adminMonitor).backup(w, r)
|
||||
assert.Nil(t, handlerErr, "Handler should not fail")
|
||||
|
||||
response := w.Result()
|
||||
|
|
|
@ -6,8 +6,6 @@ import (
|
|||
|
||||
"github.com/portainer/portainer/api/adminmonitor"
|
||||
"github.com/portainer/portainer/api/dataservices"
|
||||
"github.com/portainer/portainer/api/demo"
|
||||
"github.com/portainer/portainer/api/http/middlewares"
|
||||
"github.com/portainer/portainer/api/http/offlinegate"
|
||||
"github.com/portainer/portainer/api/http/security"
|
||||
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
||||
|
@ -34,10 +32,7 @@ func NewHandler(
|
|||
filestorePath string,
|
||||
shutdownTrigger context.CancelFunc,
|
||||
adminMonitor *adminmonitor.Monitor,
|
||||
demoService *demo.Service,
|
||||
|
||||
) *Handler {
|
||||
|
||||
h := &Handler{
|
||||
Router: mux.NewRouter(),
|
||||
bouncer: bouncer,
|
||||
|
@ -48,11 +43,8 @@ func NewHandler(
|
|||
adminMonitor: adminMonitor,
|
||||
}
|
||||
|
||||
demoRestrictedRouter := h.NewRoute().Subrouter()
|
||||
demoRestrictedRouter.Use(middlewares.RestrictDemoEnv(demoService.IsDemo))
|
||||
|
||||
demoRestrictedRouter.Handle("/backup", bouncer.RestrictedAccess(adminAccess(httperror.LoggerHandler(h.backup)))).Methods(http.MethodPost)
|
||||
demoRestrictedRouter.Handle("/restore", bouncer.PublicAccess(httperror.LoggerHandler(h.restore))).Methods(http.MethodPost)
|
||||
h.Handle("/backup", bouncer.RestrictedAccess(adminAccess(httperror.LoggerHandler(h.backup)))).Methods(http.MethodPost)
|
||||
h.Handle("/restore", bouncer.PublicAccess(httperror.LoggerHandler(h.restore))).Methods(http.MethodPost)
|
||||
|
||||
return h
|
||||
}
|
||||
|
|
|
@ -14,7 +14,6 @@ import (
|
|||
|
||||
portainer "github.com/portainer/portainer/api"
|
||||
"github.com/portainer/portainer/api/adminmonitor"
|
||||
"github.com/portainer/portainer/api/demo"
|
||||
"github.com/portainer/portainer/api/http/offlinegate"
|
||||
"github.com/portainer/portainer/api/internal/testhelpers"
|
||||
|
||||
|
@ -63,7 +62,6 @@ func Test_restoreArchive_usingCombinationOfPasswords(t *testing.T) {
|
|||
"./test_assets/handler_test",
|
||||
func() {},
|
||||
adminMonitor,
|
||||
&demo.Service{},
|
||||
)
|
||||
|
||||
//backup
|
||||
|
@ -96,7 +94,6 @@ func Test_restoreArchive_shouldFailIfSystemWasAlreadyInitialized(t *testing.T) {
|
|||
"./test_assets/handler_test",
|
||||
func() {},
|
||||
adminMonitor,
|
||||
&demo.Service{},
|
||||
)
|
||||
|
||||
//backup
|
||||
|
|
|
@ -10,10 +10,7 @@ import (
|
|||
)
|
||||
|
||||
func TestEmptyGlobalKey(t *testing.T) {
|
||||
handler := NewHandler(
|
||||
helper.NewTestRequestBouncer(),
|
||||
nil,
|
||||
)
|
||||
handler := NewHandler(helper.NewTestRequestBouncer())
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, "https://portainer.io:9443/endpoints/global-key", nil)
|
||||
if err != nil {
|
||||
|
|
|
@ -9,7 +9,6 @@ import (
|
|||
|
||||
portainer "github.com/portainer/portainer/api"
|
||||
"github.com/portainer/portainer/api/dataservices"
|
||||
httperrors "github.com/portainer/portainer/api/http/errors"
|
||||
"github.com/portainer/portainer/api/internal/endpointutils"
|
||||
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
||||
"github.com/portainer/portainer/pkg/libhttp/request"
|
||||
|
@ -67,10 +66,6 @@ func (handler *Handler) endpointDelete(w http.ResponseWriter, r *http.Request) *
|
|||
return httperror.BadRequest("Invalid boolean query parameter", err)
|
||||
}
|
||||
|
||||
if handler.demoService.IsDemoEnvironment(portainer.EndpointID(endpointID)) {
|
||||
return httperror.Forbidden(httperrors.ErrNotAvailableInDemo.Error(), httperrors.ErrNotAvailableInDemo)
|
||||
}
|
||||
|
||||
err = handler.DataStore.UpdateTx(func(tx dataservices.DataStoreTx) error {
|
||||
return handler.deleteEndpoint(tx, portainer.EndpointID(endpointID), deleteCluster)
|
||||
})
|
||||
|
@ -112,15 +107,6 @@ func (handler *Handler) endpointDeleteMultiple(w http.ResponseWriter, r *http.Re
|
|||
|
||||
err := handler.DataStore.UpdateTx(func(tx dataservices.DataStoreTx) error {
|
||||
for _, e := range p.Endpoints {
|
||||
// Demo endpoints cannot be deleted.
|
||||
if handler.demoService.IsDemoEnvironment(portainer.EndpointID(e.ID)) {
|
||||
resps = append(resps, DeleteMultipleResp{
|
||||
Name: e.Name,
|
||||
Err: httperrors.ErrNotAvailableInDemo,
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
// Attempt deletion.
|
||||
err := handler.deleteEndpoint(
|
||||
tx,
|
||||
|
|
|
@ -9,7 +9,6 @@ import (
|
|||
|
||||
portainer "github.com/portainer/portainer/api"
|
||||
"github.com/portainer/portainer/api/datastore"
|
||||
"github.com/portainer/portainer/api/demo"
|
||||
"github.com/portainer/portainer/api/http/proxy"
|
||||
"github.com/portainer/portainer/api/internal/testhelpers"
|
||||
)
|
||||
|
@ -19,7 +18,7 @@ func TestEndpointDeleteEdgeGroupsConcurrently(t *testing.T) {
|
|||
|
||||
_, store := datastore.MustNewTestStore(t, true, false)
|
||||
|
||||
handler := NewHandler(testhelpers.NewTestRequestBouncer(), demo.NewService())
|
||||
handler := NewHandler(testhelpers.NewTestRequestBouncer())
|
||||
handler.DataStore = store
|
||||
handler.ProxyManager = proxy.NewManager(nil)
|
||||
handler.ProxyManager.NewProxyFactory(nil, nil, nil, nil, nil, nil, nil, nil)
|
||||
|
|
|
@ -194,7 +194,7 @@ func setupEndpointListHandler(t *testing.T, endpoints []portainer.Endpoint) *Han
|
|||
|
||||
bouncer := testhelpers.NewTestRequestBouncer()
|
||||
|
||||
handler := NewHandler(bouncer, nil)
|
||||
handler := NewHandler(bouncer)
|
||||
handler.DataStore = store
|
||||
handler.ComposeStackManager = testhelpers.NewComposeStackManager()
|
||||
handler.SnapshotService, _ = snapshot.NewService("1s", store, nil, nil, nil, nil)
|
||||
|
|
|
@ -194,7 +194,7 @@ func setupFilterTest(t *testing.T, endpoints []portainer.Endpoint) *Handler {
|
|||
is.NoError(err, "error creating a user")
|
||||
|
||||
bouncer := testhelpers.NewTestRequestBouncer()
|
||||
handler := NewHandler(bouncer, nil)
|
||||
handler := NewHandler(bouncer)
|
||||
handler.DataStore = store
|
||||
handler.ComposeStackManager = testhelpers.NewComposeStackManager()
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
|
||||
portainer "github.com/portainer/portainer/api"
|
||||
"github.com/portainer/portainer/api/dataservices"
|
||||
"github.com/portainer/portainer/api/demo"
|
||||
dockerclient "github.com/portainer/portainer/api/docker/client"
|
||||
"github.com/portainer/portainer/api/http/proxy"
|
||||
"github.com/portainer/portainer/api/http/security"
|
||||
|
@ -28,7 +27,6 @@ func hideFields(endpoint *portainer.Endpoint) {
|
|||
type Handler struct {
|
||||
*mux.Router
|
||||
requestBouncer security.BouncerService
|
||||
demoService *demo.Service
|
||||
DataStore dataservices.DataStore
|
||||
FileService portainer.FileService
|
||||
ProxyManager *proxy.Manager
|
||||
|
@ -44,11 +42,10 @@ type Handler struct {
|
|||
}
|
||||
|
||||
// NewHandler creates a handler to manage environment(endpoint) operations.
|
||||
func NewHandler(bouncer security.BouncerService, demoService *demo.Service) *Handler {
|
||||
func NewHandler(bouncer security.BouncerService) *Handler {
|
||||
h := &Handler{
|
||||
Router: mux.NewRouter(),
|
||||
requestBouncer: bouncer,
|
||||
demoService: demoService,
|
||||
}
|
||||
|
||||
h.Handle("/endpoints",
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
|
||||
portainer "github.com/portainer/portainer/api"
|
||||
"github.com/portainer/portainer/api/dataservices"
|
||||
"github.com/portainer/portainer/api/demo"
|
||||
"github.com/portainer/portainer/api/http/security"
|
||||
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
||||
|
||||
|
@ -26,15 +25,14 @@ type Handler struct {
|
|||
JWTService portainer.JWTService
|
||||
LDAPService portainer.LDAPService
|
||||
SnapshotService portainer.SnapshotService
|
||||
demoService *demo.Service
|
||||
}
|
||||
|
||||
// NewHandler creates a handler to manage settings operations.
|
||||
func NewHandler(bouncer security.BouncerService, demoService *demo.Service) *Handler {
|
||||
func NewHandler(bouncer security.BouncerService) *Handler {
|
||||
h := &Handler{
|
||||
Router: mux.NewRouter(),
|
||||
demoService: demoService,
|
||||
Router: mux.NewRouter(),
|
||||
}
|
||||
|
||||
h.Handle("/settings",
|
||||
bouncer.AdminAccess(httperror.LoggerHandler(h.settingsInspect))).Methods(http.MethodGet)
|
||||
h.Handle("/settings",
|
||||
|
|
|
@ -149,11 +149,6 @@ func (handler *Handler) updateSettings(tx dataservices.DataStoreTx, payload sett
|
|||
return nil, httperror.InternalServerError("Unable to retrieve the settings from the database", err)
|
||||
}
|
||||
|
||||
if handler.demoService.IsDemo() {
|
||||
payload.EnableTelemetry = nil
|
||||
payload.LogoURL = nil
|
||||
}
|
||||
|
||||
if payload.AuthenticationMethod != nil {
|
||||
settings.AuthenticationMethod = portainer.AuthenticationMethod(*payload.AuthenticationMethod)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
|
||||
portainer "github.com/portainer/portainer/api"
|
||||
"github.com/portainer/portainer/api/dataservices"
|
||||
"github.com/portainer/portainer/api/demo"
|
||||
"github.com/portainer/portainer/api/http/security"
|
||||
"github.com/portainer/portainer/api/internal/upgrade"
|
||||
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
||||
|
@ -18,21 +17,18 @@ type Handler struct {
|
|||
*mux.Router
|
||||
status *portainer.Status
|
||||
dataStore dataservices.DataStore
|
||||
demoService *demo.Service
|
||||
upgradeService upgrade.Service
|
||||
}
|
||||
|
||||
// NewHandler creates a handler to manage status operations.
|
||||
func NewHandler(bouncer security.BouncerService,
|
||||
status *portainer.Status,
|
||||
demoService *demo.Service,
|
||||
dataStore dataservices.DataStore,
|
||||
upgradeService upgrade.Service) *Handler {
|
||||
|
||||
h := &Handler{
|
||||
Router: mux.NewRouter(),
|
||||
dataStore: dataStore,
|
||||
demoService: demoService,
|
||||
status: status,
|
||||
upgradeService: upgradeService,
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"net/http"
|
||||
|
||||
portainer "github.com/portainer/portainer/api"
|
||||
"github.com/portainer/portainer/api/demo"
|
||||
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
||||
"github.com/portainer/portainer/pkg/libhttp/response"
|
||||
|
||||
|
@ -13,7 +12,6 @@ import (
|
|||
|
||||
type status struct {
|
||||
*portainer.Status
|
||||
DemoEnvironment demo.EnvironmentDetails
|
||||
}
|
||||
|
||||
// @id systemStatus
|
||||
|
@ -26,8 +24,7 @@ type status struct {
|
|||
// @router /system/status [get]
|
||||
func (handler *Handler) systemStatus(w http.ResponseWriter, r *http.Request) *httperror.HandlerError {
|
||||
return response.JSON(w, &status{
|
||||
Status: handler.status,
|
||||
DemoEnvironment: handler.demoService.Details(),
|
||||
Status: handler.status,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
"github.com/portainer/portainer/api/apikey"
|
||||
"github.com/portainer/portainer/api/database/models"
|
||||
"github.com/portainer/portainer/api/datastore"
|
||||
"github.com/portainer/portainer/api/demo"
|
||||
"github.com/portainer/portainer/api/http/security"
|
||||
"github.com/portainer/portainer/api/internal/testhelpers"
|
||||
"github.com/portainer/portainer/api/jwt"
|
||||
|
@ -40,7 +39,7 @@ func Test_getSystemVersion(t *testing.T) {
|
|||
apiKeyService := apikey.NewAPIKeyService(store.APIKeyRepository(), store.User())
|
||||
requestBouncer := security.NewRequestBouncer(store, jwtService, apiKeyService)
|
||||
|
||||
h := NewHandler(requestBouncer, &portainer.Status{}, &demo.Service{}, store, nil)
|
||||
h := NewHandler(requestBouncer, &portainer.Status{}, store, nil)
|
||||
|
||||
// generate standard and admin user tokens
|
||||
jwt, _, _ := jwtService.GenerateToken(&portainer.TokenData{ID: adminUser.ID, Username: adminUser.Username, Role: adminUser.Role})
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
portainer "github.com/portainer/portainer/api"
|
||||
"github.com/portainer/portainer/api/apikey"
|
||||
"github.com/portainer/portainer/api/dataservices"
|
||||
"github.com/portainer/portainer/api/demo"
|
||||
"github.com/portainer/portainer/api/http/security"
|
||||
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
||||
|
||||
|
@ -31,7 +30,6 @@ type Handler struct {
|
|||
*mux.Router
|
||||
bouncer security.BouncerService
|
||||
apiKeyService apikey.APIKeyService
|
||||
demoService *demo.Service
|
||||
DataStore dataservices.DataStore
|
||||
CryptoService portainer.CryptoService
|
||||
passwordStrengthChecker security.PasswordStrengthChecker
|
||||
|
@ -40,12 +38,11 @@ type Handler struct {
|
|||
}
|
||||
|
||||
// NewHandler creates a handler to manage user operations.
|
||||
func NewHandler(bouncer security.BouncerService, rateLimiter *security.RateLimiter, apiKeyService apikey.APIKeyService, demoService *demo.Service, passwordStrengthChecker security.PasswordStrengthChecker) *Handler {
|
||||
func NewHandler(bouncer security.BouncerService, rateLimiter *security.RateLimiter, apiKeyService apikey.APIKeyService, passwordStrengthChecker security.PasswordStrengthChecker) *Handler {
|
||||
h := &Handler{
|
||||
Router: mux.NewRouter(),
|
||||
bouncer: bouncer,
|
||||
apiKeyService: apiKeyService,
|
||||
demoService: demoService,
|
||||
passwordStrengthChecker: passwordStrengthChecker,
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ func Test_userCreateAccessToken(t *testing.T) {
|
|||
rateLimiter := security.NewRateLimiter(10, 1*time.Second, 1*time.Hour)
|
||||
passwordChecker := security.NewPasswordStrengthChecker(store.SettingsService)
|
||||
|
||||
h := NewHandler(requestBouncer, rateLimiter, apiKeyService, nil, passwordChecker)
|
||||
h := NewHandler(requestBouncer, rateLimiter, apiKeyService, passwordChecker)
|
||||
h.DataStore = store
|
||||
h.CryptoService = testhelpers.NewCryptoService()
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ func Test_deleteUserRemovesAccessTokens(t *testing.T) {
|
|||
rateLimiter := security.NewRateLimiter(10, 1*time.Second, 1*time.Hour)
|
||||
passwordChecker := security.NewPasswordStrengthChecker(store.SettingsService)
|
||||
|
||||
h := NewHandler(requestBouncer, rateLimiter, apiKeyService, nil, passwordChecker)
|
||||
h := NewHandler(requestBouncer, rateLimiter, apiKeyService, passwordChecker)
|
||||
h.DataStore = store
|
||||
|
||||
t.Run("standard user deletion removes all associated access tokens", func(t *testing.T) {
|
||||
|
|
|
@ -40,7 +40,7 @@ func Test_userGetAccessTokens(t *testing.T) {
|
|||
rateLimiter := security.NewRateLimiter(10, 1*time.Second, 1*time.Hour)
|
||||
passwordChecker := security.NewPasswordStrengthChecker(store.SettingsService)
|
||||
|
||||
h := NewHandler(requestBouncer, rateLimiter, apiKeyService, nil, passwordChecker)
|
||||
h := NewHandler(requestBouncer, rateLimiter, apiKeyService, passwordChecker)
|
||||
h.DataStore = store
|
||||
|
||||
// generate standard and admin user tokens
|
||||
|
|
|
@ -12,7 +12,6 @@ import (
|
|||
portainer "github.com/portainer/portainer/api"
|
||||
"github.com/portainer/portainer/api/apikey"
|
||||
"github.com/portainer/portainer/api/datastore"
|
||||
"github.com/portainer/portainer/api/demo"
|
||||
"github.com/portainer/portainer/api/http/security"
|
||||
"github.com/portainer/portainer/api/internal/authorization"
|
||||
"github.com/portainer/portainer/api/internal/testhelpers"
|
||||
|
@ -40,7 +39,7 @@ func Test_userList(t *testing.T) {
|
|||
rateLimiter := security.NewRateLimiter(10, 1*time.Second, 1*time.Hour)
|
||||
passwordChecker := security.NewPasswordStrengthChecker(store.SettingsService)
|
||||
|
||||
h := NewHandler(requestBouncer, rateLimiter, apiKeyService, &demo.Service{}, passwordChecker)
|
||||
h := NewHandler(requestBouncer, rateLimiter, apiKeyService, passwordChecker)
|
||||
h.DataStore = store
|
||||
|
||||
// generate admin user tokens
|
||||
|
|
|
@ -38,7 +38,7 @@ func Test_userRemoveAccessToken(t *testing.T) {
|
|||
rateLimiter := security.NewRateLimiter(10, 1*time.Second, 1*time.Hour)
|
||||
passwordChecker := security.NewPasswordStrengthChecker(store.SettingsService)
|
||||
|
||||
h := NewHandler(requestBouncer, rateLimiter, apiKeyService, nil, passwordChecker)
|
||||
h := NewHandler(requestBouncer, rateLimiter, apiKeyService, passwordChecker)
|
||||
h.DataStore = store
|
||||
|
||||
// generate standard and admin user tokens
|
||||
|
|
|
@ -68,10 +68,6 @@ func (handler *Handler) userUpdate(w http.ResponseWriter, r *http.Request) *http
|
|||
return httperror.BadRequest("Invalid user identifier route variable", err)
|
||||
}
|
||||
|
||||
if handler.demoService.IsDemoUser(portainer.UserID(userID)) {
|
||||
return httperror.Forbidden(httperrors.ErrNotAvailableInDemo.Error(), httperrors.ErrNotAvailableInDemo)
|
||||
}
|
||||
|
||||
tokenData, err := security.RetrieveTokenData(r)
|
||||
if err != nil {
|
||||
return httperror.InternalServerError("Unable to retrieve user authentication token", err)
|
||||
|
|
|
@ -55,10 +55,6 @@ func (handler *Handler) userUpdatePassword(w http.ResponseWriter, r *http.Reques
|
|||
return httperror.BadRequest("Invalid user identifier route variable", err)
|
||||
}
|
||||
|
||||
if handler.demoService.IsDemoUser(portainer.UserID(userID)) {
|
||||
return httperror.Forbidden(httperrors.ErrNotAvailableInDemo.Error(), httperrors.ErrNotAvailableInDemo)
|
||||
}
|
||||
|
||||
tokenData, err := security.RetrieveTokenData(r)
|
||||
if err != nil {
|
||||
return httperror.InternalServerError("Unable to retrieve user authentication token", err)
|
||||
|
|
|
@ -32,7 +32,7 @@ func Test_updateUserRemovesAccessTokens(t *testing.T) {
|
|||
rateLimiter := security.NewRateLimiter(10, 1*time.Second, 1*time.Hour)
|
||||
passwordChecker := security.NewPasswordStrengthChecker(store.SettingsService)
|
||||
|
||||
h := NewHandler(requestBouncer, rateLimiter, apiKeyService, nil, passwordChecker)
|
||||
h := NewHandler(requestBouncer, rateLimiter, apiKeyService, passwordChecker)
|
||||
h.DataStore = store
|
||||
|
||||
t.Run("standard user deletion removes all associated access tokens", func(t *testing.T) {
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
package middlewares
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/portainer/portainer/api/http/errors"
|
||||
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
// restrict functionality on demo environments
|
||||
func RestrictDemoEnv(isDemo func() bool) mux.MiddlewareFunc {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if !isDemo() {
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
httperror.WriteError(w, http.StatusBadRequest, errors.ErrNotAvailableInDemo.Error(), errors.ErrNotAvailableInDemo)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
package middlewares
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_demoEnvironment_shouldFail(t *testing.T) {
|
||||
r := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(`{}`))
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
h := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {})
|
||||
|
||||
RestrictDemoEnv(func() bool { return true }).Middleware(h).ServeHTTP(w, r)
|
||||
|
||||
response := w.Result()
|
||||
defer response.Body.Close()
|
||||
|
||||
assert.Equal(t, http.StatusBadRequest, response.StatusCode)
|
||||
|
||||
body, _ := io.ReadAll(response.Body)
|
||||
assert.Contains(t, string(body), "This feature is not available in the demo version of Portainer")
|
||||
}
|
||||
|
||||
func Test_notDemoEnvironment_shouldSucceed(t *testing.T) {
|
||||
r := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(`{}`))
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
h := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {})
|
||||
|
||||
RestrictDemoEnv(func() bool { return false }).Middleware(h).ServeHTTP(w, r)
|
||||
|
||||
response := w.Result()
|
||||
assert.Equal(t, http.StatusOK, response.StatusCode)
|
||||
|
||||
}
|
|
@ -13,7 +13,6 @@ import (
|
|||
"github.com/portainer/portainer/api/apikey"
|
||||
"github.com/portainer/portainer/api/crypto"
|
||||
"github.com/portainer/portainer/api/dataservices"
|
||||
"github.com/portainer/portainer/api/demo"
|
||||
"github.com/portainer/portainer/api/docker"
|
||||
dockerclient "github.com/portainer/portainer/api/docker/client"
|
||||
"github.com/portainer/portainer/api/http/csrf"
|
||||
|
@ -109,7 +108,6 @@ type Server struct {
|
|||
ShutdownCtx context.Context
|
||||
ShutdownTrigger context.CancelFunc
|
||||
StackDeployer deployments.StackDeployer
|
||||
DemoService *demo.Service
|
||||
UpgradeService upgrade.Service
|
||||
AdminCreationDone chan struct{}
|
||||
PendingActionsService *pendingactions.PendingActionsService
|
||||
|
@ -145,7 +143,6 @@ func (server *Server) Start() error {
|
|||
server.FileService.GetDatastorePath(),
|
||||
server.ShutdownTrigger,
|
||||
adminMonitor,
|
||||
server.DemoService,
|
||||
)
|
||||
|
||||
var roleHandler = roles.NewHandler(requestBouncer)
|
||||
|
@ -170,7 +167,7 @@ func (server *Server) Start() error {
|
|||
var edgeTemplatesHandler = edgetemplates.NewHandler(requestBouncer)
|
||||
edgeTemplatesHandler.DataStore = server.DataStore
|
||||
|
||||
var endpointHandler = endpoints.NewHandler(requestBouncer, server.DemoService)
|
||||
var endpointHandler = endpoints.NewHandler(requestBouncer)
|
||||
endpointHandler.DataStore = server.DataStore
|
||||
endpointHandler.FileService = server.FileService
|
||||
endpointHandler.ProxyManager = server.ProxyManager
|
||||
|
@ -226,7 +223,7 @@ func (server *Server) Start() error {
|
|||
var resourceControlHandler = resourcecontrols.NewHandler(requestBouncer)
|
||||
resourceControlHandler.DataStore = server.DataStore
|
||||
|
||||
var settingsHandler = settings.NewHandler(requestBouncer, server.DemoService)
|
||||
var settingsHandler = settings.NewHandler(requestBouncer)
|
||||
settingsHandler.DataStore = server.DataStore
|
||||
settingsHandler.FileService = server.FileService
|
||||
settingsHandler.JWTService = server.JWTService
|
||||
|
@ -269,7 +266,6 @@ func (server *Server) Start() error {
|
|||
|
||||
var systemHandler = system.NewHandler(requestBouncer,
|
||||
server.Status,
|
||||
server.DemoService,
|
||||
server.DataStore,
|
||||
server.UpgradeService)
|
||||
|
||||
|
@ -281,7 +277,7 @@ func (server *Server) Start() error {
|
|||
var uploadHandler = upload.NewHandler(requestBouncer)
|
||||
uploadHandler.FileService = server.FileService
|
||||
|
||||
var userHandler = users.NewHandler(requestBouncer, rateLimiter, server.APIKeyService, server.DemoService, passwordStrengthChecker)
|
||||
var userHandler = users.NewHandler(requestBouncer, rateLimiter, server.APIKeyService, passwordStrengthChecker)
|
||||
userHandler.DataStore = server.DataStore
|
||||
userHandler.CryptoService = server.CryptoService
|
||||
userHandler.AdminCreationDone = server.AdminCreationDone
|
||||
|
|
|
@ -124,7 +124,6 @@ type (
|
|||
Assets *string
|
||||
Data *string
|
||||
FeatureFlags *[]string
|
||||
DemoEnvironment *bool
|
||||
EnableEdgeComputeFeatures *bool
|
||||
EndpointURL *string
|
||||
Labels *[]Pair
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
class DemoFeatureIndicatorController {
|
||||
/* @ngInject */
|
||||
constructor(StateManager) {
|
||||
Object.assign(this, { StateManager });
|
||||
|
||||
this.isDemo = false;
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
const state = this.StateManager.getState();
|
||||
|
||||
this.isDemo = state.application.demoEnvironment.enabled;
|
||||
}
|
||||
}
|
||||
|
||||
export default DemoFeatureIndicatorController;
|
|
@ -1,10 +0,0 @@
|
|||
<div class="row" ng-if="$ctrl.isDemo">
|
||||
<div class="col-lg-12 col-md-12 col-xs-12">
|
||||
<rd-widget>
|
||||
<rd-widget-header icon="alert-triangle" title-text="Feature not available"> </rd-widget-header>
|
||||
<rd-widget-body>
|
||||
<span class="small text-muted">{{ $ctrl.content }}</span>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
</div>
|
||||
</div>
|
|
@ -1,12 +0,0 @@
|
|||
import angular from 'angular';
|
||||
import controller from './demo-feature-indicator.controller.js';
|
||||
|
||||
export const demoFeatureIndicator = {
|
||||
templateUrl: './demo-feature-indicator.html',
|
||||
controller,
|
||||
bindings: {
|
||||
content: '<',
|
||||
},
|
||||
};
|
||||
|
||||
angular.module('portainer.app').component('demoFeatureIndicator', demoFeatureIndicator);
|
|
@ -30,10 +30,8 @@ export default class ThemeSettingsController {
|
|||
|
||||
async updateThemeSettings(theme) {
|
||||
try {
|
||||
if (!this.state.isDemo) {
|
||||
await this.UserService.updateUserTheme(this.state.userId, theme);
|
||||
await queryClient.invalidateQueries(userQueryKeys.user(this.state.userId));
|
||||
}
|
||||
await this.UserService.updateUserTheme(this.state.userId, theme);
|
||||
await queryClient.invalidateQueries(userQueryKeys.user(this.state.userId));
|
||||
|
||||
notifySuccess('Success', 'User theme settings successfully updated');
|
||||
} catch (err) {
|
||||
|
@ -43,12 +41,9 @@ export default class ThemeSettingsController {
|
|||
|
||||
$onInit() {
|
||||
return this.$async(async () => {
|
||||
const state = this.StateManager.getState();
|
||||
|
||||
this.state = {
|
||||
userId: null,
|
||||
themeColor: 'auto',
|
||||
isDemo: state.application.demoEnvironment.enabled,
|
||||
};
|
||||
|
||||
this.state.availableThemes = options;
|
||||
|
|
|
@ -4,7 +4,6 @@ export function StatusViewModel(data) {
|
|||
this.Version = data.Version;
|
||||
this.Edition = data.Edition;
|
||||
this.InstanceID = data.InstanceID;
|
||||
this.DemoEnvironment = data.DemoEnvironment;
|
||||
}
|
||||
|
||||
export function StatusVersionViewModel(data) {
|
||||
|
|
|
@ -109,7 +109,6 @@ function StateManagerFactory(
|
|||
state.application.version = status.Version;
|
||||
state.application.edition = status.Edition;
|
||||
state.application.instanceId = status.InstanceID;
|
||||
state.application.demoEnvironment = status.DemoEnvironment;
|
||||
|
||||
state.application.enableTelemetry = settings.EnableTelemetry;
|
||||
state.application.logo = settings.LogoURL;
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
<page-header title="'User settings'" breadcrumbs="['User settings']" reload="true"> </page-header>
|
||||
|
||||
<demo-feature-indicator ng-if="isDemoUser" content="'You cannot change the password of this account in the demo version of Portainer.'"> </demo-feature-indicator>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-xs-12">
|
||||
<theme-settings></theme-settings>
|
||||
|
@ -56,7 +54,7 @@
|
|||
<button
|
||||
type="submit"
|
||||
class="btn btn-primary btn-sm"
|
||||
ng-disabled="isDemoUser || (AuthenticationMethod !== 1 && !isInitialAdmin) || !formValues.currentPassword || !formValues.newPassword || form.$invalid || formValues.newPassword !== formValues.confirmPassword"
|
||||
ng-disabled="(AuthenticationMethod !== 1 && !isInitialAdmin) || !formValues.currentPassword || !formValues.newPassword || form.$invalid || formValues.newPassword !== formValues.confirmPassword"
|
||||
ng-click="updatePassword()"
|
||||
>
|
||||
Update password
|
||||
|
|
|
@ -76,10 +76,6 @@ angular.module('portainer.app').controller('AccountController', [
|
|||
$scope.forceChangePassword = userDetails.forceChangePassword;
|
||||
$scope.isInitialAdmin = userDetails.ID === 1;
|
||||
|
||||
if (state.application.demoEnvironment.enabled) {
|
||||
$scope.isDemoUser = state.application.demoEnvironment.users.includes($scope.userID);
|
||||
}
|
||||
|
||||
SettingsService.publicSettings()
|
||||
.then(function success(data) {
|
||||
$scope.AuthenticationMethod = data.AuthenticationMethod;
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
import { useIsDemo } from '@/react/portainer/system/useSystemStatus';
|
||||
|
||||
export function DemoAlert() {
|
||||
const isDemoQuery = useIsDemo();
|
||||
if (!isDemoQuery.data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="col-sm-12 mt-2">
|
||||
<span className="small text-muted">
|
||||
You cannot use this feature in the demo version of Portainer.
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -1,13 +1,8 @@
|
|||
import { useField } from 'formik';
|
||||
|
||||
import { useIsDemo } from '@/react/portainer/system/useSystemStatus';
|
||||
|
||||
import { SwitchField } from '@@/form-components/SwitchField';
|
||||
|
||||
import { DemoAlert } from './DemoAlert';
|
||||
|
||||
export function EnableTelemetryField() {
|
||||
const isDemoQuery = useIsDemo();
|
||||
const [{ value }, , { setValue }] = useField<boolean>('enableTelemetry');
|
||||
|
||||
return (
|
||||
|
@ -20,12 +15,9 @@ export function EnableTelemetryField() {
|
|||
checked={value}
|
||||
name="toggle_enableTelemetry"
|
||||
onChange={(checked) => setValue(checked)}
|
||||
disabled={isDemoQuery.data}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<DemoAlert />
|
||||
|
||||
<div className="col-sm-12 text-muted small mt-2">
|
||||
You can find more information about this in our{' '}
|
||||
<a
|
||||
|
|
|
@ -1,18 +1,13 @@
|
|||
import { useField, Field } from 'formik';
|
||||
|
||||
import { useIsDemo } from '@/react/portainer/system/useSystemStatus';
|
||||
|
||||
import { FormControl } from '@@/form-components/FormControl';
|
||||
import { Input } from '@@/form-components/Input';
|
||||
import { SwitchField } from '@@/form-components/SwitchField';
|
||||
|
||||
import { useToggledValue } from '../useToggledValue';
|
||||
|
||||
import { DemoAlert } from './DemoAlert';
|
||||
|
||||
export function LogoFieldset() {
|
||||
const [{ name }, { error }] = useField<string>('logo');
|
||||
const isDemoQuery = useIsDemo();
|
||||
|
||||
const [isEnabled, setIsEnabled] = useToggledValue('logo');
|
||||
|
||||
|
@ -26,12 +21,9 @@ export function LogoFieldset() {
|
|||
checked={isEnabled}
|
||||
name="toggle_logo"
|
||||
labelClass="col-sm-3 col-lg-2"
|
||||
disabled={isDemoQuery.data}
|
||||
onChange={(checked) => setIsEnabled(checked)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<DemoAlert />
|
||||
</div>
|
||||
|
||||
{isEnabled && (
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { useField, Field } from 'formik';
|
||||
|
||||
import { FeatureId } from '@/react/portainer/feature-flags/enums';
|
||||
import { useIsDemo } from '@/react/portainer/system/useSystemStatus';
|
||||
|
||||
import { FormControl } from '@@/form-components/FormControl';
|
||||
import { TextArea } from '@@/form-components/Input/Textarea';
|
||||
|
@ -9,10 +8,7 @@ import { SwitchField } from '@@/form-components/SwitchField';
|
|||
|
||||
import { useToggledValue } from '../useToggledValue';
|
||||
|
||||
import { DemoAlert } from './DemoAlert';
|
||||
|
||||
export function ScreenBannerFieldset() {
|
||||
const isDemoQuery = useIsDemo();
|
||||
const [{ name }, { error }] = useField<string>('loginBanner');
|
||||
const [isEnabled, setIsEnabled] = useToggledValue('loginBanner');
|
||||
|
||||
|
@ -26,14 +22,11 @@ export function ScreenBannerFieldset() {
|
|||
label="Login screen banner"
|
||||
checked={isEnabled}
|
||||
name="toggle_login_banner"
|
||||
disabled={isDemoQuery.data}
|
||||
onChange={(checked) => setIsEnabled(checked)}
|
||||
featureId={FeatureId.CUSTOM_LOGIN_BANNER}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<DemoAlert />
|
||||
|
||||
<div className="col-sm-12 text-muted small mt-2">
|
||||
You can set a custom banner that will be shown to all users during
|
||||
login.
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
import { UseQueryOptions, useQuery } from '@tanstack/react-query';
|
||||
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
import { UserId } from '@/portainer/users/types';
|
||||
|
||||
import { isBE } from '../feature-flags/feature-flags.service';
|
||||
import { EnvironmentId } from '../environments/types';
|
||||
|
||||
import { buildUrl } from './build-url';
|
||||
import { queryKeys } from './query-keys';
|
||||
|
@ -15,11 +13,6 @@ export interface StatusResponse {
|
|||
Edition: string;
|
||||
Version: string;
|
||||
InstanceID: string;
|
||||
DemoEnvironment: {
|
||||
Enabled: boolean;
|
||||
Users: Array<UserId>;
|
||||
Environments: Array<EnvironmentId>;
|
||||
};
|
||||
}
|
||||
|
||||
export async function getSystemStatus() {
|
||||
|
@ -53,9 +46,3 @@ export function useSystemStatus<T = StatusResponse>({
|
|||
onSuccess,
|
||||
});
|
||||
}
|
||||
|
||||
export function useIsDemo() {
|
||||
return useSystemStatus({
|
||||
select: (status) => status.DemoEnvironment.Enabled,
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue