Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Capabilities <-> Actor association change to many-to-many #360

Merged
merged 2 commits into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ gem 'hiredis', '~> 0.6.3'
gem 'mail', '~> 2.8'
gem 'nokogiri', '~> 1.16'
gem 'stringex', '~> 2.8', require: 'stringex_lite'
gem 'data_migrate'

# functionality
gem 'acts-as-taggable-on', '~> 11.0'
Expand Down
4 changes: 4 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ GEM
concurrent-ruby (1.3.4)
connection_pool (2.4.1)
crass (1.0.6)
data_migrate (11.1.0)
activerecord (>= 6.1)
railties (>= 6.1)
database_cleaner-active_record (2.2.0)
activerecord (>= 5.a)
database_cleaner-core (~> 2.0.0)
Expand Down Expand Up @@ -536,6 +539,7 @@ DEPENDENCIES
bullet
bundler-audit (~> 0.9.2)
byebug
data_migrate
database_cleaner-active_record
devise
factory_bot_rails
Expand Down
3 changes: 1 addition & 2 deletions app/controllers/capabilities_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ class CapabilitiesController < ApplicationController
before_action :get_capability, only: %i[show edit update destroy]

def index
@actors = OrderedTree.result_for(authorized_scope(@exercise.actors))
@capabilities = authorized_scope(@exercise.capabilities).order(:name)
end

Expand Down Expand Up @@ -45,7 +44,7 @@ def destroy

private
def capability_params
params.require(:capability).permit(:name, :description, :actor_id)
params.require(:capability).permit(:name, :description, actor_ids: [])
end

def get_capability
Expand Down
1 change: 1 addition & 0 deletions app/models/actor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class Actor < ApplicationRecord
has_many :numbered_virtual_machines, class_name: 'VirtualMachine', as: :numbered_by
has_many :capabilities
has_many :role_bindings
has_and_belongs_to_many :capabilities

scope :numbered, -> {
where.not(number: nil)
Expand Down
2 changes: 1 addition & 1 deletion app/models/capability.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ class Capability < ApplicationRecord
extend FriendlyId

belongs_to :exercise, touch: true
belongs_to :actor, touch: true
has_and_belongs_to_many :customization_specs
has_and_belongs_to_many :actors, touch: true

validates :name, uniqueness: { scope: :exercise }, presence: true

Expand Down
3 changes: 2 additions & 1 deletion app/presenters/api/v3/capability_presenter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ def as_json(_opts)
id: capability.slug,
name: capability.name,
description: capability.description,
virtual_machines: capability.customization_specs.pluck(:slug)
actors: capability.actors.map(&:abbreviation),
hosts: capability.customization_specs.pluck(:slug)
}
end
end
Expand Down
2 changes: 1 addition & 1 deletion app/views/capabilities/_form.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
.px-4.py-5.bg-white.dark:bg-gray-800.space-y-6.sm:p-6
.grid.grid-cols-6.gap-6
.col-span-2= f.input :name
.col-span-2= f.association :actor, collection: sorted_tree_options(authorized_scope(@exercise.actors)), input_html: { data: { controller: 'select' } }
.col-span-2= f.association :actors, collection: sorted_tree_options(authorized_scope(@exercise.actors)), input_html: { data: { controller: 'select' } }
- if f.object.persisted?
.col-span-2
%div
Expand Down
5 changes: 3 additions & 2 deletions app/views/capabilities/_result_set.html.haml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
- if actor
- if actors
.py-4.text-center.text-xl.font-semibold
= render ActorChipComponent.new(actor:)
- actors.each do |actor|
%span.mx-1= render ActorChipComponent.new(actor:)
.pb-5
.border-t.border-gray-200.dark:border-gray-600

Expand Down
7 changes: 2 additions & 5 deletions app/views/capabilities/index.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,8 @@


- if @capabilities.any?
- grouped_caps = @capabilities.group_by(&:actor)
= render 'result_set', actor: nil, capabilities: grouped_caps[nil] if grouped_caps[nil]
- @actors.each do |actor|
- next unless grouped_caps[actor]
= render 'result_set', actor:, capabilities: grouped_caps[actor]
- @capabilities.group_by(&:actor_ids).each do |actor_ids, capabilities|
= render 'result_set', actors: authorized_scope(@exercise.actors).find(actor_ids) , capabilities:

- else
= render 'shared/empty', klass: Capability
2 changes: 1 addition & 1 deletion app/views/capabilities/show.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

