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