foreman_scc_manager 1.8.3 → 1.8.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -0
  3. data/app/controllers/api/v2/scc_accounts_controller.rb +9 -7
  4. data/app/controllers/scc_accounts_controller.rb +30 -4
  5. data/app/lib/actions/scc_manager/subscribe_product.rb +26 -13
  6. data/app/lib/actions/scc_manager/sync.rb +5 -5
  7. data/app/lib/actions/scc_manager/sync_products.rb +10 -13
  8. data/app/lib/actions/scc_manager/sync_repositories.rb +9 -13
  9. data/app/models/scc_account.rb +63 -5
  10. data/app/models/scc_product.rb +20 -2
  11. data/app/models/scc_repository.rb +11 -9
  12. data/app/views/scc_accounts/_form.html.erb +6 -0
  13. data/app/views/scc_accounts/index.html.erb +4 -3
  14. data/app/views/scc_accounts/show.html.erb +13 -4
  15. data/db/migrate/20200520281300_fix_scc_permissions.rb +22 -0
  16. data/db/migrate/20201119084201_add_gpg_key_to_scc_account.rb +6 -0
  17. data/db/migrate/20210205082733_add_subscription_valid_to_scc_products_and_repos.rb +6 -0
  18. data/db/migrate/20210210104407_add_root_repository_id_to_scc_repository.rb +6 -0
  19. data/db/migrate/20210224095050_connect_katello_root_repository_to_scc_repository.rb +28 -0
  20. data/lib/foreman_scc_manager/engine.rb +36 -25
  21. data/lib/foreman_scc_manager/version.rb +1 -1
  22. data/lib/tasks/test.rake +1 -1
  23. data/locale/de/LC_MESSAGES/foreman_scc_manager.mo +0 -0
  24. data/locale/de/foreman_scc_manager.edit.po +574 -0
  25. data/locale/de/foreman_scc_manager.po +40 -21
  26. data/locale/de/foreman_scc_manager.po.time_stamp +0 -0
  27. data/locale/en/foreman_scc_manager.edit.po +566 -0
  28. data/locale/en/foreman_scc_manager.po +21 -3
  29. data/locale/en/foreman_scc_manager.po.time_stamp +0 -0
  30. data/locale/foreman_scc_manager.pot +65 -38
  31. data/test/controllers/api/v2/scc_accounts_test.rb +9 -3
  32. data/test/controllers/scc_accounts_controller_test.rb +104 -0
  33. data/test/controllers/scc_accounts_controller_test2.rb +51 -0
  34. data/test/fixtures/models/scc_extendings.yml +6 -0
  35. data/test/fixtures/models/scc_products.yml +30 -2
  36. data/test/fixtures/models/scc_repositories.yml +29 -0
  37. data/test/models/scc_account_test.rb +70 -0
  38. data/test/models/scc_product_test.rb +69 -1
  39. data/test/support/fixtures_support.rb +3 -2
  40. data/test/test_controller_helper.rb +15 -0
  41. data/test/test_plugin_helper.rb +9 -0
  42. metadata +33 -14
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '090b5f9a98b9857d79b99c0206249dc632ad381f65e513da9a7fbcd5b4065e4d'
4
- data.tar.gz: 6f099c604ebaedbda016c4b107acac1a8333516673d69976809a6329866c9f07
3
+ metadata.gz: 2d51eed6c2336237f44aa0fad512060a43f4bc0dae6fd9a93daa2baa555f915a
4
+ data.tar.gz: 876ebdd4e76443deec6016c657b44ddcb1e60dcc2c8a81631e5f87cccafcc9b1
5
5
  SHA512:
6
- metadata.gz: 2c4e5ed794d362e22128bb90efa721e9d5539fec4854e95da82f50076e5d2fb75220da7b9b6b6175343518ca25b30ed50b4a6f3d98944d30f767af2da31423c2
7
- data.tar.gz: 061fc929ec7698229893e16bf1873c7e3006de9647d351c64f5f69404331730f8b394759db5d922314b51f0cbb2645401d153e4dac5666d9e242b3ee4f3311a0
6
+ metadata.gz: ef379e703604fc444d312969f4dd389c952b03dc3f3d5ba98d95989941c9b397b7879bef97d309ae54270f70ffb5b1ef50ee1ba214571800dc82f2ea7d301bd7
7
+ data.tar.gz: 70c8ddeef5a5ad620dfb6fe1ed3b2296e56cef24be9fc3b07223bc2978b5fb0f116d996bddea4e0bc50db1accef6a82ed263183d13fad7d23a56a9c15da077fc
data/README.md CHANGED
@@ -13,6 +13,8 @@ for how to install Foreman plugins
13
13
 
