Skip to content

Commit

Permalink
Merge b036de7 into 16c2f2b
Browse files Browse the repository at this point in the history
  • Loading branch information
imobachgs committed Sep 12, 2018
2 parents 16c2f2b + b036de7 commit cfaf734
Show file tree
Hide file tree
Showing 4 changed files with 290 additions and 29 deletions.
78 changes: 68 additions & 10 deletions src/lib/y2firewall/widgets/allowed_services.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,32 +34,48 @@ def initialize(zone)
textdomain "firewall"
@zone = zone
self.widget_id = "allowed_services"
@available_svcs_table = ServicesTable.new
@allowed_svcs_table = ServicesTable.new
@available_svcs_table = ServicesTable.new(widget_id: "available:#{zone.name}")
@allowed_svcs_table = ServicesTable.new(widget_id: "allowed:#{zone.name}")
refresh_services
end

# @macro seeAbstractWidget
def label
_("Allowed Services")
end

# @macro seeCustomWidget
def contents
return @contents if @contents

VBox(
HBox(
available_svcs_table,
VBox(
PushButton(Id(:add), _("Add")),
PushButton(Id(:remove), _("Remove"))
Left(Label(_("Available"))),
available_svcs_table
),
allowed_svcs_table
VBox(*add_remove_buttons),
VBox(
Left(Label(_("Allowed"))),
allowed_svcs_table
)
)
)
end

# @macro seeAbstractWidget
def handle(event)
return unless event["ID"]

case event["ID"]
when :add
add_service
when :add_all
add_all_services
when :remove
remove_service
when :remove_all
remove_all_services
end
refresh_services
nil
Expand All @@ -79,20 +95,62 @@ def handle(event)

# Adds a service to the list of allowed ones
def add_service
zone.add_service(available_svcs_table.selected_service)
available_svcs_table.selected_services.each { |s| zone.add_service(s) }
end

def add_all_services
firewall.current_service_names.each { |s| zone.add_service(s) }
end

# Removes a service from the list of allowed ones
def remove_service
zone.remove_service(allowed_svcs_table.selected_service)
allowed_svcs_table.selected_services.each { |s| zone.remove_service(s) }
end

def remove_all_services
zone.services.clone.each { |s| zone.remove_service(s) }
end

# Refresh the content of the services tables
def refresh_services
available_svcs_table.update(firewall.api.services - zone.services)
allowed_svcs_table.update(zone.services.clone)
available_svcs_table.services = (firewall.current_service_names - zone.services)
allowed_svcs_table.services = zone.services.clone
end

# Return a list of buttons to add/remove elements
#
# @return [Array<Yast::Term>] Buttons set UI terms
def add_remove_buttons
[
PushButton(
Id(:add),
Opt(:hstretch),
_("Add") + Yast::UI.Glyph(:ArrowRight).to_s
),
PushButton(
Id(:add_all),
Opt(:hstretch),
_("Add All") + Yast::UI.Glyph(:ArrowRight).to_s
),
VSpacing(1),
PushButton(
Id(:remove),
Opt(:hstretch),
"#{Yast::UI.Glyph} " + _("<- Remove")
),
PushButton(
Id(:remove_all),
Opt(:hstretch),
"#{Yast::UI.Glyph} " + _("<- Remove All")
)
]
end

# Return the current `Y2Firewall::Firewalld` instance
#
# This is just a convenience method.
#
# @return [Y2Firewall::Firewalld]
def firewall
Y2Firewall::Firewalld.instance
end
Expand Down
48 changes: 29 additions & 19 deletions src/lib/y2firewall/widgets/services_table.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,40 @@
# To contact SUSE LLC about this file by physical or electronic mail, you may
# find current contact information at www.suse.com.

require "cwm"
require "cwm/table"

Yast.import "UI"

module Y2Firewall
module Widgets
# A table with all firewall services.
# Table containing a set of firewalld services
#
# @example Creating a new table
# names = Y2Firewall::Firewalld.instance.current_service_names
# table = Y2Firewall::Widgets::Services.new(names)
#
# @example Updating content
# table.services = ["dhcp", "dhcpv6", "dhcpv6-client"]
class ServicesTable < ::CWM::Table
# @!attribute [r] services
# @return [Array<String>] Services to be displayed
attr_reader :services

alias_method :selected_services, :value

# Constructor
#
# @param services [Array<String>] Services to be displayed
def initialize(services = [])
def initialize(services: [], widget_id: nil)
textdomain "firewall"
@services = services
self.widget_id = "services_table:#{object_id}"
self.widget_id = widget_id || "services_table:#{object_id}"
end

# @macro seeAbstractWidget
def opt
[:multiSelection]
end

# @see CWM::Table#header
Expand All @@ -45,29 +62,22 @@ def header

# @see CWM::Table#items
def items
@items ||= services.sort_by(&:downcase).map { |s| [s, s] }
services.sort_by(&:downcase).map { |s| [s, s] }
end

# Updates the list of services
#
# @note When running on graphical mode, the new elements are kept selected.
#
# @param services [Array<String>] New list of services
def update(services)
old_index = items.map(&:first).index(value) unless items.empty?
def services=(services)
old_services = @services
@services = services
refresh
self.value = items[old_index].first if old_index && !items.empty?
end

