mno-enterprise-core 3.2.1 → 3.3.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.
- checksums.yaml +4 -4
- data/app/controllers/mno_enterprise/application_controller.rb +5 -5
- data/app/helpers/mno_enterprise/image_helper.rb +32 -0
- data/app/models/mno_enterprise/app.rb +11 -2
- data/app/models/mno_enterprise/base_resource.rb +2 -0
- data/app/models/mno_enterprise/credit_card.rb +7 -4
- data/app/models/mno_enterprise/impac/dashboard.rb +4 -1
- data/app/models/mno_enterprise/impac/widget.rb +10 -4
- data/app/models/mno_enterprise/org_invite.rb +7 -3
- data/app/models/mno_enterprise/shared_entity.rb +17 -0
- data/app/models/mno_enterprise/user.rb +7 -2
- data/app/pdf/mno_enterprise/invoice_pdf.rb +176 -183
- data/app/views/system_notifications/email-change.html.erb +1 -1
- data/app/views/system_notifications/email-change.text.erb +1 -1
- data/config/initializers/audit_log.rb +28 -1
- data/config/locales/templates/components/en.yml +29 -4
- data/config/locales/templates/dashboard/en.yml +2 -2
- data/config/locales/templates/dashboard/marketplace/en.yml +5 -5
- data/config/locales/templates/dashboard/organization/en.yml +14 -8
- data/config/locales/templates/dashboard/organization/id.yml +4 -4
- data/config/locales/templates/dashboard/organization/zh.yml +4 -4
- data/config/locales/templates/dashboard/teams/en.yml +3 -3
- data/config/locales/templates/dashboard/teams/id.yml +3 -3
- data/config/locales/templates/dashboard/teams/zh.yml +3 -3
- data/config/locales/templates/onboarding/en.yml +45 -0
- data/config/locales/views/auth/confirmations/en.yml +5 -3
- data/config/locales/views/webhook/o_auth/providers/en.yml +2 -2
- data/lib/generators/mno_enterprise/install/install_generator.rb +19 -1
- data/lib/generators/mno_enterprise/install/templates/Procfile.dev +1 -0
- data/lib/generators/mno_enterprise/install/templates/config/initializers/mno_enterprise.rb +7 -50
- data/lib/generators/mno_enterprise/install/templates/config/newrelic.yml +3 -3
- data/lib/generators/mno_enterprise/install/templates/config/settings.yml +49 -2
- data/lib/generators/mno_enterprise/install/templates/nginx.conf +71 -0
- data/lib/generators/mno_enterprise/install/templates/stylesheets/variables.less +148 -141
- data/lib/html_processor.rb +14 -14
- data/lib/mno_enterprise/concerns/controllers/auth/registrations_controller.rb +18 -15
- data/lib/mno_enterprise/concerns/models/ability.rb +6 -3
- data/lib/mno_enterprise/concerns/models/app_instance.rb +2 -3
- data/lib/mno_enterprise/concerns/models/intercom_user.rb +22 -0
- data/lib/mno_enterprise/concerns/models/organization.rb +8 -0
- data/lib/mno_enterprise/concerns/models/shared_entity.rb +36 -0
- data/lib/mno_enterprise/concerns/models/team.rb +7 -0
- data/lib/mno_enterprise/testing_support/common_rake.rb +1 -1
- data/lib/mno_enterprise/testing_support/factories/apps.rb +6 -0
- data/lib/mno_enterprise/testing_support/factories/audit_event.rb +2 -0
- data/lib/mno_enterprise/testing_support/mno_enterprise_api_test_helper.rb +47 -16
- data/lib/mno_enterprise/testing_support/organizations_shared_helpers.rb +6 -9
- data/lib/mno_enterprise/version.rb +1 -1
- data/spec/config/initializers/audit_log_spec.rb +5 -0
- data/spec/controllers/mno_enterprise/application_controller_spec.rb +4 -4
- data/spec/helpers/image_helper_spec.rb +69 -0
- data/spec/models/mno_enterprise/ability_spec.rb +5 -0
- data/spec/models/mno_enterprise/app_spec.rb +1 -1
- data/spec/models/mno_enterprise/base_resource_spec.rb +37 -0
- data/spec/models/mno_enterprise/credit_card_spec.rb +18 -0
- data/spec/models/mno_enterprise/organization_spec.rb +16 -0
- data/spec/models/mno_enterprise/shared_entity_spec.rb +7 -0
- data/spec/models/mno_enterprise/user_spec.rb +83 -15
- metadata +15 -2
data/lib/html_processor.rb
CHANGED
@@ -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).
|
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
|
-
|
133
|
-
|
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
|
147
|
+
if user.admin_role.to_s.casecmp('admin').zero?
|
145
148
|
can :manage_app_instances, MnoEnterprise::Organization
|
146
149
|
end
|
147
150
|
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
|
@@ -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
|
@@ -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
|
-
|
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
|
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
|