uffizzi_core 0.2.0 → 0.2.1

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 (56) hide show
  1. checksums.yaml +4 -4
  2. data/app/forms/uffizzi_core/api/cli/v1/compose_file/create_form.rb +0 -2
  3. data/app/lib/uffizzi_core/concerns/models/account.rb +84 -0
  4. data/app/lib/uffizzi_core/concerns/models/activity_item.rb +39 -0
  5. data/app/lib/uffizzi_core/concerns/models/build.rb +47 -0
  6. data/app/lib/uffizzi_core/concerns/models/comment.rb +20 -0
  7. data/app/lib/uffizzi_core/concerns/models/compose_file.rb +60 -0
  8. data/app/lib/uffizzi_core/concerns/models/config_file.rb +21 -0
  9. data/app/lib/uffizzi_core/concerns/models/container.rb +95 -0
  10. data/app/lib/uffizzi_core/concerns/models/container_config_file.rb +12 -0
  11. data/app/lib/uffizzi_core/concerns/models/coupon.rb +9 -0
  12. data/app/lib/uffizzi_core/concerns/models/credential.rb +65 -0
  13. data/app/lib/uffizzi_core/concerns/models/deployment.rb +71 -0
  14. data/app/lib/uffizzi_core/concerns/models/event.rb +17 -0
  15. data/app/lib/uffizzi_core/concerns/models/invitation.rb +31 -0
  16. data/app/lib/uffizzi_core/concerns/models/membership.rb +20 -0
  17. data/app/lib/uffizzi_core/concerns/models/payment.rb +15 -0
  18. data/app/lib/uffizzi_core/concerns/models/price.rb +13 -0
  19. data/app/lib/uffizzi_core/concerns/models/product.rb +15 -0
  20. data/app/lib/uffizzi_core/concerns/models/project.rb +62 -0
  21. data/app/lib/uffizzi_core/concerns/models/rating.rb +24 -0
  22. data/app/lib/uffizzi_core/concerns/models/repo.rb +33 -0
  23. data/app/lib/uffizzi_core/concerns/models/role.rb +21 -0
  24. data/app/lib/uffizzi_core/concerns/models/secret.rb +13 -0
  25. data/app/lib/uffizzi_core/concerns/models/template.rb +23 -0
  26. data/app/lib/uffizzi_core/concerns/models/user.rb +66 -0
  27. data/app/lib/uffizzi_core/concerns/models/user_project.rb +18 -0
  28. data/app/models/uffizzi_core/account.rb +1 -79
  29. data/app/models/uffizzi_core/activity_item.rb +1 -31
  30. data/app/models/uffizzi_core/build.rb +1 -35
  31. data/app/models/uffizzi_core/comment.rb +1 -12
  32. data/app/models/uffizzi_core/compose_file.rb +1 -44
  33. data/app/models/uffizzi_core/config_file.rb +1 -13
  34. data/app/models/uffizzi_core/container.rb +1 -85
  35. data/app/models/uffizzi_core/container_config_file.rb +1 -4
  36. data/app/models/uffizzi_core/coupon.rb +1 -1
  37. data/app/models/uffizzi_core/credential.rb +1 -57
  38. data/app/models/uffizzi_core/deployment.rb +1 -63
  39. data/app/models/uffizzi_core/event.rb +1 -9
  40. data/app/models/uffizzi_core/invitation.rb +1 -23
  41. data/app/models/uffizzi_core/membership.rb +1 -12
  42. data/app/models/uffizzi_core/payment.rb +1 -7
  43. data/app/models/uffizzi_core/price.rb +1 -5
  44. data/app/models/uffizzi_core/product.rb +1 -7
  45. data/app/models/uffizzi_core/project.rb +1 -54
  46. data/app/models/uffizzi_core/rating.rb +1 -16
  47. data/app/models/uffizzi_core/repo.rb +1 -25
  48. data/app/models/uffizzi_core/role.rb +1 -13
  49. data/app/models/uffizzi_core/secret.rb +1 -5
  50. data/app/models/uffizzi_core/template.rb +1 -15
  51. data/app/models/uffizzi_core/user.rb +1 -58
  52. data/app/models/uffizzi_core/user_project.rb +1 -10
  53. data/app/repositories/uffizzi_core/template_repo.rb +14 -6
  54. data/lib/uffizzi_core/version.rb +1 -1
  55. data/lib/uffizzi_core.rb +2 -0
  56. metadata +27 -2
