- <% @announcements.select(&:valid?).each do |announcement| %> - - <% end %> + <%= render "layouts/announcements" %> <%= render "layouts/browser_warning" %> diff --git a/apps/dashboard/config/locales/en.yml b/apps/dashboard/config/locales/en.yml index c7c7bc95ef..4f2a1eb0a8 100644 --- a/apps/dashboard/config/locales/en.yml +++ b/apps/dashboard/config/locales/en.yml @@ -260,6 +260,10 @@ en: jobs_scripts_fixed_field: "Fixed Value" settings_updated: "Settings updated" + settings_invalid_request: "Invalid settings submitted" + + announcements_required_button: "Accept" + announcements_dismissible_button: "OK" bc_saved_settings: title: "Saved Settings" diff --git a/apps/dashboard/test/fixtures/config/announcements/announcement_id.yml b/apps/dashboard/test/fixtures/config/announcements/announcement_id.yml new file mode 100644 index 0000000000..232c9b0b88 --- /dev/null +++ b/apps/dashboard/test/fixtures/config/announcements/announcement_id.yml @@ -0,0 +1,2 @@ +type: info +msg: This is yaml \ No newline at end of file diff --git a/apps/dashboard/test/fixtures/config/announcements/announcement_md.md b/apps/dashboard/test/fixtures/config/announcements/announcement_md.md new file mode 100644 index 0000000000..92187e1922 --- /dev/null +++ b/apps/dashboard/test/fixtures/config/announcements/announcement_md.md @@ -0,0 +1 @@ +This is md \ No newline at end of file diff --git a/apps/dashboard/test/fixtures/config/announcements/announcement_view.yml b/apps/dashboard/test/fixtures/config/announcements/announcement_view.yml new file mode 100644 index 0000000000..fe1cbc989e --- /dev/null +++ b/apps/dashboard/test/fixtures/config/announcements/announcement_view.yml @@ -0,0 +1,4 @@ +type: danger +msg: This is the announcement. +id: view_id +dismissible: true \ No newline at end of file diff --git a/apps/dashboard/test/fixtures/config/announcements/announcement_yml.yml b/apps/dashboard/test/fixtures/config/announcements/announcement_yml.yml new file mode 100644 index 0000000000..ad5cbf103d --- /dev/null +++ b/apps/dashboard/test/fixtures/config/announcements/announcement_yml.yml @@ -0,0 +1,5 @@ +type: danger +msg: This is yaml +id: yml_id +dismissible: true +required: true \ No newline at end of file diff --git a/apps/dashboard/test/fixtures/file_output/user_settings/announcements.yml b/apps/dashboard/test/fixtures/file_output/user_settings/announcements.yml new file mode 100644 index 0000000000..b0f92bf406 --- /dev/null +++ b/apps/dashboard/test/fixtures/file_output/user_settings/announcements.yml @@ -0,0 +1,3 @@ +--- +announcements: + completed_id: '2024-07-11 13:37:03' diff --git a/apps/dashboard/test/integration/announcement_views_test.rb b/apps/dashboard/test/integration/announcement_views_test.rb index a2ccee687d..9b15810293 100644 --- a/apps/dashboard/test/integration/announcement_views_test.rb +++ b/apps/dashboard/test/integration/announcement_views_test.rb @@ -1,17 +1,34 @@ require 'test_helper' class AnnouncementViewsTest < ActionDispatch::IntegrationTest - test "announcement is displayed if exists" do - f = Tempfile.open(["announcement", ".md"]) - f.write %{Test announcement.} + test 'announcement is displayed if exists' do + f = Tempfile.open(%w[announcement .md]) + f.write %(Test announcement.) f.close - stub_user_configuration({announcement_path: [f.path]}) + stub_user_configuration({ announcement_path: [f.path] }) begin - get "/" + get '/' assert_response :success - assert_select "div.announcement", "Test announcement." + assert_select 'div.announcement div.announcement-body', 'Test announcement.' + ensure + stub_user_configuration({}) + end + end + + test 'dismissible announcement have a button to close the announcement' do + file = "#{Rails.root}/test/fixtures/config/announcements/announcement_view.yml" + stub_user_configuration({ announcement_path: [file] }) + + begin + get '/' + assert_response :success + assert_select 'div.announcement div.announcement-body', 'This is the announcement.' + assert_select 'div.announcement .announcement-button', I18n.t('dashboard.announcements_dismissible_button') + form = css_select('div.announcement .announcement-form') + assert_equal 1, form.size + assert_equal settings_path(action: 'announcement'), form[0]['action'] ensure stub_user_configuration({}) end diff --git a/apps/dashboard/test/integration/settings_controller_test.rb b/apps/dashboard/test/integration/settings_controller_test.rb index 7c2d9a9cfe..64e7479de8 100644 --- a/apps/dashboard/test/integration/settings_controller_test.rb +++ b/apps/dashboard/test/integration/settings_controller_test.rb @@ -12,45 +12,102 @@ def setup @headers = { 'X-CSRF-Token' => @token } end - test "should save user_settings when posting settings data" do - data = { - settings: { - profile: "test_profile" - } - } - Dir.mktmpdir {|temp_data_dir| + test 'should save and override profile settings when posting profile' do + Dir.mktmpdir do |temp_data_dir| Configuration.stubs(:user_settings_file).returns("#{temp_data_dir}/settings.yml") + data = { settings: {} } + data[:settings][:profile] = 'first_profile' post settings_path, params: data, headers: @headers assert_response :redirect - assert_equal "test_profile", TestUserSettings.new.user_settings[:profile] - } - end + assert_equal I18n.t('dashboard.settings_updated'), flash[:notice] + assert_equal 'first_profile', TestUserSettings.new.user_settings[:profile] - test "should not save user settings when no data" do - data = { settings: {} } + data[:settings][:profile] = 'override_profile' + post settings_path, params: data, headers: @headers + assert_response :redirect + assert_equal I18n.t('dashboard.settings_updated'), flash[:notice] + assert_equal 'override_profile', TestUserSettings.new.user_settings[:profile] + end + end - Dir.mktmpdir {|temp_data_dir| + test 'should allow empty or nil profile settings when posting profile' do + Dir.mktmpdir do |temp_data_dir| Configuration.stubs(:user_settings_file).returns("#{temp_data_dir}/settings.yml") + data = { settings: {} } + + data[:settings][:profile] = '' + post settings_path, params: data, headers: @headers + assert_response :redirect + assert_equal I18n.t('dashboard.settings_updated'), flash[:notice] + assert_equal '', TestUserSettings.new.user_settings[:profile] + + data[:settings][:profile] = nil post settings_path, params: data, headers: @headers assert_response :redirect + assert_equal I18n.t('dashboard.settings_updated'), flash[:notice] assert_nil TestUserSettings.new.user_settings[:profile] - } + end + end + + test 'should save announcement settings and allow multiple announcements when posting announcement' do + Dir.mktmpdir do |temp_data_dir| + Configuration.stubs(:user_settings_file).returns("#{temp_data_dir}/settings.yml") + data = { settings: {} } + + value = Time.now.localtime.strftime('%Y-%m-%d %H:%M:%S') + data[:settings] = { announcements: { 'announcement_id' => value } } + post settings_path, params: data, headers: @headers + assert_response :redirect + assert_equal I18n.t('dashboard.settings_updated'), flash[:notice] + assert_equal value, TestUserSettings.new.user_settings[:announcements][:announcement_id] + + data[:settings] = { announcements: { 'other_announcement_id' => value } } + post settings_path, params: data, headers: @headers + assert_response :redirect + assert_equal I18n.t('dashboard.settings_updated'), flash[:notice] + assert_equal value, TestUserSettings.new.user_settings[:announcements][:announcement_id] + assert_equal value, TestUserSettings.new.user_settings[:announcements][:other_announcement_id] + end + end + + test 'should not save user_settings when no data' do + Dir.mktmpdir do |temp_data_dir| + Configuration.stubs(:user_settings_file).returns("#{temp_data_dir}/settings.yml") + data = { settings: {} } + + post settings_path, params: data, headers: @headers + assert_response :redirect + assert_equal I18n.t('dashboard.settings_updated'), flash[:notice] + assert_empty TestUserSettings.new.user_settings + end end test "should not save user_settings when parameters are outside the settings namespace" do - data = { profile: "root_value" } + Dir.mktmpdir do |temp_data_dir| + Configuration.stubs(:user_settings_file).returns("#{temp_data_dir}/settings.yml") + data = { profile: "root_value" } - Dir.mktmpdir {|temp_data_dir| + post settings_path, params: data, headers: @headers + assert_response :redirect + assert_equal I18n.t('dashboard.settings_updated'), flash[:notice] + assert_empty TestUserSettings.new.user_settings + end + end + + test 'should not save user_settings when parameters are not in the allowed list' do + Dir.mktmpdir do |temp_data_dir| Configuration.stubs(:user_settings_file).returns("#{temp_data_dir}/settings.yml") + data = { settings: { not_allowed: 'root_value' } } + post settings_path, params: data, headers: @headers assert_response :redirect - assert_nil TestUserSettings.new.user_settings[:profile] - } + assert_equal I18n.t('dashboard.settings_updated'), flash[:notice] + assert_empty TestUserSettings.new.user_settings + end end class TestUserSettings include UserSettingStore end - -end \ No newline at end of file +end diff --git a/apps/dashboard/test/models/announcement_test.rb b/apps/dashboard/test/models/announcement_test.rb new file mode 100644 index 0000000000..9f8b17a501 --- /dev/null +++ b/apps/dashboard/test/models/announcement_test.rb @@ -0,0 +1,106 @@ +# frozen_string_literal: true + +require 'test_helper' + +# Announcement model basic tests +class AnnouncementTest < ActiveSupport::TestCase + + test 'default values' do + target = Announcement.new({}) + + assert_equal(:warning, target.type) + assert_nil(target.msg) + assert_nil(target.id) + assert_equal(false, target.completed?) + assert_equal(true, target.dismissible?) + assert_equal(false, target.required?) + end + + test 'default id for announcement file is msg sha1' do + path = Rails.root.join('test/fixtures/config/announcements/announcement_id.yml').to_s + target = Announcement.new(path) + + assert_equal('9b4ad10e7b43c149e08c1530db6810c7a6bbea13', target.id) + end + + test 'can set values with hash' do + target = Announcement.new( + { type: 'info', + msg: 'This is the message', + id: '12345', + dismissible: true, + required: true } + ) + + assert_equal(:info, target.type) + assert_equal('This is the message', target.msg) + assert_equal('12345', target.id) + assert_equal(false, target.completed?) + assert_equal(true, target.dismissible?) + assert_equal(true, target.required?) + end + + test 'can set values with YAML file' do + path = Rails.root.join('test/fixtures/config/announcements/announcement_yml.yml').to_s + target = Announcement.new(path) + + assert_equal(:danger, target.type) + assert_equal('This is yaml', target.msg) + assert_equal('yml_id', target.id) + assert_equal(false, target.completed?) + assert_equal(true, target.dismissible?) + assert_equal(true, target.required?) + end + + test 'can set message with MD file' do + path = Rails.root.join('test/fixtures/config/announcements/announcement_md.md').to_s + target = Announcement.new(path) + + assert_equal(:warning, target.type) + assert_equal('This is md', target.msg) + assert_equal('77b8dd73d876bb58be9eae133fb8f5c614b95171', target.id) + assert_equal(false, target.completed?) + assert_equal(true, target.dismissible?) + assert_equal(false, target.required?) + end + + test 'required announcements are dismissible' do + target = Announcement.new({ required: true }) + assert_equal(true, target.dismissible?) + assert_equal(true, target.required?) + end + + test 'required takes precedence over dismissible' do + target = Announcement.new( + { dismissible: false, + required: true } + ) + assert_equal(true, target.dismissible?) + assert_equal(true, target.required?) + end + + test 'valid? should be false if msg is not present' do + target = Announcement.new({id: '12345', dismissible: true, required: true}) + assert_equal(false, target.valid?) + end + + test 'valid? should be true if msg is present' do + target = Announcement.new({ msg: 'message value' }) + assert_equal(true, target.valid?) + end + + test 'valid? should be true if required? is true and id and msg are present' do + target = Announcement.new({ msg: 'message value', id: '12345', required: true }) + assert_equal(true, target.valid?) + end + + test 'completed? should be true if announcement is dismissible and id is stored in the user settings' do + file = "#{Rails.root}/test/fixtures/file_output/user_settings/announcements.yml" if file.blank? + Configuration.stubs(:user_settings_file).returns(file) + target = Announcement.new({ id: 'completed_id', dismissible: false }) + assert_equal(false, target.completed?) + + target = Announcement.new({ id: 'completed_id', dismissible: true }) + assert_equal(true, target.completed?) + end +end