zuora_connect 2.0.3i → 2.0.3j
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/models/zuora_connect/app_instance_base.rb +17 -8
- data/app/models/zuora_connect/zuora_user.rb +6 -0
- data/app/views/zuora_connect/static/invalid_app_instance_error.html.erb +1 -1
- data/app/views/zuora_connect/static/invalid_launch_request.html.erb +4 -1
- data/app/views/zuora_connect/static/launch.html.erb +6 -3
- data/app/views/zuora_connect/static/permission_error.html.erb +80 -0
- data/lib/zuora_connect/configuration.rb +2 -1
- data/lib/zuora_connect/controllers/helpers.rb +96 -58
- data/lib/zuora_connect/version.rb +1 -1
- metadata +8 -7
- data/app/models/zuora_connect/zuora_login.rb +0 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d3dffd068d3d5a57b16bbf1fa5e00eb96e60301cf19ac1153454c89c70934f39
|
4
|
+
data.tar.gz: 22fd7f60c7b3f3f68876d050e70a8d4c55bd8f797b0d0f215dd096c9bb138668
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c99a8e9830e1b3ff39a84d7ab7422529d2db2721c2c3b9af23c453bc7b3b5aa5cfbafef33a44a191629d5139f539609e34154c3b845a2da271679f2885af73ca
|
7
|
+
data.tar.gz: 904613ed66f2f1396c926d2983c23fb25b36dec82462746874f1e1e6a59af67d0798a84a1612d6b377dca1078363291d044c1a092fb422ce5892287177cfa541
|
@@ -206,18 +206,26 @@ module ZuoraConnect
|
|
206
206
|
|
207
207
|
def refresh(session: {}, session_fallback: false)
|
208
208
|
refresh_count ||= 0
|
209
|
-
|
210
|
-
|
211
|
-
|
209
|
+
#Check how app was deployed
|
210
|
+
if self.id < 24999999
|
211
|
+
start = Time.now
|
212
|
+
response = HTTParty.get(ZuoraConnect.configuration.url + "/api/#{self.api_version}/tools/tasks/#{self.id}.json",:body => {:access_token => self.access_token})
|
213
|
+
response_time = Time.now - start
|
212
214
|
|
213
|
-
|
214
|
-
|
215
|
-
|
215
|
+
ZuoraConnect.logger.debug("[#{self.id}] REFRESH TASK - Connect Task Info Request Time #{response_time.round(2).to_s}")
|
216
|
+
if response.code == 200
|
217
|
+
self.build_task(task_data: JSON.parse(response.body), session: session)
|
218
|
+
self.last_refresh = Time.now.to_i
|
219
|
+
self.cache_app_instance
|
220
|
+
self.reset_mark_for_refresh
|
221
|
+
else
|
222
|
+
raise ZuoraConnect::Exceptions::ConnectCommunicationError.new("Error Communicating with Connect", response.body, response.code)
|
223
|
+
end
|
224
|
+
else
|
225
|
+
self.build_task(task_data: JSON.parse(self.zuora_logins), session: session)
|
216
226
|
self.last_refresh = Time.now.to_i
|
217
227
|
self.cache_app_instance
|
218
228
|
self.reset_mark_for_refresh
|
219
|
-
else
|
220
|
-
raise ZuoraConnect::Exceptions::ConnectCommunicationError.new("Error Communicating with Connect", response.body, response.code)
|
221
229
|
end
|
222
230
|
rescue *(ZuoraAPI::Login::CONNECTION_EXCEPTIONS).concat(ZuoraAPI::Login::CONNECTION_READ_EXCEPTIONS) => ex
|
223
231
|
if (refresh_count += 1) < 3
|
@@ -362,6 +370,7 @@ module ZuoraConnect
|
|
362
370
|
end
|
363
371
|
end
|
364
372
|
rescue => ex
|
373
|
+
ZuoraConnect.logger.error(ex)
|
365
374
|
ZuoraConnect.logger.error("Task Data: #{task_data}") if task_data.present?
|
366
375
|
if session.present?
|
367
376
|
ZuoraConnect.logger.error("Task Session: #{session.to_h}") if session.methods.include?(:to_h)
|
@@ -1,5 +1,5 @@
|
|
1
1
|
<html><head>
|
2
|
-
<title>We're sorry, but something went wrong
|
2
|
+
<title>We're sorry, but something went wrong</title>
|
3
3
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
4
4
|
<style>
|
5
5
|
body {
|
@@ -49,6 +49,9 @@
|
|
49
49
|
color: #666;
|
50
50
|
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
|
51
51
|
}
|
52
|
+
div#main{
|
53
|
+
background: white;
|
54
|
+
}
|
52
55
|
</style>
|
53
56
|
</head>
|
54
57
|
|
@@ -38,8 +38,11 @@
|
|
38
38
|
line-height: 1.5em;
|
39
39
|
}
|
40
40
|
|
41
|
-
|
41
|
+
|
42
|
+
div.launch_button {
|
42
43
|
margin: 1em 0 1em;
|
44
|
+
margin-right: auto;
|
45
|
+
margin-left: auto;
|
43
46
|
padding: 1em;
|
44
47
|
width: 300px;
|
45
48
|
font-size: 12pt;
|
@@ -67,8 +70,8 @@
|
|
67
70
|
<input type="hidden" id="name_hash" value="<%= @names.to_s %>" />
|
68
71
|
<input type="hidden" id="app_instance_list" value="<%= @app_instance_ids.to_s %>" />
|
69
72
|
|
70
|
-
<%
|
71
|
-
<div class="
|
73
|
+
<% names.each do |id, name| %>
|
74
|
+
<div class="launch_button" >
|
72
75
|
<% label = name.present? ? "#{id} - #{name}" : id %>
|
73
76
|
<%= link_to label, root_path(app_instance_id: id) %>
|
74
77
|
</div>
|
@@ -0,0 +1,80 @@
|
|
1
|
+
<html><head>
|
2
|
+
<title>Select Task ID</title>
|
3
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
4
|
+
<style>
|
5
|
+
body {
|
6
|
+
background-color: #EFEFEF;
|
7
|
+
color: #2E2F30;
|
8
|
+
text-align: center;
|
9
|
+
font-family: arial, sans-serif;
|
10
|
+
margin: 0;
|
11
|
+
}
|
12
|
+
|
13
|
+
div.dialog {
|
14
|
+
width: 95%;
|
15
|
+
max-width: 33em;
|
16
|
+
margin: 4em auto 0;
|
17
|
+
}
|
18
|
+
|
19
|
+
div.dialog > div {
|
20
|
+
margin: 0 0 1em;
|
21
|
+
border: 1px solid #CCC;
|
22
|
+
border-right-color: #999;
|
23
|
+
border-left-color: #999;
|
24
|
+
border-bottom-color: #BBB;
|
25
|
+
border-top: #3D4B5A solid 4px;
|
26
|
+
border-top-left-radius: 9px;
|
27
|
+
border-top-right-radius: 9px;
|
28
|
+
border-bottom-left-radius: 9px;
|
29
|
+
border-bottom-right-radius: 9px;
|
30
|
+
background-color: white;
|
31
|
+
padding: 7px 12% 0;
|
32
|
+
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
|
33
|
+
}
|
34
|
+
|
35
|
+
h1 {
|
36
|
+
font-size: 100%;
|
37
|
+
color: #3D4B5A;
|
38
|
+
line-height: 1.5em;
|
39
|
+
}
|
40
|
+
|
41
|
+
|
42
|
+
div.launch_button {
|
43
|
+
margin: 1em 0 1em;
|
44
|
+
margin-right: auto;
|
45
|
+
margin-left: auto;
|
46
|
+
padding: 1em;
|
47
|
+
width: 300px;
|
48
|
+
font-size: 12pt;
|
49
|
+
font-weight: bold;
|
50
|
+
background-color: #F7F7F7;
|
51
|
+
border: 1px solid #CCC;
|
52
|
+
border-right-color: #999;
|
53
|
+
border-left-color: #999;
|
54
|
+
border-bottom-color: #999;
|
55
|
+
border-top-left-radius: 4px;
|
56
|
+
border-top-right-radius: 4px;
|
57
|
+
border-bottom-left-radius: 4px;
|
58
|
+
border-bottom-right-radius: 4px;
|
59
|
+
border-top-color: #999;
|
60
|
+
color: #666;
|
61
|
+
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
|
62
|
+
}
|
63
|
+
</style>
|
64
|
+
</head>
|
65
|
+
|
66
|
+
<body style='background: white;'>
|
67
|
+
<div class="dialog">
|
68
|
+
<div>
|
69
|
+
<h1>You currently don't have access to the deployed workflow instance.</h1>
|
70
|
+
<p style='text-align:left'>Please contact one of the below system administrators and have them give you access.</p>
|
71
|
+
<ul style='text-align:left'>
|
72
|
+
<% admins.each do |admin| %>
|
73
|
+
<li><%= admin.username %></li>
|
74
|
+
<% end %>
|
75
|
+
</ul>
|
76
|
+
</div>
|
77
|
+
</div>
|
78
|
+
|
79
|
+
|
80
|
+
</body></html>
|
@@ -3,7 +3,7 @@ module ZuoraConnect
|
|
3
3
|
|
4
4
|
attr_accessor :default_locale, :default_time_zone, :url, :mode, :delayed_job,:private_key, :additional_apartment_models
|
5
5
|
|
6
|
-
attr_accessor :enable_metrics, :telegraf_endpoint, :telegraf_debug, :custom_prometheus_update_block, :silencer_resque_finish, :blpop_queue
|
6
|
+
attr_accessor :enable_metrics, :telegraf_endpoint, :telegraf_debug, :custom_prometheus_update_block, :silencer_resque_finish, :blpop_queue, :app_access_permissions
|
7
7
|
|
8
8
|
attr_accessor :oauth_client_id, :oauth_client_secret, :oauth_client_redirect_uri
|
9
9
|
|
@@ -19,6 +19,7 @@ module ZuoraConnect
|
|
19
19
|
@additional_apartment_models = []
|
20
20
|
@silencer_resque_finish = true
|
21
21
|
@blpop_queue = false
|
22
|
+
@app_access_permissions = false
|
22
23
|
|
23
24
|
# Setting the app name for telegraf write
|
24
25
|
@enable_metrics = false
|
@@ -59,65 +59,19 @@ module ZuoraConnect
|
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
|
-
def verify_with_navbar
|
63
|
-
if !session[params[:app_instance_ids]].present?
|
64
|
-
host = request.headers["HTTP_X_FORWARDED_HOST"]
|
65
|
-
zuora_client = ZuoraAPI::Login.new(url: "https://#{host}")
|
66
|
-
menus = zuora_client.get_full_nav(cookies.to_h)["menus"]
|
67
|
-
app = menus.select do |item|
|
68
|
-
matches = /(?<=.com\/services\/)(.*?)(?=\?|$)/.match(item["url"])
|
69
|
-
if !matches.blank?
|
70
|
-
matches[0].split("?").first == ENV["DEIS_APP"]
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
session[params[:app_instance_ids]] = app[0]
|
75
|
-
return app[0]
|
76
|
-
else
|
77
|
-
return session[params[:app_instance_ids]]
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
def select_instance
|
82
|
-
begin
|
83
|
-
app = verify_with_navbar
|
84
|
-
|
85
|
-
url_tasks = JSON.parse(Base64.urlsafe_decode64(CGI.parse(URI.parse(app["url"]).query)["app_instance_ids"][0]))
|
86
|
-
@app_instance_ids = JSON.parse(Base64.urlsafe_decode64(params[:app_instance_ids]))
|
87
|
-
|
88
|
-
if (url_tasks & @app_instance_ids).size == @app_instance_ids.size
|
89
|
-
sql = "select name,id from zuora_connect_app_instances where id = ANY(ARRAY#{@app_instance_ids})"
|
90
|
-
result = ActiveRecord::Base.connection.execute(sql)
|
91
|
-
@names = {}
|
92
|
-
result.each do |x|
|
93
|
-
@names[x["id"].to_i] = x["name"]
|
94
|
-
end
|
95
|
-
render "zuora_connect/static/launch"
|
96
|
-
else
|
97
|
-
render "zuora_connect/static/invalid_launch_request"
|
98
|
-
end
|
99
|
-
rescue => ex
|
100
|
-
ZuoraConnect.logger.debug("Error parsing Instance ID's: #{ex.message}")
|
101
|
-
render "zuora_connect/static/invalid_launch_request"
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
62
|
def authenticate_connect_app_request
|
106
63
|
ElasticAPM.set_tag(:trace_id, request.uuid) if defined?(ElasticAPM) && ElasticAPM.running?
|
107
64
|
Thread.current[:appinstance] = nil
|
108
65
|
|
109
|
-
if request.headers['Zuora-Auth-Token'].present?
|
110
|
-
|
111
|
-
#Debug
|
112
|
-
headers = request.headers.env.select do |k, _|
|
113
|
-
k.downcase.start_with?('http') ||
|
114
|
-
k.in?(ActionDispatch::Http::Headers::CGI_VARIABLES)
|
115
|
-
end
|
116
|
-
puts headers
|
117
|
-
|
66
|
+
if request.headers['Zuora-Auth-Token'].present?
|
67
|
+
|
118
68
|
#Do we need to refresh session identity
|
119
69
|
zuora_host = request.headers["HTTP_X_FORWARDED_HOST"] || "apisandbox.zuora.com"
|
120
|
-
|
70
|
+
if request.headers["Zuora-Auth-Token"].present?
|
71
|
+
zuora_client = ZuoraAPI::Oauth.new(url: "https://#{zuora_host}", bearer_token: request.headers["Zuora-Auth-Token"], oauth_session_expires_at: Time.now + 5.minutes )
|
72
|
+
else
|
73
|
+
zuora_client = ZuoraAPI::Basic.new(url: "https://#{zuora_host}", session: cookies['ZSession'])
|
74
|
+
end
|
121
75
|
zuora_entity_id = request.headers['ZuoraCurrentEntity']
|
122
76
|
zuora_instance_id = params[:sidebar_launch].to_bool ? nil : (params[:app_instance_id] || session["appInstance"])
|
123
77
|
|
@@ -160,20 +114,104 @@ module ZuoraConnect
|
|
160
114
|
end
|
161
115
|
end
|
162
116
|
|
117
|
+
zuora_user_id = cookies['Zuora-User-Id'] || session["ZuoraCurrentIdentity"]['userId']
|
118
|
+
|
163
119
|
#One deployed instance
|
164
120
|
if appinstances.size == 1
|
165
121
|
ZuoraConnect.logger.debug("Instance is #{appinstances.to_h.keys.first}")
|
166
|
-
session["appInstance"] = appinstances.to_h.keys.first
|
167
122
|
|
123
|
+
#Add user/update
|
124
|
+
user = ZuoraConnect::ZuoraUser.where(:zuora_user_id => zuora_user_id).first
|
125
|
+
if user.present?
|
126
|
+
ZuoraConnect.logger.debug("Current zuora user #{zuora_user_id}")
|
127
|
+
if user.updated_at < Time.now - 1.day
|
128
|
+
user.zuora_identity_response[zuora_entity_id] = session["ZuoraCurrentIdentity"]
|
129
|
+
user.save!
|
130
|
+
end
|
131
|
+
else
|
132
|
+
ZuoraConnect.logger.debug("New zuora user object for #{zuora_user_id}")
|
133
|
+
user = ZuoraConnect::ZuoraUser.create!(:zuora_user_id => zuora_user_id, :zuora_identity_response => {zuora_entity_id => session["ZuoraCurrentIdentity"]})
|
134
|
+
end
|
135
|
+
#Update access if admin in tenant
|
136
|
+
if session["ZuoraCurrentIdentity"]['platformRole'] == 'ADMIN' && !user.app_permissions['access'].to_bool
|
137
|
+
user.app_permissions['access'] = true
|
138
|
+
user.save!
|
139
|
+
end
|
140
|
+
|
141
|
+
#If user has has access to application
|
142
|
+
if user.app_permissions['access'].to_bool || !ZuoraConnect.configuration.app_access_permissions
|
143
|
+
session["appInstance"] = appinstances.to_h.keys.first
|
144
|
+
else
|
145
|
+
Thread.current[:appinstance] = nil
|
146
|
+
session["appInstance"] = nil
|
147
|
+
admin_users = ZuoraConnect::ZuoraUser.select("zuora_identity_response #>> '{#{zuora_entity_id},username}' as username").where("zuora_identity_response #>> :selector = 'ADMIN' ", :selector => "{#{zuora_entity_id},platformRole}")
|
148
|
+
render "zuora_connect/static/permission_error", :locals => {:admins => admin_users}
|
149
|
+
return
|
150
|
+
end
|
168
151
|
#We have multiple, user must pick
|
169
152
|
elsif appinstances.size > 1
|
170
153
|
ZuoraConnect.logger.debug("User must select instance. #{@names}")
|
171
|
-
|
172
|
-
render "zuora_connect/static/launch"
|
154
|
+
render "zuora_connect/static/launch", :locals => {:names => appinstances.to_h}
|
173
155
|
return
|
174
156
|
else
|
175
|
-
|
176
|
-
|
157
|
+
begin
|
158
|
+
#Ensure user can access oauth creation API
|
159
|
+
if session["ZuoraCurrentIdentity"]['platformRole'] != 'ADMIN'
|
160
|
+
raise ZuoraConnect::Exceptions::Error.new("User is not admin, workflow cannot be deployed.")
|
161
|
+
end
|
162
|
+
|
163
|
+
body = {
|
164
|
+
'clientId' => SecureRandom.uuid,
|
165
|
+
'clientSecret' => SecureRandom.hex(10),
|
166
|
+
'userId' => zuora_user_id,
|
167
|
+
'entityIds' => [zuora_entity_id.unpack("a8a4a4a4a12").join('-')],
|
168
|
+
'customAuthorities' => [],
|
169
|
+
'additionalInformation' => {
|
170
|
+
'description' => 'This user is for workflow application.',
|
171
|
+
'name' => 'Workflow API User'
|
172
|
+
}
|
173
|
+
}
|
174
|
+
|
175
|
+
oauth_response, response = zuora_client.rest_call(method: :post, body: body.to_json, url: zuora_client.rest_endpoint("genesis/clients").gsub('v1/', ''), session_type: :bearer)
|
176
|
+
|
177
|
+
new_zuora_client = ZuoraAPI::Oauth.new(url: "https://#{zuora_host}", oauth_client_id: oauth_response["clientId"], oauth_secret: oauth_response["clientSecret"] )
|
178
|
+
|
179
|
+
client_describe, response = new_zuora_client.rest_call(body: body.to_json, url: zuora_client.rest_endpoint("genesis/user/info").gsub('v1/', ''), session_type: :bearer)
|
180
|
+
|
181
|
+
Apartment::Tenant.switch!("public")
|
182
|
+
next_id = (ZuoraConnect::AppInstance.all.where(:access_token => nil).order(id: :desc).limit(1).pluck(:id).first || 24999999) + 1
|
183
|
+
begin
|
184
|
+
Apartment::Tenant.create(next_id.to_s)
|
185
|
+
rescue Apartment::TenantExists => ex
|
186
|
+
ZuoraConnect.logger.debug("Tenant Already Exists")
|
187
|
+
end
|
188
|
+
|
189
|
+
task_data = {
|
190
|
+
"id": next_id,
|
191
|
+
"name": client_describe["tenantName"],
|
192
|
+
"mode": "Collections",
|
193
|
+
"status": "Running",
|
194
|
+
"target_login": {
|
195
|
+
"tenant_type": "Zuora",
|
196
|
+
"username": session["ZuoraCurrentIdentity"]["username"],
|
197
|
+
"url": new_zuora_client.url,
|
198
|
+
"status": "Active",
|
199
|
+
"oauth_client_id": body['clientId'],
|
200
|
+
"oauth_secret": body['clientSecret'],
|
201
|
+
"authentication_type": "OAUTH",
|
202
|
+
"entities": client_describe["accessibleEntities"].map {|e| e.merge({'displayName' => client_describe["tenantName"]})} #needs work
|
203
|
+
},
|
204
|
+
"tenant_ids": client_describe["accessibleEntities"].map{|e| e['entityId'] }.push(client_describe["tenantId"]).uniq,
|
205
|
+
}
|
206
|
+
|
207
|
+
appinstance = ZuoraConnect::AppInstance.new(:id => next_id, :zuora_logins => task_data.to_json, :oauth_expires_at => Time.now + 1000.years)
|
208
|
+
appinstance.save(:validate => false)
|
209
|
+
session["appInstance"] = appinstance.id
|
210
|
+
rescue => ex
|
211
|
+
ZuoraConnect.logger.error(ex)
|
212
|
+
render "zuora_connect/static/invalid_launch_request", :locals => {:exception => ex}
|
213
|
+
return
|
214
|
+
end
|
177
215
|
end
|
178
216
|
end
|
179
217
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zuora_connect
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.3j
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Connect Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-05-
|
11
|
+
date: 2019-05-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: apartment
|
@@ -44,20 +44,20 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 1.6.
|
47
|
+
version: 1.6.42
|
48
48
|
- - "~>"
|
49
49
|
- !ruby/object:Gem::Version
|
50
|
-
version: 1.6.
|
50
|
+
version: 1.6.42
|
51
51
|
type: :runtime
|
52
52
|
prerelease: false
|
53
53
|
version_requirements: !ruby/object:Gem::Requirement
|
54
54
|
requirements:
|
55
55
|
- - ">="
|
56
56
|
- !ruby/object:Gem::Version
|
57
|
-
version: 1.6.
|
57
|
+
version: 1.6.42
|
58
58
|
- - "~>"
|
59
59
|
- !ruby/object:Gem::Version
|
60
|
-
version: 1.6.
|
60
|
+
version: 1.6.42
|
61
61
|
- !ruby/object:Gem::Dependency
|
62
62
|
name: httparty
|
63
63
|
requirement: !ruby/object:Gem::Requirement
|
@@ -305,12 +305,13 @@ files:
|
|
305
305
|
- app/models/zuora_connect/app_instance_base.rb
|
306
306
|
- app/models/zuora_connect/login.rb
|
307
307
|
- app/models/zuora_connect/telegraf.rb
|
308
|
-
- app/models/zuora_connect/
|
308
|
+
- app/models/zuora_connect/zuora_user.rb
|
309
309
|
- app/views/layouts/zuora_connect/application.html.erb
|
310
310
|
- app/views/sql/refresh_aggregate_table.txt
|
311
311
|
- app/views/zuora_connect/static/invalid_app_instance_error.html.erb
|
312
312
|
- app/views/zuora_connect/static/invalid_launch_request.html.erb
|
313
313
|
- app/views/zuora_connect/static/launch.html.erb
|
314
|
+
- app/views/zuora_connect/static/permission_error.html.erb
|
314
315
|
- app/views/zuora_connect/static/session_error.html.erb
|
315
316
|
- config/initializers/apartment.rb
|
316
317
|
- config/initializers/aws.rb
|