@@ -20,67 +20,5 @@
20
20
  # @property deployed_by [object]
21
21
 
22
22
  class UffizziCore::Deployment < UffizziCore::ApplicationRecord
23
- include AASM
24
- include UffizziCore::StateMachineConcern
25
- include UffizziCore::DeploymentRepo
26
- extend Enumerize
27
-
28
- self.table_name = UffizziCore.table_names[:deployments]
29
-
30
- enumerize :kind, in: [:standard, :performance, :enterprise, :free], predicates: true, default: :standard
31
-
32
- belongs_to :project, touch: true
33
- belongs_to :deployed_by, class_name: UffizziCore::User.name, foreign_key: :deployed_by_id, optional: true
34
- belongs_to :template, optional: true
35
- belongs_to :compose_file, optional: true
36
-
37
- has_many :credentials, through: :project
38
- has_many :containers, dependent: :destroy, index_errors: true
39
- has_many :activity_items, dependent: :destroy
40
-
41
- has_one :ingress_container, -> { where(receive_incoming_requests: true) }, class_name: UffizziCore::Container.name
42
-
43
- validates :kind, presence: true
44
-
45
- enumerize :creation_source, in: [:manual, :continuous_preview, :compose_file_manual, :compose_file_continuous_preview], predicates: true,
46
- scope: true, default: :manual
47
-
48
- accepts_nested_attributes_for :containers, allow_destroy: true
49
-
50
- after_destroy_commit :clean
51
-
52
- def active_containers
53
- containers.active
54
- end
55
-
56
- aasm(:state) do
57
- state :active, initial: true
58
- state :failed
59
- state :disabled
60
-
61
- event :activate do
62
- transitions from: [:disabled], to: :active
63
- end
64
-
65
- event :fail, after: :after_fail do
66
- transitions from: [:active], to: :failed
67
- end
68
-
69
- event :disable, after: :after_disable do
70
- transitions from: [:active, :failed], to: :disabled
71
- end
72
- end
73
-
74
- def after_disable
75
- clean
76
- end
77
-
78
- def after_fail
79
- active_containers.each(&:disable!)
80
- end
81
-
82
- def clean
83
- active_containers.each(&:disable!)
84
- UffizziCore::Deployment::DeleteJob.perform_async(id)
85
- end
23
+ include UffizziCore::Concerns::Models::Deployment
86
24
  end
@@ -1,13 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class UffizziCore::Event < UffizziCore::ApplicationRecord
4
- include UffizziCore::EventRepo
5
- extend Enumerize
6
-
7
- self.table_name = UffizziCore.table_names[:events]
8
-
9
- enumerize :state, in: [:queued, :successful, :deployed, :failed, :building, :timeout, :cancelled, :deploying], predicates: true,
10
- scope: true
11
-
12
- belongs_to :activity_item, touch: true
4
+ include UffizziCore::Concerns::Models::Event
13
5
  end
@@ -1,27 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class UffizziCore::Invitation < UffizziCore::ApplicationRecord
4
- include AASM
5
- include UffizziCore::StateMachineConcern
6
- extend Enumerize
7
-
8
- self.table_name = UffizziCore.table_names[:invitations]
9
-
10
- enumerize :role, in: [:admin, :developer, :viewer], predicates: true
11
-
12
- belongs_to :entityable, polymorphic: true
13
- belongs_to :invited_by, class_name: UffizziCore::User.name, foreign_key: :invited_by_id
14
- belongs_to :invitee, class_name: UffizziCore::User.name, foreign_key: :invitee_id, optional: true
15
-
16
- validates :email, presence: true, 'uffizzi_core/email': true
17
- validates :token, presence: true, uniqueness: true
18
-
19
- aasm(:status) do
20
- state :pending, initial: true
21
- state :accepted
22
-
23
- event :accept do
24
- transitions from: :pending, to: :accepted
25
- end
26
- end
4
+ include UffizziCore::Concerns::Models::Invitation
27
5
  end
