summaryrefslogtreecommitdiff
path: root/lib/api/feature_flag_scopes.rb
blob: 3f3bf4d9f4267b8d9e50887c8029dd6603f5877e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# frozen_string_literal: true

module API
  class FeatureFlagScopes < ::API::Base
    include PaginationParams

    ENVIRONMENT_SCOPE_ENDPOINT_REQUIREMENTS = FeatureFlags::FEATURE_FLAG_ENDPOINT_REQUIREMENTS
      .merge(environment_scope: API::NO_SLASH_URL_PART_REGEX)

    feature_category :feature_flags

    before do
      authorize_read_feature_flags!
    end

    params do
      requires :id, type: String, desc: 'The ID of a project'
    end
    resource 'projects/:id', requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
      resource :feature_flag_scopes do
        desc 'Get all effective feature flags under the environment' do
          detail 'This feature was introduced in GitLab 12.5'
          success ::API::Entities::FeatureFlag::DetailedLegacyScope
        end
        params do
          requires :environment, type: String, desc: 'The environment name'
        end
        get do
          present scopes_for_environment, with: ::API::Entities::FeatureFlag::DetailedLegacyScope
        end
      end

      params do
        requires :name, type: String, desc: 'The name of the feature flag'
      end
      resource 'feature_flags/:name', requirements: FeatureFlags::FEATURE_FLAG_ENDPOINT_REQUIREMENTS do
        resource :scopes do
          desc 'Get all scopes of a feature flag' do
            detail 'This feature was introduced in GitLab 12.5'
            success ::API::Entities::FeatureFlag::LegacyScope
          end
          params do
            use :pagination
          end
          get do
            present paginate(feature_flag.scopes), with: ::API::Entities::FeatureFlag::LegacyScope
          end

          desc 'Create a scope of a feature flag' do
            detail 'This feature was introduced in GitLab 12.5'
            success ::API::Entities::FeatureFlag::LegacyScope
          end
          params do
            requires :environment_scope, type: String, desc: 'The environment scope of the scope'
            requires :active, type: Boolean, desc: 'Whether the scope is active'
            requires :strategies, type: JSON, desc: 'The strategies of the scope'
          end
          post do
            authorize_update_feature_flag!

            result = ::FeatureFlags::UpdateService
              .new(user_project, current_user, scopes_attributes: [declared_params])
              .execute(feature_flag)

            if result[:status] == :success
              present scope, with: ::API::Entities::FeatureFlag::LegacyScope
            else
              render_api_error!(result[:message], result[:http_status])
            end
          end

          params do
            requires :environment_scope, type: String, desc: 'URL-encoded environment scope'
          end
          resource ':environment_scope', requirements: ENVIRONMENT_SCOPE_ENDPOINT_REQUIREMENTS do
            desc 'Get a scope of a feature flag' do
              detail 'This feature was introduced in GitLab 12.5'
              success ::API::Entities::FeatureFlag::LegacyScope
            end
            get do
              present scope, with: ::API::Entities::FeatureFlag::LegacyScope
            end

            desc 'Update a scope of a feature flag' do
              detail 'This feature was introduced in GitLab 12.5'
              success ::API::Entities::FeatureFlag::LegacyScope
            end
            params do
              optional :active, type: Boolean, desc: 'Whether the scope is active'
              optional :strategies, type: JSON, desc: 'The strategies of the scope'
            end
            put do
              authorize_update_feature_flag!

              scope_attributes = declared_params.merge(id: scope.id)

              result = ::FeatureFlags::UpdateService
                .new(user_project, current_user, scopes_attributes: [scope_attributes])
                .execute(feature_flag)

              if result[:status] == :success
                updated_scope = result[:feature_flag].scopes
                  .find { |scope| scope.environment_scope == params[:environment_scope] }

                present updated_scope, with: ::API::Entities::FeatureFlag::LegacyScope
              else
                render_api_error!(result[:message], result[:http_status])
              end
            end

            desc 'Delete a scope from a feature flag' do
              detail 'This feature was introduced in GitLab 12.5'
              success ::API::Entities::FeatureFlag::LegacyScope
            end
            delete do
              authorize_update_feature_flag!

              param = { scopes_attributes: [{ id: scope.id, _destroy: true }] }

              result = ::FeatureFlags::UpdateService
                .new(user_project, current_user, param)
                .execute(feature_flag)

              if result[:status] == :success
                status :no_content
              else
                render_api_error!(result[:message], result[:http_status])
              end
            end
          end
        end
      end
    end

    helpers do
      def authorize_read_feature_flags!
        authorize! :read_feature_flag, user_project
      end

      def authorize_update_feature_flag!
        authorize! :update_feature_flag, feature_flag
      end

      def feature_flag
        @feature_flag ||= user_project.operations_feature_flags
                                      .find_by_name!(params[:name])
      end

      def scope
        @scope ||= feature_flag.scopes
          .find_by_environment_scope!(CGI.unescape(params[:environment_scope]))
      end

      def scopes_for_environment
        Operations::FeatureFlagScope
          .for_unleash_client(user_project, params[:environment])
      end
    end
  end
end