14
14
  | Foreman Version | Katello Version | Plugin Version |
15
15
  | --------------- | --------------- | -------------- |
16
+ | 2.1 | 3.16 | ~> 1.8.5 |
17
+ | 2.0 | 3.16 | ~> 1.8.4 |
16
18
  | 1.24 | 3.14 | ~> 1.8.0 |
17
19
  | 1.22 | 3.12 | ~> 1.7.0 |
18
20
  | 1.21 | 3.10 | ~> 1.6.0 |
@@ -23,6 +25,9 @@ for how to install Foreman plugins
23
25
  | 1.16 | 3.5 | <= 1.3.0 |
24
26
  | 1.15 | 3.4 | ~> 1.1.0 |
25
27
 
28
+ ## Documentation
29
+ The plugin documentation can be found at https://docs.orcharhino.com/sources/management_ui/the_content_menu/suse_subscriptions.html.
30
+
26
31
  ## Contributing
27
32
 
28
33
  Fork and send a Pull Request. Thanks!
@@ -18,7 +18,7 @@ module Api
18
18
  def index
19
19
  scope = resource_scope
20
20
  scope = scope.where(:organization => params[:organization_id]) if params[:organization_id].present?
21
- @scc_accounts = scope.search_for(params[:search], :order => params[:order]).paginate(:page => params[:page])
21
+ @scc_accounts = scope.search_for(params[:search], :order => params[:order]).paginate(:page => params[:page], :per_page => params[:per_page])
22
22
  end
23
23
 
24
24
  api :GET, '/scc_accounts/:id/', N_('Show scc_account')
@@ -34,7 +34,8 @@ module Api
34
34
  param :password, String, :required => true, :desc => N_('Password of scc_account')
35
35
  param :base_url, String, :required => false, :desc => N_('URL of SUSE for scc_account')
36
36
  param :interval, ['never', 'daily', 'weekly', 'monthy'], :desc => N_('Interval for syncing scc_account')
37
- param :sync_date, String, :desc => N_('Last Sync time of scc_account')
37
+ param :sync_date, String, :desc => N_('Date and time relative to which the sync interval is run')
38
+ param :katello_gpg_key_id, :identifier, :required => false, :desc => N_('Associated GPG key of scc_account')
38
39
  end
39
40
  end
40
41
 
@@ -79,9 +80,9 @@ module Api
79
80
  end
80
81
  respond_to do |format|
81
82
  if @scc_account.test_connection
82
- format.json { render json: 'Success'.to_json, status: :ok }
83
+ format.json { render json: { 'success' => true }.to_json, status: :ok }
83
84
  else
84
- format.json { render json: 'Failed'.to_json, status: :not_found }
85
+ format.json { render json: { 'success' => false, 'error' => 'Test failed. Check your credentials.' }.to_json, status: :not_found }
85
86
  end
86
87
  end
87
88
  end
@@ -102,7 +103,7 @@ module Api
102
103
 
103
104
  api :PUT, '/scc_accounts/:id/bulk_subscribe/', N_('Bulk subscription of scc_products for scc_account')
104
105
  param :id, :identifier_dottable, :required => true
105
- param :scc_subscribe_product_ids, Array
106
+ param :scc_subscribe_product_ids, Array, :required => true
106
107
  def bulk_subscribe
107
108
  scc_products_to_subscribe = @scc_account.scc_products.where(:id => params[:scc_subscribe_product_ids])
108
109
  respond_to do |format|
@@ -112,7 +113,7 @@ module Api
112
113
  scc_products_to_subscribe)
113
114
  format.json { render json: subscribe_task.to_json, status: :ok }
114
115
  else
115
- format.json { render json: 'No Product selected'.to_json, status: :expectation_failed }
116
+ format.json { render json: { error: 'No Product selected' }, status: :expectation_failed }
116
117
  end
117
118
  end
118
119
  rescue ::Foreman::Exception => e
@@ -132,7 +133,8 @@ module Api
132
133
  :base_url,
133
134
  :interval,
134
135
  :sync_date,
135
- :organization_id
136
+ :organization_id,
137
+ :katello_gpg_key_id
136
138
  )
137
139
  end
138
140
 
@@ -1,12 +1,19 @@
1
1
  class SccAccountsController < ApplicationController
