mno-enterprise-core 3.2.1 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/mno_enterprise/application_controller.rb +5 -5
  3. data/app/helpers/mno_enterprise/image_helper.rb +32 -0
  4. data/app/models/mno_enterprise/app.rb +11 -2
  5. data/app/models/mno_enterprise/base_resource.rb +2 -0
  6. data/app/models/mno_enterprise/credit_card.rb +7 -4
  7. data/app/models/mno_enterprise/impac/dashboard.rb +4 -1
  8. data/app/models/mno_enterprise/impac/widget.rb +10 -4
  9. data/app/models/mno_enterprise/org_invite.rb +7 -3
  10. data/app/models/mno_enterprise/shared_entity.rb +17 -0
  11. data/app/models/mno_enterprise/user.rb +7 -2
  12. data/app/pdf/mno_enterprise/invoice_pdf.rb +176 -183
  13. data/app/views/system_notifications/email-change.html.erb +1 -1
  14. data/app/views/system_notifications/email-change.text.erb +1 -1
  15. data/config/initializers/audit_log.rb +28 -1
  16. data/config/locales/templates/components/en.yml +29 -4
  17. data/config/locales/templates/dashboard/en.yml +2 -2
  18. data/config/locales/templates/dashboard/marketplace/en.yml +5 -5
  19. data/config/locales/templates/dashboard/organization/en.yml +14 -8
  20. data/config/locales/templates/dashboard/organization/id.yml +4 -4
  21. data/config/locales/templates/dashboard/organization/zh.yml +4 -4
  22. data/config/locales/templates/dashboard/teams/en.yml +3 -3
  23. data/config/locales/templates/dashboard/teams/id.yml +3 -3
  24. data/config/locales/templates/dashboard/teams/zh.yml +3 -3
  25. data/config/locales/templates/onboarding/en.yml +45 -0
  26. data/config/locales/views/auth/confirmations/en.yml +5 -3
  27. data/config/locales/views/webhook/o_auth/providers/en.yml +2 -2
  28. data/lib/generators/mno_enterprise/install/install_generator.rb +19 -1
  29. data/lib/generators/mno_enterprise/install/templates/Procfile.dev +1 -0
  30. data/lib/generators/mno_enterprise/install/templates/config/initializers/mno_enterprise.rb +7 -50
  31. data/lib/generators/mno_enterprise/install/templates/config/newrelic.yml +3 -3
  32. data/lib/generators/mno_enterprise/install/templates/config/settings.yml +49 -2
  33. data/lib/generators/mno_enterprise/install/templates/nginx.conf +71 -0
  34. data/lib/generators/mno_enterprise/install/templates/stylesheets/variables.less +148 -141
  35. data/lib/html_processor.rb +14 -14
  36. data/lib/mno_enterprise/concerns/controllers/auth/registrations_controller.rb +18 -15
  37. data/lib/mno_enterprise/concerns/models/ability.rb +6 -3
  38. data/lib/mno_enterprise/concerns/models/app_instance.rb +2 -3
  39. data/lib/mno_enterprise/concerns/models/intercom_user.rb +22 -0
  40. data/lib/mno_enterprise/concerns/models/organization.rb +8 -0
  41. data/lib/mno_enterprise/concerns/models/shared_entity.rb +36 -0
  42. data/lib/mno_enterprise/concerns/models/team.rb +7 -0
  43. data/lib/mno_enterprise/testing_support/common_rake.rb +1 -1
  44. data/lib/mno_enterprise/testing_support/factories/apps.rb +6 -0
  45. data/lib/mno_enterprise/testing_support/factories/audit_event.rb +2 -0
  46. data/lib/mno_enterprise/testing_support/mno_enterprise_api_test_helper.rb +47 -16
  47. data/lib/mno_enterprise/testing_support/organizations_shared_helpers.rb +6 -9
  48. data/lib/mno_enterprise/version.rb +1 -1
  49. data/spec/config/initializers/audit_log_spec.rb +5 -0
  50. data/spec/controllers/mno_enterprise/application_controller_spec.rb +4 -4
  51. data/spec/helpers/image_helper_spec.rb +69 -0
  52. data/spec/models/mno_enterprise/ability_spec.rb +5 -0
  53. data/spec/models/mno_enterprise/app_spec.rb +1 -1
  54. data/spec/models/mno_enterprise/base_resource_spec.rb +37 -0
  55. data/spec/models/mno_enterprise/credit_card_spec.rb +18 -0
  56. data/spec/models/mno_enterprise/organization_spec.rb +16 -0
  57. data/spec/models/mno_enterprise/shared_entity_spec.rb +7 -0
  58. data/spec/models/mno_enterprise/user_spec.rb +83 -15
  59. metadata +15 -2