def selected_service
value.to_s
end

private

# Refreshes the table content
def refresh
@items = nil
change_items(items)
unless Yast::UI.TextMode
new_services = services - old_services
self.value = new_services
end
end
end
end
Expand Down
124 changes: 124 additions & 0 deletions test/lib/y2firewall/widgets/allowed_services_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#!/usr/bin/env rspec
# encoding: utf-8

# Copyright (c) [2018] SUSE LLC
#
# All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of version 2 of the GNU General Public License as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, contact SUSE LLC.
#
# To contact SUSE LLC about this file by physical or electronic mail, you may
# find current contact information at www.suse.com.

require_relative "../../../test_helper"

require "cwm/rspec"
require "y2firewall/widgets/allowed_services"

describe Y2Firewall::Widgets::AllowedServices do
include_examples "CWM::CustomWidget"

AVAILABLE_SERVICES = ["dhcp", "https", "ssh"].freeze

subject(:widget) { described_class.new(zone) }

let(:zone) do
Y2Firewall::Firewalld::Zone.new(name: "public").tap { |s| s.services = ["dhcp"] }
end

let(:firewall) do
instance_double(Y2Firewall::Firewalld, current_service_names: AVAILABLE_SERVICES)
end

let(:available_svcs_table) do
instance_double(
Y2Firewall::Widgets::ServicesTable, :services= => nil, selected_services: ["ssh"]
)
end

let(:allowed_svcs_table) do
instance_double(
Y2Firewall::Widgets::ServicesTable, :services= => nil, selected_services: ["dhcp"]
)
end

before do
allow(Y2Firewall::Firewalld).to receive(:instance).and_return(firewall)
allow(Y2Firewall::Widgets::ServicesTable).to receive(:new)
.with(widget_id: "available:#{zone.name}").and_return(available_svcs_table)
allow(Y2Firewall::Widgets::ServicesTable).to receive(:new)
.with(widget_id: "allowed:#{zone.name}").and_return(allowed_svcs_table)
end

describe "#handle" do
context "when it receives an event to add a service" do
let(:event) { { "ID" => :add } }

it "adds the selected service to the zone" do
widget.handle(event)
expect(zone.services).to contain_exactly("dhcp", "ssh")
end

it "updates services tables" do
expect(allowed_svcs_table).to receive(:services=).with(["dhcp", "ssh"])
expect(available_svcs_table).to receive(:services=).with(["https"])
widget.handle(event)
end
end

context "when it receives an event to remove a service" do
let(:event) { { "ID" => :remove } }

it "removes the selected service from the zone" do
widget.handle(event)
expect(zone.services).to be_empty
end

it "updates the services tables" do
expect(available_svcs_table).to receive(:services=).with(["dhcp", "https", "ssh"])
expect(allowed_svcs_table).to receive(:services=).with([])
widget.handle(event)
end
end

context "when it receives an event to add all available services" do
let(:event) { { "ID" => :add_all } }

it "adds all services to the zone" do
widget.handle(event)
expect(zone.services).to eq(AVAILABLE_SERVICES)
end

it "updates the services tables" do
expect(allowed_svcs_table).to receive(:services=).with(AVAILABLE_SERVICES)
expect(available_svcs_table).to receive(:services=).with([])
widget.handle(event)
end
end

context "when it receives an event to remove all available services" do
let(:event) { { "ID" => :remove_all } }

it "removes all services from the zone" do
widget.handle(event)
expect(zone.services).to be_empty
end

it "updates the services tables" do
expect(available_svcs_table).to receive(:services=).with(AVAILABLE_SERVICES)
expect(allowed_svcs_table).to receive(:services=).with([])
widget.handle(event)
end
end
end
end
69 changes: 69 additions & 0 deletions test/lib/y2firewall/widgets/services_table_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#!/usr/bin/env rspec
# encoding: utf-8

# Copyright (c) [2018] SUSE LLC
#
# All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of version 2 of the GNU General Public License as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, contact SUSE LLC.
#
# To contact SUSE LLC about this file by physical or electronic mail, you may
# find current contact information at www.suse.com.

require_relative "../../../test_helper"

require "cwm/rspec"
require "y2firewall/widgets/services_table"

describe Y2Firewall::Widgets::ServicesTable do
include_examples "CWM::CustomWidget"

subject(:widget) { described_class.new(services: ["dhcp"], widget_id: "table") }

before do
allow(Yast::UI).to receive(:QueryWidget).with(Id("table"), :SelectedItems)
.and_return(["dhcp"])
end

describe "#services" do
it "updates the list of items" do
subject.services = ["ssh"]
expect(widget.items).to eq([["ssh", "ssh"]])
expect(widget.services).to eq(["ssh"])
end

context "when some items are added" do
before do
allow(Yast::UI).to receive(:TextMode).and_return(textmode)
end

context "and YaST is running in graphical mode" do
let(:textmode) { false }

it "sets new items as selected" do
expect(widget).to receive(:value=).with(["ssh"])
subject.services = ["ssh"]
end
end

context "and YaST is running in text mode" do
let(:textmode) { true }

it "does not set any item as selected" do
expect(widget).to_not receive(:value=)
subject.services = ["ssh"]
end
end
end
end
end

0 comments on commit cfaf734

Please sign in to comment.