mno-enterprise-api 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/javascripts/mno_enterprise/angular/loading-page.app.js.coffee +156 -0
- data/app/assets/javascripts/mno_enterprise/application.js +13 -0
- data/app/controllers/devise/password_expired_controller.rb +55 -0
- data/app/controllers/mno_enterprise/auth/confirmations_controller.rb +5 -0
- data/app/controllers/mno_enterprise/auth/omniauth_callbacks_controller.rb +30 -0
- data/app/controllers/mno_enterprise/auth/passwords_controller.rb +5 -0
- data/app/controllers/mno_enterprise/auth/registrations_controller.rb +5 -0
- data/app/controllers/mno_enterprise/auth/sessions_controller.rb +7 -0
- data/app/controllers/mno_enterprise/auth/unlocks_controller.rb +5 -0
- data/app/controllers/mno_enterprise/deletion_requests_controller.rb +5 -0
- data/app/controllers/mno_enterprise/impersonate_controller.rb +48 -0
- data/app/controllers/mno_enterprise/jpi/v1/admin/audit_events_controller.rb +16 -0
- data/app/controllers/mno_enterprise/jpi/v1/admin/base_resource_controller.rb +5 -0
- data/app/controllers/mno_enterprise/jpi/v1/admin/cloud_apps_controller.rb +46 -0
- data/app/controllers/mno_enterprise/jpi/v1/admin/invoices_controller.rb +47 -0
- data/app/controllers/mno_enterprise/jpi/v1/admin/organizations_controller.rb +27 -0
- data/app/controllers/mno_enterprise/jpi/v1/admin/tenant_invoices_controller.rb +14 -0
- data/app/controllers/mno_enterprise/jpi/v1/admin/users_controller.rb +63 -0
- data/app/controllers/mno_enterprise/jpi/v1/app_instances_controller.rb +24 -0
- data/app/controllers/mno_enterprise/jpi/v1/app_instances_sync_controller.rb +36 -0
- data/app/controllers/mno_enterprise/jpi/v1/base_resource_controller.rb +32 -0
- data/app/controllers/mno_enterprise/jpi/v1/current_users_controller.rb +5 -0
- data/app/controllers/mno_enterprise/jpi/v1/deletion_requests_controller.rb +5 -0
- data/app/controllers/mno_enterprise/jpi/v1/impac/dashboards_controller.rb +5 -0
- data/app/controllers/mno_enterprise/jpi/v1/impac/kpis_controller.rb +80 -0
- data/app/controllers/mno_enterprise/jpi/v1/impac/widgets_controller.rb +63 -0
- data/app/controllers/mno_enterprise/jpi/v1/industry_bundle_controller.rb +25 -0
- data/app/controllers/mno_enterprise/jpi/v1/marketplace_controller.rb +22 -0
- data/app/controllers/mno_enterprise/jpi/v1/organizations_controller.rb +5 -0
- data/app/controllers/mno_enterprise/jpi/v1/shopping_cart_controller.rb +93 -0
- data/app/controllers/mno_enterprise/jpi/v1/teams_controller.rb +88 -0
- data/app/controllers/mno_enterprise/org_invites_controller.rb +5 -0
- data/app/controllers/mno_enterprise/pages_controller.rb +5 -0
- data/app/controllers/mno_enterprise/provision_controller.rb +5 -0
- data/app/controllers/mno_enterprise/status_controller.rb +27 -0
- data/app/controllers/mno_enterprise/webhook/o_auth_controller.rb +5 -0
- data/app/mailers/mno_enterprise/system_notification_mailer.rb +5 -0
- data/app/models/mno_enterprise/health_check.rb +16 -0
- data/app/views/devise/password_expired/show.html.haml +32 -0
- data/app/views/mno_enterprise/auth/confirmations/default/_form.html.haml +49 -0
- data/app/views/mno_enterprise/auth/confirmations/default/_lounge.html.haml +34 -0
- data/app/views/mno_enterprise/auth/confirmations/default/_show.html.haml +10 -0
- data/app/views/mno_enterprise/auth/confirmations/lounge.html.haml +4 -0
- data/app/views/mno_enterprise/auth/confirmations/material/_form.html.haml +44 -0
- data/app/views/mno_enterprise/auth/confirmations/material/_lounge.html.haml +18 -0
- data/app/views/mno_enterprise/auth/confirmations/material/_show.html.haml +21 -0
- data/app/views/mno_enterprise/auth/confirmations/new.html.haml +31 -0
- data/app/views/mno_enterprise/auth/confirmations/show.html.haml +4 -0
- data/app/views/mno_enterprise/auth/mailer/confirmation_instructions.html.haml +4 -0
- data/app/views/mno_enterprise/auth/mailer/reset_password_instructions.html.haml +6 -0
- data/app/views/mno_enterprise/auth/mailer/unlock_instructions.html.haml +5 -0
- data/app/views/mno_enterprise/auth/passwords/edit.html.haml +53 -0
- data/app/views/mno_enterprise/auth/passwords/new.html.haml +34 -0
- data/app/views/mno_enterprise/auth/registrations/default/_form.html.haml +35 -0
- data/app/views/mno_enterprise/auth/registrations/default/_new.html.haml +11 -0
- data/app/views/mno_enterprise/auth/registrations/material/_form.html.haml +30 -0
- data/app/views/mno_enterprise/auth/registrations/material/_new.html.haml +10 -0
- data/app/views/mno_enterprise/auth/registrations/new.html.haml +4 -0
- data/app/views/mno_enterprise/auth/sessions/default/_form.html.haml +17 -0
- data/app/views/mno_enterprise/auth/sessions/default/_new.html.haml +11 -0
- data/app/views/mno_enterprise/auth/sessions/material/_form.html.haml +26 -0
- data/app/views/mno_enterprise/auth/sessions/material/_new.html.haml +11 -0
- data/app/views/mno_enterprise/auth/sessions/new.html.haml +4 -0
- data/app/views/mno_enterprise/auth/shared/_links.html.haml +24 -0
- data/app/views/mno_enterprise/auth/unlocks/new.html.haml +10 -0
- data/app/views/mno_enterprise/deletion_requests/show.html.haml +131 -0
- data/app/views/mno_enterprise/jpi/v1/admin/audit_events/_audit_event.json.jbuilder +5 -0
- data/app/views/mno_enterprise/jpi/v1/admin/audit_events/index.json.jbuilder +4 -0
- data/app/views/mno_enterprise/jpi/v1/admin/cloud_apps/_cloud_app.json.jbuilder +1 -0
- data/app/views/mno_enterprise/jpi/v1/admin/cloud_apps/index.json.jbuilder +1 -0
- data/app/views/mno_enterprise/jpi/v1/admin/cloud_apps/show.json.jbuilder +1 -0
- data/app/views/mno_enterprise/jpi/v1/admin/invoices/_invoice.json.jbuilder +2 -0
- data/app/views/mno_enterprise/jpi/v1/admin/invoices/index.json.jbuilder +1 -0
- data/app/views/mno_enterprise/jpi/v1/admin/invoices/show.json.jbuilder +2 -0
- data/app/views/mno_enterprise/jpi/v1/admin/organizations/_credit_card.json.jbuilder +7 -0
- data/app/views/mno_enterprise/jpi/v1/admin/organizations/_invoices.json.jbuilder +8 -0
- data/app/views/mno_enterprise/jpi/v1/admin/organizations/_member.json.jbuilder +14 -0
- data/app/views/mno_enterprise/jpi/v1/admin/organizations/_organization.json.jbuilder +1 -0
- data/app/views/mno_enterprise/jpi/v1/admin/organizations/in_arrears.json.jbuilder +8 -0
- data/app/views/mno_enterprise/jpi/v1/admin/organizations/index.json.jbuilder +7 -0
- data/app/views/mno_enterprise/jpi/v1/admin/organizations/show.json.jbuilder +11 -0
- data/app/views/mno_enterprise/jpi/v1/admin/tenant_invoices/_tenant_invoice.json.jbuilder +5 -0
- data/app/views/mno_enterprise/jpi/v1/admin/tenant_invoices/index.json.jbuilder +1 -0
- data/app/views/mno_enterprise/jpi/v1/admin/tenant_invoices/show.json.jbuilder +1 -0
- data/app/views/mno_enterprise/jpi/v1/admin/users/_user.json.jbuilder +1 -0
- data/app/views/mno_enterprise/jpi/v1/admin/users/index.json.jbuilder +2 -0
- data/app/views/mno_enterprise/jpi/v1/admin/users/show.json.jbuilder +9 -0
- data/app/views/mno_enterprise/jpi/v1/app_instances/_resource.json.jbuilder +23 -0
- data/app/views/mno_enterprise/jpi/v1/app_instances/index.json.jbuilder +9 -0
- data/app/views/mno_enterprise/jpi/v1/app_instances/show.json.jbuilder +3 -0
- data/app/views/mno_enterprise/jpi/v1/billing/index.json.jbuilder +0 -0
- data/app/views/mno_enterprise/jpi/v1/current_users/show.json.jbuilder +37 -0
- data/app/views/mno_enterprise/jpi/v1/impac/dashboards/_dashboard.json.jbuilder +9 -0
- data/app/views/mno_enterprise/jpi/v1/impac/dashboards/index.json.jbuilder +1 -0
- data/app/views/mno_enterprise/jpi/v1/impac/dashboards/show.json.jbuilder +1 -0
- data/app/views/mno_enterprise/jpi/v1/impac/kpis/_kpi.json.jbuilder +1 -0
- data/app/views/mno_enterprise/jpi/v1/impac/kpis/show.json.jbuilder +1 -0
- data/app/views/mno_enterprise/jpi/v1/impac/widgets/_widget.json.jbuilder +6 -0
- data/app/views/mno_enterprise/jpi/v1/impac/widgets/show.json.jbuilder +1 -0
- data/app/views/mno_enterprise/jpi/v1/marketplace/_app.json.jbuilder +14 -0
- data/app/views/mno_enterprise/jpi/v1/marketplace/index.json.jbuilder +3 -0
- data/app/views/mno_enterprise/jpi/v1/marketplace/show.json.jbuilder +3 -0
- data/app/views/mno_enterprise/jpi/v1/organizations/_arrears.json.jbuilder +11 -0
- data/app/views/mno_enterprise/jpi/v1/organizations/_billing.json.jbuilder +4 -0
- data/app/views/mno_enterprise/jpi/v1/organizations/_credit_card.json.jbuilder +7 -0
- data/app/views/mno_enterprise/jpi/v1/organizations/_current_user.json.jbuilder +5 -0
- data/app/views/mno_enterprise/jpi/v1/organizations/_invoices.json.jbuilder +8 -0
- data/app/views/mno_enterprise/jpi/v1/organizations/_member.json.jbuilder +13 -0
- data/app/views/mno_enterprise/jpi/v1/organizations/_organization.json.jbuilder +13 -0
- data/app/views/mno_enterprise/jpi/v1/organizations/credit_card.json.jbuilder +1 -0
- data/app/views/mno_enterprise/jpi/v1/organizations/index.json.jbuilder +1 -0
- data/app/views/mno_enterprise/jpi/v1/organizations/members.json.jbuilder +3 -0
- data/app/views/mno_enterprise/jpi/v1/organizations/show.json.jbuilder +15 -0
- data/app/views/mno_enterprise/jpi/v1/organizations/show_reduced.json.jbuilder +3 -0
- data/app/views/mno_enterprise/jpi/v1/shopping_cart/organizations.json.jbuilder +5 -0
- data/app/views/mno_enterprise/jpi/v1/shopping_cart/show.json.jbuilder +59 -0
- data/app/views/mno_enterprise/jpi/v1/shopping_cart/show_item.json.jbuilder +34 -0
- data/app/views/mno_enterprise/jpi/v1/teams/_team.json.jbuilder +20 -0
- data/app/views/mno_enterprise/jpi/v1/teams/index.json.jbuilder +1 -0
- data/app/views/mno_enterprise/jpi/v1/teams/show.json.jbuilder +3 -0
- data/app/views/mno_enterprise/pages/app_access_unauthorized.html.haml +19 -0
- data/app/views/mno_enterprise/pages/app_logout.html.haml +18 -0
- data/app/views/mno_enterprise/pages/billing_details_required.html.haml +19 -0
- data/app/views/mno_enterprise/pages/loading.html.erb +69 -0
- data/app/views/mno_enterprise/provision/_provision_apps.html.haml +42 -0
- data/app/views/mno_enterprise/provision/_select_organization.html.haml +17 -0
- data/app/views/mno_enterprise/provision/new.html.haml +4 -0
- data/app/views/mno_enterprise/webhook/o_auth/authorize.html.haml +26 -0
- data/app/views/mno_enterprise/webhook/o_auth/providers/myob.html.haml +29 -0
- data/app/views/mno_enterprise/webhook/o_auth/providers/xero.html.haml +34 -0
- data/config/initializers/devise.rb +273 -0
- data/config/initializers/devise_extension.rb +9 -0
- data/config/initializers/devise_log.rb +12 -0
- data/config/initializers/health_check.rb +35 -0
- data/config/initializers/main_app_version.rb +6 -0
- data/config/routes.rb +152 -0
- data/lib/mno-enterprise-api.rb +1 -0
- data/lib/mno_enterprise/api.rb +14 -0
- data/lib/mno_enterprise/api/engine.rb +9 -0
- data/lib/mno_enterprise/concerns/controllers/deletion_requests_controller.rb +108 -0
- data/lib/mno_enterprise/concerns/controllers/jpi/v1/admin/base_resource_controller.rb +34 -0
- data/lib/mno_enterprise/concerns/controllers/jpi/v1/current_users_controller.rb +58 -0
- data/lib/mno_enterprise/concerns/controllers/jpi/v1/deletion_requests_controller.rb +69 -0
- data/lib/mno_enterprise/concerns/controllers/jpi/v1/impac/dashboards_controller.rb +76 -0
- data/lib/mno_enterprise/concerns/controllers/jpi/v1/organizations_controller.rb +180 -0
- data/lib/mno_enterprise/concerns/controllers/org_invites_controller.rb +44 -0
- data/lib/mno_enterprise/concerns/controllers/pages_controller.rb +78 -0
- data/lib/mno_enterprise/concerns/controllers/provision_controller.rb +71 -0
- data/lib/mno_enterprise/concerns/controllers/webhook/o_auth_controller.rb +107 -0
- data/lib/mno_enterprise/concerns/mailers/system_notification_mailer.rb +158 -0
- data/lib/mno_enterprise/event_logger.rb +32 -0
- data/spec/controllers/mno_enterprise/auth/confirmation_controller_spec.rb +68 -0
- data/spec/controllers/mno_enterprise/deletion_requests_controller_spec.rb +141 -0
- data/spec/controllers/mno_enterprise/impersonate_controller_spec.rb +48 -0
- data/spec/controllers/mno_enterprise/jpi/v1/admin/audit_events_controller_spec.rb +51 -0
- data/spec/controllers/mno_enterprise/jpi/v1/admin/cloud_apps_controller_spec.rb +92 -0
- data/spec/controllers/mno_enterprise/jpi/v1/admin/invoices_controller_spec.rb +159 -0
- data/spec/controllers/mno_enterprise/jpi/v1/admin/organizations_controller_spec.rb +116 -0
- data/spec/controllers/mno_enterprise/jpi/v1/admin/tenant_invoices_controller_spec.rb +92 -0
- data/spec/controllers/mno_enterprise/jpi/v1/admin/users_controller_spec.rb +136 -0
- data/spec/controllers/mno_enterprise/jpi/v1/app_instances_controller_spec.rb +76 -0
- data/spec/controllers/mno_enterprise/jpi/v1/app_instances_sync_controller_spec.rb +94 -0
- data/spec/controllers/mno_enterprise/jpi/v1/current_users_controller_spec.rb +128 -0
- data/spec/controllers/mno_enterprise/jpi/v1/deletion_requests_controller_spec.rb +72 -0
- data/spec/controllers/mno_enterprise/jpi/v1/impac/kpis_controller_spec.rb +80 -0
- data/spec/controllers/mno_enterprise/jpi/v1/marketplace_controller_spec.rb +115 -0
- data/spec/controllers/mno_enterprise/jpi/v1/organizations_controller_spec.rb +516 -0
- data/spec/controllers/mno_enterprise/jpi/v1/team_controller_spec.rb +86 -0
- data/spec/controllers/mno_enterprise/org_invites_controller_spec.rb +29 -0
- data/spec/controllers/mno_enterprise/pages_controller_spec.rb +49 -0
- data/spec/controllers/mno_enterprise/provision_controller_spec.rb +94 -0
- data/spec/controllers/mno_enterprise/status_controller_spec.rb +34 -0
- data/spec/controllers/mno_enterprise/webhook/o_auth_controller_spec.rb +104 -0
- data/spec/lib/mno_enterprise/event_logger_spec.rb +28 -0
- data/spec/mailer/mno_enterprise/system_notification_mailer_spec.rb +132 -0
- data/spec/rails_helper.rb +94 -0
- data/spec/requests/devise/authentication_spec.rb +43 -0
- data/spec/requests/devise/registration_spec.rb +64 -0
- data/spec/routing/devise/confirmation_routing_spec.rb +20 -0
- data/spec/routing/devise/passwords_routing_spec.rb +24 -0
- data/spec/routing/devise/registrations_routing_spec.rb +16 -0
- data/spec/routing/devise/sessions_routing_spec.rb +20 -0
- data/spec/routing/mno_enterprise/deletion_requests_controller_routing_spec.rb +20 -0
- data/spec/routing/mno_enterprise/impersonate_controller_routing.spec.rb +15 -0
- data/spec/routing/mno_enterprise/jpi/v1/admin/audit_events_controller_routing_spec.rb +11 -0
- data/spec/routing/mno_enterprise/jpi/v1/admin/cloud_apps_controller_routing_spec.rb +24 -0
- data/spec/routing/mno_enterprise/jpi/v1/admin/invoices_controller_routing_spec.rb +37 -0
- data/spec/routing/mno_enterprise/jpi/v1/admin/organizations_controller_routing_spec.rb +20 -0
- data/spec/routing/mno_enterprise/jpi/v1/admin/tenant_invoices_controller_routing_spec.rb +16 -0
- data/spec/routing/mno_enterprise/jpi/v1/admin/users_controller_routing_spec.rb +24 -0
- data/spec/routing/mno_enterprise/jpi/v1/app_instances_controller_routing_spec.rb +12 -0
- data/spec/routing/mno_enterprise/jpi/v1/app_instances_sync_controller_routing_spec.rb +15 -0
- data/spec/routing/mno_enterprise/jpi/v1/current_users_controller_routing_spec.rb +28 -0
- data/spec/routing/mno_enterprise/jpi/v1/deletion_requests_controller_routing_spec.rb +24 -0
- data/spec/routing/mno_enterprise/jpi/v1/impac/kpis_controller_routing_spec.rb +22 -0
- data/spec/routing/mno_enterprise/jpi/v1/marketplace_controller_routing_spec.rb +16 -0
- data/spec/routing/mno_enterprise/jpi/v1/organizations_controller_routing_spec.rb +44 -0
- data/spec/routing/mno_enterprise/jpi/v1/teams_controller_routing_spec.rb +36 -0
- data/spec/routing/mno_enterprise/org_invites_controller_routing_spec.rb +12 -0
- data/spec/routing/mno_enterprise/pages_controller_routing_spec.rb +29 -0
- data/spec/routing/mno_enterprise/provision_controller_routing_spec.rb +15 -0
- data/spec/routing/mno_enterprise/status_controller_routing_spec.rb +19 -0
- data/spec/routing/mno_enterprise/webhook/o_auth_controller_routing_spec.rb +27 -0
- data/spec/spec_helper.rb +88 -0
- metadata +402 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
module MnoEnterprise::Concerns::Controllers::ProvisionController
|
|
2
|
+
extend ActiveSupport::Concern
|
|
3
|
+
|
|
4
|
+
#==================================================================
|
|
5
|
+
# Included methods
|
|
6
|
+
#==================================================================
|
|
7
|
+
# 'included do' causes the included code to be evaluated in the
|
|
8
|
+
# context where it is included rather than being executed in the module's context
|
|
9
|
+
included do
|
|
10
|
+
before_filter :authenticate_user_or_signup!
|
|
11
|
+
|
|
12
|
+
protected
|
|
13
|
+
# The path used after purchased apps have been provisionned
|
|
14
|
+
def after_provision_path
|
|
15
|
+
# MySpace only defined in frontend
|
|
16
|
+
# This should be overriden by the main app when not loading frontend
|
|
17
|
+
if mno_enterprise.respond_to?(:myspace_path)
|
|
18
|
+
mno_enterprise.myspace_path(anchor: '/')
|
|
19
|
+
else
|
|
20
|
+
main_app.root_path
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
helper_method :after_provision_path # To use in the provision view
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
#==================================================================
|
|
28
|
+
# Class methods
|
|
29
|
+
#==================================================================
|
|
30
|
+
module ClassMethods
|
|
31
|
+
# def some_class_method
|
|
32
|
+
# 'some text'
|
|
33
|
+
# end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
#==================================================================
|
|
37
|
+
# Instance methods
|
|
38
|
+
#==================================================================
|
|
39
|
+
# GET /provision/new?apps[]=vtiger&organization_id=1
|
|
40
|
+
# TODO: check organization accessibility via ability
|
|
41
|
+
def new
|
|
42
|
+
@apps = params[:apps]
|
|
43
|
+
@organizations = current_user.organizations.to_a
|
|
44
|
+
@organization = @organizations.find { |o| o.id && o.id.to_s == params[:organization_id].to_s }
|
|
45
|
+
|
|
46
|
+
unless @organization
|
|
47
|
+
@organization = @organizations.one? ? @organizations.first : nil
|
|
48
|
+
end
|
|
49
|
+
authorize! :manage_app_instances, @organization
|
|
50
|
+
|
|
51
|
+
# Redirect to dashboard if no applications
|
|
52
|
+
unless @apps && @apps.any?
|
|
53
|
+
redirect_to after_provision_path
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# POST /provision
|
|
58
|
+
# TODO: check organization accessibility via ability
|
|
59
|
+
def create
|
|
60
|
+
@organization = current_user.organizations.to_a.find { |o| o.id && o.id.to_s == params[:organization_id].to_s }
|
|
61
|
+
authorize! :manage_app_instances, @organization
|
|
62
|
+
|
|
63
|
+
app_instances = []
|
|
64
|
+
params[:apps].each do |product_name|
|
|
65
|
+
app_instances << @organization.app_instances.create(product: product_name)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
render json: app_instances.map(&:attributes).to_json, status: :created
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
end
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
module MnoEnterprise::Concerns::Controllers::Webhook::OAuthController
|
|
2
|
+
extend ActiveSupport::Concern
|
|
3
|
+
|
|
4
|
+
#==================================================================
|
|
5
|
+
# Included methods
|
|
6
|
+
#==================================================================
|
|
7
|
+
# 'included do' causes the included code to be evaluated in the
|
|
8
|
+
# context where it is included rather than being executed in the module's context
|
|
9
|
+
included do
|
|
10
|
+
before_filter :authenticate_user!, only: [:authorize, :disconnect, :sync]
|
|
11
|
+
before_filter :redirect_to_lounge_if_unconfirmed
|
|
12
|
+
before_filter :check_permissions, only: [:authorize, :disconnect, :sync]
|
|
13
|
+
|
|
14
|
+
PROVIDERS_WITH_OPTIONS = ['xero','myob']
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
def app_instance
|
|
18
|
+
@app_instance ||= MnoEnterprise::AppInstance.where(uid: params[:id]).first
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Redirect with an error if user is unauthorized
|
|
22
|
+
def check_permissions
|
|
23
|
+
unless can?(:manage_app_instances, app_instance.owner)
|
|
24
|
+
redirect_to mnoe_home_path, alert: "You are not authorized to perform this action"
|
|
25
|
+
return false
|
|
26
|
+
end
|
|
27
|
+
true
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Return a hash of extra parameters that were passed along with
|
|
31
|
+
# the request
|
|
32
|
+
def extra_params
|
|
33
|
+
params.reject { |k,v| [:controller,:action,:id, :perform].include?(k.to_sym) }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Current user web token
|
|
37
|
+
def wtk
|
|
38
|
+
MnoEnterprise.jwt(user_id: current_user.uid)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Append params to the fragment part of an existing url String
|
|
42
|
+
# add_param("/#/platform/accounts", 'foo', 'bar')
|
|
43
|
+
# => "/#/platform/accounts?foo=bar"
|
|
44
|
+
# add_param("/#/platform/dashboard/he/43?en=690", 'foo', 'bar')
|
|
45
|
+
# => "/#/platform/dashboard/he/43?en=690&foo=bar"
|
|
46
|
+
def add_param_to_fragment(url, param_name, param_value)
|
|
47
|
+
uri = URI(url)
|
|
48
|
+
fragment = URI(uri.fragment || "")
|
|
49
|
+
params = URI.decode_www_form(fragment.query || "") << [param_name, param_value]
|
|
50
|
+
fragment.query = URI.encode_www_form(params)
|
|
51
|
+
uri.fragment = fragment.to_s
|
|
52
|
+
uri.to_s
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def error_message(error_key)
|
|
56
|
+
case error_key.to_sym
|
|
57
|
+
when :bad_relinking
|
|
58
|
+
%{A different account "#{app_instance.oauth_company}" was previously linked to this application, please re-link the same account.}
|
|
59
|
+
when :unauthorized
|
|
60
|
+
'We could not validate your credentials, please try again'
|
|
61
|
+
else
|
|
62
|
+
error_key
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
#==================================================================
|
|
68
|
+
# Instance methods
|
|
69
|
+
#==================================================================
|
|
70
|
+
# GET /mnoe/webhook/oauth/:id/authorize
|
|
71
|
+
def authorize
|
|
72
|
+
if params[:redirect_path].present?
|
|
73
|
+
session[:redirect_path] = params[:redirect_path]
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Certain providers require options to be selected
|
|
77
|
+
if !params[:perform] && app_instance.app && PROVIDERS_WITH_OPTIONS.include?(app_instance.app.nid.to_s)
|
|
78
|
+
render "mno_enterprise/webhook/o_auth/providers/#{app_instance.app.nid}"
|
|
79
|
+
return
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
@redirect_to = MnoEnterprise.router.authorize_oauth_url(params[:id], extra_params.merge(wtk: wtk))
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# GET /mnoe/webhook/oauth/:id/callback
|
|
86
|
+
def callback
|
|
87
|
+
path = session.delete(:redirect_path).presence || mnoe_home_path
|
|
88
|
+
|
|
89
|
+
if error_key = params.fetch(:oauth, {})[:error]
|
|
90
|
+
|
|
91
|
+
path = add_param_to_fragment(path.to_s, 'flash', [{msg: error_message(error_key), type: :error}.to_json])
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
redirect_to path
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# GET /mnoe/webhook/oauth/:id/disconnect
|
|
98
|
+
def disconnect
|
|
99
|
+
redirect_to MnoEnterprise.router.disconnect_oauth_url(params[:id], extra_params.merge(wtk: wtk))
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# GET /mnoe/webhook/oauth/:id/sync
|
|
103
|
+
def sync
|
|
104
|
+
redirect_to MnoEnterprise.router.sync_oauth_url(params[:id], extra_params.merge(wtk: wtk))
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
end
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
module MnoEnterprise::Concerns::Mailers::SystemNotificationMailer
|
|
2
|
+
extend ActiveSupport::Concern
|
|
3
|
+
|
|
4
|
+
#==================================================================
|
|
5
|
+
# Included methods
|
|
6
|
+
#==================================================================
|
|
7
|
+
# 'included do' causes the included code to be evaluated in the
|
|
8
|
+
# context where it is included rather than being executed in the module's context
|
|
9
|
+
included do
|
|
10
|
+
helper :application
|
|
11
|
+
DEFAULT_SENDER = { name: MnoEnterprise.default_sender_name, email: MnoEnterprise.default_sender_email }
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
#==================================================================
|
|
15
|
+
# Instance methods
|
|
16
|
+
#==================================================================
|
|
17
|
+
|
|
18
|
+
# Default email sender
|
|
19
|
+
# Override to allow dynamic sender
|
|
20
|
+
def default_sender
|
|
21
|
+
DEFAULT_SENDER
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# ==> Devise Email
|
|
25
|
+
# Description:
|
|
26
|
+
# Email asking users to confirm their email
|
|
27
|
+
#
|
|
28
|
+
# Mandrill vars:
|
|
29
|
+
# :first_name
|
|
30
|
+
# :last_name
|
|
31
|
+
# :full_name
|
|
32
|
+
# :confirmation_link
|
|
33
|
+
#
|
|
34
|
+
def confirmation_instructions(record, token, opts={})
|
|
35
|
+
template = record.confirmed? && record.unconfirmed_email? ? 'reconfirmation-instructions' : 'confirmation-instructions'
|
|
36
|
+
MandrillClient.deliver(template,
|
|
37
|
+
default_sender,
|
|
38
|
+
recipient(record),
|
|
39
|
+
user_vars(record).merge(confirmation_link: user_confirmation_url(confirmation_token: token))
|
|
40
|
+
)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# ==> Devise Email
|
|
44
|
+
# Description:
|
|
45
|
+
# Email providing instructions + link to reset password
|
|
46
|
+
#
|
|
47
|
+
# Mandrill vars:
|
|
48
|
+
# :first_name
|
|
49
|
+
# :last_name
|
|
50
|
+
# :full_name
|
|
51
|
+
# :reset_password_link
|
|
52
|
+
#
|
|
53
|
+
def reset_password_instructions(record, token, opts={})
|
|
54
|
+
MandrillClient.deliver('reset-password-instructions',
|
|
55
|
+
default_sender,
|
|
56
|
+
recipient(record),
|
|
57
|
+
user_vars(record).merge(reset_password_link: edit_user_password_url(reset_password_token: token))
|
|
58
|
+
)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# ==> Devise Email
|
|
62
|
+
# Description:
|
|
63
|
+
# Email providing instructions + link to unlock a user account after too many failed attempts
|
|
64
|
+
#
|
|
65
|
+
# Mandrill vars:
|
|
66
|
+
# :first_name
|
|
67
|
+
# :last_name
|
|
68
|
+
# :full_name
|
|
69
|
+
# :unlock_link
|
|
70
|
+
#
|
|
71
|
+
def unlock_instructions(record, token, opts={})
|
|
72
|
+
MandrillClient.deliver('unlock-instructions',
|
|
73
|
+
default_sender,
|
|
74
|
+
recipient(record),
|
|
75
|
+
user_vars(record).merge(unlock_link: user_unlock_url(unlock_token: token))
|
|
76
|
+
)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Description:
|
|
80
|
+
# Send an email inviting the user to join an existing organization. If the user
|
|
81
|
+
# is already confirmed it is directed to the organization invite page where he
|
|
82
|
+
# can accept or decline the invite
|
|
83
|
+
# If the user is not confirmed yet then it is considered a new user and will be directed
|
|
84
|
+
# to the confirmation page
|
|
85
|
+
#
|
|
86
|
+
# Mandrill vars:
|
|
87
|
+
# :organization
|
|
88
|
+
# :team
|
|
89
|
+
# :ref_first_name
|
|
90
|
+
# :ref_last_name
|
|
91
|
+
# :ref_full_name
|
|
92
|
+
# :ref_email
|
|
93
|
+
# :invitee_first_name
|
|
94
|
+
# :invitee_last_name
|
|
95
|
+
# :invitee_full_name
|
|
96
|
+
# :invitee_email
|
|
97
|
+
# :confirmation_link
|
|
98
|
+
#
|
|
99
|
+
def organization_invite(org_invite)
|
|
100
|
+
new_user = !org_invite.user.confirmed?
|
|
101
|
+
confirmation_link = new_user ? user_confirmation_url(confirmation_token: org_invite.user.confirmation_token) : org_invite_url(org_invite, token: org_invite.token)
|
|
102
|
+
email_template = new_user ? 'organization-invite-new-user' : 'organization-invite-existing-user'
|
|
103
|
+
|
|
104
|
+
MandrillClient.deliver(email_template,
|
|
105
|
+
default_sender,
|
|
106
|
+
recipient(org_invite.user,new_user),
|
|
107
|
+
invite_vars(org_invite,new_user).merge(confirmation_link: confirmation_link)
|
|
108
|
+
)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Description:
|
|
112
|
+
# Email providing instructions + link to initiate the account termination
|
|
113
|
+
# process.
|
|
114
|
+
#
|
|
115
|
+
# Mandrill vars:
|
|
116
|
+
# :first_name
|
|
117
|
+
# :last_name
|
|
118
|
+
# :full_name
|
|
119
|
+
# :terminate_account_link
|
|
120
|
+
def deletion_request_instructions(record, deletion_request)
|
|
121
|
+
MandrillClient.deliver('deletion-request-instructions',
|
|
122
|
+
default_sender,
|
|
123
|
+
recipient(record),
|
|
124
|
+
user_vars(record).merge(terminate_account_link: deletion_request_url(deletion_request))
|
|
125
|
+
)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
protected
|
|
129
|
+
|
|
130
|
+
def recipient(record, new_user = false)
|
|
131
|
+
hash = { email: record.email }
|
|
132
|
+
hash[:name] = "#{record.name} #{record.surname}".strip unless new_user
|
|
133
|
+
hash
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def user_vars(record)
|
|
137
|
+
{
|
|
138
|
+
first_name: record.name,
|
|
139
|
+
last_name: record.surname,
|
|
140
|
+
full_name: "#{record.name} #{record.surname}".strip
|
|
141
|
+
}
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def invite_vars(org_invite, new_user = true)
|
|
145
|
+
{
|
|
146
|
+
organization: org_invite.organization.name,
|
|
147
|
+
team: org_invite.team.present? ? org_invite.team.name : nil,
|
|
148
|
+
ref_first_name: org_invite.referrer.name,
|
|
149
|
+
ref_last_name: org_invite.referrer.surname,
|
|
150
|
+
ref_full_name: "#{org_invite.referrer.name} #{org_invite.referrer.surname}".strip,
|
|
151
|
+
ref_email: org_invite.referrer.email,
|
|
152
|
+
invitee_first_name: new_user ? nil : org_invite.user.name,
|
|
153
|
+
invitee_last_name: new_user ? nil : org_invite.user.surname,
|
|
154
|
+
invitee_full_name: new_user ? nil : "#{org_invite.user.name} #{org_invite.user.surname}".strip,
|
|
155
|
+
invitee_email: org_invite.user.email,
|
|
156
|
+
}
|
|
157
|
+
end
|
|
158
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require 'httparty'
|
|
2
|
+
|
|
3
|
+
module MnoEnterprise
|
|
4
|
+
class EventLogger
|
|
5
|
+
include HTTParty
|
|
6
|
+
base_uri "#{MnoEnterprise.mno_api_private_host || MnoEnterprise.mno_api_host}/api/mnoe/v1/audit_events"
|
|
7
|
+
read_timeout 0.1
|
|
8
|
+
basic_auth MnoEnterprise.tenant_id, MnoEnterprise.tenant_key
|
|
9
|
+
|
|
10
|
+
def self.info(key, current_user_id, description, metadata, object)
|
|
11
|
+
post('', body: {
|
|
12
|
+
data: {
|
|
13
|
+
key: key,
|
|
14
|
+
user_id: current_user_id,
|
|
15
|
+
description: description,
|
|
16
|
+
metadata: format_metadata(metadata, object),
|
|
17
|
+
subject_type: object.class.name,
|
|
18
|
+
subject_id: object.id
|
|
19
|
+
}})
|
|
20
|
+
rescue Net::ReadTimeout
|
|
21
|
+
# Meant to fail
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.format_metadata(metadata, object)
|
|
25
|
+
if metadata.blank? && object.respond_to?(:to_audit_event)
|
|
26
|
+
object.to_audit_event
|
|
27
|
+
else
|
|
28
|
+
metadata
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
require 'rails_helper'
|
|
2
|
+
|
|
3
|
+
module MnoEnterprise
|
|
4
|
+
describe Auth::ConfirmationsController, type: :controller do
|
|
5
|
+
routes { MnoEnterprise::Engine.routes }
|
|
6
|
+
|
|
7
|
+
before { @request.env['devise.mapping'] = Devise.mappings[:user] }
|
|
8
|
+
|
|
9
|
+
let(:unconfirmed_user) { build(:user, :unconfirmed, organizations: [])}
|
|
10
|
+
let(:confirmed_user) { build(:user, organizations: [])}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
describe 'GET #show' do
|
|
14
|
+
subject { get :show, confirmation_token: user.confirmation_token }
|
|
15
|
+
|
|
16
|
+
before do
|
|
17
|
+
allow(MnoEnterprise::User).to receive(:find_for_confirmation) { user }
|
|
18
|
+
allow(user).to receive(:save)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
context 'unconfirmed user' do
|
|
22
|
+
let(:user) { unconfirmed_user }
|
|
23
|
+
|
|
24
|
+
it 'does not sign in the user' do
|
|
25
|
+
subject
|
|
26
|
+
expect(controller.current_user).to be_nil
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'render the template' do
|
|
30
|
+
expect(subject).to render_template('show')
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
context 'confirmed user' do
|
|
35
|
+
let(:user) { confirmed_user }
|
|
36
|
+
|
|
37
|
+
context 'with a new email' do
|
|
38
|
+
let(:email) { 'unconfirmed@example.com' }
|
|
39
|
+
|
|
40
|
+
before do
|
|
41
|
+
user.unconfirmed_email = email
|
|
42
|
+
|
|
43
|
+
api_stub_for(get: "/users?filter[email]=#{email}&limit=1", response: from_api(nil))
|
|
44
|
+
api_stub_for(get: "/org_invites?filter[user_email]=#{email}", response: from_api(nil))
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it 'sign in the user' do
|
|
48
|
+
subject
|
|
49
|
+
expect(controller.current_user).to eq(user)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'redirects to the dashboard' do
|
|
53
|
+
expect(subject).to redirect_to(controller.signed_in_root_path(user))
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it 'does not sign in the user' do
|
|
58
|
+
subject
|
|
59
|
+
expect(controller.current_user).to be_nil
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it 'returns an error' do
|
|
63
|
+
expect(subject).to render_template("new")
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
require 'rails_helper'
|
|
2
|
+
|
|
3
|
+
# TODO: DRY Specs with shared examples
|
|
4
|
+
module MnoEnterprise
|
|
5
|
+
describe DeletionRequestsController, type: :controller do
|
|
6
|
+
render_views
|
|
7
|
+
routes { MnoEnterprise::Engine.routes }
|
|
8
|
+
|
|
9
|
+
# Stub controller ability
|
|
10
|
+
let!(:ability) { stub_ability }
|
|
11
|
+
before { allow(ability).to receive(:can?).with(any_args).and_return(true) }
|
|
12
|
+
|
|
13
|
+
# Stub model calls
|
|
14
|
+
let(:deletion_req) { build(:deletion_request) }
|
|
15
|
+
let(:user) { build(:user, deletion_request: deletion_req) }
|
|
16
|
+
|
|
17
|
+
before do
|
|
18
|
+
api_stub_for(get: "/users/#{user.id}", response: from_api(user))
|
|
19
|
+
api_stub_for(get: "/users/#{user.id}/deletion_request", response: from_api(user))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
describe "GET #show'" do
|
|
23
|
+
before { sign_in user }
|
|
24
|
+
subject { get :show, id: deletion_req.token }
|
|
25
|
+
|
|
26
|
+
# TODO: use behavior
|
|
27
|
+
it_behaves_like "a navigatable protected user action"
|
|
28
|
+
# it_behaves_like "a user protected resource"
|
|
29
|
+
|
|
30
|
+
context 'when no current_request' do
|
|
31
|
+
let(:user) { build(:user, deletion_request: nil) }
|
|
32
|
+
|
|
33
|
+
it 'redirects to the root_path' do
|
|
34
|
+
subject
|
|
35
|
+
expect(response).to redirect_to(main_app.root_path)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
context 'when not the current request' do
|
|
40
|
+
let(:new_deletion_req) { build(:deletion_request) }
|
|
41
|
+
let(:user) { build(:user, deletion_request: new_deletion_req) }
|
|
42
|
+
|
|
43
|
+
it 'redirects to the root_path' do
|
|
44
|
+
subject
|
|
45
|
+
expect(response).to redirect_to(main_app.root_path)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
describe "PUT #freeze_account" do
|
|
51
|
+
# before { api_stub_for(get: "/deletion_requests/#{deletion_req.id}", response: from_api(deletion_req)) }
|
|
52
|
+
before { api_stub_for(put: "/deletion_requests/#{deletion_req.id}", response: from_api(deletion_req)) }
|
|
53
|
+
|
|
54
|
+
before { sign_in user }
|
|
55
|
+
subject { put :freeze_account, id: deletion_req.token }
|
|
56
|
+
|
|
57
|
+
# TODO: use behavior
|
|
58
|
+
it_behaves_like "a navigatable protected user action"
|
|
59
|
+
|
|
60
|
+
context 'when the request is pending' do
|
|
61
|
+
it 'freezes the account' do
|
|
62
|
+
expect(controller.current_user).to receive(:deletion_request).and_return(deletion_req)
|
|
63
|
+
expect(deletion_req).to receive(:freeze_account!)
|
|
64
|
+
subject
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it 'redirects to the deletion request' do
|
|
68
|
+
subject
|
|
69
|
+
expect(response).to redirect_to(deletion_request_url(deletion_req))
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
context 'when the request is not pending' do
|
|
74
|
+
let(:deletion_req) { build(:deletion_request, status: 'account_frozen') }
|
|
75
|
+
|
|
76
|
+
it 'does not freezes the account' do
|
|
77
|
+
expect_any_instance_of(MnoEnterprise::DeletionRequest).not_to receive(:freeze_account!)
|
|
78
|
+
subject
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it 'redirects to the deletion request' do
|
|
82
|
+
subject
|
|
83
|
+
expect(response).to redirect_to(deletion_request_url(deletion_req))
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it 'displays an error message' do
|
|
87
|
+
subject
|
|
88
|
+
expect(flash[:alert]).to eq("Invalid action")
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
context 'when no valid request' do
|
|
93
|
+
let(:user) { build(:user, deletion_request: nil) }
|
|
94
|
+
it 'redirects to the root_path' do
|
|
95
|
+
subject
|
|
96
|
+
expect(response).to redirect_to(main_app.root_path)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
describe "PUT #checkout" do
|
|
103
|
+
before { api_stub_for(put: "/deletion_requests/#{deletion_req.id}", response: from_api(deletion_req)) }
|
|
104
|
+
|
|
105
|
+
before { sign_in user }
|
|
106
|
+
subject { put :checkout, id: deletion_req.token }
|
|
107
|
+
|
|
108
|
+
# TODO: use behavior
|
|
109
|
+
it_behaves_like "a navigatable protected user action"
|
|
110
|
+
|
|
111
|
+
context 'when the request is not account_frozen' do
|
|
112
|
+
let(:deletion_req) { build(:deletion_request, status: 'pending') }
|
|
113
|
+
|
|
114
|
+
# it 'does not freezes the account' do
|
|
115
|
+
# expect_any_instance_of(MnoEnterprise::DeletionRequest).not_to receive(:freeze_account!)
|
|
116
|
+
# subject
|
|
117
|
+
# end
|
|
118
|
+
|
|
119
|
+
it 'redirects to the deletion request' do
|
|
120
|
+
subject
|
|
121
|
+
expect(response).to redirect_to(deletion_request_url(deletion_req))
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
it 'displays an error message' do
|
|
125
|
+
subject
|
|
126
|
+
expect(flash[:alert]).to eq("Invalid action")
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
context 'when no valid request' do
|
|
131
|
+
let(:user) { build(:user, deletion_request: nil) }
|
|
132
|
+
it 'redirects to the root_path' do
|
|
133
|
+
subject
|
|
134
|
+
expect(response).to redirect_to(main_app.root_path)
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
describe "PUT #terminate"
|
|
140
|
+
end
|
|
141
|
+
end
|