summaryrefslogtreecommitdiff
path: root/app/controllers/projects/feature_flags_controller.rb
diff options
context:
space:
mode:
Diffstat (limited to 'app/controllers/projects/feature_flags_controller.rb')
-rw-r--r--app/controllers/projects/feature_flags_controller.rb174
1 files changed, 174 insertions, 0 deletions
diff --git a/app/controllers/projects/feature_flags_controller.rb b/app/controllers/projects/feature_flags_controller.rb
new file mode 100644
index 00000000000..e9d450a6ce3
--- /dev/null
+++ b/app/controllers/projects/feature_flags_controller.rb
@@ -0,0 +1,174 @@
+# frozen_string_literal: true
+
+class Projects::FeatureFlagsController < Projects::ApplicationController
+ respond_to :html
+
+ before_action :authorize_read_feature_flag!
+ before_action :authorize_create_feature_flag!, only: [:new, :create]
+ before_action :authorize_update_feature_flag!, only: [:edit, :update]
+ before_action :authorize_destroy_feature_flag!, only: [:destroy]
+
+ before_action :feature_flag, only: [:edit, :update, :destroy]
+
+ before_action :ensure_legacy_flags_writable!, only: [:update]
+
+ before_action do
+ push_frontend_feature_flag(:feature_flag_permissions)
+ push_frontend_feature_flag(:feature_flags_new_version, project, default_enabled: true)
+ push_frontend_feature_flag(:feature_flags_legacy_read_only, project, default_enabled: true)
+ push_frontend_feature_flag(:feature_flags_legacy_read_only_override, project)
+ end
+
+ feature_category :feature_flags
+
+ def index
+ @feature_flags = FeatureFlagsFinder
+ .new(project, current_user, scope: params[:scope])
+ .execute
+ .page(params[:page])
+ .per(30)
+
+ respond_to do |format|
+ format.html
+ format.json do
+ Gitlab::PollingInterval.set_header(response, interval: 10_000)
+
+ render json: { feature_flags: feature_flags_json }.merge(summary_json)
+ end
+ end
+ end
+
+ def new
+ end
+
+ def show
+ respond_to do |format|
+ format.json do
+ Gitlab::PollingInterval.set_header(response, interval: 10_000)
+
+ render_success_json(feature_flag)
+ end
+ end
+ end
+
+ def create
+ result = FeatureFlags::CreateService.new(project, current_user, create_params).execute
+
+ if result[:status] == :success
+ respond_to do |format|
+ format.json { render_success_json(result[:feature_flag]) }
+ end
+ else
+ respond_to do |format|
+ format.json { render_error_json(result[:message]) }
+ end
+ end
+ end
+
+ def edit
+ end
+
+ def update
+ result = FeatureFlags::UpdateService.new(project, current_user, update_params).execute(feature_flag)
+
+ if result[:status] == :success
+ respond_to do |format|
+ format.json { render_success_json(result[:feature_flag]) }
+ end
+ else
+ respond_to do |format|
+ format.json { render_error_json(result[:message]) }
+ end
+ end
+ end
+
+ def destroy
+ result = FeatureFlags::DestroyService.new(project, current_user).execute(feature_flag)
+
+ if result[:status] == :success
+ respond_to do |format|
+ format.html { redirect_to_index(notice: _('Feature flag was successfully removed.')) }
+ format.json { render_success_json(feature_flag) }
+ end
+ else
+ respond_to do |format|
+ format.html { redirect_to_index(alert: _('Feature flag was not removed.')) }
+ format.json { render_error_json(result[:message]) }
+ end
+ end
+ end
+
+ protected
+
+ def feature_flag
+ @feature_flag ||= @noteable = if new_version_feature_flags_enabled?
+ project.operations_feature_flags.find_by_iid!(params[:iid])
+ else
+ project.operations_feature_flags.legacy_flag.find_by_iid!(params[:iid])
+ end
+ end
+
+ def new_version_feature_flags_enabled?
+ ::Feature.enabled?(:feature_flags_new_version, project, default_enabled: true)
+ end
+
+ def ensure_legacy_flags_writable!
+ if ::Feature.enabled?(:feature_flags_legacy_read_only, project, default_enabled: true) &&
+ ::Feature.disabled?(:feature_flags_legacy_read_only_override, project) &&
+ feature_flag.legacy_flag?
+ render_error_json(['Legacy feature flags are read-only'])
+ end
+ end
+
+ def create_params
+ params.require(:operations_feature_flag)
+ .permit(:name, :description, :active, :version,
+ scopes_attributes: [:environment_scope, :active,
+ strategies: [:name, parameters: [:groupId, :percentage, :userIds]]],
+ strategies_attributes: [:name, :user_list_id,
+ parameters: [:groupId, :percentage, :userIds, :rollout, :stickiness],
+ scopes_attributes: [:environment_scope]])
+ end
+
+ def update_params
+ params.require(:operations_feature_flag)
+ .permit(:name, :description, :active,
+ scopes_attributes: [:id, :environment_scope, :active, :_destroy,
+ strategies: [:name, parameters: [:groupId, :percentage, :userIds]]],
+ strategies_attributes: [:id, :name, :user_list_id, :_destroy,
+ parameters: [:groupId, :percentage, :userIds, :rollout, :stickiness],
+ scopes_attributes: [:id, :environment_scope, :_destroy]])
+ end
+
+ def feature_flag_json(feature_flag)
+ FeatureFlagSerializer
+ .new(project: @project, current_user: @current_user)
+ .represent(feature_flag)
+ end
+
+ def feature_flags_json
+ FeatureFlagSerializer
+ .new(project: @project, current_user: @current_user)
+ .with_pagination(request, response)
+ .represent(@feature_flags)
+ end
+
+ def summary_json
+ FeatureFlagSummarySerializer
+ .new(project: @project, current_user: @current_user)
+ .represent(@project)
+ end
+
+ def redirect_to_index(**args)
+ redirect_to project_feature_flags_path(@project), status: :found, **args
+ end
+
+ def render_success_json(feature_flag)
+ render json: feature_flag_json(feature_flag), status: :ok
+ end
+
+ def render_error_json(messages)
+ render json: { message: messages },
+ status: :bad_request
+ end
+end