mno-enterprise-core 2.0.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 +7 -0
- data/LICENSE +1 -0
- data/Rakefile +12 -0
- data/app/assets/images/mno_enterprise/main-logo.png +0 -0
- data/app/controllers/mno_enterprise/application_controller.rb +116 -0
- data/app/helpers/mno_enterprise/application_helper.rb +67 -0
- data/app/helpers/mno_enterprise/impersonate_helper.rb +27 -0
- data/app/models/mno_enterprise/ability.rb +6 -0
- data/app/models/mno_enterprise/app.rb +72 -0
- data/app/models/mno_enterprise/app_instance.rb +36 -0
- data/app/models/mno_enterprise/app_instances_sync.rb +6 -0
- data/app/models/mno_enterprise/arrears_situation.rb +6 -0
- data/app/models/mno_enterprise/audit_event.rb +21 -0
- data/app/models/mno_enterprise/base_resource.rb +228 -0
- data/app/models/mno_enterprise/credit_card.rb +40 -0
- data/app/models/mno_enterprise/deletion_request.rb +35 -0
- data/app/models/mno_enterprise/impac/dashboard.rb +36 -0
- data/app/models/mno_enterprise/impac/dashboard_provisioner.rb +5 -0
- data/app/models/mno_enterprise/impac/kpi.rb +9 -0
- data/app/models/mno_enterprise/impac/widget.rb +13 -0
- data/app/models/mno_enterprise/invoice.rb +53 -0
- data/app/models/mno_enterprise/org_invite.rb +50 -0
- data/app/models/mno_enterprise/organization.rb +33 -0
- data/app/models/mno_enterprise/team.rb +50 -0
- data/app/models/mno_enterprise/tenant.rb +5 -0
- data/app/models/mno_enterprise/tenant_invoice.rb +5 -0
- data/app/models/mno_enterprise/user.rb +183 -0
- data/app/pdf/mno_enterprise/invoice_pdf.rb +516 -0
- data/config/initializers/audit_log.rb +5 -0
- data/config/locales/devise.en.yml +60 -0
- data/config/routes.rb +2 -0
- data/config/styleguide.yml +106 -0
- data/lib/accountingjs_serializer.rb +51 -0
- data/lib/devise/controllers/extension_helpers.rb +52 -0
- data/lib/devise/extension_routes.rb +11 -0
- data/lib/devise/hooks/password_expirable.rb +5 -0
- data/lib/devise/models/password_expirable.rb +28 -0
- data/lib/devise/models/remote_authenticatable.rb +48 -0
- data/lib/devise/strategies/remote_authenticatable.rb +44 -0
- data/lib/devise_extension.rb +36 -0
- data/lib/faraday/adapter/net_http_no_proxy.rb +19 -0
- data/lib/generators/mno_enterprise/database_extension/USAGE +11 -0
- data/lib/generators/mno_enterprise/database_extension/database_extension_generator.rb +36 -0
- data/lib/generators/mno_enterprise/database_extension/templates/model.rb +9 -0
- data/lib/generators/mno_enterprise/dummy/dummy_generator.rb +98 -0
- data/lib/generators/mno_enterprise/dummy/templates/rails/application.rb.erb +9 -0
- data/lib/generators/mno_enterprise/dummy/templates/rails/boot.rb.erb +6 -0
- data/lib/generators/mno_enterprise/dummy/templates/rails/database.yml +22 -0
- data/lib/generators/mno_enterprise/dummy/templates/rails/routes.rb +8 -0
- data/lib/generators/mno_enterprise/dummy/templates/rails/test-env.rb +45 -0
- data/lib/generators/mno_enterprise/install/install_generator.rb +140 -0
- data/lib/generators/mno_enterprise/install/templates/Procfile +1 -0
- data/lib/generators/mno_enterprise/install/templates/config/initializers/mno_enterprise.rb +135 -0
- data/lib/generators/mno_enterprise/install/templates/config/mno_enterprise_styleguide.yml +104 -0
- data/lib/generators/mno_enterprise/install/templates/javascripts/mno_enterprise_extensions.js +7 -0
- data/lib/generators/mno_enterprise/install/templates/stylesheets/main.less_erb +25 -0
- data/lib/generators/mno_enterprise/install/templates/stylesheets/theme.less_erb +59 -0
- data/lib/generators/mno_enterprise/install/templates/stylesheets/variables.less +337 -0
- data/lib/generators/mno_enterprise/install/templates/tasks/sprites.rake +14 -0
- data/lib/generators/mno_enterprise/puma_stack/puma_stack_generator.rb +58 -0
- data/lib/generators/mno_enterprise/templates/scripts/monit/app-server.conf +8 -0
- data/lib/generators/mno_enterprise/templates/scripts/nginx/app +51 -0
- data/lib/generators/mno_enterprise/templates/scripts/puma.rb +25 -0
- data/lib/generators/mno_enterprise/templates/scripts/setup.sh +27 -0
- data/lib/generators/mno_enterprise/templates/scripts/upstart/app-web-hotrestart.conf +26 -0
- data/lib/generators/mno_enterprise/templates/scripts/upstart/app-web-server.conf +34 -0
- data/lib/generators/mno_enterprise/templates/scripts/upstart/app-web.conf +2 -0
- data/lib/generators/mno_enterprise/templates/scripts/upstart/app.conf +11 -0
- data/lib/her_extension/her_orm_adapter.rb +54 -0
- data/lib/her_extension/middleware/mnoe_api_v1_parse_json.rb +54 -0
- data/lib/her_extension/model/associations/association.rb +61 -0
- data/lib/her_extension/model/associations/association_proxy.rb +34 -0
- data/lib/her_extension/model/associations/has_many_association.rb +115 -0
- data/lib/her_extension/model/attributes.rb +43 -0
- data/lib/her_extension/model/orm.rb +59 -0
- data/lib/her_extension/model/parse.rb +40 -0
- data/lib/her_extension/model/relation.rb +92 -0
- data/lib/her_extension/validations/remote_uniqueness_validation.rb +33 -0
- data/lib/html_processor.rb +106 -0
- data/lib/mandrill_client.rb +58 -0
- data/lib/mno-enterprise-core.rb +1 -0
- data/lib/mno_enterprise/concerns.rb +4 -0
- data/lib/mno_enterprise/concerns/controllers.rb +6 -0
- data/lib/mno_enterprise/concerns/controllers/angular_csrf.rb +59 -0
- data/lib/mno_enterprise/concerns/controllers/auth.rb +9 -0
- data/lib/mno_enterprise/concerns/controllers/auth/confirmations_controller.rb +187 -0
- data/lib/mno_enterprise/concerns/controllers/auth/passwords_controller.rb +54 -0
- data/lib/mno_enterprise/concerns/controllers/auth/registrations_controller.rb +136 -0
- data/lib/mno_enterprise/concerns/controllers/auth/sessions_controller.rb +54 -0
- data/lib/mno_enterprise/concerns/controllers/auth/unlocks_controller.rb +50 -0
- data/lib/mno_enterprise/concerns/models.rb +6 -0
- data/lib/mno_enterprise/concerns/models/ability.rb +108 -0
- data/lib/mno_enterprise/concerns/models/app_instance.rb +100 -0
- data/lib/mno_enterprise/concerns/models/organization.rb +102 -0
- data/lib/mno_enterprise/core.rb +279 -0
- data/lib/mno_enterprise/database_extendable.rb +57 -0
- data/lib/mno_enterprise/engine.rb +33 -0
- data/lib/mno_enterprise/testing_support/ability_test_helper.rb +10 -0
- data/lib/mno_enterprise/testing_support/common_rake.rb +19 -0
- data/lib/mno_enterprise/testing_support/factories.rb +13 -0
- data/lib/mno_enterprise/testing_support/factories/app_instances.rb +30 -0
- data/lib/mno_enterprise/testing_support/factories/apps.rb +45 -0
- data/lib/mno_enterprise/testing_support/factories/arrears_situation.rb +14 -0
- data/lib/mno_enterprise/testing_support/factories/audit_event.rb +15 -0
- data/lib/mno_enterprise/testing_support/factories/credit_card.rb +33 -0
- data/lib/mno_enterprise/testing_support/factories/deletion_request.rb +17 -0
- data/lib/mno_enterprise/testing_support/factories/impac/dashboards.rb +15 -0
- data/lib/mno_enterprise/testing_support/factories/impac/kpis.rb +20 -0
- data/lib/mno_enterprise/testing_support/factories/impac/widgets.rb +15 -0
- data/lib/mno_enterprise/testing_support/factories/invoices.rb +51 -0
- data/lib/mno_enterprise/testing_support/factories/org_invite.rb +24 -0
- data/lib/mno_enterprise/testing_support/factories/organizations.rb +25 -0
- data/lib/mno_enterprise/testing_support/factories/team.rb +17 -0
- data/lib/mno_enterprise/testing_support/factories/tenant.rb +12 -0
- data/lib/mno_enterprise/testing_support/factories/tenant_invoice.rb +29 -0
- data/lib/mno_enterprise/testing_support/factories/users.rb +48 -0
- data/lib/mno_enterprise/testing_support/jpi_v1_test_helper.rb +49 -0
- data/lib/mno_enterprise/testing_support/mno_enterprise_api_test_helper.rb +167 -0
- data/lib/mno_enterprise/testing_support/mnoe_faraday_test_adapter.rb +173 -0
- data/lib/mno_enterprise/testing_support/organizations_shared_helpers.rb +175 -0
- data/lib/mno_enterprise/testing_support/user_action_shared.rb +47 -0
- data/lib/mno_enterprise/version.rb +3 -0
- data/lib/tasks/mno_enterprise_tasks.rake +22 -0
- data/spec/controllers/mno_enterprise/angular_csrf_spec.rb +42 -0
- data/spec/lib/her_extension/her_orm_adapter.rb +7 -0
- data/spec/lib/her_extension/model/relation_spec.rb +7 -0
- data/spec/lib/mandrill_client_spec.rb +64 -0
- data/spec/mno_enterprise_spec.rb +79 -0
- data/spec/models/mno_enterprise/app_instance_spec.rb +7 -0
- data/spec/models/mno_enterprise/app_spec.rb +62 -0
- data/spec/models/mno_enterprise/base_resource_spec.rb +28 -0
- data/spec/models/mno_enterprise/deletion_request_spec.rb +26 -0
- data/spec/models/mno_enterprise/invoice_spec.rb +7 -0
- data/spec/models/mno_enterprise/organization_spec.rb +7 -0
- data/spec/models/mno_enterprise/user_spec.rb +44 -0
- data/spec/rails_helper.rb +73 -0
- data/spec/spec_helper.rb +78 -0
- metadata +421 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: b3986ecdbc3ba353f17f75ca72fde9e71fdde276
|
|
4
|
+
data.tar.gz: c338d9efa311e9ce8cb372e764572a3f1f14ba08
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 2f8a203a4719b6e6f19e5f104b363dd50fb431c24b8e2dab49e86d2f5077d423e93b5060e33f224377f104a6c482668bc157800468797e670b537fab58caa2bb
|
|
7
|
+
data.tar.gz: aa56b90af90560b69a6af6f412b1cffdbd71f2765fb2705037bb43b2d2495f5a9fa0fa540dce18d9bf5a983a642f93ad05f5aaa67c4df60ec02bdfb17af764ac
|
data/LICENSE
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Copyright 2015 Maestrano Pty Ltd
|
data/Rakefile
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
require 'rspec/core/rake_task'
|
|
2
|
+
require 'mno_enterprise/testing_support/common_rake'
|
|
3
|
+
|
|
4
|
+
RSpec::Core::RakeTask.new
|
|
5
|
+
|
|
6
|
+
task default: :spec
|
|
7
|
+
|
|
8
|
+
desc "Generates a dummy app for testing"
|
|
9
|
+
task :test_app do
|
|
10
|
+
ENV['LIB_NAME'] = 'mno_enterprise/core'
|
|
11
|
+
Rake::Task['mno_enterprise:testing:create_dummy_app'].invoke
|
|
12
|
+
end
|
|
Binary file
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
module MnoEnterprise
|
|
2
|
+
class ApplicationController < ActionController::Base
|
|
3
|
+
protect_from_forgery
|
|
4
|
+
include ApplicationHelper
|
|
5
|
+
prepend_before_filter :skip_devise_trackable_on_xhr
|
|
6
|
+
|
|
7
|
+
before_filter :set_default_meta
|
|
8
|
+
before_filter :store_location
|
|
9
|
+
before_filter :perform_return_to
|
|
10
|
+
|
|
11
|
+
# Angular CSRF
|
|
12
|
+
if MnoEnterprise.include_angular_csrf
|
|
13
|
+
include MnoEnterprise::Concerns::Controllers::AngularCSRF
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
#============================================
|
|
17
|
+
# CanCan Authorization Rescue
|
|
18
|
+
#============================================
|
|
19
|
+
# Rescue the CanCan permission denied error
|
|
20
|
+
rescue_from CanCan::AccessDenied do |_exception|
|
|
21
|
+
respond_to do |format|
|
|
22
|
+
format.html { redirect_to main_app.root_path, alert: 'Unauthorized Action' }
|
|
23
|
+
format.json { render nothing: true, status: :forbidden }
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def current_ability
|
|
28
|
+
MnoEnterprise::Ability.new(current_user)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def set_default_meta
|
|
32
|
+
@meta = {}
|
|
33
|
+
@meta[:title] = "Application"
|
|
34
|
+
@meta[:description] = "Enterprise Applications"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
#============================================
|
|
38
|
+
# Devise
|
|
39
|
+
#============================================
|
|
40
|
+
protected
|
|
41
|
+
|
|
42
|
+
# Do not updated devise last access timestamps on ajax call so that
|
|
43
|
+
# timeout feature works properly
|
|
44
|
+
# Only GET request get ignored - POST/PUT/DELETE requests reflect a
|
|
45
|
+
# user action and should therefore be taken into account
|
|
46
|
+
def skip_devise_trackable_on_xhr
|
|
47
|
+
if request.format == 'application/json' && request.get?
|
|
48
|
+
request.env["devise.skip_trackable"] = true
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Return the user to the 'return_to' url if one was specified
|
|
53
|
+
# previously. Only if user is signed in
|
|
54
|
+
def perform_return_to
|
|
55
|
+
return true unless current_user && (url = return_to_url(current_user))
|
|
56
|
+
redirect_to url
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Devise will always redirect to the last non devise route
|
|
60
|
+
# (alias not starting with /auth)
|
|
61
|
+
# ---
|
|
62
|
+
# WARNING: if one day you change the below please also check that
|
|
63
|
+
# the new behaviour fits with ConfirmationsController (yes...I know...it's not clean)
|
|
64
|
+
def store_location
|
|
65
|
+
capture_return_to_redirection || capture_previous_url
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def capture_previous_url
|
|
69
|
+
if request.format == 'text/html' && request.fullpath =~ /\/(myspace|deletion_requests|org_invites|provision)/
|
|
70
|
+
session[:previous_url] = request.original_url
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Handle return_to parameter in URL if present
|
|
75
|
+
def capture_return_to_redirection
|
|
76
|
+
return false unless request.format == 'text/html' && params[:return_to].present?
|
|
77
|
+
|
|
78
|
+
# Capture return url
|
|
79
|
+
session[:return_to] = params[:return_to]
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Return the URL that the user should be immediately returned to
|
|
83
|
+
def return_to_url(resource)
|
|
84
|
+
return nil unless (url = session.delete(:return_to)).present?
|
|
85
|
+
|
|
86
|
+
# Add Web Token to URL
|
|
87
|
+
separator = (url =~ /\?/ ? '&' : '?')
|
|
88
|
+
|
|
89
|
+
url + "#{separator}wtk=#{MnoEnterprise.jwt({user_id: resource.uid})}"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Redirect to previous url and reset it
|
|
93
|
+
def after_sign_in_path_for(resource)
|
|
94
|
+
previous_url = session.delete(:previous_url)
|
|
95
|
+
url = mno_enterprise.respond_to?(:myspace_url) ? mno_enterprise.myspace_url : main_app.root_url
|
|
96
|
+
return (return_to_url(resource) || previous_url || url)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Some controllers needs to redirect to 'MySpace' which breaks if you dont use mnoe-frontend
|
|
100
|
+
# Rather than relying on the MainApp to define myspace_path we check it here
|
|
101
|
+
# The MainApp can redefine this two methods to fit its structure
|
|
102
|
+
# Some of these are extracted to individuals methods like after_provision_path.
|
|
103
|
+
def mnoe_home_path
|
|
104
|
+
mno_enterprise.respond_to?(:myspace_path) ? mno_enterprise.myspace_path : main_app.root_path
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def mnoe_home_url
|
|
108
|
+
mno_enterprise.respond_to?(:myspace_url) ? mno_enterprise.myspace_url : main_app.root_url
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Overwriting the sign_out redirect path method
|
|
112
|
+
def after_sign_out_path_for(resource_or_scope)
|
|
113
|
+
MnoEnterprise.router.after_sign_out_url || super
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
module MnoEnterprise
|
|
2
|
+
module ApplicationHelper
|
|
3
|
+
|
|
4
|
+
def support_email
|
|
5
|
+
MnoEnterprise.support_email
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
# Re-implement Devise filter
|
|
9
|
+
# For some reasons the original Devise filter seems to ignore the
|
|
10
|
+
# mnoe prefix when using custom devise controllers
|
|
11
|
+
def authenticate_user!
|
|
12
|
+
redirect_to(new_user_session_path) unless current_user
|
|
13
|
+
true
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Redirect a signed in user to the confirmation
|
|
17
|
+
# lounge if unconfirmed
|
|
18
|
+
def redirect_to_lounge_if_unconfirmed
|
|
19
|
+
if current_user && !current_user.confirmed?
|
|
20
|
+
redirect_to user_confirmation_lounge_path
|
|
21
|
+
end
|
|
22
|
+
return true
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Redirect to signup page if user not authenticated
|
|
26
|
+
def authenticate_user_or_signup!
|
|
27
|
+
unless current_user
|
|
28
|
+
redirect_to new_user_registration_path
|
|
29
|
+
false
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
true
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def notice_hash(notice)
|
|
36
|
+
return {} unless notice
|
|
37
|
+
# TODO: refactor
|
|
38
|
+
auto_close = (notice =~ /signed (in|out)/i ? 5*1000 : nil)
|
|
39
|
+
# Check if a timeout has been defined in flash
|
|
40
|
+
unless auto_close
|
|
41
|
+
auto_close = flash[:flash_options][:timeout] if flash[:flash_options] && flash[:flash_options][:timeout]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
{
|
|
45
|
+
type:'success',
|
|
46
|
+
msg: (notice || '').html_safe,
|
|
47
|
+
timeout: auto_close
|
|
48
|
+
}
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def alert_hash(alert)
|
|
52
|
+
return {} unless alert
|
|
53
|
+
{
|
|
54
|
+
type:'danger',
|
|
55
|
+
msg: (alert || '').html_safe,
|
|
56
|
+
timeout: -1
|
|
57
|
+
}
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# This helper converts markdown content
|
|
61
|
+
# to html, using the HtmlProcessor (see /lib)
|
|
62
|
+
def markdown(text)
|
|
63
|
+
return text unless text.present?
|
|
64
|
+
HtmlProcessor.new(text, format: :markdown).html.html_safe
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module MnoEnterprise
|
|
2
|
+
module ImpersonateHelper
|
|
3
|
+
|
|
4
|
+
# current_user changes from a staff user to
|
|
5
|
+
# +new_user+; current user stored in +session[:impersonator_user_id]+
|
|
6
|
+
def impersonate(new_user)
|
|
7
|
+
session[:impersonator_user_id] = current_user.id
|
|
8
|
+
sign_out(current_user)
|
|
9
|
+
sign_in new_user
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# revert the +current_user+ back to the staff user
|
|
13
|
+
# stored in +session[:impersonator_user_id]+
|
|
14
|
+
def revert_impersonate
|
|
15
|
+
return unless current_impersonator
|
|
16
|
+
sign_out(current_user)
|
|
17
|
+
sign_in(current_impersonator)
|
|
18
|
+
session[:impersonator_user_id] = nil
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def current_impersonator
|
|
22
|
+
return unless session[:impersonator_user_id]
|
|
23
|
+
@admin_user ||= MnoEnterprise::User.find(session[:impersonator_user_id])
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# == Schema Information
|
|
2
|
+
#
|
|
3
|
+
# Endpoint: /v1/apps
|
|
4
|
+
#
|
|
5
|
+
# id :integer not null, primary key
|
|
6
|
+
# nid :string e.g.: 'wordpress'
|
|
7
|
+
# name :string(255)
|
|
8
|
+
# description :text
|
|
9
|
+
# created_at :datetime not null
|
|
10
|
+
# updated_at :datetime not null
|
|
11
|
+
# logo :string(255)
|
|
12
|
+
# version :string(255)
|
|
13
|
+
# website :string(255)
|
|
14
|
+
# slug :string(255)
|
|
15
|
+
# categories :text
|
|
16
|
+
# key_benefits :text
|
|
17
|
+
# key_features :text
|
|
18
|
+
# testimonials :text
|
|
19
|
+
# worldwide_usage :integer
|
|
20
|
+
# tiny_description :text
|
|
21
|
+
# popup_description :text
|
|
22
|
+
# stack :string(255)
|
|
23
|
+
# terms_url :string(255)
|
|
24
|
+
# tags :text
|
|
25
|
+
#
|
|
26
|
+
|
|
27
|
+
module MnoEnterprise
|
|
28
|
+
class App < BaseResource
|
|
29
|
+
scope :active, -> { where(active: true) }
|
|
30
|
+
scope :cloud, -> { where(stack: 'cloud') }
|
|
31
|
+
|
|
32
|
+
attributes :id, :uid, :nid, :name, :description, :tiny_description, :created_at, :updated_at, :logo, :website, :slug,
|
|
33
|
+
:categories, :key_benefits, :key_features, :testimonials, :worldwide_usage, :tiny_description,
|
|
34
|
+
:popup_description, :stack, :terms_url, :pictures, :tags, :api_key, :metadata_url, :metadata, :details
|
|
35
|
+
|
|
36
|
+
# Return the list of available categories
|
|
37
|
+
def self.categories(list = nil)
|
|
38
|
+
app_list = list || self.all.to_a
|
|
39
|
+
app_list.select { |a| a.categories.present? }.map(&:categories).flatten.uniq { |e| e.downcase }.sort
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def to_audit_event
|
|
43
|
+
{
|
|
44
|
+
app_id: id,
|
|
45
|
+
app_nid: nid,
|
|
46
|
+
app_name: name
|
|
47
|
+
}
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Sanitize the app description
|
|
51
|
+
# E.g.: replace any mention of Maestrano by the tenant name
|
|
52
|
+
def sanitized_description
|
|
53
|
+
@sanitized_description ||= (self.description || '').gsub(/maestrano/i,MnoEnterprise.app_name)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Methods for appinfo flags
|
|
57
|
+
%w(coming_soon single_billing).each do |method|
|
|
58
|
+
define_method "#{method}?" do
|
|
59
|
+
appinfo.presence && appinfo[method]
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def regenerate_api_key!
|
|
64
|
+
data = self.put(operation: 'regenerate_api_key')
|
|
65
|
+
self.api_key = data[:data][:api_key]
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def refresh_metadata!(metadata_url)
|
|
69
|
+
self.put(operation: 'refresh_metadata', metadata_url: metadata_url)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# == Schema Information
|
|
2
|
+
#
|
|
3
|
+
# Endpoint:
|
|
4
|
+
# - /v1/app_instances
|
|
5
|
+
# - /v1/organizations/:organization_id/app_instances
|
|
6
|
+
#
|
|
7
|
+
# id :integer not null, primary key
|
|
8
|
+
# uid :string(255)
|
|
9
|
+
# name :string(255)
|
|
10
|
+
# status :string(255)
|
|
11
|
+
# app_id :integer
|
|
12
|
+
# created_at :datetime not null
|
|
13
|
+
# updated_at :datetime not null
|
|
14
|
+
# started_at :datetime
|
|
15
|
+
# stack :string(255)
|
|
16
|
+
# owner_id :integer
|
|
17
|
+
# owner_type :string(255)
|
|
18
|
+
# terminated_at :datetime
|
|
19
|
+
# stopped_at :datetime
|
|
20
|
+
# billing_type :string(255)
|
|
21
|
+
# autostop_at :datetime
|
|
22
|
+
# autostop_interval :integer
|
|
23
|
+
# next_status :string(255)
|
|
24
|
+
# soa_enabled :boolean default(FALSE)
|
|
25
|
+
#
|
|
26
|
+
# ===> to be confirmed
|
|
27
|
+
# http_url
|
|
28
|
+
# durations :text
|
|
29
|
+
# microsoft_licence_id :integer
|
|
30
|
+
#
|
|
31
|
+
|
|
32
|
+
module MnoEnterprise
|
|
33
|
+
class AppInstance < BaseResource
|
|
34
|
+
include MnoEnterprise::Concerns::Models::AppInstance
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module MnoEnterprise
|
|
2
|
+
class AuditEvent < BaseResource
|
|
3
|
+
def formatted_details
|
|
4
|
+
case details
|
|
5
|
+
when String
|
|
6
|
+
details
|
|
7
|
+
when Hash
|
|
8
|
+
format_serialized_details
|
|
9
|
+
else
|
|
10
|
+
nil
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def format_serialized_details
|
|
15
|
+
AUDIT_LOG_CONFIG.fetch('events', {}).fetch(key, '') % details.symbolize_keys
|
|
16
|
+
rescue KeyError => e
|
|
17
|
+
e.message
|
|
18
|
+
# details.inspect
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# TODO: spec the ActiveRecord behaviour
|
|
2
|
+
# - processing of remote errors
|
|
3
|
+
# - response parsing (using data: [] format)
|
|
4
|
+
# - save methods
|
|
5
|
+
module MnoEnterprise
|
|
6
|
+
class BaseResource
|
|
7
|
+
include Her::Model
|
|
8
|
+
include HerExtension::Validations::RemoteUniquenessValidation
|
|
9
|
+
|
|
10
|
+
include_root_in_json :data
|
|
11
|
+
use_api MnoEnterprise.mnoe_api_v1
|
|
12
|
+
|
|
13
|
+
# TODO: spec that changed_attributes is empty
|
|
14
|
+
# after a KLASS.all / KLASS.where etc..
|
|
15
|
+
after_find { |res| res.instance_variable_set(:@changed_attributes, {}) }
|
|
16
|
+
|
|
17
|
+
# Attributes common to all classes
|
|
18
|
+
attributes :id, :created_at, :updated_at
|
|
19
|
+
|
|
20
|
+
# Class query methods
|
|
21
|
+
class << self
|
|
22
|
+
# Delegate the following methods to `scoped`
|
|
23
|
+
# Clear relation params for each class level query
|
|
24
|
+
[:all, :where, :create, :find, :first_or_create, :first_or_initialize, :limit, :skip, :order_by, :sort_by, :order, :sort].each do |method|
|
|
25
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
26
|
+
def #{method}(*params)
|
|
27
|
+
Her::Model::Relation.new(self).send(#{method.to_sym.inspect}, *params)
|
|
28
|
+
end
|
|
29
|
+
RUBY
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# ActiveRecord Compatibility for Her
|
|
33
|
+
def first(n = 1)
|
|
34
|
+
return [] unless n > 0
|
|
35
|
+
q = self.order_by('id.asc').limit(n)
|
|
36
|
+
n == 1 ? q.to_a.first : q.to_a
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# ActiveRecord Compatibility for Her
|
|
40
|
+
def last(n = 1)
|
|
41
|
+
return [] unless n > 0
|
|
42
|
+
q = self.order_by('id.desc').limit(n)
|
|
43
|
+
n == 1 ? q.to_a.first : q.to_a
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Find first record using a hash of attributes
|
|
47
|
+
def find_by(hash)
|
|
48
|
+
self.where(hash).limit(1).first
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# ActiveRecord Compatibility for Her
|
|
52
|
+
# Returns the class descending directly from MnoEnterprise::BaseResource, or
|
|
53
|
+
# an abstract class, if any, in the inheritance hierarchy.
|
|
54
|
+
#
|
|
55
|
+
# If A extends MnoEnterprise::BaseResource, A.base_class will return A. If B descends from A
|
|
56
|
+
# through some arbitrarily deep hierarchy, B.base_class will return A.
|
|
57
|
+
#
|
|
58
|
+
# If B < A and C < B and if A is an abstract_class then both B.base_class
|
|
59
|
+
# and C.base_class would return B as the answer since A is an abstract_class.
|
|
60
|
+
def base_class
|
|
61
|
+
unless self < BaseResource
|
|
62
|
+
raise Error, "#{name} doesn't belong in a hierarchy descending from BaseResource"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
if superclass == BaseResource || superclass.abstract_class?
|
|
66
|
+
self
|
|
67
|
+
else
|
|
68
|
+
superclass.base_class
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
#======================================================================
|
|
74
|
+
# Instance methods
|
|
75
|
+
#======================================================================
|
|
76
|
+
# Returns a cache key that can be used to identify this record.
|
|
77
|
+
#
|
|
78
|
+
# Product.new.cache_key # => "products/new"
|
|
79
|
+
# Product.find(5).cache_key # => "products/5" (updated_at not available)
|
|
80
|
+
# Person.find(5).cache_key # => "people/5-20071224150000" (updated_at available)
|
|
81
|
+
#
|
|
82
|
+
# You can also pass a list of named timestamps, and the newest in the list will be
|
|
83
|
+
# used to generate the key:
|
|
84
|
+
#
|
|
85
|
+
# Person.find(5).cache_key(:updated_at, :last_reviewed_at)
|
|
86
|
+
#
|
|
87
|
+
# Notes: copied from ActiveRecord
|
|
88
|
+
def cache_key(*timestamp_names)
|
|
89
|
+
case
|
|
90
|
+
when new?
|
|
91
|
+
"#{model_name.cache_key}/new"
|
|
92
|
+
when timestamp_names.any?
|
|
93
|
+
timestamp = max_updated_column_timestamp(timestamp_names)
|
|
94
|
+
timestamp = timestamp.utc.to_s(:nsec)
|
|
95
|
+
"#{model_name.cache_key}/#{id}-#{timestamp}"
|
|
96
|
+
when timestamp = max_updated_column_timestamp
|
|
97
|
+
timestamp = timestamp.utc.to_s(:nsec)
|
|
98
|
+
"#{model_name.cache_key}/#{id}-#{timestamp}"
|
|
99
|
+
else
|
|
100
|
+
"#{model_name.cache_key}/#{id}"
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def max_updated_column_timestamp(timestamp_names = [:updated_at])
|
|
105
|
+
timestamp_names
|
|
106
|
+
.map { |attr| self[attr] }
|
|
107
|
+
.compact
|
|
108
|
+
.map(&:to_time)
|
|
109
|
+
.max
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def clear_association_cache
|
|
113
|
+
self.class.associations[:has_many].each do |assoc|
|
|
114
|
+
instance_variable_set(:"@_her_association_#{assoc[:name]}", nil)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# ActiveRecord Compatibility for Her
|
|
119
|
+
def read_attribute(attr_name)
|
|
120
|
+
get_attribute(attr_name)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# ActiveRecord Compatibility for Her
|
|
124
|
+
def write_attribute(attr_name, value)
|
|
125
|
+
assign_attributes(attr_name => value)
|
|
126
|
+
end
|
|
127
|
+
alias []= write_attribute
|
|
128
|
+
|
|
129
|
+
# ActiveRecord Compatibility for Her
|
|
130
|
+
def save(options={})
|
|
131
|
+
if perform_validations(options)
|
|
132
|
+
ret = super()
|
|
133
|
+
process_response_errors
|
|
134
|
+
ret
|
|
135
|
+
else
|
|
136
|
+
false
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# ActiveRecord Compatibility for Her
|
|
141
|
+
def save!(options={})
|
|
142
|
+
if perform_validations(options)
|
|
143
|
+
ret = super()
|
|
144
|
+
process_response_errors
|
|
145
|
+
raise_record_invalid
|
|
146
|
+
else
|
|
147
|
+
false
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# ActiveRecord Compatibility for Her
|
|
152
|
+
def reload(options = nil)
|
|
153
|
+
@attributes.update(self.class.find(self.id).attributes)
|
|
154
|
+
self.run_callbacks :find
|
|
155
|
+
self
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# ActiveRecord Compatibility for Her
|
|
159
|
+
def update(attributes)
|
|
160
|
+
assign_attributes(attributes)
|
|
161
|
+
save
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Reset the ActiveModel hash containing all attribute changes
|
|
165
|
+
# Useful when initializing a existing resource using a hash fetched
|
|
166
|
+
# via http call (e.g.: MnoEnterprise::User.authenticate)
|
|
167
|
+
def clear_attribute_changes!
|
|
168
|
+
self.instance_variable_set(:@changed_attributes, {})
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Returns true if +comparison_object+ is the same exact object, or +comparison_object+
|
|
172
|
+
# is of the same type and +self+ has an ID and it is equal to +comparison_object.id+.
|
|
173
|
+
#
|
|
174
|
+
# Note that new records are different from any other record by definition, unless the
|
|
175
|
+
# other record is the receiver itself. Besides, if you fetch existing records with
|
|
176
|
+
# +select+ and leave the ID out, you're on your own, this predicate will return false.
|
|
177
|
+
#
|
|
178
|
+
# Note also that destroying a record preserves its ID in the model instance, so deleted
|
|
179
|
+
# models are still comparable.
|
|
180
|
+
def ==(comparison_object)
|
|
181
|
+
super ||
|
|
182
|
+
comparison_object.instance_of?(self.class) &&
|
|
183
|
+
!id.nil? &&
|
|
184
|
+
comparison_object.id == id
|
|
185
|
+
end
|
|
186
|
+
alias :eql? :==
|
|
187
|
+
|
|
188
|
+
protected
|
|
189
|
+
# Process errors from the servers and add them to the
|
|
190
|
+
# model
|
|
191
|
+
# Servers are returned using the jsonapi format
|
|
192
|
+
# E.g.:
|
|
193
|
+
# errors: [
|
|
194
|
+
# {
|
|
195
|
+
# :id=>"f720ca10-b104-0132-dbc0-600308937d74",
|
|
196
|
+
# :href=>"http://maestrano.github.io/enterprise/#users-users-list-post",
|
|
197
|
+
# :status=>"400",
|
|
198
|
+
# :code=>"name-can-t-be-blank",
|
|
199
|
+
# :title=>"Name can't be blank",
|
|
200
|
+
# :detail=>"Name can't be blank"
|
|
201
|
+
# :attribute => "name"
|
|
202
|
+
# :value => "can't be blank"
|
|
203
|
+
# }
|
|
204
|
+
# ]
|
|
205
|
+
def process_response_errors
|
|
206
|
+
if self.response_errors && self.response_errors.any?
|
|
207
|
+
self.response_errors.each do |error|
|
|
208
|
+
key = error[:attribute] && !error[:attribute].empty? ? error[:attribute] : :base
|
|
209
|
+
val = error[:value] && !error[:value].empty? ? error[:value] : error[:title]
|
|
210
|
+
self.errors[key.to_sym] << val
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
# ActiveRecord Compatibility for Her
|
|
216
|
+
def raise_record_invalid
|
|
217
|
+
raise(Her::Errors::ResourceInvalid.new(self))
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
# ActiveRecord Compatibility for Her
|
|
221
|
+
def perform_validations(options={}) # :nodoc:
|
|
222
|
+
# errors.blank? to avoid the unexpected case when errors is nil...
|
|
223
|
+
# -> THIS IS A TEMPORARY UGLY FIX
|
|
224
|
+
options[:validate] == false || self.errors.nil? || valid?(options[:context])
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
end
|
|
228
|
+
end
|