@@ -1,16 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class UffizziCore::Membership < UffizziCore::ApplicationRecord
4
- include UffizziCore::MembershipRepo
5
- extend Enumerize
6
-
7
- self.table_name = UffizziCore.table_names[:memberships]
8
-
9
- enumerize :role, in: [:admin, :developer, :viewer], predicates: true
10
- validates :role, presence: true
11
-
12
- belongs_to :account
13
- belongs_to :user
14
-
15
- validates :role, presence: true
4
+ include UffizziCore::Concerns::Models::Membership
16
5
  end
@@ -1,11 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class UffizziCore::Payment < UffizziCore::ApplicationRecord
4
- self.table_name = UffizziCore.table_names[:payments]
5
-
6
- belongs_to :account
7
-
8
- scope :succeeded, -> { where(status: :succeeded) }
9
- scope :pending, -> { where(status: :pending) }
10
- scope :failed, -> { where(status: :failed) }
4
+ include UffizziCore::Concerns::Models::Payment
11
5
  end
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class UffizziCore::Price < UffizziCore::ApplicationRecord
4
- include UffizziCore::PriceRepo
5
-
6
- self.table_name = UffizziCore.table_names[:prices]
7
-
8
- belongs_to :product
4
+ include UffizziCore::Concerns::Models::Price
9
5
  end
@@ -1,11 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class UffizziCore::Product < UffizziCore::ApplicationRecord
4
- include UffizziCore::ProductRepo
5
-
6
- self.table_name = UffizziCore.table_names[:products]
7
-
8
- has_one :price, dependent: :destroy
9
-
10
- UffizziCore::Product.inheritance_column = :sti
4
+ include UffizziCore::Concerns::Models::Product
11
5
  end
@@ -10,58 +10,5 @@
10
10
  # @property deployments [object<id: integer, domain: string>]
11
11
 
12
12
  class UffizziCore::Project < UffizziCore::ApplicationRecord
13
- include AASM
14
- include UffizziCore::StateMachineConcern
15
- include UffizziCore::ProjectRepo
16
-
17
- self.table_name = UffizziCore.table_names[:projects]
18
-
19
- belongs_to :account
20
-
21
- has_many :repos
22
- has_many :deployments, dependent: :destroy
23
- has_many :user_projects, dependent: :destroy
24
- has_many :users, through: :user_projects
25
- has_many :invitations, as: :entityable
26
- has_many :config_files, dependent: :destroy
27
- has_many :templates, dependent: :destroy
28
- has_many :credentials, through: :account
29
- has_many :compose_files, dependent: :destroy
30
- has_many :secrets, dependent: :destroy, as: :resource
31
-
32
- validates :name, presence: true, uniqueness: { scope: :account, message: 'Name already exists' }
33
- validates :slug, presence: true, uniqueness: { message: 'Project slug already taken' }
34
-
35
- aasm(:state) do
36
- state :active, initial: true
37
- state :disabled
38
-
39
- event :activate do
40
- transitions from: [:disabled], to: :active
41
- end
42
-
43
- event :disable, after: :after_disable do
44
- transitions from: [:active], to: :disabled
45
- end
46
- end
47
-
48
- def after_disable
49
- update(name: "#{name} deleted #{DateTime.current.strftime('%H:%M:%S-%m%d%Y')}")
50
- update(slug: "#{slug} deleted #{DateTime.current.strftime('%H:%M:%S-%m%d%Y')}")
51
- disable_deployments
52
- end
53
-
54
- def active_deployments
55
- deployments.active
56
- end
57
-
58
- def disable_deployments
59
- active_deployments.each do |deployment|
60
- UffizziCore::DeploymentService.disable!(deployment)
61
- end
62
- end
63
-
64
- def compose_file
65
- compose_files.main.first
66
- end
13
+ include UffizziCore::Concerns::Models::Project
67
14
  end