2
+ helper_method :scc_filtered_products
2
3
  before_action :find_organization
3
4
  before_action :find_resource, only: %i[show edit update destroy sync bulk_subscribe]
5
+ before_action :find_available_gpg_keys, only: %i[new edit]
4
6
  include Foreman::Controller::AutoCompleteSearch
5
7
 
6
8
  # GET /scc_accounts
7
9
  def index
8
- @scc_accounts = resource_base.search_for(params[:search], order: params[:order])
9
- .paginate(page: params[:page])
10
+ @scc_accounts = resource_base.where(organization: @organization)
11
+ .search_for(params[:search], order: params[:order])
12
+ .paginate(:page => params[:page], :per_page => params[:per_page])
13
+ # overwrite the product list with filtered products that do not include products with empty repositories
14
+ @scc_accounts.each do |scc_account|
15
+ scc_account.scc_products_with_repos_count = scc_account.scc_products.only_products_with_repos.count
16
+ end
10
17
  end
11
18
 
12
19
  # GET /scc_accounts/new
@@ -92,6 +99,11 @@ class SccAccountsController < ApplicationController
92
99
 
93
100
  private
94
101
 
102
+ def find_available_gpg_keys
103
+ @scc_account ? org = @scc_account.organization : org = @organization
104
+ @selectable_gpg_keys = ::Katello::GpgKey.where(organization: org).collect { |p| [p.name, p.id] }.unshift ['None', nil]
105
+ end
106
+
95
107
  def find_organization
96
108
  @organization = Organization.current
97
109
  redirect_to '/select_organization?toState=' + request.path unless @organization
@@ -108,7 +120,8 @@ class SccAccountsController < ApplicationController
108
120
  :base_url,
109
121
  :interval,
110
122
  :sync_date,
111
- :organization_id
123
+ :organization_id,
124
+ :katello_gpg_key_id
112
125
  )
113
126
  end
114
127
 
@@ -121,9 +134,22 @@ class SccAccountsController < ApplicationController
121
134
  when 'sync', 'test_connection'
122
135
  :sync
123
136
  when 'bulk_subscribe'
124
- :bulk_subscribe
137
+ :use
125
138
  else
126
139
  super
127
140
  end
128
141
  end
142
+
143
+ # Function filters a product list and removes all products without valid repositories
144
+ # The .order call is necessary to apply the ordering to repository that have already been loaded from the database.
145
+ # Input parameters:
146
+ # product_list: list of SccProduct
147
+ # product_type: return only base products if type is set (default), else all
148
+ def scc_filtered_products(product_list, product_type = 'base')
149
+ if product_type == 'base'
150
+ product_list.only_products_with_repos.where(product_type: 'base').order(:friendly_name)
151
+ else
152
+ product_list.only_products_with_repos.order(:friendly_name)
153
+ end
154
+ end
129
155
  end
@@ -8,27 +8,38 @@ module Actions
8
8
  .info("Initiating subscription for SccProduct '#{scc_product.friendly_name}'.")
9
9
  sequence do
10
10
  product_create_action = plan_action(CreateProduct,
11
- product_name: scc_product.uniq_name,
12
- product_description: scc_product.description,
13
- organization_id: scc_product.organization.id)
11
+ :product_name => scc_product.pretty_name,
12
+ :product_description => scc_product.pretty_description,
13
+ :organization_id => scc_product.organization.id,
14
+ :gpg_key => scc_product.scc_account.katello_gpg_key_id)
15
+ katello_repos = {}
14
16
  scc_product.scc_repositories.each do |repo|
15
- uniq_name = scc_product.uniq_name + ' ' + repo.description
16
17
  arch = scc_product.arch || 'noarch'
17
- plan_action(CreateRepository,
18
- :product_id => product_create_action.output[:product_id],
19
- :uniq_name => uniq_name,
20
- :url => repo.full_url,
21
- :arch => arch)
18
+ repo_create_action = plan_action(CreateRepository,
19
+ :product_id => product_create_action.output[:product_id],
20
+ :uniq_name => repo.uniq_name(scc_product),
21
+ :pretty_repo_name => repo.pretty_name,
22
+ :url => repo.full_url,
23
+ :arch => arch)
24
+ katello_repos[repo.id] = repo_create_action.output[:katello_root_repository_id]
22
25
  end
26
+ # connect action to resource (=> make parameters accessable in input)
23
27
  action_subject(scc_product, product_id: product_create_action.output[:product_id])
