Skip to content

Commit

Permalink
VACMS-19453: Banner endpoint (#19342)
Browse files Browse the repository at this point in the history
* VACMS-19453: Adds initial route for banners.

* VACMS-19453: Updates banner endpoint to respond with banners for a given path.

* VACMS-19453: Adds db seed script for banners. It does not automatically seed with db:seed.

* VACMS-19453: Adds test for .by_path_and_type scope.

* VACMS-19453: Adds test for controller.

* VACMS-19453: Updates CODEOWNERS.

* VACMS-19453: Move CODEOWNERS change to alphabetical.

* VACMS-19453: Adds missing frozen string literal comment.

* VACMS-19453: Adds support for subpage matching.
  • Loading branch information
dsasser authored Nov 18, 2024
1 parent 936415e commit 5358815
Show file tree
Hide file tree
Showing 9 changed files with 218 additions and 7 deletions.
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ app/controllers/concerns/traceable.rb @department-of-veterans-affairs/va-api-eng
app/controllers/concerns/vet360 @department-of-veterans-affairs/vfs-authenticated-experience-backend @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group
app/controllers/flipper_controller.rb @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group
app/controllers/gids_controller.rb @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group
app/controllers/v0/banners_controller.rb @department-of-veterans-affairs/vfs-facilities-frontend @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group
app/controllers/v0/income_and_assets_claims_controller.rb @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/backend-review-group
app/controllers/preneeds_controller.rb @department-of-veterans-affairs/mbs-core-team @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group
app/controllers/rx_controller.rb @department-of-veterans-affairs/vfs-mhv-medications @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group
Expand Down
18 changes: 18 additions & 0 deletions app/controllers/v0/banners_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# frozen_string_literal: true

module V0
class BannersController < ApplicationController
service_tag 'banners'
skip_before_action :authenticate

def by_path
path = params[:path]
# Default to 'full_width_banner_alert' banner (bundle) type.
banner_type = params.fetch(:type, 'full_width_banner_alert')
banners = []
banners = Banner.by_path_and_type(path, banner_type) if path && banner_type
response = { banners: banners, path: path, banner_type: banner_type }
render json: response
end
end
end
3 changes: 2 additions & 1 deletion config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,8 @@
resources :form1010_ezrs, only: %i[create]

post 'map_services/:application/token', to: 'map_services#token', as: :map_services_token

get 'banners', to: 'banners#by_path'
end
# end /v0

Expand Down Expand Up @@ -460,7 +462,6 @@
mount AccreditedRepresentativePortal::Engine, at: '/accredited_representative_portal'
mount AskVAApi::Engine, at: '/ask_va_api'
mount Avs::Engine, at: '/avs'
mount Banners::Engine, at: '/banners'
mount CheckIn::Engine, at: '/check_in'
mount CovidResearch::Engine, at: '/covid-research'
mount CovidVaccine::Engine, at: '/covid_vaccine'
Expand Down
39 changes: 39 additions & 0 deletions modules/banners/app/models/banner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,43 @@ class Banner < ApplicationRecord
validates :email_updates_button, inclusion: { in: [true, false] }
validates :find_facilities_cta, inclusion: { in: [true, false] }
validates :limit_subpage_inheritance, inclusion: { in: [true, false] }

# Returns banners for a given path and banner bundle type.
scope :by_path_and_type, lambda { |path, type|
normalized_path = path.sub(%r{^/?}, '')

# Direct path matches.
exact_path_conditions = where('banners.context @> ?',
[
{ entity:
{ entityUrl:
{ path: path } } }
].to_json)
.or(where('banners.context @> ?',
[
{ entity:
{ fieldOffice:
{ entity:
{ entityUrl:
{ path: path } } } } }
].to_json))

# Subpage inheritance check: Matches on any `fieldOffice` entity path where `limit_subpage_inheritance` is false.
subpage_pattern = "#{normalized_path.split('/').first}/%"
subpage_condition = where('banners.context @> ?',
[
{ entity:
{ fieldOffice:
{ entity:
{ entityUrl:
{ path: subpage_pattern } } } } }
].to_json)
.where(limit_subpage_inheritance: false)

# Bundle type match
type_condition = where(entity_bundle: type)

# Combine conditions with the "AND" for type, and "OR" between exact paths and subpage matches
type_condition.and(exact_path_conditions.or(subpage_condition))
}
end
4 changes: 0 additions & 4 deletions modules/banners/config/routes.rb

This file was deleted.

56 changes: 56 additions & 0 deletions modules/banners/db/seeds/banner_seeds.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# frozen_string_literal: true

# Create sample Banner records
puts 'Creating sample banners...'

Banner.create!(
entity_id: 1,
entity_bundle: 'full_width_banner_alert',
headline: 'Important Update',
alert_type: 'warning',
show_close: true,
content: 'Please be aware of system maintenance scheduled for tomorrow.',
context:
[
{
entity: {
title: 'Operating status | VA Facility health care',
entityUrl: {
path: '/va-facility-health-care/operating-status'
},
fieldOffice: {
entity: {
fieldVamcEhrSystem: 'vista',
title: 'VA Facility health care',
entityUrl: {
path: '/va-facility-health-care'
}
}
}
}
},
{
entity: {
title: 'Operating status | VAMC health care',
entityUrl: {
path: '/vamc-health-care/operating-status'
},
fieldOffice: {
entity: {
fieldVamcEhrSystem: 'vista',
title: 'VAMC health care',
entityUrl: {
path: '/vamc-health-care'
}
}
}
}
}
],
operating_status_cta: true,
email_updates_button: true,
find_facilities_cta: false,
limit_subpage_inheritance: false
)

puts 'Sample banners created!'
38 changes: 38 additions & 0 deletions modules/banners/spec/controllers/v0/banners_controller_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# frozen_string_literal: true

require 'rails_helper'

RSpec.describe V0::BannersController, type: :controller do
describe 'GET #by_path' do
let(:path) { '/sample/path' }
let(:banner_type) { 'full_width_banner_alert' }

# Create banners that should match the query
let!(:matching_banner) do
create(:banner, entity_bundle: banner_type, context: [{ entity: { entityUrl: { path: path } } }])
end
let!(:non_matching_banner) do
create(:banner, entity_bundle: 'different_type', context: [{ entity: { entityUrl: { path: '/other/path' } } }])
end

it 'returns banners matching the specified path and banner type' do
get :by_path, params: { path: path, type: banner_type }

expect(response).to have_http_status(:ok)
json_response = JSON.parse(response.body)

# Ensure only the matching banner is returned
expect(json_response['banners'].length).to eq(1)
expect(json_response['banners'][0]['id']).to eq(matching_banner.id)
end

it 'returns an empty array if no banners match the criteria' do
get :by_path, params: { path: '/nonexistent/path', type: 'nonexistent_type' }

expect(response).to have_http_status(:ok)
json_response = JSON.parse(response.body)

expect(json_response['banners']).to eq([])
end
end
end
2 changes: 1 addition & 1 deletion modules/banners/spec/factories/banners.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

FactoryBot.define do
factory :banner do
entity_id { 1 }
sequence(:entity_id) { |n| n }
entity_bundle { 'full_width_banner_alert' }
headline { 'Important Alert!' }
alert_type { 'warning' }
Expand Down
64 changes: 63 additions & 1 deletion modules/banners/spec/models/banner_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
require 'rails_helper'

Rspec.describe Banner, type: :model do
# Use FactoryBot to create banner which can be used in all test.
# Use FactoryBot to create banners which can be used in all tests.
let(:banner) { create(:banner) }

# Test that the model is valid with all required attributes.
Expand All @@ -24,4 +24,66 @@
expect(new_banner).not_to be_valid
expect(new_banner.errors[:headline]).to include("can't be blank")
end

describe '.by_path_and_type' do
let(:path) { '/va-facility-health-care' }
let(:banner_type) { 'full_width_banner_alert' }

let!(:matching_banner1) do
create(:banner, entity_bundle: banner_type, context: [
{
entity: {
entityUrl: { path: path },
fieldOffice: {
entity: {
entityUrl: { path: '/some-other-path' }
}
}
}
}
])
end

let!(:matching_banner2) do
create(:banner, entity_bundle: banner_type, context: [
{
entity: {
entityUrl: { path: '/some-other-path' },
fieldOffice: {
entity: {
entityUrl: { path: path }
}
}
}
}
])
end

let!(:non_matching_banner) do
create(:banner, entity_bundle: 'different_type', context: [
{
entity: {
entityUrl: { path: '/some-other-path' },
fieldOffice: {
entity: {
entityUrl: { path: '/another-path' }
}
}
}
}
])
end

it 'returns banners that match the path and banner type' do
result = Banner.by_path_and_type(path, banner_type)

expect(result).to contain_exactly(matching_banner1, matching_banner2)
end

it 'does not return banners that do not match the path or banner type' do
result = Banner.by_path_and_type(path, banner_type)

expect(result).not_to include(non_matching_banner)
end
end
end

0 comments on commit 5358815

Please sign in to comment.