@@ -1,20 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class UffizziCore::Rating < UffizziCore::ApplicationRecord
4
- include AASM
5
-
6
- self.table_name = UffizziCore.table_names[:ratings]
7
-
8
- aasm(:state) do
9
- state :active, initial: true
10
- state :disabled
11
-
12
- event :activate do
13
- transitions from: [:disabled], to: :active
14
- end
15
-
16
- event :disable do
17
- transitions from: [:active], to: :disabled
18
- end
19
- end
4
+ include UffizziCore::Concerns::Models::Rating
20
5
  end
@@ -1,29 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class UffizziCore::Repo < UffizziCore::ApplicationRecord
4
- extend Enumerize
5
- include UffizziCore::RepoRepo
6
-
7
- self.table_name = UffizziCore.table_names[:repos]
8
-
9
- enumerize :kind, in: [:buildpacks18, :dockerfile, :dotnet, :gatsby, :barestatic], predicates: true
10
-
11
- belongs_to :project
12
- has_one :container, inverse_of: :repo, dependent: :destroy
13
- has_many :builds, dependent: :destroy
14
-
15
- validates :dockerfile_path, presence: true, if: :dockerfile?
16
- validates :delete_preview_after, numericality: { greater_than: 0, only_integer: true }, allow_nil: true
17
-
18
- def docker_hub?
19
- type == UffizziCore::Repo::DockerHub.name
20
- end
21
-
22
- def azure?
23
- type == UffizziCore::Repo::Azure.name
24
- end
25
-
26
- def google?
27
- type == UffizziCore::Repo::Google.name
28
- end
4
+ include UffizziCore::Concerns::Models::Repo
29
5
  end
@@ -1,17 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class UffizziCore::Role < UffizziCore::ApplicationRecord
4
- self.table_name = UffizziCore.table_names[:roles]
5
-
6
- has_and_belongs_to_many :users, join_table: UffizziCore.table_names[:users_roles]
7
-
8
- belongs_to :resource,
9
- polymorphic: true,
10
- optional: true
11
-
12
- validates :resource_type,
13
- inclusion: { in: Rolify.resource_types },
14
- allow_nil: true
15
-
16
- scopify
4
+ include UffizziCore::Concerns::Models::Role
17
5
  end
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class UffizziCore::Secret < ApplicationRecord
4
- self.table_name = UffizziCore.table_names[:secrets]
5
-
6
- belongs_to :resource, polymorphic: true
7
-
8
- validates :name, presence: true, uniqueness: { scope: :resource }
4
+ include UffizziCore::Concerns::Models::Secret
9
5
  end
@@ -1,19 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class UffizziCore::Template < UffizziCore::ApplicationRecord
4
- include UffizziCore::TemplateRepo
5
- extend Enumerize
6
-
7
- self.table_name = UffizziCore.table_names[:templates]
8
-
9
- belongs_to :added_by, class_name: UffizziCore::User.name, foreign_key: :added_by_id
10
- belongs_to :project, touch: true
11
- belongs_to :compose_file, optional: true
12
-
13
- has_many :deployments, dependent: :nullify
14
-
15
- enumerize :creation_source, in: [:manual, :compose_file, :system], predicates: true, scope: true
16
-
17
- validates :name, presence: true
18
- validates :name, uniqueness: { scope: :project }, if: -> { compose_file.blank? || compose_file.kind.main? }
4
+ include UffizziCore::Concerns::Models::Template
19
5
  end