.col-span-4
%dt.text-sm.text-gray-500.dark:text-gray-400= Actor.model_name.human
%dd.mt-1.text-sm.text-gray-900.dark:text-white.mt-0= @capability.actor&.name
%dd.mt-1.text-sm.text-gray-900.dark:text-white.mt-0= @capability.actors.pluck(:name).join(', ')

.px-6.py-5
%dt.text-sm.text-gray-500.dark:text-gray-400= Capability.human_attribute_name(:description)
Expand Down
2 changes: 1 addition & 1 deletion bin/setup
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ FileUtils.chdir APP_ROOT do
# end

puts "\n== Preparing database =="
system! "bin/rails db:prepare"
system! "bin/rails db:prepare:with_data"

puts "\n== Removing old logs and tempfiles =="
system! "bin/rails log:clear tmp:clear"
Expand Down
16 changes: 16 additions & 0 deletions db/data/20241114081829_migrate_capabilities_to_multiple_actors.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# frozen_string_literal: true

class MigrateCapabilitiesToMultipleActors < ActiveRecord::Migration[7.2]
def up
Capability.all.each do |cap|
if cap.actor_id
cap.actors << Actor.find(cap.actor_id)
cap.save
end
end
end

def down
raise ActiveRecord::IrreversibleMigration
end
end
3 changes: 3 additions & 0 deletions db/data_schema.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# frozen_string_literal: true

DataMigrate::Data.define(version: 20241114081829)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

class AddJoinTableForActorCapabilities < ActiveRecord::Migration[7.2]
def change
create_join_table :actors, :capabilities do |t|
t.index [:actor_id, :capability_id], name: 'actor_capability_index'
end
end
end
11 changes: 10 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

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

Expand Down Expand Up @@ -39,6 +39,12 @@
t.index ["exercise_id"], name: "index_actors_on_exercise_id"
end

create_table "actors_capabilities", id: false, force: :cascade do |t|
t.bigint "actor_id", null: false
t.bigint "capability_id", null: false
t.index ["actor_id", "capability_id"], name: "actor_capability_index"
end

create_table "address_pools", force: :cascade do |t|
t.bigint "network_id", null: false
t.string "name", null: false
Expand Down Expand Up @@ -143,6 +149,9 @@
t.index ["customization_spec_id", "service_id"], name: "spec_service_index"
end

create_table "data_migrations", primary_key: "version", id: :string, force: :cascade do |t|
end

create_table "exercises", force: :cascade do |t|
t.string "name", null: false
t.string "abbreviation", null: false
Expand Down
2 changes: 1 addition & 1 deletion docker/dev/docker-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ fi

git describe --tags >CURRENT_VERSION
touch tmp/caching-dev.txt
bundle exec rake db:prepare
bundle exec rake db:prepare:with_data
bundle exec rake db:seed
yarn

Expand Down
2 changes: 1 addition & 1 deletion docker/prod/docker-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ if [ ! -f config/credentials.yml.enc ]; then
EDITOR=true bundle exec rails credentials:edit
fi

bundle exec rails db:prepare
bundle exec rails db:prepare:with_data
bundle exec rails db:seed

exec "$@"
2 changes: 1 addition & 1 deletion spec/factories.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
factory :capability do
sequence(:name) { |n| "Capability #{n}" }
sequence(:slug) { |n| "capability#{n}" }
actor { exercise.actors.sample }
actors { [exercise.actors.sample] }
exercise
end

Expand Down
4 changes: 2 additions & 2 deletions spec/models/service_subject_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@
}
let!(:nic1) { create(:network_interface, virtual_machine: virtual_machine1, network: create(:network, exercise: service.exercise), egress: true) }
let(:spec1) { create(:customization_spec, tag_list: 'tag1') }
let(:capability1) { create(:capability, actor:, exercise: service.exercise) }
let(:capability1) { create(:capability, actors: [actor], exercise: service.exercise) }
before { spec1.capabilities << capability1 }


Expand All @@ -129,7 +129,7 @@
}
let!(:nic3) { create(:network_interface, virtual_machine: virtual_machine3, network: nic1.network, egress: true) }
let(:spec3) { create(:customization_spec, tag_list: 'tag3') }
let(:capability3) { create(:capability, actor: actor3, exercise: service.exercise) }
let(:capability3) { create(:capability, actors: [actor3], exercise: service.exercise) }
before { spec3.capabilities << capability3 }

let(:actor_matcher) { ServiceSubjectMatchCondition.new(matcher_type: 'Actor', matcher_id: actor.id.to_s) }
Expand Down