mno-enterprise-core 3.1.4 → 3.2.0

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 (77) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/images/mno_enterprise/logo-intuit.png +0 -0
  3. data/app/assets/images/mno_enterprise/main-logo.png +0 -0
  4. data/app/assets/stylesheets/mno_enterprise/mail.css +1 -4
  5. data/app/controllers/mno_enterprise/application_controller.rb +1 -1
  6. data/app/helpers/mno_enterprise/application_helper.rb +7 -7
  7. data/app/models/mno_enterprise/app.rb +12 -3
  8. data/app/models/mno_enterprise/app_answer.rb +13 -0
  9. data/app/models/mno_enterprise/app_comment.rb +10 -0
  10. data/app/models/mno_enterprise/app_feedback.rb +7 -0
  11. data/app/models/mno_enterprise/app_question.rb +9 -0
  12. data/app/models/mno_enterprise/app_review.rb +7 -0
  13. data/app/models/mno_enterprise/base_resource.rb +6 -1
  14. data/app/models/mno_enterprise/identity.rb +24 -0
  15. data/app/models/mno_enterprise/impac/alert.rb +10 -0
  16. data/app/models/mno_enterprise/impac/dashboard.rb +10 -11
  17. data/app/models/mno_enterprise/impac/kpi.rb +4 -2
  18. data/app/models/mno_enterprise/impac/widget.rb +4 -1
  19. data/app/models/mno_enterprise/team.rb +1 -33
  20. data/app/models/mno_enterprise/user.rb +109 -28
  21. data/app/views/system_notifications/email-change.html.erb +27 -0
  22. data/app/views/system_notifications/email-change.text.erb +10 -0
  23. data/app/views/system_notifications/password-change.html.erb +25 -0
  24. data/app/views/system_notifications/password-change.text.erb +7 -0
  25. data/app/views/system_notifications/reconfirmation-instructions.html.erb +7 -5
  26. data/app/views/system_notifications/reconfirmation-instructions.text.erb +3 -2
  27. data/config/initializers/config.rb +5 -0
  28. data/config/locales/models/user/en.yml +5 -0
  29. data/config/locales/templates/components/en.yml +9 -0
  30. data/config/locales/templates/dashboard/en.yml +14 -0
  31. data/config/locales/templates/dashboard/marketplace/en.yml +111 -8
  32. data/config/locales/templates/dashboard/organization/en.yml +1 -0
  33. data/config/locales/templates/impac/dock/en.yml +28 -0
  34. data/config/locales/views/auth/shared/en.yml +1 -2
  35. data/config/locales/views/webhook/o_auth/providers/en.yml +11 -6
  36. data/lib/devise/hooks/lockable.rb +13 -0
  37. data/lib/devise/models/remote_authenticatable.rb +31 -5
  38. data/lib/generators/mno_enterprise/install/install_generator.rb +7 -0
  39. data/lib/generators/mno_enterprise/install/templates/Procfile +1 -1
  40. data/lib/generators/mno_enterprise/install/templates/Procfile.dev +1 -1
  41. data/lib/generators/mno_enterprise/install/templates/config/application.yml +17 -0
  42. data/lib/generators/mno_enterprise/install/templates/config/initializers/mno_enterprise.rb +8 -3
  43. data/lib/generators/mno_enterprise/install/templates/config/newrelic.yml +46 -0
  44. data/lib/generators/mno_enterprise/install/templates/config/puma.rb +56 -0
  45. data/lib/generators/mno_enterprise/install/templates/config/settings/production.yml +1 -1
  46. data/lib/generators/mno_enterprise/install/templates/config/settings/uat.yml +1 -1
  47. data/lib/generators/mno_enterprise/install/templates/config/settings.yml +21 -0
  48. data/lib/generators/mno_enterprise/install/templates/stylesheets/variables.less +3 -0
  49. data/lib/her_extension/model/associations/association_proxy.rb +10 -6
  50. data/lib/mno_enterprise/concerns/controllers/auth/confirmations_controller.rb +1 -1
  51. data/lib/mno_enterprise/concerns/controllers/auth/omniauth_callbacks_controller.rb +203 -0
  52. data/lib/mno_enterprise/concerns/models/ability.rb +28 -0
  53. data/lib/mno_enterprise/concerns/models/app_instance.rb +22 -4
  54. data/lib/mno_enterprise/concerns/models/intercom_user.rb +28 -0
  55. data/lib/mno_enterprise/concerns/models/organization.rb +14 -1
  56. data/lib/mno_enterprise/concerns/models/team.rb +67 -0
  57. data/lib/mno_enterprise/core.rb +22 -3
  58. data/lib/mno_enterprise/impac_client.rb +19 -0
  59. data/lib/mno_enterprise/mail_adapters/mandrill_adapter.rb +4 -1
  60. data/lib/mno_enterprise/testing_support/factories/app_review.rb +51 -0
  61. data/lib/mno_enterprise/testing_support/factories/apps.rb +12 -10
  62. data/lib/mno_enterprise/testing_support/factories/identity.rb +9 -0
  63. data/lib/mno_enterprise/testing_support/factories/impac/alerts.rb +18 -0
  64. data/lib/mno_enterprise/testing_support/factories/impac/kpis.rb +5 -9
  65. data/lib/mno_enterprise/testing_support/factories/users.rb +4 -0
  66. data/lib/mno_enterprise/testing_support/jpi_v1_test_helper.rb +39 -0
  67. data/lib/mno_enterprise/testing_support/organizations_shared_helpers.rb +2 -1
  68. data/lib/mno_enterprise/testing_support/shared_examples/jpi_v1_admin.rb +38 -0
  69. data/lib/mno_enterprise/version.rb +1 -1
  70. data/spec/lib/devise/model/remote_authenticable_spec.rb +76 -0
  71. data/spec/lib/mno_enterprise/impac_client_spec.rb +31 -0
  72. data/spec/mno_enterprise_spec.rb +7 -8
  73. data/spec/models/mno_enterprise/app_spec.rb +1 -1
  74. data/spec/models/mno_enterprise/identity_spec.rb +39 -0
  75. data/spec/models/mno_enterprise/organization_spec.rb +19 -2
  76. data/spec/models/mno_enterprise/user_spec.rb +238 -0
  77. metadata +86 -22
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9b2136652697969f675be8a746722177281d2ddd
4
- data.tar.gz: 364a904419110a78129648cbe3c96a550dfa2593
3
+ metadata.gz: 04d03f902dba4992c2dcf7dfc79bcde79328f734
4
+ data.tar.gz: 7abe37f46afd67baf9b2c01aa6e71f915887e91e
5
5
  SHA512:
