mno-enterprise-core 3.1.4 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
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