@@ -8,13 +8,13 @@ require 'sanitize'
8
8
  # You can initialize it with html or markdown text
9
9
  class HtmlProcessor
10
10
  attr_reader :html, :original
11
-
11
+
12
12
  #======================================
13
13
  # Constants
14
14
  #======================================
15
15
  DESCRIPTION_PROCESSING_ORDER = %w( p h1 h2 h3 h4 h5 h6 )
16
-
17
-
16
+
17
+
18
18
  # Define Youtube transformer for Sanitize
19
19
  YOUTUBE_TRANSFORMER = lambda do |env|
20
20
  node = env[:node]
@@ -45,7 +45,7 @@ class HtmlProcessor
45
45
  # to whitelist the current node.
46
46
  {:node_whitelist => [node]}
47
47
  end
48
-
48
+
49
49
  # Default options for Sanitize
50
50
  SANITIZER_OPTS = Sanitize::Config::RELAXED.merge(
51
51
  attributes: Sanitize::Config::RELAXED[:attributes].merge(
@@ -53,18 +53,18 @@ class HtmlProcessor
53
53
  ),
54
54
  transformers: YOUTUBE_TRANSFORMER
55
55
  )
56
-
56
+
57
57
  #======================================
58
58
  # Methods
59
59
  #======================================
60
60
  def initialize(text, options = { })
61
61
  @original = text
62
-
62
+
63
63
  # Process markdown or leave original
64
64
  if options[:format].to_s == 'markdown' && text
65
65
  html_options = { :safe_links_only => true, :hard_wrap => true, :filter_html => false }
66
66
  renderer_options = { :autolink => true, :no_intraemphasis => true, :fenced_code_blocks => true, :superscript => true }
67
-
67
+
68
68
  renderer = Redcarpet::Markdown.new(Redcarpet::Render::HTML.new(html_options), renderer_options)
69
69
  raw_html = renderer.render(text)
70
70
  @html = Sanitize.fragment(raw_html, SANITIZER_OPTS)
@@ -72,27 +72,27 @@ class HtmlProcessor
72
72
  @html = text
73
73
  end
74
74
  end
75
-
75
+
76
76
  # Return a Nokogiri document based
77
77
  # on processor html
78
78
  def document
79
79
  @document ||= Nokogiri::HTML(@html)
80
80
  end
81
-
81
+
82
82
  # Return a description of the document
83
83
  # by returning the first sentence of the
84
84
  # first DESCRIPTION_PROCESSING_ORDER found
85
85
  def description
86
86
  # Return cached value if one
87
87
  return @description if @description
88
-
88
+
89
89
  # Parse the html document to try to find
90
90
  # a description
91
91
  @description = ''
92
92
  DESCRIPTION_PROCESSING_ORDER.each do |selector|
93
- elem = self.document.css(selector).select { |e| e && !e.content.blank? }.first
93
+ elem = self.document.css(selector).detect { |e| e && !e.content.blank? }
94
94
  next if elem.blank? #skip if nil or empty
95
-
95
+
96
96
  # Try to get the first two sentences
97
97
  match = elem.content.match(/([^.!?]+[.!?]?)([^.!?]+[.!?]?)?/)
98
98
  if match && match.captures.any?
@@ -100,7 +100,7 @@ class HtmlProcessor
100
100
  end
101
101
  break if !@description.empty?
102
102
  end
103
-
103
+
104
104
  return @description
105
105
  end
106
- end
106
+ end
@@ -1,6 +1,6 @@
1
1
  module MnoEnterprise::Concerns::Controllers::Auth::RegistrationsController
2
2
  extend ActiveSupport::Concern
3
-
3
+
4
4
  #==================================================================
5
5
  # Included methods
6
6
  #==================================================================
@@ -9,22 +9,22 @@ module MnoEnterprise::Concerns::Controllers::Auth::RegistrationsController
9
9
  included do
10
10
  before_filter :configure_sign_up_params, only: [:create]
11
11
  # before_filter :configure_account_update_params, only: [:update]
12
-
12
+
13
13
  protected
14
14
  def configure_sign_up_params
15
15
  devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(
16
- :email,
17
- :password,
18
- :password_confirmation,
19
- :name,
16
+ :email,
17
+ :password,
18
+ :password_confirmation,
19
+ :name,
20
20
  :surname,
21
21
  :company,
22
22
  :phone,
23
23
  :phone_country_code
24
- )}
24
+ )}
25
25
  end