28
+ input.update(katello_repos: katello_repos)
24
29
  plan_self
25
30
  end
26
31
  end
27
32
 
28
33
  def finalize
34
+ # connect Scc products and Katello products
29
35
  scc_product = SccProduct.find(input[:scc_product][:id])
30
36
  product = ::Katello::Product.find(input[:product_id])
31
37
  scc_product.update!(product: product)
38
+ # extract Katello repo ids from input hash and store to database
39
+ input[:katello_repos].each do |scc_repo_id, katello_root_repository_id|
40
+ scc_repo = SccRepository.find(scc_repo_id)
41
+ scc_repo.update!(katello_root_repository_id: katello_root_repository_id)
42
+ end
32
43
  end
33
44
 
34
45
  def humanized_name
@@ -43,6 +54,7 @@ module Actions
43
54
  def create_sub_plans
44
55
  product = ::Katello::Product.new
45
56
  product.name = input[:product_name]
57
+ product.gpg_key = ::Katello::GpgKey.find_by(id: input[:gpg_key], organization: input[:organization_id])
46
58
  product.description = input[:product_description]
47
59
  trigger(::Actions::Katello::Product::Create,
48
60
  product,
@@ -58,12 +70,11 @@ module Actions
58
70
 
59
71
  def create_sub_plans
60
72
  product = ::Katello::Product.find(input[:product_id])
61
- uniq_name = input[:uniq_name]
62
- label = ::Katello::Util::Model.labelize(uniq_name)
73
+ label = ::Katello::Util::Model.labelize(input[:uniq_name])
63
74
  unprotected = true
64
75
  gpg_key = product.gpg_key
65
76
  repo_param = { :label => label,
66
- :name => uniq_name,
77
+ :name => input[:pretty_repo_name],
67
78
  :url => input[:url],
68
79
  :content_type => 'yum',
69
80
  :unprotected => unprotected,
@@ -73,7 +84,9 @@ module Actions
73
84
  repository = product.add_repo(repo_param)
74
85
  repository.mirror_on_sync = true
75
86
  repository.verify_ssl_on_sync = true
76
- trigger(::Actions::Katello::Repository::CreateRoot, repository)
87
+ trigger(::Actions::Katello::Repository::CreateRoot, repository).tap do
88
+ output[:katello_root_repository_id] = repository.id
89
+ end
77
90
  end
78
91
  end
79
92
  end
@@ -1,21 +1,21 @@
1
1
  module Actions
2
2
  module SccManager
3
+ # for dynflow documentation see here: https://dynflow.github.io/documentation/
3
4
  class Sync < Actions::EntryAction
4
5
  def plan(scc_account)
5
6
  ::Foreman::Logging.logger('foreman_scc_manager')
6
7
  .info("Initiating 'sync' for SccAccount '#{scc_account.name}'.")
7
8
  action_subject(scc_account)
8
9
  sequence do
9
- sync_repo_action = plan_action(::Actions::SccManager::SyncRepositories, scc_account)
10
- sync_prod_action = plan_action(::Actions::SccManager::SyncProducts, scc_account)
11
- plan_self(repo_status: sync_repo_action.output[:status], prod_status: sync_prod_action.output[:status])
10
+ plan_action(::Actions::SccManager::SyncRepositories, scc_account)
11
+ plan_action(::Actions::SccManager::SyncProducts, scc_account)
12
+ plan_self
12
13
  end
13
14
  end
14
15
 
15
16
  def finalize
17
+ # this is only executed if run actions of SyncRepositories and SyncProducts were successful
16
18
  scc_account = SccAccount.find(input[:scc_account][:id])
17
- raise 'Updating failed' unless input[:repo_status] == 'SUCCESS' && input[:prod_status] == 'SUCCESS'
18
-
19
19
  scc_account.update! synced: Time.current
20
20
  end
21
21
 
@@ -13,22 +13,19 @@ module Actions
13
13
  end
14
14
 
15
15
  def run
16
- output[:status] = 'SUCCESS'
17
- begin
18
- products = ::SccManager.get_scc_data(input.fetch(:base_url),
19
- '/connect/organizations/products',
20
- input.fetch(:login),
21
- decrypt_field(input.fetch(:password)))
22
- output[:data] = ::SccManager.sanitize_products(products).values
23
- rescue StandardError => e
24
- ::Foreman::Logging.logger('foreman_scc_manager').error "Error while syncronizing SCC-Products: #{e}"
25
- output[:error] = e.to_s
26
- output[:status] = 'FAILURE'
27
- end
16
+ products = ::SccManager.get_scc_data(input.fetch(:base_url),
17
+ '/connect/organizations/products',
18
+ input.fetch(:login),
19
+ decrypt_field(input.fetch(:password)))
20
+ output[:data] = ::SccManager.sanitize_products(products).values
21
+ rescue StandardError => e
22
+ ::Foreman::Logging.logger('foreman_scc_manager').error "Error while syncronizing SCC-Products: #{e}"
23
+ error! e.to_s
28
24
  end
29
25
 
30
26
  def finalize
31
- SccAccount.find(input.fetch(:id)).update_scc_products(output.fetch(:data)) if output[:status] == 'SUCCESS'
27
+ # this is only executed if 'run' succeeds
28
+ SccAccount.find(input.fetch(:id)).update_scc_products(output.fetch(:data))
32
29
  end
33
30
 
34
31
  def rescue_strategy
@@ -12,22 +12,18 @@ module Actions
12
12
  end
13
13
 
14
14
  def run
15
- output[:status] = 'IN PROGRESS'
16
- begin
17
- output[:data] = ::SccManager.get_scc_data(input[:base_url],
18
- '/connect/organizations/repositories',
19
- input[:login],
20
- decrypt_field(input[:password]))
21
- output[:status] = 'SUCCESS'
22
- rescue StandardError => e
23
- ::Foreman::Logging.logger('foreman_scc_manager').error "Error while syncronizing SCC-Repositories: #{e}"
24
- output[:error] = e.to_s
25
- output[:status] = 'FAILURE'
26
- end
15
+ output[:data] = ::SccManager.get_scc_data(input[:base_url],
16
+ '/connect/organizations/repositories',
17
+ input[:login],
18
+ decrypt_field(input[:password]))
19
+ rescue StandardError => e
20
+ ::Foreman::Logging.logger('foreman_scc_manager').error "Error while syncronizing SCC-Repositories: #{e}"
21
+ error! e.to_s
27
22
  end
28
23
 
29
24
  def finalize
30
- SccAccount.find(input[:scc_account][:id]).update_scc_repositories(output[:data]) if output[:status] == 'SUCCESS'
25
+ # this is only executed if 'run' succeeds
26
+ SccAccount.find(input[:scc_account][:id]).update_scc_repositories(output[:data])
31
27
  end
32
28
 
33
29
  def rescue_strategy
@@ -2,6 +2,9 @@ class SccAccount < ApplicationRecord
2
2
  include Authorizable
3
3
  include Encryptable
4
4
  include ForemanTasks::Concerns::ActionSubject
5
+
6
+ attr_accessor :scc_products_with_repos_count
7
+
5
8
  encrypts :password
6
9
 
7
10
  NEVER = 'never'.freeze
@@ -173,21 +176,34 @@ class SccAccount < ApplicationRecord
173
176
 
174
177
  def update_scc_repositories(upstream_repositories)
175
178
  upstream_repo_ids = []
179
+ # initially invalidate all repositories and validate them during update
180
+ invalidated_repos = invalidate_subscription_status(scc_repositories)
176
181
  # import repositories
177
182
  upstream_repositories.each do |ur|
178
183
  cached_repository = scc_repositories.find_or_initialize_by(scc_id: ur['id'])
179
- cached_repository.name = ur['name']
180
184
  cached_repository.distro_target = ur['distro_target']
181
185
  cached_repository.description = ur['description']
182
186
  cached_repository.url, cached_repository.token = ur['url'].split('?')
183
187
  cached_repository.enabled = ur['enabled']
184
188
  cached_repository.autorefresh = ur['autorefresh']
185
189
  cached_repository.installer_updates = ur['installer_updates']
190
+ # should be called after all attributes are set in case of dependencies (currently: description)
191
+ cached_repository.name = cached_repository.pretty_name
192
+ cached_repository.subscription_valid = true
186
193
  cached_repository.save!
187
194
  upstream_repo_ids << ur['id']
195
+ # set invalidated record to true, if exists
196
+ invalidated_repos = revalidate_subscription_status(invalidated_repos, ur[id])
188
197
  end
189
198
  ::Foreman::Logging.logger('foreman_scc_manager').debug "Found #{upstream_repo_ids.length} repositories"
190
- # delete repositories beeing removed upstream
199
+
200
+ # all scc repos that are kept but not available upstream need to be marked invalid
201
+ # subscription_valid can be set to nil
202
+ to_invalidate = invalidated_repos.select { |ir| ir.katello_root_repository_id.present? && !ir.subscription_valid }
203
+ ::Foreman::Logging.logger('foreman_scc_manager').debug "Invalidating #{to_invalidate.count} expired repositories"
204
+ invalidate_subscription_status(to_invalidate, true)
205
+
206
+ # delete repositories being removed upstream and that are not subscribed to
191
207
  to_delete = scc_repositories.where.not(scc_id: upstream_repo_ids)
192
208
  ::Foreman::Logging.logger('foreman_scc_manager').debug "Deleting #{to_delete.count} old repositories"
193
209
  to_delete.destroy_all
@@ -195,10 +211,11 @@ class SccAccount < ApplicationRecord
195
211
 
196
212
  def update_scc_products(upstream_products)
197
213
  upstream_product_ids = []
214
+ # initially invalidate all products and validate them during update
215
+ invalidated_products = invalidate_subscription_status(scc_products)
198
216
  # import products
199
217
  upstream_products.each do |up|
200
218
  cached_product = scc_products.find_or_initialize_by(scc_id: up['id'])
201
- cached_product.name = up['name']
202
219
  cached_product.version = up['version']
203
220
  cached_product.arch = up['arch']
204
221
  cached_product.description = up['description']
@@ -206,12 +223,25 @@ class SccAccount < ApplicationRecord
206
223
  cached_product.product_type = up['product_type']
207
224
  cached_product.scc_repositories =
208
225
  scc_repositories.where(scc_id: up['repositories'].map { |repo| repo['id'] })
226
+ # name should be set after friendly_name because it depends on friendly_name
227
+ cached_product.name = cached_product.pretty_name
228
+ cached_product.description = cached_product.pretty_description
229
+ cached_product.subscription_valid = true
209
230
  cached_product.save!
210
231
  upstream_product_ids << up['id']
232
+ # set invalidated record to true, if exists
233
+ invalidated_products = revalidate_subscription_status(invalidated_products, up['id'])
211
234
  end
212
235
  ::Foreman::Logging.logger('foreman_scc_manager').debug "Found #{upstream_product_ids.length} products"
213
- # delete products beeing removed upstream
214
- to_delete = scc_products.where.not(scc_id: upstream_product_ids)
236
+
237
+ # all scc products that are kept but not available upstream need to be marked invalid
238
+ # subscription_valid can be set to nil
239
+ to_invalidate = invalidated_products.select { |ip| ip.product_id.present? && !ip.subscription_valid }
240
+ ::Foreman::Logging.logger('foreman_scc_manager').debug "Invalidating #{to_invalidate.count} expired products"
241
+ invalidate_subscription_status(to_invalidate, true)
242
+
243
+ # delete products being removed upstream and that are not subscribed to
244
+ to_delete = scc_products.where.not(scc_id: upstream_product_ids).where(product_id: nil)
215
245
  ::Foreman::Logging.logger('foreman_scc_manager').debug "Deleting #{to_delete.count} old products"
216
246
  to_delete.destroy_all
217
247
  # rewire product to product relationships
@@ -224,4 +254,32 @@ class SccAccount < ApplicationRecord
224
254
  end
225
255
  end
226
256
  end
257
+
258
+ # validate the subscription status of a product/repo
259
+ # no saving to database
260
+ # params: elements: scc repos or products, Array or ActiveRecord_(*)
261
+ # scc_id: scc_id of the element that should be revalidated
262
+ # return: elements where for the element with scc_id subscription_valid is true
263
+ def revalidate_subscription_status(elements, scc_id)
264
+ return nil if elements.nil?
265
+
266
+ revalidate = elements.find { |e| e.scc_id == scc_id }
267
+ revalidate.subscription_valid = true unless revalidate.nil?
268
+ # return modified list
269
+ elements
270
+ end
271
+
272
+ # set all products/repos invalid
273
+ # params: items_to_invalidate: ActiveRecord_(*)
274
+ # save_record: store in database or not (default)
275
+ # return: ActiveRecord elements with invalidated subscription status
276
+ def invalidate_subscription_status(items_to_invalidate, save_record = false)
277
+ if items_to_invalidate.present?
278
+ items_to_invalidate.each do |inv|
279
+ inv.subscription_valid = false
280
+ inv.save! if save_record
281
+ end
282
+ end
283
+ items_to_invalidate
284
+ end
227
285
  end