@@ -1,62 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class UffizziCore::User < ActiveRecord::Base
4
- include AASM
5
- include ActiveModel::Validations
6
- include UffizziCore::StateMachineConcern
7
- include UffizziCore::HashidConcern
8
- include UffizziCore::UserRepo
9
- extend Enumerize
10
-
11
- self.table_name = UffizziCore.table_names[:users]
12
-
13
- rolify
14
-
15
- has_secure_password
16
-
17
- validates :email, presence: true, 'uffizzi_core/email': true, uniqueness: { case_sensitive: false }
18
- validates :password, allow_nil: true, length: { minimum: 8 }, on: :update
19
-
20
- has_many :memberships, dependent: :destroy
21
- has_many :accounts, through: :memberships
22
- has_many :user_projects
23
- has_many :projects, through: :user_projects
24
-
25
- has_one_attached :avatar
26
-
27
- enumerize :creation_source, in: [:system, :online_registration, :google, :sso], predicates: true
28
-
29
- def organizational_account
30
- accounts.find_by(kind: UffizziCore::Account.kind.organizational)
31
- end
32
-
33
- def active_projects
34
- projects.active
35
- end
36
-
37
- def deployments
38
- UffizziCore::Deployment.where(project_id: active_projects)
39
- end
40
-
41
- def full_name
42
- "#{first_name} #{last_name}"
43
- end
44
-
45
- aasm(:state) do
46
- state :initial, initial: true
47
- state :active
48
- state :disabled
49
-
50
- event :activate do
51
- transitions from: [:initial, :disabled], to: :active
52
- end
53
-
54
- event :disable do
55
- transitions from: [:initial, :active], to: :disabled
56
- end
57
- end
58
-
59
- def admin_access_to_project?(project)
60
- projects.by_ids(project).by_accounts(memberships.by_role_admin.select(:account_id)).exists?
61
- end
4
+ include UffizziCore::Concerns::Models::User
62
5
  end
@@ -1,14 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class UffizziCore::UserProject < UffizziCore::ApplicationRecord
4
- extend Enumerize
5
-
6
- self.table_name = UffizziCore.table_names[:user_projects]
7
-
8
- enumerize :role, in: [:admin, :developer, :viewer], predicates: true
9
- validates :role, presence: true
10
-
11
- belongs_to :user
12
- belongs_to :project
13
- belongs_to :invited_by, class_name: UffizziCore::User.name, foreign_key: :invited_by_id, optional: true
4
+ include UffizziCore::Concerns::Models::UserProject
14
5
  end
@@ -30,7 +30,7 @@ module UffizziCore::TemplateRepo
30
30
  ],
31
31
  }
32
32
 
33
- where('payload @> ?', general_query.to_json).where.not('payload @> ?', excluding_query.to_json)
33
+ where('templates.payload @> ?', general_query.to_json).where.not('templates.payload @> ?', excluding_query.to_json)
34
34
  }
35
35
 
36
36
  scope :by_docker_containers_with_delete_preview_when_image_tag_is_updated, ->(source, image, tag) {
@@ -47,7 +47,7 @@ module UffizziCore::TemplateRepo
47
47
  ],
48
48
  }
49
49
 
50
- where('payload @> ?', general_query.to_json)
50
+ where('templates.payload @> ?', general_query.to_json)
51
51
  }
52
52
 