26
26
  end
27
-
27
+
28
28
  #==================================================================
29
29
  # Class methods
30
30
  #==================================================================
@@ -33,7 +33,7 @@ module MnoEnterprise::Concerns::Controllers::Auth::RegistrationsController
33
33
  # 'some text'
34
34
  # end
35
35
  end
36
-
36
+
37
37
  #==================================================================
38
38
  # Instance methods
39
39
  #==================================================================
@@ -46,10 +46,13 @@ module MnoEnterprise::Concerns::Controllers::Auth::RegistrationsController
46
46
  def create
47
47
  build_resource(sign_up_params)
48
48
  resource.password ||= Devise.friendly_token
49
-
49
+
50
50
  resource_saved = resource.save
51
-
51
+
52
52
  if resource_saved
53
+
54
+ MnoEnterprise::EventLogger.info('user_add', resource_saved.id, 'User Signup', resource_saved)
55
+
53
56
  if resource.active_for_authentication?
54
57
  set_flash_message :notice, :signed_up if is_flashing_format?
55
58
  sign_up(resource_name, resource)
@@ -97,7 +100,7 @@ module MnoEnterprise::Concerns::Controllers::Auth::RegistrationsController
97
100
  # end
98
101
 
99
102
  protected
100
-
103
+
101
104
  # You can put the params you want to permit in the empty array.
102
105
  # def configure_account_update_params
103
106
  # devise_parameter_sanitizer.for(:account_update) << :attribute
@@ -112,12 +115,12 @@ module MnoEnterprise::Concerns::Controllers::Auth::RegistrationsController
112
115
  # def after_inactive_sign_up_path_for(resource)
113
116
  # super(resource)
114
117
  # end
115
-
118
+
116
119
  def sign_up_params
117
120
  attrs = super
118
121
  attrs.merge(orga_on_create: create_orga_on_user_creation(attrs))
119
122
  end
120
-
123
+
121
124
  # Check whether we should create an organization for the user
122
125
  def create_orga_on_user_creation(user_attrs)
123
126
  return false unless user_attrs['email']
@@ -133,4 +136,4 @@ module MnoEnterprise::Concerns::Controllers::Auth::RegistrationsController
133
136
  # Get remaining invites via email address
134
137
  return MnoEnterprise::OrgInvite.where(user_email: user_attrs['email']).empty?
135
138
  end
136
- end
139
+ end
@@ -129,8 +129,11 @@ module MnoEnterprise::Concerns::Models::Ability
129
129
  end
130
130
 
131
131
  can :manage_kpi, MnoEnterprise::Impac::Kpi do |kpi|
132
- dashboard = kpi.dashboard
133
- authorize! :manage_dashboard, dashboard
132
+ if kpi.widget.present?
133
+ authorize! :manage_widget, MnoEnterprise::Impac::Widget.find(kpi.widget.id)
134
+ else
135
+ authorize! :manage_dashboard, kpi.dashboard
136
+ end
134
137
  end
135
138
 
136
139
  can :manage_alert, MnoEnterprise::Impac::Alert do |alert|
@@ -141,7 +144,7 @@ module MnoEnterprise::Concerns::Models::Ability
141
144
 
142
145
  # Abilities for admin user
143
146
  def admin_abilities(user)
144
- if user.admin_role == 'admin'
147
+ if user.admin_role.to_s.casecmp('admin').zero?
145
148
  can :manage_app_instances, MnoEnterprise::Organization
146
149
  end
147
150
  end
@@ -106,9 +106,8 @@ module MnoEnterprise::Concerns::Models::AppInstance
106
106
  id: id,
107
107
  uid: uid,
108
108
  name: name,
109
- app_nid: app ? app.nid : nil
109
+ app_nid: app ? app.nid : nil,
110
+ organization_id: owner_id || owner.id
110
111
  }
111
112
  end
112
-
113
-
114
113
  end
@@ -25,4 +25,26 @@ module MnoEnterprise::Concerns::Models::IntercomUser
25
25
  def intercom_user_hash
26
26
  OpenSSL::HMAC.hexdigest('sha256', MnoEnterprise.intercom_api_secret, (self.id || self.email).to_s) if MnoEnterprise.intercom_api_secret
27
27
  end
