diff --git a/server/channels/api4/access_control.go b/server/channels/api4/access_control.go index d9db767e3f0..96d792d1006 100644 --- a/server/channels/api4/access_control.go +++ b/server/channels/api4/access_control.go @@ -56,6 +56,13 @@ func createAccessControlPolicy(c *Context, w http.ResponseWriter, r *http.Reques hasManageSystemPermission := c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionManageSystem) if !hasManageSystemPermission { + // FEATURE_FLAG_REMOVAL: ChannelAdminManageABACRules - Remove this check when feature is GA + if !c.App.Config().FeatureFlags.ChannelAdminManageABACRules { + c.SetPermissionError(model.PermissionManageSystem) + return + } + // END FEATURE_FLAG_REMOVAL: ChannelAdminManageABACRules + // For non-system admins, check channel-specific permission if !model.IsValidId(policy.ID) { c.SetInvalidParam("policy.id") @@ -110,6 +117,13 @@ func getAccessControlPolicy(c *Context, w http.ResponseWriter, r *http.Request) // Check if user has system admin permission OR channel-specific permission hasManageSystemPermission := c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionManageSystem) if !hasManageSystemPermission { + // FEATURE_FLAG_REMOVAL: ChannelAdminManageABACRules - Remove this check when feature is GA + if !c.App.Config().FeatureFlags.ChannelAdminManageABACRules { + c.SetPermissionError(model.PermissionManageSystem) + return + } + // END FEATURE_FLAG_REMOVAL: ChannelAdminManageABACRules + // For non-system admins, validate policy access permission if appErr := c.App.ValidateAccessControlPolicyPermission(c.AppContext, c.AppContext.Session().UserId, policyID); appErr != nil { c.SetPermissionError(model.PermissionManageSystem) @@ -148,6 +162,13 @@ func deleteAccessControlPolicy(c *Context, w http.ResponseWriter, r *http.Reques // Check if user has system admin permission OR channel-specific permission hasManageSystemPermission := c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionManageSystem) if !hasManageSystemPermission { + // FEATURE_FLAG_REMOVAL: ChannelAdminManageABACRules - Remove this check when feature is GA + if !c.App.Config().FeatureFlags.ChannelAdminManageABACRules { + c.SetPermissionError(model.PermissionManageSystem) + return + } + // END FEATURE_FLAG_REMOVAL: ChannelAdminManageABACRules + // For non-system admins, validate policy access permission if appErr := c.App.ValidateAccessControlPolicyPermission(c.AppContext, c.AppContext.Session().UserId, policyID); appErr != nil { c.SetPermissionError(model.PermissionManageSystem) @@ -180,6 +201,13 @@ func checkExpression(c *Context, w http.ResponseWriter, r *http.Request) { return } + // FEATURE_FLAG_REMOVAL: ChannelAdminManageABACRules - Remove this check when feature is GA + if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionManageSystem) && !c.App.Config().FeatureFlags.ChannelAdminManageABACRules { + c.SetPermissionError(model.PermissionManageSystem) + return + } + // END FEATURE_FLAG_REMOVAL: ChannelAdminManageABACRules + errs, appErr := c.App.CheckExpression(c.AppContext, checkExpressionRequest.Expression) if appErr != nil { c.Err = appErr @@ -210,6 +238,13 @@ func testExpression(c *Context, w http.ResponseWriter, r *http.Request) { return } + // FEATURE_FLAG_REMOVAL: ChannelAdminManageABACRules - Remove this check when feature is GA + if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionManageSystem) && !c.App.Config().FeatureFlags.ChannelAdminManageABACRules { + c.SetPermissionError(model.PermissionManageSystem) + return + } + // END FEATURE_FLAG_REMOVAL: ChannelAdminManageABACRules + users, count, appErr := c.App.TestExpression(c.AppContext, checkExpressionRequest.Expression, model.SubjectSearchOptions{ Term: checkExpressionRequest.Term, Limit: checkExpressionRequest.Limit, @@ -490,6 +525,13 @@ func getFieldsAutocomplete(c *Context, w http.ResponseWriter, r *http.Request) { return } + // FEATURE_FLAG_REMOVAL: ChannelAdminManageABACRules - Remove this check when feature is GA + if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionManageSystem) && !c.App.Config().FeatureFlags.ChannelAdminManageABACRules { + c.SetPermissionError(model.PermissionManageSystem) + return + } + // END FEATURE_FLAG_REMOVAL: ChannelAdminManageABACRules + after := r.URL.Query().Get("after") if after != "" && !model.IsValidId(after) { c.SetInvalidParam("after") @@ -533,6 +575,13 @@ func convertToVisualAST(c *Context, w http.ResponseWriter, r *http.Request) { return } + // FEATURE_FLAG_REMOVAL: ChannelAdminManageABACRules - Remove this check when feature is GA + if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionManageSystem) && !c.App.Config().FeatureFlags.ChannelAdminManageABACRules { + c.SetPermissionError(model.PermissionManageSystem) + return + } + // END FEATURE_FLAG_REMOVAL: ChannelAdminManageABACRules + var cel struct { Expression string `json:"expression"` } diff --git a/server/channels/api4/access_control_test.go b/server/channels/api4/access_control_test.go index 1620efc76cd..6f4464fd5a1 100644 --- a/server/channels/api4/access_control_test.go +++ b/server/channels/api4/access_control_test.go @@ -16,10 +16,14 @@ import ( func TestCreateAccessControlPolicy(t *testing.T) { os.Setenv("MM_FEATUREFLAGS_ATTRIBUTEBASEDACCESSCONTROL", "true") + // FEATURE_FLAG_REMOVAL: ChannelAdminManageABACRules - Remove this env var when feature is GA + os.Setenv("MM_FEATUREFLAGS_CHANNELADMINMANAGEABACRULES", "true") th := Setup(t).InitBasic() t.Cleanup(func() { th.TearDown() os.Unsetenv("MM_FEATUREFLAGS_ATTRIBUTEBASEDACCESSCONTROL") + // FEATURE_FLAG_REMOVAL: ChannelAdminManageABACRules - Remove this unsetenv when feature is GA + os.Unsetenv("MM_FEATUREFLAGS_CHANNELADMINMANAGEABACRULES") }) samplePolicy := &model.AccessControlPolicy{ diff --git a/server/public/model/feature_flags.go b/server/public/model/feature_flags.go index ab12ad710af..f84a54d2566 100644 --- a/server/public/model/feature_flags.go +++ b/server/public/model/feature_flags.go @@ -73,6 +73,10 @@ type FeatureFlags struct { // Enable AppsForm for Interactive Dialogs instead of legacy dialog implementation InteractiveDialogAppsForm bool + + // FEATURE_FLAG_REMOVAL: ChannelAdminManageABACRules - Remove this field when feature is GA + // Enable channel admins to manage ABAC rules for their channels + ChannelAdminManageABACRules bool } func (f *FeatureFlags) SetDefaults() { @@ -103,6 +107,8 @@ func (f *FeatureFlags) SetDefaults() { f.AttributeBasedAccessControl = true f.ContentFlagging = false f.InteractiveDialogAppsForm = true + // FEATURE_FLAG_REMOVAL: ChannelAdminManageABACRules - Remove this default when feature is GA + f.ChannelAdminManageABACRules = false // Default to false for safety } // ToMap returns the feature flags as a map[string]string diff --git a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/billing_subscriptions.scss b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/billing_subscriptions.scss index 470d70966d1..c22a11dc0b0 100644 --- a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/billing_subscriptions.scss +++ b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/billing_subscriptions.scss @@ -126,7 +126,9 @@ } .PrivateCloudCard__actionButton { - display: block; + display: flex; + align-items: center; + justify-content: center; margin-top: 16px; } diff --git a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/cloud_trial_banner.tsx b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/cloud_trial_banner.tsx index e3bbbcabcac..be90f8d0dd0 100644 --- a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/cloud_trial_banner.tsx +++ b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/cloud_trial_banner.tsx @@ -14,7 +14,6 @@ import {getCurrentUser} from 'mattermost-redux/selectors/entities/common'; import {get as getPreference} from 'mattermost-redux/selectors/entities/preferences'; import AlertBanner from 'components/alert_banner'; -import useOpenSalesLink from 'components/common/hooks/useOpenSalesLink'; import UpgradeLink from 'components/widgets/links/upgrade_link'; import {CloudBanners, Preferences} from 'utils/constants'; @@ -30,7 +29,6 @@ const CloudTrialBanner = ({trialEndDate}: Props): JSX.Element | null => { const endDate = new Date(trialEndDate); const DISMISSED_DAYS = 10; const {formatMessage} = useIntl(); - const [openSalesLink] = useOpenSalesLink(); const dispatch = useDispatch(); const user = useSelector(getCurrentUser); const storedDismissedEndDate = useSelector((state: GlobalState) => getPreference(state, Preferences.CLOUD_TRIAL_BANNER, CloudBanners.UPGRADE_FROM_TRIAL)); @@ -72,7 +70,7 @@ const CloudTrialBanner = ({trialEndDate}: Props): JSX.Element | null => { title={( )} message={( @@ -94,17 +92,7 @@ const CloudTrialBanner = ({trialEndDate}: Props): JSX.Element | null => { /> )} actionButtonRight={( - + null )} /> ); diff --git a/webapp/channels/src/components/admin_console/billing/billing_summary/billing_summary.tsx b/webapp/channels/src/components/admin_console/billing/billing_summary/billing_summary.tsx index 832b0b0f42c..e931074a931 100644 --- a/webapp/channels/src/components/admin_console/billing/billing_summary/billing_summary.tsx +++ b/webapp/channels/src/components/admin_console/billing/billing_summary/billing_summary.tsx @@ -98,14 +98,14 @@ export const FreeTrial = ({daysLeftOnTrial}: FreeTrialProps) => { {daysLeftOnTrial > TrialPeriodDays.TRIAL_WARNING_THRESHOLD && } {(daysLeftOnTrial > TrialPeriodDays.TRIAL_1_DAY && daysLeftOnTrial <= TrialPeriodDays.TRIAL_WARNING_THRESHOLD) && } @@ -119,9 +119,8 @@ export const FreeTrial = ({daysLeftOnTrial}: FreeTrialProps) => {