53
53
  scope :by_github_containers_with_deploy_preview_when_pull_request_is_opened, ->(repository_id, branch) {
@@ -55,7 +55,7 @@ module UffizziCore::TemplateRepo
55
55
  containers_attributes: [
56
56
  {
57
57
  repo_attributes: {
58
- type: Repo::Github.name,
58
+ type: UffizziCore::Repo::Github.name,
59
59
  repository_id: repository_id,
60
60
  branch: branch,
61
61
  deploy_preview_when_pull_request_is_opened: true,
@@ -64,7 +64,7 @@ module UffizziCore::TemplateRepo
64
64
  ],
65
65
  }
66
66
 
67
- where('payload @> ?', query.to_json)
67
+ where('templates.payload @> ?', query.to_json)
68
68
  }
69
69
 
70
70
  scope :by_github_containers_with_delete_preview_when_pull_request_is_closed, ->(repository_id, branch) {
@@ -72,7 +72,7 @@ module UffizziCore::TemplateRepo
72
72
  containers_attributes: [
73
73
  {
74
74
  repo_attributes: {
75
- type: Repo::Github.name,
75
+ type: UffizziCore::Repo::Github.name,
76
76
  repository_id: repository_id,
77
77
  branch: branch,
78
78
  delete_preview_when_pull_request_is_closed: true,
@@ -81,7 +81,15 @@ module UffizziCore::TemplateRepo
81
81
  ],
82
82
  }
83
83
 
84
- where('payload @> ?', query.to_json)
84
+ where('templates.payload @> ?', query.to_json)
85
+ }
86
+
87
+ scope :by_compose_file_kind, ->(kind) {
88
+ left_joins(:compose_file).where(compose_files: { kind: kind })
89
+ }
90
+
91
+ scope :without_compose, -> {
92
+ left_joins(:compose_file).where(compose_files: { id: nil })
85
93
  }
86
94
  end
87
95
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module UffizziCore
4
- VERSION = '0.2.0'
4
+ VERSION = '0.2.1'
5
5
  end
data/lib/uffizzi_core.rb CHANGED
@@ -58,4 +58,6 @@ module UffizziCore
58
58
  users: :uffizzi_core_users,
59
59
  users_roles: :uffizzi_core_users_roles,
60
60
  }
61
+ mattr_accessor :user_creation_sources, default: [:system, :online_registration, :google, :sso]
62
+ mattr_accessor :user_project_roles, default: [:admin, :developer, :viewer]
61
63
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uffizzi_core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josh Thurman
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-06-07 00:00:00.000000000 Z
12
+ date: 2022-06-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: aasm
@@ -759,6 +759,31 @@ files:
759
759
  - app/jobs/uffizzi_core/deployment/delete_job.rb
760
760
  - app/jobs/uffizzi_core/deployment/deploy_containers_job.rb
761
761
  - app/jobs/uffizzi_core/deployment/manage_deploy_activity_item_job.rb
762
+ - app/lib/uffizzi_core/concerns/models/account.rb
763
+ - app/lib/uffizzi_core/concerns/models/activity_item.rb
764
+ - app/lib/uffizzi_core/concerns/models/build.rb
765
+ - app/lib/uffizzi_core/concerns/models/comment.rb
766
+ - app/lib/uffizzi_core/concerns/models/compose_file.rb
767
+ - app/lib/uffizzi_core/concerns/models/config_file.rb
768
+ - app/lib/uffizzi_core/concerns/models/container.rb
769
+ - app/lib/uffizzi_core/concerns/models/container_config_file.rb
770
+ - app/lib/uffizzi_core/concerns/models/coupon.rb
771
+ - app/lib/uffizzi_core/concerns/models/credential.rb
772
+ - app/lib/uffizzi_core/concerns/models/deployment.rb
773
+ - app/lib/uffizzi_core/concerns/models/event.rb
774
+ - app/lib/uffizzi_core/concerns/models/invitation.rb
775
+ - app/lib/uffizzi_core/concerns/models/membership.rb
776
+ - app/lib/uffizzi_core/concerns/models/payment.rb
777
+ - app/lib/uffizzi_core/concerns/models/price.rb
778
+ - app/lib/uffizzi_core/concerns/models/product.rb
779
+ - app/lib/uffizzi_core/concerns/models/project.rb
780
+ - app/lib/uffizzi_core/concerns/models/rating.rb
781
+ - app/lib/uffizzi_core/concerns/models/repo.rb
782
+ - app/lib/uffizzi_core/concerns/models/role.rb
783
+ - app/lib/uffizzi_core/concerns/models/secret.rb
784
+ - app/lib/uffizzi_core/concerns/models/template.rb
785
+ - app/lib/uffizzi_core/concerns/models/user.rb
786
+ - app/lib/uffizzi_core/concerns/models/user_project.rb
762
787
  - app/lib/uffizzi_core/rbac/user_access_service.rb
763
788
  - app/mailers/uffizzi_core/application_mailer.rb
764
789
  - app/models/concerns/uffizzi_core/hashid_concern.rb