28
+
29
+ # Return Intercom user data hash
30
+ def intercom_data(update_last_request_at = true)
31
+ data = {
32
+ user_id: self.id,
33
+ name: [self.name, self.surname].join(' '),
34
+ email: self.email,
35
+ created_at: self.created_at.to_i,
36
+ last_seen_ip: self.last_sign_in_ip,
37
+ custom_attributes: {
38
+ first_name: self.name,
39
+ surname: self.surname,
40
+ confirmed_at: self.confirmed_at,
41
+ admin_role: self.admin_role
42
+ },
43
+ update_last_request_at: update_last_request_at
44
+ }
45
+ data[:custom_attributes][:phone]= self.phone if self.phone
46
+ data[:custom_attributes][:external_id]= self.external_id if self.external_id
47
+
48
+ data
49
+ end
28
50
  end
@@ -41,6 +41,10 @@ module MnoEnterprise::Concerns::Models::Organization
41
41
 
42
42
  scope :in_arrears, -> { where(in_arrears?: true) }
43
43
 
44
+ scope :active, -> { where(account_frozen: false) }
45
+
46
+ default_scope lambda { where(account_frozen: false) }
47
+
44
48
  #================================
45
49
  # Associations
46
50
  #================================
@@ -115,4 +119,8 @@ module MnoEnterprise::Concerns::Models::Organization
115
119
  def payment_restriction
116
120
  meta_data && meta_data['payment_restriction']
117
121
  end
122
+
123
+ def has_credit_card_details?
124
+ credit_card.persisted?
125
+ end
118
126
  end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+ # == Schema Information
3
+ #
4
+ # Endpoint:
5
+ # - /v1/app/:app_id/shared_entities
6
+ #
7
+ # id :integer not null, primary key
8
+ # nid :string
9
+ # name :string
10
+ # created_at :datetime not null
11
+ # updated_at :datetime not null
12
+
13
+ module MnoEnterprise::Concerns::Models::SharedEntity
14
+ extend ActiveSupport::Concern
15
+
16
+ #==================================================================
17
+ # Included methods
18
+ #==================================================================
19
+ included do
20
+ # == Relationships ==============================================
21
+ belongs_to :app
22
+ end
23
+
24
+ #==================================================================
25
+ # Class methods
26
+ #==================================================================
27
+ module ClassMethods
28
+ # def some_class_method
29
+ # 'some text'
30
+ # end
31
+ end
32
+
33
+ #==================================================================
34
+ # Instance methods
35
+ #==================================================================
36
+ end
@@ -64,4 +64,11 @@ module MnoEnterprise::Concerns::Models::Team
64
64
  self.reload
65
65
  self
66
66
  end
67
+
68
+ def to_audit_event
69
+ {
70
+ name: name,
71
+ organization_id: self.organization.id
72
+ }
73
+ end
67
74
  end
@@ -13,7 +13,7 @@ namespace :mno_enterprise do
13
13
  ENV["RAILS_ENV"] = 'test'
14
14
 
15
15
  MnoEnterprise::DummyGenerator.start %W[--quiet --lib_name=#{ENV['LIB_NAME']} --database=#{ENV['DB'].presence || 'sqlite3'}]
16
- MnoEnterprise::Generators::InstallGenerator.start %w[--quiet --skip-rspec --skip-sprite --skip-factory-girl --skip-frontend --skip-admin]
16
+ MnoEnterprise::Generators::InstallGenerator.start %w[--quiet --skip-rspec --skip-sprite --skip-factory-girl --skip-application-config --skip-frontend --skip-admin]
17
17
  end
18
18
  end
19
19
  end
@@ -16,11 +16,15 @@ FactoryGirl.define do
16
16
  tags ['Foo', 'Bar']
17
17
  key_benefits ['Super', 'Hyper', 'Good']
18
18
  key_features ['Super', 'Hyper', 'Good']
19
+ key_workflows ['1st workflow', '2nd workflow']
20
+ known_limitations "No limitations"
19
21
  testimonials [{text: 'Bla', company: 'Doe Pty Ltd', author: 'John'}]
20
22
  worldwide_usage 120000
21
23
  tiny_description "A great app"
22
24
  stack 'cube'
23
25
  terms_url "http://opensource.org/licenses/MIT"
26
+ support_url "http://example.com/su pport"
27
+ getting_started "Let's get started"
24
28
  appinfo { {} }
25
29
  average_rating { rand(1..5) }
26
30
  sequence(:rank) { |n| n }
@@ -29,6 +33,8 @@ FactoryGirl.define do
29
33
  'default' => [{name: 'Monthly Plan', price: '20.0', currency: 'AUD', factor: '/month'}]
30
34
  } }