6
- metadata.gz: 7fbcaa5cc80fa061845fe612054fab9b203664a34ef781b154b127b17c93ecedbfad105d78c7c354f7593e4dbd3491fa243ed7c4151d5d4395c28844fc352bb6
7
- data.tar.gz: 64e9c84dbf5b379182ea162b808a89b377a8f04d8052c48687c65b2b2981625eda367cc0d5f836ca9ec79d783a4fc494161a10f4ddd135ac5344f32512b3e1b4
6
+ metadata.gz: f102931d14d82727074363e7492e5212005693ec5124cbf13cbaf4f6366a2bbac9b661f5f48661ec4a20b4f893a4aa7e03e2bca728738f9e728b31a4991c87fb
7
+ data.tar.gz: 504de1f76c89a3a3b8f77c4948b6a5bc47b32b16437ff02e95746584e90c5a3bbff26e2989b5ee2efa70e858b8332513f6c74388a0046ed9305e4935f2b1a5a4
@@ -8,11 +8,8 @@
8
8
  }
9
9
  .header img{
10
10
  display: block;
11
- width: 40%;
12
- min-width: 200px;
13
- max-width: 400px;
14
-
15
11
  margin: 0 auto;
12
+ max-height: 120px;
16
13
  }
17
14
 
18
15
  .footer {
@@ -36,7 +36,7 @@ module MnoEnterprise
36
36
 
37
37
  def set_default_meta
38
38
  @meta = {}
39
- @meta[:title] = "Application"
39
+ @meta[:title] = MnoEnterprise.app_name
40
40
  @meta[:description] = "Enterprise Applications"
41
41
  end
42
42
 
@@ -1,18 +1,18 @@
1
1
  module MnoEnterprise
2
2
  module ApplicationHelper
3
-
3
+
4
4
  def support_email
5
5
  MnoEnterprise.support_email
6
6
  end
7
-
7
+
8
8
  # Re-implement Devise filter
9
9
  # For some reasons the original Devise filter seems to ignore the
10
10
  # mnoe prefix when using custom devise controllers
11
- def authenticate_user!
11
+ def authenticate_user!(_favourite=nil, opts={})
12
12
  redirect_to(new_user_session_path) unless current_user
13
13
  true
14
14
  end
15
-
15
+
16
16
  # Redirect a signed in user to the confirmation
17
17
  # lounge if unconfirmed
18
18
  def redirect_to_lounge_if_unconfirmed
@@ -21,17 +21,17 @@ module MnoEnterprise
21
21
  end
22
22
  return true
23
23
  end
24
-
24
+
25
25
  # Redirect to signup page if user not authenticated
26
26
  def authenticate_user_or_signup!
27
27
  unless current_user
28
28
  redirect_to new_user_registration_path
29
29
  false
30
30
  end
31
-
31
+
32
32
  true
33
33
  end
34
-
34
+
35
35
  def notice_hash(notice)
36
36
  return {} unless notice
37
37
  # TODO: refactor
@@ -31,8 +31,17 @@ module MnoEnterprise
31
31
  scope :cloud, -> { where(stack: 'cloud') }
32
32
 
33
33
  attributes :id, :uid, :nid, :name, :description, :tiny_description, :created_at, :updated_at, :logo, :website, :slug,
34
- :categories, :key_benefits, :key_features, :testimonials, :worldwide_usage, :tiny_description,
35
- :popup_description, :stack, :terms_url, :pictures, :tags, :api_key, :metadata_url, :metadata, :details, :rank
34
+ :categories, :key_benefits, :key_features, :testimonials, :worldwide_usage, :tiny_description,
35
+ :popup_description, :stack, :terms_url, :pictures, :tags, :api_key, :metadata_url, :metadata, :details, :rank,
36
+ :multi_instantiable, :subcategories, :reviews, :average_rating, :running_instances_count
37
+
38
+
39
+ #================================
40
+ # Associations
41
+ #================================
42
+ has_many :reviews, class_name: 'AppReview'
43
+ has_many :feedbacks, class_name: 'AppFeedback'
44
+ has_many :questions, class_name: 'AppQuestion'
36
45
 
37
46
  # Return the list of available categories
38
47
  def self.categories(list = nil)
@@ -55,7 +64,7 @@ module MnoEnterprise
55
64
  end
56
65
 
57
66
  # Methods for appinfo flags
58
- %w(coming_soon single_billing).each do |method|
67
+ %w(coming_soon single_billing add_on).each do |method|
59
68
  define_method "#{method}?" do
60
69
  appinfo.presence && appinfo[method]
61
70
  end
@@ -0,0 +1,13 @@
1
+ module MnoEnterprise
2
+ # List All Answers
3
+ # MnoEnterprise::AppAnswer.all
4
+ # Create an AppAnswer
5
+ # MnoEnterprise::AppAnswer.create(description: "This is my answer", organization_id: 3, user_id: 9, app_id: 43, question_id: 1)
6
+
7
+ # An AppAnswer belong to an AppQuestion
8
+ class AppAnswer < AppReview
9
+ attributes :question_id
10
+
11
+ belongs_to :question, class_name: 'AppQuestion', foreign_key: :question_id
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ module MnoEnterprise
2
+
3
+ # Create an AppComment
4
+ # MnoEnterprise::AppComment.create(description: "description", organization_id: 3, user_id: 9, app_id: 43, feedback_id: 1)
5
+ class AppComment < AppReview
6
+ attributes :feeback_id
7
+
8
+ belongs_to :feedback, class_name: 'AppFeedback', foreign_key: :feedback_id
9
+ end
10
+ end
@@ -0,0 +1,7 @@
1
+ module MnoEnterprise
2
+ # Create an AppFeedback
3
+ # MnoEnterprise::AppFeedback.create(description: "description", organization_id: 3, user_id: 9, app_id: 43, rating: 5)
4
+ class AppFeedback < AppReview
5
+ belongs_to :app
6
+ end
7
+ end
@@ -0,0 +1,9 @@
1
+ module MnoEnterprise
2
+ # Create an AppQuestion
3
+ # MnoEnterprise::AppQuestion.create(description: "This is my question", organization_id: 3, user_id: 9, app_id: 43)
4
+ class AppQuestion < AppReview
5
+ belongs_to :app
6
+
7
+ scope :search, ->(search) { where("description.like" => "%#{search}%") }
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ module MnoEnterprise
2
+ class AppReview < BaseResource
3
+ attributes :id, :rating, :description, :created_at, :updated_at, :app_id, :user_id, :organization_id, :status, :parent_id, :type, :edited, :edited_by_name, :edited_by_admin_role, :edited_by_id
4
+
5
+ scope :approved, -> { where(status: 'approved') }
6
+ end
7
+ end
@@ -49,6 +49,11 @@ module MnoEnterprise
49
49
  self.where(hash).limit(1).first
50
50
  end
51
51
 
52
+ # ActiveRecord Compatibility for Her
53
+ def exists?(hash)
54
+ find_by(hash).present?
55
+ end
56
+
52
57
  # ActiveRecord Compatibility for Her
53
58
  # Returns the class descending directly from MnoEnterprise::BaseResource, or
54
59
  # an abstract class, if any, in the inheritance hierarchy.
@@ -146,7 +151,7 @@ module MnoEnterprise
146
151
  raise_record_invalid if self.errors.any?
147
152
  ret
148
153
  else
149
- false
154
+ raise_record_invalid
150
155
  end
151
156
  end
152
157
 
@@ -0,0 +1,24 @@
1
+ # == Schema Information
2
+ #
3
+ # Endpoint: /v1/identities
4
+ #
5
+ # id :integer not null, primary key
6
+ # user_id :integer
7
+ # provider :string(255)
8
+ # uid :string(255)
9
+ # created_at :datetime not null
10
+ # updated_at :datetime not null
11
+ #
12
+
13
+ module MnoEnterprise
14
+ class Identity < BaseResource
15
+
16
+ attributes :id, :user_id, :provider, :uid, :created_at, :updated_at
17
+
18
+ belongs_to :user, class_name: 'MnoEnterprise::User'
19
+
20
+ def self.find_for_oauth(auth)
21
+ where(uid: auth.uid, provider: auth.provider).first_or_create
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,10 @@
1
+ module MnoEnterprise
2
+ class Impac::Alert < BaseResource
3
+
4
+ attributes :title, :webhook, :service, :settings, :sent
5
+
6
+ belongs_to :kpi, class_name: 'MnoEnterprise::Impac::Kpi', foreign_key: 'impac_kpi_id'
7
+ has_many :recipients, class_name: 'MnoEnterprise::User'
8
+
9
+ end
10
+ end
@@ -1,10 +1,10 @@
1
1
  module MnoEnterprise
2
2
  class Impac::Dashboard < BaseResource
3
3
 
4
- attributes :name, :widgets_order, :organization_ids, :widgets_templates, :currency
4
+ attributes :full_name, :widgets_order, :settings, :organization_ids, :widgets_templates, :currency
5
5
 
6
- has_many :widgets, class_name: 'MnoEnterprise::Impac::Widget', dependent: :destroy
7
- has_many :kpis, class_name: 'MnoEnterprise::Impac::Kpi', dependent: :destroy
6
+ has_many :widgets, class_name: 'MnoEnterprise::Impac::Widget'
7
+ has_many :kpis, class_name: 'MnoEnterprise::Impac::Kpi'
8
8
  belongs_to :owner, polymorphic: true
9
9
 
10
10
  #============================================
@@ -18,13 +18,12 @@ module MnoEnterprise
18
18
 
19
19
  # Return all the organizations linked to this dashboard and to which
20
20
  # the user has access
21
- def organizations
22
- MnoEnterprise::Organization.where('uid.in' => self.organization_ids).to_a
23
- end
24
-
25
- def sorted_widgets
26
- order = self.widgets_order.map(&:to_i) | self.widgets.map{|w| w.id }
27
- order.map { |id| self.widgets.to_a.find{ |w| w.id == id} }.compact
21
+ def organizations(org_list = nil)
22
+ if org_list
23
+ org_list.to_a.select { |e| self.organization_ids.include?(e.uid) }
24
+ else
25
+ MnoEnterprise::Organization.where('uid.in' => self.organization_ids).to_a
26
+ end
28
27
  end
29
28
 
30
29
  # Filter widgets list based on config
@@ -39,7 +38,7 @@ module MnoEnterprise
39
38
  end
40
39
 
41
40
  def to_audit_event
42
- name
41
+ {name: name}
43
42
  end
44
43
  end
45
44
  end
@@ -1,9 +1,11 @@
1
1
  module MnoEnterprise
2
2
  class Impac::Kpi < BaseResource
3
3
 
4
- attributes :settings, :targets, :extra_params, :endpoint, :source, :element_watched
4
+ attributes :settings, :targets, :extra_params, :endpoint, :source, :element_watched, :extra_watchables
5
5
 
6
6
  belongs_to :dashboard, class_name: 'MnoEnterprise::Impac::Dashboard'
7
-
7
+ belongs_to :widget, class_name: 'MnoEnterprise::Impac::Widget'
8
+ has_many :alerts, class_name: 'MnoEnterprise::Impac::Alert'
9
+
8
10
  end
9
11
  end
@@ -3,10 +3,13 @@ module MnoEnterprise
3
3
 
4
4
  attributes :name, :width, :widget_category, :settings
5
5
 
6
+ alias_attribute :endpoint, :widget_category
7
+
6
8
  belongs_to :dashboard, class_name: 'MnoEnterprise::Impac::Dashboard'
9
+ has_many :kpis, class_name: 'MnoEnterprise::Impac::Kpi'
7
10
 
8
11
  def to_audit_event
9
- name
12
+ {name: name}
10
13
  end
11
14
 
12
15
  end
@@ -13,38 +13,6 @@
13
13
 
14
14
  module MnoEnterprise
15
15
  class Team < BaseResource
16
-
17
- attributes :id, :name, :organization_id
18
-
19
- #=====================================
20
- # Associations
21
- #=====================================
22
- belongs_to :organization, class_name: 'MnoEnterprise::Organization'
23
- has_many :users, class_name: 'MnoEnterprise::User'
24
- has_many :app_instances, class_name: 'MnoEnterprise::AppInstance'
25
-
26
-
27
- # Add a user to the team
28
- # TODO: specs
29
- def add_user(user)
30
- self.users.create(id: user.id)
31
- end
32
-
33
- # Remove a user from the team
34
- # TODO: specs
35
- def remove_user(user)
36
- self.users.destroy(id: user.id)
37
- end
38
-
39
- # Set the app_instance permissions of this team
40
- # Accept a collection of hashes or an array of ids
41
- # TODO: specs
42
- def set_access_to(collection_or_array)
43
- # Empty arrays do not seem to be passed in the request. Force value in this case
44
- list = collection_or_array.empty? ? [""] : collection_or_array
45
- self.put(data: { set_access_to: list })
46
- self.reload
47
- self
48
- end
16
+ include MnoEnterprise::Concerns::Models::Team
49
17
  end
50
18
  end
@@ -1,6 +1,6 @@
1
1
  # == Schema Information
2
2
  #
3
- # Endpoint:
3
+ # Endpoint:
4
4
  # - /v1/users
5
5
  # - /v1/organizations/:organization_id/users
6
6
  #
@@ -27,31 +27,36 @@
27
27
  # created_at :datetime not null
28
28
  # updated_at :datetime not null
29
29
  # name :string(255)
30
- # surname :string(255)
31
- # company :string(255)
30
+ # surname :string(255)
31
+ # company :string(255)
32
32
  # phone :string(255)
33
33
  # phone_country_code :string(255)
34
34
  # geo_country_code :string(255)
35
35
  # geo_state_code :string(255)
36
- # geo_city :string(255)
37
- # website :string(255)
36
+ # geo_city :string(255)
37
+ # website :string(255)
38
+ # api_key :string(255)
39
+ # api_secret :string(255)
38
40
  #
39
41
 
40
42
  module MnoEnterprise
41
43
  class User < BaseResource
44
+ include MnoEnterprise::Concerns::Models::IntercomUser if MnoEnterprise.intercom_enabled?
42
45
  extend Devise::Models
43
-
46
+
44
47
  # Note: password and encrypted_password are write-only attributes and are never returned by
45
48
  # the remote API. If you are looking for a session token, use authenticatable_salt
46
- attributes :uid, :email, :password, :current_password, :password_confirmation, :authenticatable_salt, :encrypted_password, :reset_password_token, :reset_password_sent_at,
47
- :remember_created_at, :sign_in_count, :current_sign_in_at, :last_sign_in_at, :current_sign_in_ip,
48
- :last_sign_in_ip, :confirmation_token, :confirmed_at, :confirmation_sent_at, :unconfirmed_email,
49
- :failed_attempts, :unlock_token, :locked_at, :name, :surname, :company, :phone, :phone_country_code,
50
- :geo_country_code, :geo_state_code, :geo_city, :website, :orga_on_create, :sso_session, :current_password_required, :admin_role
51
-
49
+ attributes :uid, :email, :password, :current_password, :password_confirmation, :authenticatable_salt, :encrypted_password, :reset_password_token, :reset_password_sent_at,
50
+ :remember_created_at, :sign_in_count, :current_sign_in_at, :last_sign_in_at, :current_sign_in_ip,
51
+ :last_sign_in_ip, :confirmation_token, :confirmed_at, :confirmation_sent_at, :unconfirmed_email,
52
+ :failed_attempts, :unlock_token, :locked_at, :name, :surname, :company, :phone, :phone_country_code,
53
+ :geo_country_code, :geo_state_code, :geo_city, :website, :orga_on_create, :sso_session, :current_password_required, :admin_role,
54
+ :api_key, :api_secret, :developer, :kpi_enabled, :external_id, :meta_data
55
+
52
56
  define_model_callbacks :validation #required by Devise
53
57
  devise :remote_authenticatable, :registerable, :recoverable, :rememberable,
54
- :trackable, :validatable, :lockable, :confirmable, :timeoutable, :password_expirable
58
+ :trackable, :validatable, :lockable, :confirmable, :timeoutable, :password_expirable,
59
+ :omniauthable, omniauth_providers: Devise.omniauth_providers
55
60
 
56
61
  #================================
57
62
  # Validation
@@ -67,9 +72,12 @@ module MnoEnterprise
67
72
  has_many :organizations, class_name: 'MnoEnterprise::Organization'
68
73
  has_many :org_invites, class_name: 'MnoEnterprise::OrgInvite'
69
74
  has_one :deletion_request, class_name: 'MnoEnterprise::DeletionRequest'
70
- has_many :dashboards, class_name: 'MnoEnterprise::Impac::Dashboard'
71
75
  has_many :teams, class_name: 'MnoEnterprise::Team'
72
76
 
77
+ # Impac
78
+ has_many :dashboards, class_name: 'MnoEnterprise::Impac::Dashboard'
79
+ has_many :alerts, class_name: 'MnoEnterprise::Impac::Alert'
80
+
73
81
  #================================
74
82
  # Callbacks
75
83
  #================================
@@ -82,25 +90,26 @@ module MnoEnterprise
82
90
  # Return nil in case of failure
83
91
  def self.authenticate(auth_hash)
84
92
  u = self.post("user_sessions", auth_hash)
85
-
93
+
86
94
  if u && u.id
87
95
  u.clear_attribute_changes!
88
96
  return u
89
97
  end
90
-
98
+
91
99
  nil
92
100
  end
93
-
101
+
102
+
94
103
  #================================
95
104
  # Devise Confirmation
96
105
  # TODO: should go in a module
97
106
  #================================
98
-
99
-
107
+
108
+
100
109
  # Override Devise to allow confirmation via original token
101
110
  # Less secure but useful if user has been created by Maestrano Enterprise
102
111
  # (happens when an orga_invite is sent to a new user)
103
- #
112
+ #
104
113
  # Find a user by its confirmation token and try to confirm it.
105
114
  # If no user is found, returns a new user with an error.
106
115
  # If the user is already confirmed, create an error for the user
@@ -110,23 +119,23 @@ module MnoEnterprise
110
119
  confirmable.perform_confirmation(confirmation_token)
111
120
  confirmable
112
121
  end
113
-
122
+
114
123
  # Find a user using a confirmation token
115
124
  def self.find_for_confirmation(confirmation_token)
116
125
  original_token = confirmation_token
117
126
  confirmation_token = Devise.token_generator.digest(self, :confirmation_token, confirmation_token)
118
-
127
+
119
128
  confirmable = find_or_initialize_with_error_by(:confirmation_token, confirmation_token)
120
129
  confirmable = find_or_initialize_with_error_by(:confirmation_token, original_token) if confirmable.errors.any?
121
130
  confirmable
122
131
  end
123
-
132
+
124
133
  # Confirm the user and store confirmation_token
125
134
  def perform_confirmation(confirmation_token)
126
135
  self.confirm if self.persisted?
127
136
  self.confirmation_token = confirmation_token
128
137
  end
129
-
138
+
130
139
  # It may happen that that the errors attribute become nil, which breaks the controller logic (rails responder)
131
140
  # This getter ensures that 'errors' is always initialized
132
141
  def errors
@@ -158,19 +167,28 @@ module MnoEnterprise
158
167
  def failed_attempts
159
168
  read_attribute(:failed_attempts) || 0
160
169
  end
161
-
170
+
162
171
  # Override Devise default method
163
172
  def authenticatable_salt
164
173
  read_attribute(:authenticatable_salt)
165
174
  end
166
-
175
+
167
176
  # Return the role of this user for the provided
168
177
  # organization
169
178
  def role(organization = nil)
170
179
  # Return cached version if available
171
180
  return self.read_attribute(:role) if !organization
172
-
173
- org = self.organizations.to_a.find { |o| o.id.to_s == organization.id.to_s }
181
+
182
+ # Find in arrays if organizations have been fetched
183
+ # already. Perform remote query otherwise
184
+ org = begin
185
+ if self.organizations.loaded?
186
+ self.organizations.to_a.find { |e| e.id == organization.id }
187
+ else
188
+ self.organizations.where(id: organization.id).first
189
+ end
190
+ end
191
+
174
192
  org ? org.role : nil
175
193
  end
176
194
 
@@ -182,6 +200,69 @@ module MnoEnterprise
182
200
  def refresh_user_cache
183
201
  self.reload
184
202
  Rails.cache.write(['user', self.to_key], self)
203
+ # singleton can't be dumped / undefined method `marshal_dump' for nil
204
+ rescue TypeError, NoMethodError
205
+ expire_user_cache
206
+ end
207
+
208
+ # Used by omniauth providers to find or create users
209
+ # on maestrano
210
+ # See Auth::OmniauthCallbacksController
211
+ def self.find_for_oauth(auth, opts = {}, signed_in_resource = nil)
212
+ # Get the identity and user if they exist
213
+ identity = Identity.find_for_oauth(auth)
214
+
215
+ # If a signed_in_resource is provided it always overrides the existing user
216
+ # to prevent the identity being locked with accidentally created accounts.
217
+ # Note that this may leave zombie accounts (with no associated identity) which
218
+ # can be cleaned up at a later date.
219
+ user = signed_in_resource ? signed_in_resource : identity.user
220
+
221
+ # Create the user if needed
222
+ if user.blank? # WTF is wrong with user.nil?
223
+ # Get the existing user by email.
224
+ email = auth.info.email
225
+ user = self.where(email: email).first if email
226
+
227
+ # Create the user if it's a new registration
228
+ if user.nil?
229
+ user = create_from_omniauth(auth, opts.except(:authorized_link_to_email))
230
+ elsif auth.provider == 'intuit'
231
+ unless opts[:authorized_link_to_email] == user.email
232
+ # Intuit email is NOT a confirmed email. Therefore we need to ask the user to
233
+ # login the old fashion to make sure it is the right user!
234
+ fail(SecurityError, 'reconfirm credentials')
235
+ end
236
+ end
237
+ end
238
+
239
+ # Associate the identity with the user if needed
240
+ if identity.user != user
241
+ identity.user_id = user.id
242
+ identity.save!
243
+ end
244
+ user
245
+ end
246
+
247
+ # Create a new user from omniauth hash
248
+ def self.create_from_omniauth(auth, opts = {})
249
+ user = User.new(
250
+ name: auth.info.first_name.presence || auth.info.email[/(\S*)@/, 1],
251
+ surname: auth.info.last_name.presence || '',
252
+ email: auth.info.email,
253
+ password: Devise.friendly_token[0, 20],
254
+ avatar_url: auth.info.image.presence
255
+ )
256
+
257
+ # opts hash is expected to contain additional attributes
258
+ # to set on the model
259
+ user.assign_attributes(opts)
260
+
261
+ # Skip email confirmation if not from Intuit (Intuit email is NOT a confirmed email)
262
+ user.skip_confirmation! unless auth.provider == 'intuit'
263
+ user.save!
264
+
265
+ user
185
266
  end
186
267
  end
187
268
  end
@@ -0,0 +1,27 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta content='text/html; charset=UTF-8' http-equiv='Content-Type' />
5
+ <%= stylesheet_link_tag('mno_enterprise/mail.css') %>
6
+ </head>
7
+ <body>
8
+ <p class="header">
9
+ <%= image_tag('mno_enterprise/main-logo.png') %>
10
+ </p>
11
+
12
+ <p>Hi <%= @info[:first_name] %></p>
13
+
14
+ <p>We received a request to change your email address in the platform to <%= @info[:unconfirmed_email] %>.</p>
15
+
16
+ <p>If you did not request an email change, contact us.</p>
17
+
18
+ <p>
19
+ Regards,<br/>
20
+ The Marketplace team
21
+ </p>
22
+
23
+ <p class="footer">
24
+ <%= @info[:company] %>
25
+ </p>
26
+ </body>
27
+ </html>
@@ -0,0 +1,10 @@
1
+ Hi <%= @info[:first_name] %>
2
+ =================================================================
3
+
4
+ We received a request to change your email address in the platform to <%= @info[:unconfirmed_email] %>.
5
+
6
+ If you did not request an email change, contact us.
7
+
8
+
9
+ Regards,
10
+ The Marketplace team
@@ -0,0 +1,25 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta content='text/html; charset=UTF-8' http-equiv='Content-Type' />
5
+ <%= stylesheet_link_tag('mno_enterprise/mail.css') %>
6
+ </head>
7
+ <body>
8
+ <p class="header">
9
+ <%= image_tag('mno_enterprise/main-logo.png') %>
10
+ </p>
11
+
12
+ <p>Hi <%= @info[:first_name] %></p>
13
+
14
+ <p>We're contacting you to notify you that your password has been changed.</p>
15
+
16
+ <p>
17
+ Regards,<br/>
18
+ The Marketplace team
19
+ </p>
20
+
21
+ <p class="footer">
22
+ <%= @info[:company] %>
23
+ </p>
24
+ </body>
25
+ </html>
@@ -0,0 +1,7 @@
1
+ Hi <%= @info[:first_name] %>
2
+ =================================================================
3
+
4
+ We're contacting you to notify you that your password has been changed.
5
+
6
+ Regards,
7
+ The Marketplace team