Migrate to flipper
This commit is contained in:
parent
28d869e818
commit
65e227c44b
33 changed files with 186 additions and 181 deletions
3
Gemfile
3
Gemfile
|
@ -27,6 +27,9 @@ gem 'devise' # Gestion des comptes utilisateurs
|
||||||
gem 'devise-async'
|
gem 'devise-async'
|
||||||
gem 'dotenv-rails', require: 'dotenv/rails-now' # dotenv should always be loaded before rails
|
gem 'dotenv-rails', require: 'dotenv/rails-now' # dotenv should always be loaded before rails
|
||||||
gem 'flipflop'
|
gem 'flipflop'
|
||||||
|
gem 'flipper'
|
||||||
|
gem 'flipper-active_record'
|
||||||
|
gem 'flipper-ui'
|
||||||
gem 'fog-openstack'
|
gem 'fog-openstack'
|
||||||
gem 'font-awesome-rails'
|
gem 'font-awesome-rails'
|
||||||
gem 'gon'
|
gem 'gon'
|
||||||
|
|
12
Gemfile.lock
12
Gemfile.lock
|
@ -222,6 +222,15 @@ GEM
|
||||||
ffi (1.9.25)
|
ffi (1.9.25)
|
||||||
flipflop (2.4.0)
|
flipflop (2.4.0)
|
||||||
activesupport (>= 4.0)
|
activesupport (>= 4.0)
|
||||||
|
flipper (0.16.2)
|
||||||
|
flipper-active_record (0.16.2)
|
||||||
|
activerecord (>= 3.2, < 6)
|
||||||
|
flipper (~> 0.16.2)
|
||||||
|
flipper-ui (0.16.2)
|
||||||
|
erubis (~> 2.7.0)
|
||||||
|
flipper (~> 0.16.2)
|
||||||
|
rack (>= 1.4, < 3)
|
||||||
|
rack-protection (>= 1.5.3, < 2.1.0)
|
||||||
fog-core (2.1.2)
|
fog-core (2.1.2)
|
||||||
builder
|
builder
|
||||||
excon (~> 0.58)
|
excon (~> 0.58)
|
||||||
|
@ -725,6 +734,9 @@ DEPENDENCIES
|
||||||
dotenv-rails
|
dotenv-rails
|
||||||
factory_bot
|
factory_bot
|
||||||
flipflop
|
flipflop
|
||||||
|
flipper
|
||||||
|
flipper-active_record
|
||||||
|
flipper-ui
|
||||||
fog-openstack
|
fog-openstack
|
||||||
font-awesome-rails
|
font-awesome-rails
|
||||||
gon
|
gon
|
||||||
|
|
|
@ -12,7 +12,7 @@ class ApplicationController < ActionController::Base
|
||||||
before_action :set_raven_context
|
before_action :set_raven_context
|
||||||
before_action :redirect_if_untrusted
|
before_action :redirect_if_untrusted
|
||||||
before_action :authorize_request_for_profiler
|
before_action :authorize_request_for_profiler
|
||||||
before_action :reject, if: -> { Flipflop.maintenance_mode? }
|
before_action :reject, if: -> { feature_enabled?(:maintenance_mode) }
|
||||||
|
|
||||||
before_action :staging_authenticate
|
before_action :staging_authenticate
|
||||||
before_action :set_active_storage_host
|
before_action :set_active_storage_host
|
||||||
|
@ -28,7 +28,7 @@ class ApplicationController < ActionController::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
def authorize_request_for_profiler
|
def authorize_request_for_profiler
|
||||||
if Flipflop.mini_profiler_enabled?
|
if feature_enabled?(:mini_profiler)
|
||||||
Rack::MiniProfiler.authorize_request
|
Rack::MiniProfiler.authorize_request
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -77,6 +77,10 @@ class ApplicationController < ActionController::Base
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
|
def feature_enabled?(feature_name)
|
||||||
|
Flipper.enabled?(feature_name, current_user)
|
||||||
|
end
|
||||||
|
|
||||||
def authenticate_logged_user!
|
def authenticate_logged_user!
|
||||||
if instructeur_signed_in?
|
if instructeur_signed_in?
|
||||||
authenticate_instructeur!
|
authenticate_instructeur!
|
||||||
|
@ -190,7 +194,7 @@ class ApplicationController < ActionController::Base
|
||||||
def redirect_if_untrusted
|
def redirect_if_untrusted
|
||||||
if instructeur_signed_in? &&
|
if instructeur_signed_in? &&
|
||||||
sensitive_path &&
|
sensitive_path &&
|
||||||
!Flipflop.bypass_email_login_token? &&
|
!feature_enabled?(:instructeur_bypass_email_login_token) &&
|
||||||
!IPService.ip_trusted?(request.headers['X-Forwarded-For']) &&
|
!IPService.ip_trusted?(request.headers['X-Forwarded-For']) &&
|
||||||
!trusted_device?
|
!trusted_device?
|
||||||
|
|
||||||
|
|
|
@ -191,7 +191,7 @@ module Instructeurs
|
||||||
end
|
end
|
||||||
|
|
||||||
def telecharger_pjs
|
def telecharger_pjs
|
||||||
return head(:forbidden) if !Flipflop.download_as_zip_enabled? || !dossier.attachments_downloadable?
|
return head(:forbidden) if !feature_enabled?(:instructeur_download_as_zip) || !dossier.attachments_downloadable?
|
||||||
|
|
||||||
files = ActiveStorage::DownloadableFile.create_list_from_dossier(dossier)
|
files = ActiveStorage::DownloadableFile.create_list_from_dossier(dossier)
|
||||||
|
|
||||||
|
|
|
@ -19,20 +19,6 @@ module Manager
|
||||||
redirect_to manager_administrateur_path(params[:id])
|
redirect_to manager_administrateur_path(params[:id])
|
||||||
end
|
end
|
||||||
|
|
||||||
def enable_feature
|
|
||||||
administrateur = Administrateur.find(params[:id])
|
|
||||||
|
|
||||||
params[:features].each do |key, enable|
|
|
||||||
if enable
|
|
||||||
administrateur.enable_feature(key.to_sym)
|
|
||||||
else
|
|
||||||
administrateur.disable_feature(key.to_sym)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
head :ok
|
|
||||||
end
|
|
||||||
|
|
||||||
def delete
|
def delete
|
||||||
administrateur = Administrateur.find(params[:id])
|
administrateur = Administrateur.find(params[:id])
|
||||||
|
|
||||||
|
|
|
@ -6,19 +6,5 @@ module Manager
|
||||||
flash[:notice] = "Instructeur réinvité."
|
flash[:notice] = "Instructeur réinvité."
|
||||||
redirect_to manager_instructeur_path(instructeur)
|
redirect_to manager_instructeur_path(instructeur)
|
||||||
end
|
end
|
||||||
|
|
||||||
def enable_feature
|
|
||||||
instructeur = Instructeur.find(params[:id])
|
|
||||||
|
|
||||||
params[:features].each do |key, enable|
|
|
||||||
if enable
|
|
||||||
instructeur.enable_feature(key.to_sym)
|
|
||||||
else
|
|
||||||
instructeur.disable_feature(key.to_sym)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
head :ok
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,5 +6,19 @@ module Manager
|
||||||
flash[:notice] = "L'email d'activation de votre compte a été renvoyé."
|
flash[:notice] = "L'email d'activation de votre compte a été renvoyé."
|
||||||
redirect_to manager_user_path(user)
|
redirect_to manager_user_path(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def enable_feature
|
||||||
|
user = User.find(params[:id])
|
||||||
|
|
||||||
|
params[:features].each do |key, enable|
|
||||||
|
if enable
|
||||||
|
Flipper.enable_actor(key.to_sym, user)
|
||||||
|
else
|
||||||
|
Flipper.disable_actor(key.to_sym, user)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
head :ok
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
5
app/helpers/flipper_helper.rb
Normal file
5
app/helpers/flipper_helper.rb
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
module FlipperHelper
|
||||||
|
def feature_enabled?(feature_name)
|
||||||
|
Flipper.enabled?(feature_name, current_user)
|
||||||
|
end
|
||||||
|
end
|
|
@ -50,7 +50,7 @@ module ProcedureHelper
|
||||||
private
|
private
|
||||||
|
|
||||||
TOGGLES = {
|
TOGGLES = {
|
||||||
TypeDeChamp.type_champs.fetch(:integer_number) => :champ_integer_number?
|
TypeDeChamp.type_champs.fetch(:integer_number) => :administrateur_champ_integer_number
|
||||||
}
|
}
|
||||||
|
|
||||||
def types_de_champ_types
|
def types_de_champ_types
|
||||||
|
@ -58,7 +58,7 @@ module ProcedureHelper
|
||||||
|
|
||||||
types_de_champ_types.select! do |tdc|
|
types_de_champ_types.select! do |tdc|
|
||||||
toggle = TOGGLES[tdc.last]
|
toggle = TOGGLES[tdc.last]
|
||||||
toggle.blank? || Flipflop.send(toggle)
|
toggle.blank? || feature_enabled?(toggle)
|
||||||
end
|
end
|
||||||
|
|
||||||
types_de_champ_types
|
types_de_champ_types
|
||||||
|
|
|
@ -44,7 +44,7 @@ class ApiEntreprise::API
|
||||||
def self.url(resource_name, siret_or_siren)
|
def self.url(resource_name, siret_or_siren)
|
||||||
base_url = [API_ENTREPRISE_URL, resource_name, siret_or_siren].join("/")
|
base_url = [API_ENTREPRISE_URL, resource_name, siret_or_siren].join("/")
|
||||||
|
|
||||||
if Flipflop.insee_api_v3?
|
if Flipper.enabled?(:insee_api_v3)
|
||||||
base_url += "?with_insee_v3=true"
|
base_url += "?with_insee_v3=true"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
module Flipflop::Strategies
|
|
||||||
class UserPreferenceStrategy < AbstractStrategy
|
|
||||||
def self.default_description
|
|
||||||
"Allows configuration of features per user."
|
|
||||||
end
|
|
||||||
|
|
||||||
def switchable?
|
|
||||||
false
|
|
||||||
end
|
|
||||||
|
|
||||||
def enabled?(feature)
|
|
||||||
find_current_administrateur&.feature_enabled?(feature) ||
|
|
||||||
find_current_instructeur&.feature_enabled?(feature)
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def find_current_administrateur
|
|
||||||
administrateur_id = Current.administrateur&.id
|
|
||||||
if administrateur_id
|
|
||||||
Administrateur.find_by(id: administrateur_id)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def find_current_instructeur
|
|
||||||
instructeur_id = Current.instructeur&.id
|
|
||||||
if instructeur_id
|
|
||||||
Instructeur.find_by(id: instructeur_id)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -72,23 +72,6 @@ class Administrateur < ApplicationRecord
|
||||||
administrateur
|
administrateur
|
||||||
end
|
end
|
||||||
|
|
||||||
def feature_enabled?(feature)
|
|
||||||
Flipflop.feature_set.feature(feature)
|
|
||||||
features[feature.to_s]
|
|
||||||
end
|
|
||||||
|
|
||||||
def disable_feature(feature)
|
|
||||||
Flipflop.feature_set.feature(feature)
|
|
||||||
features.delete(feature.to_s)
|
|
||||||
save
|
|
||||||
end
|
|
||||||
|
|
||||||
def enable_feature(feature)
|
|
||||||
Flipflop.feature_set.feature(feature)
|
|
||||||
features[feature.to_s] = true
|
|
||||||
save
|
|
||||||
end
|
|
||||||
|
|
||||||
def owns?(procedure)
|
def owns?(procedure)
|
||||||
procedure.administrateurs.include?(self)
|
procedure.administrateurs.include?(self)
|
||||||
end
|
end
|
||||||
|
|
|
@ -66,7 +66,7 @@ class DossierOperationLog < ApplicationRecord
|
||||||
def self.serialize_subject(subject)
|
def self.serialize_subject(subject)
|
||||||
if subject.nil?
|
if subject.nil?
|
||||||
nil
|
nil
|
||||||
elsif !Flipflop.operation_log_serialize_subject?
|
elsif !Flipper.enabled?(:operation_log_serialize_subject)
|
||||||
{ id: subject.id }
|
{ id: subject.id }
|
||||||
else
|
else
|
||||||
case subject
|
case subject
|
||||||
|
|
|
@ -180,23 +180,6 @@ class Instructeur < ApplicationRecord
|
||||||
Follow.where(instructeur: self, dossier: dossier).update_all(attributes)
|
Follow.where(instructeur: self, dossier: dossier).update_all(attributes)
|
||||||
end
|
end
|
||||||
|
|
||||||
def feature_enabled?(feature)
|
|
||||||
Flipflop.feature_set.feature(feature)
|
|
||||||
features[feature.to_s]
|
|
||||||
end
|
|
||||||
|
|
||||||
def disable_feature(feature)
|
|
||||||
Flipflop.feature_set.feature(feature)
|
|
||||||
features.delete(feature.to_s)
|
|
||||||
save
|
|
||||||
end
|
|
||||||
|
|
||||||
def enable_feature(feature)
|
|
||||||
Flipflop.feature_set.feature(feature)
|
|
||||||
features[feature.to_s] = true
|
|
||||||
save
|
|
||||||
end
|
|
||||||
|
|
||||||
def young_login_token?
|
def young_login_token?
|
||||||
trusted_device_token = trusted_device_tokens.order(created_at: :desc).first
|
trusted_device_token = trusted_device_tokens.order(created_at: :desc).first
|
||||||
trusted_device_token&.token_young?
|
trusted_device_token&.token_young?
|
||||||
|
|
|
@ -87,6 +87,10 @@ class User < ApplicationRecord
|
||||||
user
|
user
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def flipper_id
|
||||||
|
"User:#{id}"
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def link_invites!
|
def link_invites!
|
||||||
|
|
|
@ -125,7 +125,7 @@
|
||||||
.col-md-6
|
.col-md-6
|
||||||
%h4 Options avancées
|
%h4 Options avancées
|
||||||
|
|
||||||
- if Flipflop.web_hook?
|
- if feature_enabled?(:administrateur_web_hook)
|
||||||
%label{ for: :web_hook_url } Lien de rappel HTTP (webhook)
|
%label{ for: :web_hook_url } Lien de rappel HTTP (webhook)
|
||||||
= f.text_field :web_hook_url, class: 'form-control', placeholder: 'https://callback.exemple.fr/'
|
= f.text_field :web_hook_url, class: 'form-control', placeholder: 'https://callback.exemple.fr/'
|
||||||
%p.help-block
|
%p.help-block
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
:ruby
|
:ruby
|
||||||
url = if field.resource.class.name == 'Instructeur'
|
group = field.resource.class.name.downcase
|
||||||
enable_feature_manager_instructeur_path(field.resource.id)
|
user = field.resource.user
|
||||||
else
|
url = enable_feature_manager_user_path(user)
|
||||||
enable_feature_manager_administrateur_path(field.resource.id)
|
|
||||||
end
|
|
||||||
|
|
||||||
%table#features
|
%table#features
|
||||||
- admin_features = Flipflop.feature_set.features.reject{ |f| f.group.try(:key) == :production }
|
- Flipper.features.select { |feature| feature.key.start_with?("#{group}_") }.each do |feature|
|
||||||
- admin_features.each do |feature|
|
|
||||||
%tr
|
%tr
|
||||||
%td= feature.title
|
%td= feature
|
||||||
%td
|
%td
|
||||||
= check_box_tag "enable-feature", "enable", field.data[feature.name], data: { url: url, key: feature.key }
|
= check_box_tag "enable-feature", "enable", feature.enabled?(user), data: { url: url, key: feature.key }
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
%li
|
%li
|
||||||
= link_to "Uniquement cet onglet", "#", onclick: "window.print()", class: "menu-item menu-link"
|
= link_to "Uniquement cet onglet", "#", onclick: "window.print()", class: "menu-item menu-link"
|
||||||
|
|
||||||
- if Flipflop.download_as_zip_enabled? && !PiecesJustificativesService.liste_pieces_justificatives(dossier).empty?
|
- if feature_enabled?(:instructeur_download_as_zip) && !PiecesJustificativesService.liste_pieces_justificatives(dossier).empty?
|
||||||
%span.dropdown.print-menu-opener
|
%span.dropdown.print-menu-opener
|
||||||
%button.button.dropdown-button.icon-only
|
%button.button.dropdown-button.icon-only
|
||||||
%span.icon.attachment
|
%span.icon.attachment
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
- if Flipflop.pre_maintenance_mode?
|
- if feature_enabled?(:pre_maintenance_mode)
|
||||||
.maintenance
|
.maintenance
|
||||||
%span
|
%span
|
||||||
Une opération de maintenance est prévue sur demarches-simplifiees.fr à 23 h 00. La plateforme sera inaccessible pendant une vingtaine de minutes.
|
Une opération de maintenance est prévue sur demarches-simplifiees.fr à 23 h 00. La plateforme sera inaccessible pendant une vingtaine de minutes.
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
= Gon::Base.render_data(camel_case: true, init: true, nonce: request.content_security_policy_nonce)
|
= Gon::Base.render_data(camel_case: true, init: true, nonce: request.content_security_policy_nonce)
|
||||||
|
|
||||||
- if Flipflop.xray_enabled?
|
- if feature_enabled?(:xray)
|
||||||
= stylesheet_link_tag :xray
|
= stylesheet_link_tag :xray
|
||||||
|
|
||||||
%body{ id: content_for(:page_id), class: browser.platform.ios? ? 'ios' : nil }
|
%body{ id: content_for(:page_id), class: browser.platform.ios? ? 'ios' : nil }
|
||||||
|
@ -39,7 +39,7 @@
|
||||||
- if content_for?(:footer)
|
- if content_for?(:footer)
|
||||||
= content_for(:footer)
|
= content_for(:footer)
|
||||||
|
|
||||||
- if Flipflop.xray_enabled?
|
- if feature_enabled?(:xray)
|
||||||
= javascript_include_tag :xray
|
= javascript_include_tag :xray
|
||||||
|
|
||||||
= yield :charts_js
|
= yield :charts_js
|
||||||
|
|
|
@ -24,5 +24,5 @@ as defined by the routes in the `admin/` namespace
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
<%= link_to "Delayed Jobs", manager_delayed_job_path, class: "navigation__link" %>
|
<%= link_to "Delayed Jobs", manager_delayed_job_path, class: "navigation__link" %>
|
||||||
<%= link_to "Features", manager_flipflop_path, class: "navigation__link" %>
|
<%= link_to "Features", manager_flipper_path, class: "navigation__link" %>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
|
@ -42,5 +42,6 @@ module TPS
|
||||||
|
|
||||||
config.ds_weekly_overview = ENV['APP_NAME'] == 'tps'
|
config.ds_weekly_overview = ENV['APP_NAME'] == 'tps'
|
||||||
config.middleware.use Rack::Attack
|
config.middleware.use Rack::Attack
|
||||||
|
config.middleware.use Flipper::Middleware::Memoizer, preload_all: true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,42 +0,0 @@
|
||||||
Flipflop.configure do
|
|
||||||
strategy :cookie,
|
|
||||||
secure: Rails.env.production?,
|
|
||||||
httponly: true
|
|
||||||
strategy :active_record
|
|
||||||
strategy :user_preference
|
|
||||||
strategy :default
|
|
||||||
|
|
||||||
group :champs do
|
|
||||||
feature :champ_integer_number,
|
|
||||||
title: "Champ nombre entier"
|
|
||||||
end
|
|
||||||
|
|
||||||
feature :web_hook
|
|
||||||
|
|
||||||
feature :operation_log_serialize_subject
|
|
||||||
feature :download_as_zip_enabled
|
|
||||||
feature :bypass_email_login_token,
|
|
||||||
default: Rails.env.test?
|
|
||||||
|
|
||||||
group :development do
|
|
||||||
feature :mini_profiler_enabled,
|
|
||||||
default: Rails.env.development?
|
|
||||||
feature :xray_enabled,
|
|
||||||
default: Rails.env.development?
|
|
||||||
end
|
|
||||||
|
|
||||||
group :production do
|
|
||||||
feature :insee_api_v3,
|
|
||||||
default: true
|
|
||||||
feature :pre_maintenance_mode
|
|
||||||
feature :maintenance_mode
|
|
||||||
end
|
|
||||||
|
|
||||||
if Rails.env.test?
|
|
||||||
# It would be nicer to configure this in administrateur_spec.rb in #feature_enabled?,
|
|
||||||
# but that results in a FrozenError: can't modify frozen Hash
|
|
||||||
|
|
||||||
feature :test_a
|
|
||||||
feature :test_b
|
|
||||||
end
|
|
||||||
end
|
|
46
config/initializers/flipper.rb
Normal file
46
config/initializers/flipper.rb
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
Flipper.configure do |config|
|
||||||
|
config.default do
|
||||||
|
Flipper.new(Flipper::Adapters::ActiveRecord.new)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Flipper.register('Administrateurs') do |user|
|
||||||
|
user.administrateur_id.present?
|
||||||
|
end
|
||||||
|
Flipper.register('Instructeurs') do |user|
|
||||||
|
user.instructeur_id.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
# This setup is primarily for first deployment, because consequently
|
||||||
|
# we can add new features from the Web UI. However when the new DB is created
|
||||||
|
# this will immediately migrate the default features to be controlled.
|
||||||
|
def setup_features(features)
|
||||||
|
features.each do |feature|
|
||||||
|
if Flipper.exist?(feature)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
# Disable feature by default
|
||||||
|
Flipper.disable(feature)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# A list of features to be deployed on first push
|
||||||
|
features = [
|
||||||
|
:administrateur_champ_integer_number,
|
||||||
|
:administrateur_web_hook,
|
||||||
|
:insee_api_v3,
|
||||||
|
:instructeur_bypass_email_login_token,
|
||||||
|
:instructeur_download_as_zip,
|
||||||
|
:maintenance_mode,
|
||||||
|
:mini_profiler,
|
||||||
|
:operation_log_serialize_subject,
|
||||||
|
:pre_maintenance_mode,
|
||||||
|
:xray
|
||||||
|
]
|
||||||
|
|
||||||
|
ActiveSupport.on_load(:active_record) do
|
||||||
|
if ActiveRecord::Base.connection.data_source_exists? 'flipper_features'
|
||||||
|
setup_features(features)
|
||||||
|
end
|
||||||
|
end
|
|
@ -21,17 +21,16 @@ Rails.application.routes.draw do
|
||||||
|
|
||||||
resources :administrateurs, only: [:index, :show, :new, :create] do
|
resources :administrateurs, only: [:index, :show, :new, :create] do
|
||||||
post 'reinvite', on: :member
|
post 'reinvite', on: :member
|
||||||
put 'enable_feature', on: :member
|
|
||||||
delete 'delete', on: :member
|
delete 'delete', on: :member
|
||||||
end
|
end
|
||||||
|
|
||||||
resources :users, only: [:index, :show] do
|
resources :users, only: [:index, :show] do
|
||||||
post 'resend_confirmation_instructions', on: :member
|
post 'resend_confirmation_instructions', on: :member
|
||||||
|
put 'enable_feature', on: :member
|
||||||
end
|
end
|
||||||
|
|
||||||
resources :instructeurs, only: [:index, :show] do
|
resources :instructeurs, only: [:index, :show] do
|
||||||
post 'reinvite', on: :member
|
post 'reinvite', on: :member
|
||||||
put 'enable_feature', on: :member
|
|
||||||
end
|
end
|
||||||
|
|
||||||
resources :dossiers, only: [:show]
|
resources :dossiers, only: [:show]
|
||||||
|
@ -46,7 +45,7 @@ Rails.application.routes.draw do
|
||||||
post 'demandes/refuse_administrateur'
|
post 'demandes/refuse_administrateur'
|
||||||
|
|
||||||
authenticate :administration do
|
authenticate :administration do
|
||||||
mount Flipflop::Engine => "/features"
|
mount Flipper::UI.app(-> { Flipper.instance }) => "/features", as: :flipper
|
||||||
match "/delayed_job" => DelayedJobWeb, :anchor => false, :via => [:get, :post]
|
match "/delayed_job" => DelayedJobWeb, :anchor => false, :via => [:get, :post]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
22
db/migrate/20190704094454_create_flipper_tables.rb
Normal file
22
db/migrate/20190704094454_create_flipper_tables.rb
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
class CreateFlipperTables < ActiveRecord::Migration[5.2]
|
||||||
|
def self.up
|
||||||
|
create_table :flipper_features do |t|
|
||||||
|
t.string :key, null: false
|
||||||
|
t.timestamps null: false
|
||||||
|
end
|
||||||
|
add_index :flipper_features, :key, unique: true
|
||||||
|
|
||||||
|
create_table :flipper_gates do |t|
|
||||||
|
t.string :feature_key, null: false
|
||||||
|
t.string :key, null: false
|
||||||
|
t.string :value
|
||||||
|
t.timestamps null: false
|
||||||
|
end
|
||||||
|
add_index :flipper_gates, [:feature_key, :key, :value], unique: true
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.down
|
||||||
|
drop_table :flipper_gates
|
||||||
|
drop_table :flipper_features
|
||||||
|
end
|
||||||
|
end
|
18
db/schema.rb
18
db/schema.rb
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 2019_08_22_143413) do
|
ActiveRecord::Schema.define(version: 2019_08_28_073736) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
@ -355,6 +355,22 @@ ActiveRecord::Schema.define(version: 2019_08_22_143413) do
|
||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", null: false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
create_table "flipper_features", force: :cascade do |t|
|
||||||
|
t.string "key", null: false
|
||||||
|
t.datetime "created_at", null: false
|
||||||
|
t.datetime "updated_at", null: false
|
||||||
|
t.index ["key"], name: "index_flipper_features_on_key", unique: true
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table "flipper_gates", force: :cascade do |t|
|
||||||
|
t.string "feature_key", null: false
|
||||||
|
t.string "key", null: false
|
||||||
|
t.string "value"
|
||||||
|
t.datetime "created_at", null: false
|
||||||
|
t.datetime "updated_at", null: false
|
||||||
|
t.index ["feature_key", "key", "value"], name: "index_flipper_gates_on_feature_key_and_key_and_value", unique: true
|
||||||
|
end
|
||||||
|
|
||||||
create_table "follows", id: :serial, force: :cascade do |t|
|
create_table "follows", id: :serial, force: :cascade do |t|
|
||||||
t.integer "instructeur_id", null: false
|
t.integer "instructeur_id", null: false
|
||||||
t.integer "dossier_id", null: false
|
t.integer "dossier_id", null: false
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
namespace :after_party do
|
||||||
|
desc 'Deployment task: migrate_flipflop_to_flipper'
|
||||||
|
task migrate_flipflop_to_flipper: :environment do
|
||||||
|
puts "Running deploy task 'migrate_flipflop_to_flipper'"
|
||||||
|
|
||||||
|
Instructeur.includes(:user).find_each do |instructeur|
|
||||||
|
if instructeur.features['download_as_zip_enabled']
|
||||||
|
pp "enable :instructeur_download_as_zip for #{instructeur.user.email}"
|
||||||
|
Flipper.enable_actor(:instructeur_download_as_zip, instructeur.user)
|
||||||
|
end
|
||||||
|
if instructeur.features['bypass_email_login_token']
|
||||||
|
pp "enable :instructeur_bypass_email_login_token for #{instructeur.user.email}"
|
||||||
|
Flipper.enable_actor(:instructeur_bypass_email_login_token, instructeur.user)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Administrateur.includes(:user).find_each do |administrateur|
|
||||||
|
if administrateur.features['web_hook']
|
||||||
|
pp "enable :administrateur_web_hook for #{administrateur.user.email}"
|
||||||
|
Flipper.enable_actor(:administrateur_web_hook, administrateur.user)
|
||||||
|
end
|
||||||
|
|
||||||
|
if administrateur.features['champ_integer_number']
|
||||||
|
pp "enable :administrateur_champ_integer_number for #{administrateur.user.email}"
|
||||||
|
Flipper.enable_actor(:administrateur_champ_integer_number, administrateur.user)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Update task as completed. If you remove the line below, the task will
|
||||||
|
# run with every deploy (or every time you call after_party:run).
|
||||||
|
AfterParty::TaskRecord.create version: '20190829065022'
|
||||||
|
end
|
||||||
|
end
|
|
@ -167,7 +167,7 @@ describe ApplicationController, type: :controller do
|
||||||
let(:sensitive_path) { true }
|
let(:sensitive_path) { true }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
Flipflop::FeatureSet.current.test!.switch!(:bypass_email_login_token, false)
|
Flipper.disable(:instructeur_bypass_email_login_token)
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the instructeur is signed_in' do
|
context 'when the instructeur is signed_in' do
|
||||||
|
|
|
@ -544,10 +544,6 @@ describe Instructeurs::DossiersController, type: :controller do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when zip download is disabled through flipflop' do
|
context 'when zip download is disabled through flipflop' do
|
||||||
before do
|
|
||||||
Flipflop::FeatureSet.current.test!.switch!(:download_as_zip_enabled, false)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'is forbidden' do
|
it 'is forbidden' do
|
||||||
subject
|
subject
|
||||||
expect(response).to have_http_status(:forbidden)
|
expect(response).to have_http_status(:forbidden)
|
||||||
|
|
|
@ -21,17 +21,6 @@ describe Administrateur, type: :model do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#feature_enabled?' do
|
|
||||||
let(:administrateur) { create(:administrateur) }
|
|
||||||
|
|
||||||
before do
|
|
||||||
administrateur.enable_feature(:test_a)
|
|
||||||
end
|
|
||||||
|
|
||||||
it { expect(administrateur.feature_enabled?(:test_b)).to be_falsey }
|
|
||||||
it { expect(administrateur.feature_enabled?(:test_a)).to be_truthy }
|
|
||||||
end
|
|
||||||
|
|
||||||
# describe '#password_complexity' do
|
# describe '#password_complexity' do
|
||||||
# let(:email) { 'mail@beta.gouv.fr' }
|
# let(:email) { 'mail@beta.gouv.fr' }
|
||||||
# let(:passwords) { ['pass', '12pass23', 'démarches ', 'démarches-simple', 'démarches-simplifiées-pwd'] }
|
# let(:passwords) { ['pass', '12pass23', 'démarches ', 'démarches-simple', 'démarches-simplifiées-pwd'] }
|
||||||
|
|
|
@ -139,7 +139,7 @@ RSpec.configure do |config|
|
||||||
config.include FactoryBot::Syntax::Methods
|
config.include FactoryBot::Syntax::Methods
|
||||||
|
|
||||||
config.before(:each) do
|
config.before(:each) do
|
||||||
Flipflop::FeatureSet.current.test!.reset!
|
Flipper.enable(:instructeur_bypass_email_login_token)
|
||||||
end
|
end
|
||||||
|
|
||||||
config.before(:all) {
|
config.before(:all) {
|
||||||
|
|
|
@ -22,7 +22,7 @@ module FeatureHelpers
|
||||||
fill_in :user_password, with: password
|
fill_in :user_password, with: password
|
||||||
|
|
||||||
if sign_in_by_link
|
if sign_in_by_link
|
||||||
Flipflop::FeatureSet.current.test!.switch!(:bypass_email_login_token, false)
|
Flipper.disable(:instructeur_bypass_email_login_token)
|
||||||
end
|
end
|
||||||
|
|
||||||
perform_enqueued_jobs do
|
perform_enqueued_jobs do
|
||||||
|
|
Loading…
Reference in a new issue