Skip to content

Commit

Permalink
Merge pull request #267 from pulibrary/i265_banner_flipper
Browse files Browse the repository at this point in the history
I265 banner flipper
  • Loading branch information
sandbergja authored Jul 22, 2024
2 parents 201f255 + b181045 commit a772ac8
Show file tree
Hide file tree
Showing 17 changed files with 467 additions and 102 deletions.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ gem 'activesupport'
gem 'bootsnap', require: false
gem 'ddtrace', require: 'ddtrace/auto_instrument'
gem 'dogstatsd-ruby'
gem 'flipper-active_record'
gem 'honeybadger'
gem 'lograge'
gem 'logstash-event'
Expand Down
6 changes: 6 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@ GEM
ffi (1.17.0-arm64-darwin)
ffi (1.17.0-x86_64-darwin)
ffi (1.17.0-x86_64-linux-gnu)
flipper (1.3.0)
concurrent-ruby (< 2)
flipper-active_record (1.3.0)
activerecord (>= 4.2, < 8)
flipper (~> 1.3.0)
hashdiff (1.1.0)
honeybadger (5.13.3)
i18n (1.14.5)
Expand Down Expand Up @@ -323,6 +328,7 @@ DEPENDENCIES
ddtrace
dogstatsd-ruby
ed25519
flipper-active_record
honeybadger
lograge
logstash-event
Expand Down
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,42 @@ the swagger.yaml file meets the OpenAPI standard.
brew install daveshanley/vacuum/vacuum
vacuum lint -d swagger/**/*.yaml
```
## Update the banner
In order to update the banner at `/banner`, you can either update it on the rails console, or use a rake task.
Valid values for 'alert_status' are `info|success|warning|error`
### Run the rake task
There is a rake task that can accept multiple arguments. The arguments are `[text, alert_status, dismissible, autoclear]`. The arguments are comma delimited, with no spaces. If there is an argument you want to skip, just leave it blank, but leave any commas that might surround it (similar to a csv file). Depending on your shell, you may need to escape the brackets surrounding the arguments.
If there are any commas in your text, you will need to escape them using `\`
#### Setting all four values:
```zsh
bundle exec rake banner:update\['new banner',info,true,true\]
```
#### Setting only text and autoclear
```zsh
bundle exec rake banner:update\['newer banner',,,false\]
```
#### Setting long text in multiple steps
```zsh
LONG_HTML="<h2>All-Search Updated</h2><p> Introducing our new and improved All-Search\, upgraded with advanced technology and designed based on your feedback to enhance your research experience. Share your experience and help us improve it further by completing this <a href='https://example.com'>brief survey</a></p>"
bundle exec rake banner:update\[$LONG_HTML,'info',false,true\]
```

## Set the banner to visible or not visible
### Via Capistrano
Can be run locally against a remote environment. Must be on VPN.
```zsh
bundle exec cap staging banner:enable
bundle exec cap staging banner:disable
```

### Via the Flipper CLI
Must be done on the environment where you want to change it
```bash
bundle exec flipper enable banner
bundle exec flipper disable banner
```
9 changes: 9 additions & 0 deletions app/controllers/banner_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

class BannerController < ApplicationController
def show
banner_json = Banner.first.as_json(except: [:id, :created_at, :updated_at])

render json: banner_json
end
end
21 changes: 21 additions & 0 deletions app/models/banner.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# frozen_string_literal: true

# This class is responsible for coordinating displaying an informational banner
class Banner < ApplicationRecord
enum alert_status: {
info: 1,
success: 2,
warning: 3,
error: 4
}

def display_banner
@display_banner = Flipper.enabled?(:banner)
end

# args is an instance of Rake::TaskArguments
def rake_update(args)
update(args.to_h)
save!
end
end
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

# Defines the root path route ("/")
root 'main#index', defaults: { format: 'json' }
get '/banner', to: 'banner#show', defaults: { format: 'json' }
get '/search/article', to: 'article#show', defaults: { format: 'json' }
get '/search/artmuseum/', to: 'art_museum#show', defaults: { format: 'json' }
get '/search/best-bet/', to: 'best_bet#show', defaults: { format: 'json' }
Expand Down
22 changes: 22 additions & 0 deletions db/migrate/20240717164314_create_flipper_tables.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
class CreateFlipperTables < ActiveRecord::Migration[7.1]
def 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.text :value
t.timestamps null: false
end
add_index :flipper_gates, [:feature_key, :key, :value], unique: true, length: { value: 255 }
end

def down
drop_table :flipper_gates
drop_table :flipper_features
end
end
21 changes: 21 additions & 0 deletions db/migrate/20240717173433_create_banners.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
class CreateBanners < ActiveRecord::Migration[7.1]
def change
create_table :banners do |t|
t.text :text, default: ''
t.boolean :display_banner, default: false
t.integer :alert_status, default: 1
t.boolean :dismissible, default: true
t.boolean :autoclear, default: false

t.timestamps
end

def create_banner_if_none_exists
return Rails.logger.info('Already have a banner object, update that one') if Banner.count >= 1

Banner.create!
end

create_banner_if_none_exists
end
end
28 changes: 27 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,20 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema[7.1].define(version: 2024_07_16_214838) do
ActiveRecord::Schema[7.1].define(version: 2024_07_17_173433) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"

create_table "banners", force: :cascade do |t|
t.text "text", default: ""
t.boolean "display_banner", default: false
t.integer "alert_status", default: 1
t.boolean "dismissible", default: true
t.boolean "autoclear", default: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end

create_table "best_bet_records", force: :cascade do |t|
t.string "title"
t.string "description"
Expand All @@ -24,6 +34,22 @@
t.datetime "updated_at", null: false
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.text "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 "library_database_records", force: :cascade do |t|
t.bigint "libguides_id", null: false
t.string "name", null: false
Expand Down
7 changes: 7 additions & 0 deletions db/seeds.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
def create_banner_if_none_exists
return Rails.logger.info('Already have a banner object, update that one') if Banner.count >= 1

Banner.create!
end

create_banner_if_none_exists
25 changes: 25 additions & 0 deletions lib/capistrano/tasks/banner.rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# frozen_string_literal: true

require 'flipper'

namespace :banner do
desc 'Enable banner'
task :enable do
on roles(:db) do
within '/opt/allsearch_api/current' do
execute :bundle, :exec, :flipper, :enable, :banner
end
end
run_locally { puts('The banner is now enabled and should display.') }
end

desc 'Disable banner'
task :disable do
on roles(:db) do
within '/opt/allsearch_api/current' do
execute :bundle, :exec, :flipper, :disable, :banner
end
end
run_locally { puts('The banner is now disabled and should not display.') }
end
end
23 changes: 23 additions & 0 deletions lib/tasks/banner.rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# frozen_string_literal: true

namespace :banner do
desc 'Update banner [text,alert_status[info|success|warning|error],dismissible,autoclear]'
task :update, [:text, :alert_status, :dismissible, :autoclear] => :environment do |_task, args|
banner = if Banner.count.zero?
Banner.new
else
Banner.first
end
banner.rake_update(args)
Rake::Task['banner:show'].invoke
end

desc 'Show current banner configuration'
task show: :environment do
banner = Banner.first
puts "The currently set banner text is: #{banner.text}\n"
puts "The currently set banner alert_status is: #{banner.alert_status}\n"
puts "The currently set banner is dismissible: #{banner.dismissible}\n"
puts "The currently set banner is autoclear: #{banner.autoclear}"
end
end
85 changes: 85 additions & 0 deletions spec/models/banner_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# frozen_string_literal: true

require 'rails_helper'
require 'rake'

RSpec.describe Banner do
let(:banner) { described_class.first }

it 'can be instantiated' do
expect(banner).to be_an_instance_of(described_class)
end

it 'has the expected defaults' do
expect(banner.text).to eq('')
expect(banner.display_banner).to be(false)
expect(banner.alert_status).to eq('info')
expect(banner.dismissible).to be(true)
expect(banner.autoclear).to be(false)
end

it 'has an as_json method' do
expect(banner.as_json).to be_an_instance_of(Hash)
expect(banner.as_json(except: [:id, :created_at, :updated_at]).keys)
.to contain_exactly('text', 'display_banner', 'alert_status',
'dismissible', 'autoclear')
end

it 'can be updated' do
banner.text = 'some other text'
banner.save!
expect(banner.text).to eq('some other text')
end

it 'only allows valid alert statuses' do
expect do
banner.alert_status = 'warning'
banner.save!
end.to change(banner, :alert_status)

expect do
banner.alert_status = 'potato'
banner.save!
end.to raise_error(ArgumentError, /not a valid alert_status/)
end

it 'can be updated to include html' do
banner.text = '<h2>This is a big heading about an important thing</h2><p>It includes a <a href="https://www.example.com">link</a></p>'
banner.save!
expect(banner.text).to eq('<h2>This is a big heading about an important thing</h2><p>It includes a <a href="https://www.example.com">link</a></p>')
end

context 'when updated from the rake task' do
context 'with four arguments' do
let(:args) { Rake::TaskArguments.new(%w[text alert_status dismissible autoclear], ['<a href="https://www.example.com">a is a sentence</a>', 'warning', 'false', 'true']) }

it 'can be updated using a rake task' do
banner.rake_update(args)
expect(banner.reload.text).to eq('<a href="https://www.example.com">a is a sentence</a>')
expect(banner.alert_status).to eq('warning')
expect(banner.dismissible).to be false
expect(banner.autoclear).to be true
end
end

context 'with two arguments' do
let(:args) { Rake::TaskArguments.new(%w[text alert_status], ['<a href="https://www.example.com">a is a sentence</a>', 'warning']) }

it 'can be updated using a rake task' do
banner.rake_update(args)
expect(banner.reload.text).to eq('<a href="https://www.example.com">a is a sentence</a>')
expect(banner.alert_status).to eq('warning')
end
end

context 'with one argument' do
let(:args) { Rake::TaskArguments.new(%w[text], ['different text argument']) }

it 'can be updated using a rake task' do
banner.rake_update(args)
expect(banner.reload.text).to eq('different text argument')
expect(banner.alert_status).to eq('info')
end
end
end
end
3 changes: 3 additions & 0 deletions spec/rails_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
RSpec.configure do |config|
# Remove this line to enable support for ActiveRecord
config.use_active_record = true
config.before(:suite) do
Rails.application.load_seed
end

# If you enable ActiveRecord support you should uncomment these lines,
# note if you'd prefer not to run each example within a transaction, you
Expand Down
25 changes: 25 additions & 0 deletions spec/requests/api/banner_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# frozen_string_literal: true

require 'swagger_helper'

RSpec.describe 'banner' do
path '/banner' do
get('show banner') do
tags 'Banner'
operationId 'displayBanner'
produces 'application/json'
description 'Displays the current settings for the banner'
response(200, 'successful') do
after do |example|
example.metadata[:response][:content] = {
'application/json' => {
example: JSON.parse(response.body, symbolize_names: true)
}
}
end

run_test!
end
end
end
end
Loading

0 comments on commit a772ac8

Please sign in to comment.