31
35
 
36
+ shared_entities { [] }
37
+
32
38
  trait :cloud do
33
39
  stack 'cloud'
34
40
  end
@@ -6,6 +6,8 @@ FactoryGirl.define do
6
6
  user_id 1
7
7
  description 'Blabla'
8
8
  details 'Details'
9
+ organization_id 1
10
+ organization { {name: 'Org'} }
9
11
  user { {name: 'John', surname: 'Doe'} }
10
12
 
11
13
  # Properly build the resource with Her
@@ -1,12 +1,12 @@
1
1
  module MnoEnterpriseApiTestHelper
2
-
2
+
3
3
  # Take a resource and transform it into a Hash describing
4
4
  # the resource as if it had been returned by the MnoEnterprise
5
5
  # API server
6
6
  def from_api(res)
7
7
  { data: serialize_type(res), metadata: {pagination: {count: entity_count(res)}} }
8
8
  end
9
-
9
+
10
10
  def serialize_type(res)
11
11
  case
12
12
  when res.kind_of?(Array)
@@ -42,7 +42,7 @@ module MnoEnterpriseApiTestHelper
42
42
  return 1
43
43
  end
44
44
  end
45
-
45
+
46
46
  # Reset all API stubs.
47
47
  # Called before each test (see spec_helper)
48
48
  def api_stub_reset
@@ -74,12 +74,27 @@ module MnoEnterpriseApiTestHelper
74
74
  warn("DEPRECATION WARNING: api_stub_for(MyClass,{ some: 'opts'}) is deprecated. Please use api_stub_for({ some: 'opts' }) from now on")
75
75
  real_opts = opts
76
76
  end
77
-
77
+
78
78
  set_api_stub
79
79
  api_stub_add(real_opts)
80
80
  api_stub_configure(@_api_stub)
81
81
  end
82
-
82
+
83
+ # Remove an API stub added with `api_stub_for`
84
+ # This needs to be called with the same options
85
+ def remove_api_stub(opts = {})
86
+ set_api_stub
87
+ api_stub_remove(opts)
88
+ api_stub_configure(@_api_stub)
89
+ end
90
+
91
+ # Remove all api stubs
92
+ def clear_api_stubs
93
+ set_api_stub
94
+ @_stub_list = {}
95
+ api_stub_configure(@_api_stub)
96
+ end
97
+
83
98
  private
84
99
  # Set a stub api on the provider class
85
100
  def set_api_stub
@@ -99,21 +114,37 @@ module MnoEnterpriseApiTestHelper
99
114
  def api_stub_add(orig_opts)
100
115
  @_stub_list ||= {}
101
116
  opts = orig_opts.dup
102
-
103
- # Expand options so that: { put: '/path' } becomes { path: '/path', method: :put }
117
+
118
+ expand_options(opts)
119
+
120
+ key = opts.to_param
121
+ @_stub_list[key] = opts
122
+ end
123
+
124
+ # Remove an API
125
+ # This need to be called with the exact same options as `api_stub_add` was called with
126
+ def api_stub_remove(orig_opts)
127
+ @_stub_list ||= {}
128
+ opts = orig_opts.dup
129
+
130
+ expand_options(opts)
131
+
132
+ key = opts.to_param
133
+ @_stub_list.delete(key)
134
+ end
135
+
136
+ # Expand options so that: { put: '/path' } becomes { path: '/path', method: :put }
137
+ def expand_options(opts)
104
138
  unless opts[:method] && opts[:path]
105
- [:get,:put,:post,:delete].each do |verb|
139
+ [:get, :put, :post, :delete].each do |verb|
106
140
  if path = opts.delete(verb)
107
141
  opts[:path] = path
108
142
  opts[:method] = verb
109
143
  end
110
144
  end
111
145
  end
112
-
113
- key = opts.to_param
114
- @_stub_list[key] = opts
115
146
  end
116
-
147
+
117
148
  # Configure the api and apply a list of stubs
118
149
  def api_stub_configure(api)
119
150
  # This block should match the her.rb initializer
@@ -157,12 +188,12 @@ module MnoEnterpriseApiTestHelper
157
188
  else
158
189
  resp_code = stub[:code] || 200
159
190
  end
160
-
161
-
162
- [resp_code, {}, resp.to_json]
191
+
192
+
193
+ [resp_code, {}, resp.to_json]
163
194
  }
164
195
  end
165
196
  end
166
197
  end
167
198
  end
168
- end
199
+ end