jobshop 0.0.163 → 0.0.167
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +3 -3
- data/Rakefile +8 -17
- data/app/controllers/jobshop/application_controller.rb +5 -4
- data/app/controllers/jobshop/places_controller.rb +0 -4
- data/app/controllers/jobshop/users_controller.rb +0 -3
- data/app/mailers/jobshop/application_mailer.rb +0 -2
- data/app/mailers/jobshop/rfq_responder_mailer.rb +18 -0
- data/app/models/jobshop/ability.rb +1 -1
- data/app/models/jobshop/customer.rb +30 -0
- data/app/models/jobshop/customer/category.rb +19 -0
- data/app/models/jobshop/customer/contact.rb +28 -0
- data/app/models/jobshop/employee.rb +46 -0
- data/app/models/jobshop/employment.rb +25 -0
- data/app/models/jobshop/employment_version.rb +10 -0
- data/app/models/jobshop/inspection/boolean_criterion.rb +2 -2
- data/app/models/jobshop/inspection/deviation_criterion.rb +4 -4
- data/app/models/jobshop/inspection/limit_criterion.rb +6 -4
- data/app/models/jobshop/inspection/report.rb +2 -0
- data/app/models/jobshop/inspection/result.rb +2 -2
- data/app/models/jobshop/mailman.rb +22 -0
- data/app/models/jobshop/order.rb +2 -6
- data/app/models/jobshop/order_line.rb +2 -3
- data/app/models/jobshop/organization.rb +15 -6
- data/app/models/jobshop/place.rb +2 -0
- data/app/models/jobshop/product.rb +0 -3
- data/app/models/jobshop/rfq.rb +12 -6
- data/app/models/jobshop/user.rb +2 -17
- data/app/views/jobshop/rfq_responder_mailer/verified_contact.html.erb +5 -0
- data/app/views/jobshop/rfq_responder_mailer/verified_contact.text.erb +3 -0
- data/app/views/layouts/jobshop/application.html.haml +15 -0
- data/app/views/layouts/jobshop/mailer.html.erb +13 -0
- data/config/initializers/devise.rb +290 -0
- data/config/locales/devise.en.yml +64 -0
- data/config/routes.rb +1 -2
- data/db/migrate/20170311194758_initialize_jobshop.rb +42 -2
- data/db/migrate/20171216021339_create_organizations.rb +1 -4
- data/db/migrate/20171216021400_create_employees.rb +47 -0
- data/db/migrate/20171216021554_create_people.rb +13 -18
- data/db/migrate/20171216021853_create_customers.rb +57 -0
- data/db/migrate/20171216022020_create_places.rb +8 -9
- data/db/migrate/20171216022135_create_products.rb +6 -13
- data/db/migrate/20171216022605_create_orders.rb +19 -36
- data/db/migrate/20171216023018_create_roles.rb +5 -3
- data/db/migrate/20171216035357_create_things.rb +4 -4
- data/db/migrate/20171219022118_create_routing_processes.rb +15 -15
- data/db/migrate/20180107203241_create_inspections.rb +15 -14
- data/db/migrate/20181117023949_create_rfqs.rb +27 -19
- data/db/migrate/20181118014603_create_mailmen.rb +6 -4
- data/db/seeds.rb +126 -0
- data/lib/generators/jobshop/app/app_generator.rb +1 -1
- data/lib/generators/jobshop/app/templates/Procfile.tt +1 -0
- data/lib/generators/jobshop/app/templates/config/database.yml.tt +5 -5
- data/lib/generators/jobshop/{dummy/dummy_generator.rb → canary/canary_generator.rb} +13 -14
- data/lib/generators/jobshop/{dummy → canary}/templates/config/boot.rb.tt +0 -0
- data/lib/jobshop.rb +41 -12
- data/lib/jobshop/cli.rb +16 -82
- data/lib/jobshop/cli/app_generator.rb +38 -0
- data/lib/jobshop/cli/application.rb +14 -0
- data/lib/jobshop/cli/canary.rb +52 -0
- data/lib/jobshop/configuration.rb +16 -11
- data/lib/jobshop/engine.rb +39 -28
- data/lib/jobshop/helpers/migration.rb +78 -2
- data/lib/jobshop/mailroom/base_handler.rb +33 -0
- data/lib/jobshop/mailroom/null_handler.rb +10 -0
- data/lib/jobshop/mailroom/postmaster.rb +77 -0
- data/lib/jobshop/mailroom/rfq_handler.rb +39 -0
- data/lib/jobshop/version.rb +3 -1
- data/lib/tasks/jobshop_tasks.rake +7 -6
- metadata +98 -69
- data/app/controllers/concerns/email_token_validation.rb +0 -59
- data/app/controllers/concerns/jobshop/authentication_handler.rb +0 -15
- data/app/controllers/concerns/jobshop/authorization_handler.rb +0 -29
- data/app/controllers/jobshop/session_activations_controller.rb +0 -13
- data/app/controllers/jobshop/sessions_controller.rb +0 -20
- data/app/email_handlers/jobshop/rfq_handler.rb +0 -43
- data/app/models/jobshop/company.rb +0 -35
- data/app/models/jobshop/company/type.rb +0 -17
- data/app/models/jobshop/company_person.rb +0 -15
- data/app/models/jobshop/person.rb +0 -30
- data/app/models/jobshop/session_activation.rb +0 -30
- data/app/serializers/jobshop/test_user_serializer.rb +0 -10
- data/app/services/jobshop/authentication_service.rb +0 -20
- data/app/services/jobshop/authorization_service.rb +0 -30
- data/app/services/jobshop/jwt_service.rb +0 -17
- data/db/migrate/20171216021853_create_companies.rb +0 -64
- data/db/migrate/20171216023022_create_sessions.rb +0 -23
- data/lib/jobshop/cli/spinner.rb +0 -21
- data/lib/jobshop/dummy_app.rb +0 -190
- data/lib/jobshop/postmaster.rb +0 -89
@@ -1,59 +0,0 @@
|
|
1
|
-
class EmailTokenValidation
|
2
|
-
def self.before(controller)
|
3
|
-
@token = EmailToken.new(
|
4
|
-
controller.params.fetch(:user_email, nil),
|
5
|
-
controller.params.fetch(:email_authentication_token, nil)
|
6
|
-
)
|
7
|
-
|
8
|
-
if @token.valid?
|
9
|
-
sign_out_current_scope
|
10
|
-
sign_in token.user
|
11
|
-
token.destroy
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
class EmailToken
|
16
|
-
attr_reader :token
|
17
|
-
|
18
|
-
def initialize(email, token)
|
19
|
-
@email, @token = email, token
|
20
|
-
end
|
21
|
-
|
22
|
-
def valid?
|
23
|
-
present? && user && token && !expired? && secure_compare
|
24
|
-
end
|
25
|
-
|
26
|
-
private
|
27
|
-
def present?
|
28
|
-
@email.present? && @token.present?
|
29
|
-
end
|
30
|
-
|
31
|
-
def user
|
32
|
-
@user ||= Jobshop::User.where(email: @email)
|
33
|
-
.where.not(email_authentication_token_sent_at: nil).first
|
34
|
-
end
|
35
|
-
|
36
|
-
def destroy
|
37
|
-
user.update({
|
38
|
-
email_authentication_token: nil,
|
39
|
-
email_authentication_token_sent_at: nil
|
40
|
-
})
|
41
|
-
end
|
42
|
-
|
43
|
-
def secure_compare
|
44
|
-
# Notice how we use Devise.secure_compare to compare the token in the
|
45
|
-
# database with the token given in the params, mitigating timing
|
46
|
-
# attacks.
|
47
|
-
Devise.secure_compare(user.email_authentication_token, token)
|
48
|
-
end
|
49
|
-
|
50
|
-
def expired?
|
51
|
-
@expired ||= Time.now >= expires_on
|
52
|
-
end
|
53
|
-
|
54
|
-
def expires_on
|
55
|
-
# TODO: Make token expiration configurable in initializers/jobshop.rb.
|
56
|
-
@expires_on ||= user.email_authentication_token_sent_at + 6.hours
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
module Jobshop
|
2
|
-
module AuthenticationHandler
|
3
|
-
extend ActiveSupport::Concern
|
4
|
-
|
5
|
-
class InvalidCredentials < StandardError; end
|
6
|
-
|
7
|
-
included do
|
8
|
-
rescue_from AuthenticationHandler::InvalidCredentials, with: :unauthorized
|
9
|
-
end
|
10
|
-
|
11
|
-
private def unauthorized(e)
|
12
|
-
render({ json: { message: "Invalid credentials #{e.message}" } }, :unauthorized)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
module Jobshop
|
2
|
-
module AuthorizationHandler
|
3
|
-
extend ActiveSupport::Concern
|
4
|
-
|
5
|
-
class TokenMissing < StandardError; end
|
6
|
-
class TokenInvalid < StandardError; end
|
7
|
-
|
8
|
-
included do
|
9
|
-
before_action :authorize_request
|
10
|
-
|
11
|
-
rescue_from Jobshop::AuthorizationHandler::TokenMissing, with: :four_twenty_two
|
12
|
-
rescue_from Jobshop::AuthorizationHandler::TokenInvalid, with: :four_twenty_two
|
13
|
-
rescue_from ActiveRecord::RecordInvalid, with: :four_twenty_two
|
14
|
-
rescue_from ActiveRecord::RecordNotFound do |e|
|
15
|
-
render({ json: { message: e.message } }, :not_found)
|
16
|
-
end
|
17
|
-
|
18
|
-
attr_reader :current_user
|
19
|
-
end
|
20
|
-
|
21
|
-
private def four_twenty_two(e)
|
22
|
-
render({ json: { message: e.message } }, :unprocessable_entity)
|
23
|
-
end
|
24
|
-
|
25
|
-
private def authorize_request
|
26
|
-
@current_user = (AuthorizationService.new(request.headers).perform)[:user]
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
@@ -1,13 +0,0 @@
|
|
1
|
-
require_dependency "jobshop/application_controller"
|
2
|
-
|
3
|
-
module Jobshop
|
4
|
-
class SessionActivationsController < ApplicationController
|
5
|
-
def destroy
|
6
|
-
revoked_session.destroy
|
7
|
-
end
|
8
|
-
|
9
|
-
private def revoked_session
|
10
|
-
@revoked_session ||= current_user.session_activations.find(params[:id])
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
require_dependency "jobshop/application_controller"
|
2
|
-
|
3
|
-
module Jobshop
|
4
|
-
class SessionsController < ApplicationController
|
5
|
-
skip_before_action :authorize_request, only: :new
|
6
|
-
|
7
|
-
def new
|
8
|
-
token = AuthenticationService.new(
|
9
|
-
session_params[:email],
|
10
|
-
session_params[:password]
|
11
|
-
).perform
|
12
|
-
|
13
|
-
render(json: { auth_token: token })
|
14
|
-
end
|
15
|
-
|
16
|
-
private def session_params
|
17
|
-
params.permit(:email, :password)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,43 +0,0 @@
|
|
1
|
-
# frozen_string_literals: true
|
2
|
-
|
3
|
-
module Jobshop
|
4
|
-
class RFQHandler
|
5
|
-
def initialize(message, organization:)
|
6
|
-
@from = message.from.first
|
7
|
-
@subject = message.subject
|
8
|
-
@content = message.text_part.decoded
|
9
|
-
@organization = organization
|
10
|
-
end
|
11
|
-
|
12
|
-
def process
|
13
|
-
new_rfq = @organization.rfqs.create({
|
14
|
-
from: @from,
|
15
|
-
subject: @subject,
|
16
|
-
content: @content
|
17
|
-
})
|
18
|
-
|
19
|
-
if new_rfq.persisted?
|
20
|
-
# TODO: Send response email to customer
|
21
|
-
# TODO: Send rfq to quoting queue.
|
22
|
-
return new_rfq
|
23
|
-
else
|
24
|
-
# TODO: There was some kind of failure which should be logged.
|
25
|
-
return false
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
# Whether or not to copy the original to a new location after processing.
|
30
|
-
def copy_after_processing?
|
31
|
-
true
|
32
|
-
end
|
33
|
-
|
34
|
-
# Whether or not to delete the original item after processing.
|
35
|
-
def delete_after_processing?
|
36
|
-
true
|
37
|
-
end
|
38
|
-
|
39
|
-
def processed_copy_prefix
|
40
|
-
"rfqs/processed"
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
@@ -1,35 +0,0 @@
|
|
1
|
-
# frozen_string_literals: true
|
2
|
-
|
3
|
-
module Jobshop
|
4
|
-
class Company < ApplicationRecord
|
5
|
-
self.primary_keys = %i[ organization_id company_id ]
|
6
|
-
|
7
|
-
# Because we have a column named +type+, Rails wants to activate STI
|
8
|
-
# Disable it manually
|
9
|
-
self.inheritance_column = nil
|
10
|
-
|
11
|
-
after_initialize { self.company_id ||= SecureRandom.uuid if new_record? }
|
12
|
-
|
13
|
-
belongs_to :organization, inverse_of: :companies
|
14
|
-
|
15
|
-
has_many :company_people, inverse_of: :company,
|
16
|
-
foreign_key: %i[ organization_id company_id ]
|
17
|
-
|
18
|
-
belongs_to :created_by, class_name: "Jobshop::Person",
|
19
|
-
foreign_key: %i[ organization_id created_by_id ]
|
20
|
-
|
21
|
-
has_many :orders, inverse_of: :company,
|
22
|
-
foreign_key: %i[ organization_id company_id ]
|
23
|
-
|
24
|
-
has_many :people, through: :company_people,
|
25
|
-
foreign_key: %i[ organization_id person_id ]
|
26
|
-
|
27
|
-
has_many :rfqs, inverse_of: :company,
|
28
|
-
foreign_key: %i[ organization_id company_id ]
|
29
|
-
|
30
|
-
belongs_to :type, class_name: "Jobshop::Company::Type",
|
31
|
-
foreign_key: %i[ organization_id type_id ], inverse_of: :companies
|
32
|
-
|
33
|
-
validates :name, presence: true
|
34
|
-
end
|
35
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
# frozen_string_literals: true
|
2
|
-
|
3
|
-
module Jobshop
|
4
|
-
class Company::Type < ApplicationRecord
|
5
|
-
self.primary_keys = %i[ organization_id type_id ]
|
6
|
-
|
7
|
-
after_initialize { self.type_id ||= SecureRandom.uuid if new_record? }
|
8
|
-
|
9
|
-
belongs_to :organization, inverse_of: :company_types
|
10
|
-
|
11
|
-
has_many :companies, inverse_of: :type,
|
12
|
-
foreign_key: %i[ organization_id type_id ]
|
13
|
-
|
14
|
-
validates :name,
|
15
|
-
uniqueness: { scope: :organization_id, case_sensitive: false }
|
16
|
-
end
|
17
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
# frozen_string_literals: true
|
2
|
-
|
3
|
-
module Jobshop
|
4
|
-
class CompanyPerson < ApplicationRecord
|
5
|
-
self.primary_keys = %i[ organization_id company_id person_id ]
|
6
|
-
|
7
|
-
belongs_to :organization
|
8
|
-
|
9
|
-
belongs_to :company, inverse_of: :company_people,
|
10
|
-
foreign_key: %i[ organization_id company_id ]
|
11
|
-
|
12
|
-
belongs_to :person, inverse_of: :company_person,
|
13
|
-
foreign_key: %i[ organization_id person_id ]
|
14
|
-
end
|
15
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
# frozen_string_literals: true
|
2
|
-
|
3
|
-
module Jobshop
|
4
|
-
class Person < ApplicationRecord
|
5
|
-
self.primary_keys = %i[ organization_id person_id ]
|
6
|
-
|
7
|
-
after_initialize { self.person_id ||= SecureRandom.uuid if new_record? }
|
8
|
-
|
9
|
-
belongs_to :organization, inverse_of: :people
|
10
|
-
|
11
|
-
has_one :company_person, inverse_of: :person,
|
12
|
-
foreign_key: %i[ organization_id person_id ]
|
13
|
-
|
14
|
-
has_one :company, through: :company_person,
|
15
|
-
foreign_key: %i[ organization_id company_id ]
|
16
|
-
|
17
|
-
validates :email,
|
18
|
-
presence: { if: :email_required? },
|
19
|
-
format: { if: :email_required?, with: /\A[^@\s]+@[^@\s]+\z/ },
|
20
|
-
uniqueness: { if: :email_changed?, scope: :organization_id, case_sensitive: false }
|
21
|
-
|
22
|
-
def name
|
23
|
-
@name = [ forename, surname ].join(" ")
|
24
|
-
end
|
25
|
-
|
26
|
-
private def email_required?
|
27
|
-
true
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
module Jobshop
|
2
|
-
class SessionActivation < ApplicationRecord
|
3
|
-
LIMIT = 20
|
4
|
-
|
5
|
-
class << self
|
6
|
-
def active?(token)
|
7
|
-
token && where(activation_token: token).exists?
|
8
|
-
end
|
9
|
-
|
10
|
-
def activate(token)
|
11
|
-
activation = create!(activation_token: token)
|
12
|
-
enforce_active_session_quota
|
13
|
-
activation
|
14
|
-
end
|
15
|
-
|
16
|
-
def deactivate(token)
|
17
|
-
return unless token
|
18
|
-
where(activation_token: token).delete_all
|
19
|
-
end
|
20
|
-
|
21
|
-
def enforce_active_session_quota
|
22
|
-
order("created_at desc").offset(LIMIT).destroy_all
|
23
|
-
end
|
24
|
-
|
25
|
-
def exclusive(token)
|
26
|
-
where("activation_token != ?", id).delete_all
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
module Jobshop
|
2
|
-
class AuthenticationService
|
3
|
-
attr_reader :email, :password
|
4
|
-
|
5
|
-
def initialize(email, password)
|
6
|
-
@email = email
|
7
|
-
@password = password
|
8
|
-
end
|
9
|
-
|
10
|
-
def perform
|
11
|
-
Jobshop::JWTService.encode(user_id: user.id) if user
|
12
|
-
end
|
13
|
-
|
14
|
-
private def user
|
15
|
-
user = User.find_by(email: email)
|
16
|
-
user && user.authenticate(password) ||
|
17
|
-
raise(AuthenticationHandler::InvalidCredentials)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
module Jobshop
|
2
|
-
class AuthorizationService
|
3
|
-
attr_reader :headers
|
4
|
-
|
5
|
-
def initialize(headers = {})
|
6
|
-
@headers = headers
|
7
|
-
end
|
8
|
-
|
9
|
-
def perform
|
10
|
-
{ user: user }
|
11
|
-
end
|
12
|
-
|
13
|
-
private def user
|
14
|
-
@user ||= Jobshop::User.find(decoded_auth_token[:user_id]) if decoded_auth_token
|
15
|
-
rescue ActiveRecord::RecordNotFound => e
|
16
|
-
raise(AuthorizationHandler::TokenInvalid, e.message)
|
17
|
-
end
|
18
|
-
|
19
|
-
private def decoded_auth_token
|
20
|
-
@decoded_auth_token ||= JWTService.decode(http_auth_header)
|
21
|
-
end
|
22
|
-
|
23
|
-
private def http_auth_header
|
24
|
-
if headers["Authorization"].present?
|
25
|
-
return headers["Authorization"].split(" ").last
|
26
|
-
end
|
27
|
-
raise(AuthorizationHandler::TokenMissing)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
module Jobshop
|
2
|
-
class JWTService
|
3
|
-
HMAC_SECRET = "fixme"
|
4
|
-
|
5
|
-
def self.encode(payload, exp = 24.hours.from_now)
|
6
|
-
payload[:exp] = exp.to_i
|
7
|
-
JWT.encode(payload, HMAC_SECRET)
|
8
|
-
end
|
9
|
-
|
10
|
-
def self.decode(token)
|
11
|
-
body = JWT.decode(token, HMAC_SECRET)[0]
|
12
|
-
HashWithIndifferentAccess.new body
|
13
|
-
rescue JWT::DecodeError => e
|
14
|
-
raise AuthorizationHandler::TokenInvalid, e.message
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1,64 +0,0 @@
|
|
1
|
-
# frozen_string_literals: true
|
2
|
-
|
3
|
-
require "jobshop/helpers/migration.rb"
|
4
|
-
|
5
|
-
class CreateCompanies < ActiveRecord::Migration[5.2]
|
6
|
-
include Jobshop::Helpers::Migration
|
7
|
-
|
8
|
-
def change # rubocop:disable Metrics/MethodLength
|
9
|
-
create_table :jobshop_company_types, id: false do |t|
|
10
|
-
t.uuid :organization_id, null: false
|
11
|
-
t.uuid :type_id, null: false, default: "gen_random_uuid()"
|
12
|
-
t.index %i[ organization_id type_id ],
|
13
|
-
name: :idx_jobshop_company_types_pkey, unique: true
|
14
|
-
|
15
|
-
t.citext :name, null: false
|
16
|
-
t.index %i[ organization_id name ], unique: true
|
17
|
-
|
18
|
-
t.text :description
|
19
|
-
end
|
20
|
-
|
21
|
-
idx_table_name_pkey :jobshop_company_types
|
22
|
-
fk_organization_id :jobshop_company_types
|
23
|
-
|
24
|
-
create_table :jobshop_companies, id: false do |t|
|
25
|
-
t.uuid :organization_id, null: false
|
26
|
-
t.uuid :company_id, null: false, default: "gen_random_uuid()"
|
27
|
-
t.index %i[ organization_id company_id ], unique: true,
|
28
|
-
name: :idx_jobshop_companies_pkey
|
29
|
-
|
30
|
-
t.uuid :created_by_id, null: false
|
31
|
-
|
32
|
-
t.uuid :type_id, null: false
|
33
|
-
|
34
|
-
t.citext :name, null: false
|
35
|
-
t.index %i[ organization_id name ], unique: true
|
36
|
-
|
37
|
-
t.timestamps
|
38
|
-
end
|
39
|
-
|
40
|
-
idx_table_name_pkey :jobshop_companies
|
41
|
-
fk_organization_id :jobshop_companies
|
42
|
-
fk_created_by_id :jobshop_companies
|
43
|
-
foreign_key :jobshop_companies, :jobshop_company_types,
|
44
|
-
%i[ organization_id type_id ]
|
45
|
-
|
46
|
-
create_table :jobshop_company_people, id: false do |t|
|
47
|
-
t.uuid :organization_id, null: false
|
48
|
-
t.uuid :company_id, null: false
|
49
|
-
t.uuid :person_id, null: false
|
50
|
-
t.index %i[ organization_id company_id person_id ],
|
51
|
-
name: :idx_jobshop_company_people_pkey, unique: true
|
52
|
-
|
53
|
-
t.index %i[ organization_id company_id ],
|
54
|
-
name: :idx_jobshop_company_organization_company_ids
|
55
|
-
end
|
56
|
-
|
57
|
-
idx_table_name_pkey :jobshop_company_people
|
58
|
-
fk_organization_id :jobshop_company_people
|
59
|
-
foreign_key :jobshop_company_people, :jobshop_companies,
|
60
|
-
%i[ organization_id company_id ]
|
61
|
-
foreign_key :jobshop_company_people, :jobshop_people,
|
62
|
-
%i[ organization_id person_id ]
|
63
|
-
end
|
64
|
-
end
|