diff --git a/Gemfile b/Gemfile index 1b6704e..3445c32 100644 --- a/Gemfile +++ b/Gemfile @@ -40,6 +40,9 @@ gem 'net-ldap' gem "rqrcode", "~> 2.0" gem 'rails-settings-cached', '~> 2.8.3' gem 'pagy', '~> 6.0', '>= 6.0.2' +gem 'flipper' +gem 'flipper-active_record' +gem 'flipper-ui' # HTTP requests gem 'faraday' diff --git a/Gemfile.lock b/Gemfile.lock index 2d92414..9a37e04 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -128,6 +128,17 @@ GEM ruby2_keywords (>= 0.0.4) faraday-net_http (3.0.2) ffi (1.15.5) + flipper (0.28.0) + concurrent-ruby (< 2) + flipper-active_record (0.28.0) + activerecord (>= 4.2, < 8) + flipper (~> 0.28.0) + flipper-ui (0.28.0) + erubi (>= 1.0.0, < 2.0.0) + flipper (~> 0.28.0) + rack (>= 1.4, < 3) + rack-protection (>= 1.5.3, <= 4.0.0) + sanitize (< 7) fugit (1.7.2) et-orbi (~> 1, >= 1.2.7) raabro (~> 1.4) @@ -199,6 +210,8 @@ GEM raabro (1.4.0) racc (1.6.0) rack (2.2.4) + rack-protection (3.0.6) + rack rack-test (2.0.2) rack (>= 1.3) rails (7.0.4) @@ -283,6 +296,9 @@ GEM ruby2_keywords (0.0.5) rufus-scheduler (3.8.2) fugit (~> 1.1, >= 1.1.6) + sanitize (6.0.1) + crass (~> 1.0.2) + nokogiri (>= 1.12.0) sentry-rails (5.8.0) railties (>= 5.0) sentry-ruby (~> 5.8.0) @@ -374,6 +390,9 @@ DEPENDENCIES factory_bot_rails faker faraday + flipper + flipper-active_record + flipper-ui importmap-rails jbuilder (~> 2.7) letter_opener diff --git a/README.md b/README.md index 90fec7f..df1a1e9 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,10 @@ command: * [Sidekiq](https://github.com/mperham/sidekiq/wiki/) * [ActiveJob](https://github.com/mperham/sidekiq/wiki/Active-Job) +### Feature Flags + +* [Flipper](https://www.flippercloud.io/docs/get-started/self-hosted) + ## License [GNU Affero General Public License v3.0](https://choosealicense.com/licenses/agpl-3.0/) diff --git a/app/controllers/services/remotestorage_controller.rb b/app/controllers/services/remotestorage_controller.rb new file mode 100644 index 0000000..231e359 --- /dev/null +++ b/app/controllers/services/remotestorage_controller.rb @@ -0,0 +1,30 @@ +class Services::RemotestorageController < ApplicationController + before_action :require_user_signed_in + before_action :require_service_enabled + before_action :require_feature_enabled + before_action :set_current_section + + def dashboard + # unless current_user.services_enabled.include?(:remotestorage) + # redirect_to service_remotestorage_info_path + # end + end + + private + + def require_feature_enabled + unless Flipper.enabled?(:remotestorage, current_user) + http_status :forbidden + end + end + + def require_service_enabled + unless Setting.remotestorage_enabled? + http_status :not_found + end + end + + def set_current_section + @current_section = :services + end +end diff --git a/app/views/admin/users/show.html.erb b/app/views/admin/users/show.html.erb index 42c7963..9a95e23 100644 --- a/app/views/admin/users/show.html.erb +++ b/app/views/admin/users/show.html.erb @@ -6,6 +6,10 @@

Account

+ + + + diff --git a/app/views/dashboard/index.html.erb b/app/views/dashboard/index.html.erb index 8b90fc0..8ebbec3 100644 --- a/app/views/dashboard/index.html.erb +++ b/app/views/dashboard/index.html.erb @@ -73,6 +73,17 @@

<% end %> + <% if Setting.remotestorage_enabled? && Flipper.enabled?(:remotestorage, current_user) %> +
+ <%= link_to services_storage_path, + class: "block h-full px-6 py-6 rounded-md" do %> +

Storage

+

+ Sync your data between apps and devices +

+ <% end %> +
+ <% end %> diff --git a/app/views/services/remotestorage/dashboard.html.erb b/app/views/services/remotestorage/dashboard.html.erb new file mode 100644 index 0000000..f6b0932 --- /dev/null +++ b/app/views/services/remotestorage/dashboard.html.erb @@ -0,0 +1,7 @@ +<%= render HeaderComponent.new(title: "Storage") %> + +<%= render MainSimpleComponent.new do %> +
+

Feature enabled

+
+<% end %> diff --git a/config/routes.rb b/config/routes.rb index c8dd8a4..e08f097 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -19,6 +19,8 @@ Rails.application.routes.draw do resources :invitations, only: ['index', 'show', 'create', 'destroy'] namespace :services do + get 'storage', to: 'remotestorage#dashboard' + resources :lightning, only: [:index] do collection do get 'transactions' @@ -62,6 +64,7 @@ Rails.application.routes.draw do authenticate :user, ->(user) { user.is_admin? } do mount Sidekiq::Web => '/sidekiq' + mount Flipper::UI.app(Flipper) => '/flipper' end # Letter Opener (open "sent" emails in dev and staging) diff --git a/db/migrate/20230523120753_create_flipper_tables.rb b/db/migrate/20230523120753_create_flipper_tables.rb new file mode 100644 index 0000000..b07fd68 --- /dev/null +++ b/db/migrate/20230523120753_create_flipper_tables.rb @@ -0,0 +1,22 @@ +class CreateFlipperTables < ActiveRecord::Migration[7.0] + 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 diff --git a/db/schema.rb b/db/schema.rb index 1a85f04..7f06b96 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2023_04_03_135149) do +ActiveRecord::Schema[7.0].define(version: 2023_05_23_120753) do create_table "donations", force: :cascade do |t| t.integer "user_id" t.integer "amount_sats" @@ -23,6 +23,22 @@ ActiveRecord::Schema[7.0].define(version: 2023_04_03_135149) do t.index ["user_id"], name: "index_donations_on_user_id" 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 "invitations", force: :cascade do |t| t.string "token" t.integer "user_id"
ID<%= @user.id %>
Created at <%= @user.created_at.strftime("%Y-%m-%d (%H:%M UTC)") %>