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.
- 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
|