agile-proxy 0.1.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/.bowerrc +3 -0
- data/.gitignore +8 -0
- data/.rspec +2 -0
- data/.rubocop.yml +36 -0
- data/.travis.yml +8 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +267 -0
- data/Guardfile +20 -0
- data/LICENSE +22 -0
- data/README.md +93 -0
- data/Rakefile +13 -0
- data/agile-proxy.gemspec +50 -0
- data/assets/index.html +39 -0
- data/assets/ui/app/HttpFlexibleProxyApi.js +31 -0
- data/assets/ui/app/app.js +1 -0
- data/assets/ui/app/controller/Stubs.js +64 -0
- data/assets/ui/app/controller/main.js +12 -0
- data/assets/ui/app/directive/AppEnhancedFormElement.js +21 -0
- data/assets/ui/app/directive/AppFor.js +16 -0
- data/assets/ui/app/directive/AppResponseEditor.js +54 -0
- data/assets/ui/app/model/RequestSpec.js +6 -0
- data/assets/ui/app/routes.js +10 -0
- data/assets/ui/app/service/Dialog.js +49 -0
- data/assets/ui/app/service/DomId.js +10 -0
- data/assets/ui/app/service/Error.js +7 -0
- data/assets/ui/app/service/Stub.js +36 -0
- data/assets/ui/app/view/404.html +2 -0
- data/assets/ui/app/view/dialog/error.html +10 -0
- data/assets/ui/app/view/dialog/yesNo.html +8 -0
- data/assets/ui/app/view/responses/editForm.html +78 -0
- data/assets/ui/app/view/status.html +1 -0
- data/assets/ui/app/view/stubs.html +19 -0
- data/assets/ui/app/view/stubs/edit.html +58 -0
- data/assets/ui/css/main.css +3 -0
- data/bin/agile_proxy +113 -0
- data/bower.json +27 -0
- data/config.yml +6 -0
- data/db.yml +10 -0
- data/db/migrations/20140818110800_create_users.rb +9 -0
- data/db/migrations/20140818134700_create_applications.rb +10 -0
- data/db/migrations/20140818135200_create_request_specs.rb +13 -0
- data/db/migrations/20140821115300_create_responses.rb +14 -0
- data/db/migrations/20140823082900_add_method_to_request_specs.rb +7 -0
- data/db/migrations/20140823083900_rename_request_spec_columns.rb +8 -0
- data/db/migrations/20141031072100_add_url_type_to_request_specs.rb +8 -0
- data/db/migrations/20141105125600_add_conditions_to_request_specs.rb +7 -0
- data/db/migrations/20141106083100_add_username_and_password_to_applications.rb +8 -0
- data/db/migrations/20141119143800_add_record_to_applications.rb +7 -0
- data/db/migrations/20141119174300_create_recordings.rb +18 -0
- data/db/schema.rb +78 -0
- data/examples/README.md +1 -0
- data/examples/facebook_api.html +59 -0
- data/examples/tumblr_api.html +22 -0
- data/lib/agile_proxy.rb +8 -0
- data/lib/agile_proxy/api/applications.rb +77 -0
- data/lib/agile_proxy/api/recordings.rb +52 -0
- data/lib/agile_proxy/api/request_specs.rb +85 -0
- data/lib/agile_proxy/api/root.rb +41 -0
- data/lib/agile_proxy/config.rb +63 -0
- data/lib/agile_proxy/handlers/handler.rb +43 -0
- data/lib/agile_proxy/handlers/proxy_handler.rb +110 -0
- data/lib/agile_proxy/handlers/request_handler.rb +57 -0
- data/lib/agile_proxy/handlers/stub_handler.rb +113 -0
- data/lib/agile_proxy/mitm.crt +22 -0
- data/lib/agile_proxy/mitm.key +27 -0
- data/lib/agile_proxy/model/application.rb +20 -0
- data/lib/agile_proxy/model/recording.rb +16 -0
- data/lib/agile_proxy/model/request_spec.rb +47 -0
- data/lib/agile_proxy/model/response.rb +56 -0
- data/lib/agile_proxy/model/user.rb +17 -0
- data/lib/agile_proxy/proxy_connection.rb +113 -0
- data/lib/agile_proxy/route.rb +106 -0
- data/lib/agile_proxy/router.rb +99 -0
- data/lib/agile_proxy/server.rb +85 -0
- data/lib/agile_proxy/servers/api.rb +41 -0
- data/lib/agile_proxy/servers/request_spec.rb +30 -0
- data/lib/agile_proxy/version.rb +6 -0
- data/load_proxy.js +39 -0
- data/log/.gitkeep +0 -0
- data/spec/common_helper.rb +32 -0
- data/spec/fixtures/test-server.crt +15 -0
- data/spec/fixtures/test-server.key +15 -0
- data/spec/integration/helpers/request_spec_helper.rb +60 -0
- data/spec/integration/specs/lib/server_spec.rb +407 -0
- data/spec/integration_spec_helper.rb +18 -0
- data/spec/spec_helper.rb +39 -0
- data/spec/support/test_server.rb +75 -0
- data/spec/unit/agile_proxy/api/applications_spec.rb +102 -0
- data/spec/unit/agile_proxy/api/common_helper.rb +31 -0
- data/spec/unit/agile_proxy/api/recordings_spec.rb +115 -0
- data/spec/unit/agile_proxy/api/request_specs_spec.rb +159 -0
- data/spec/unit/agile_proxy/handlers/handler_spec.rb +8 -0
- data/spec/unit/agile_proxy/handlers/proxy_handler_spec.rb +138 -0
- data/spec/unit/agile_proxy/handlers/request_handler_spec.rb +55 -0
- data/spec/unit/agile_proxy/handlers/stub_handler_spec.rb +154 -0
- data/spec/unit/agile_proxy/model/recording_spec.rb +0 -0
- data/spec/unit/agile_proxy/model/request_spec_spec.rb +45 -0
- data/spec/unit/agile_proxy/model/response_spec.rb +38 -0
- data/spec/unit/agile_proxy/server_spec.rb +88 -0
- data/spec/unit/agile_proxy/servers/api_spec.rb +31 -0
- data/spec/unit/agile_proxy/servers/request_spec_spec.rb +32 -0
- metadata +618 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
class CreateRecordings < ActiveRecord::Migration
|
|
2
|
+
def change
|
|
3
|
+
create_table :recordings do |t|
|
|
4
|
+
t.integer :application_id
|
|
5
|
+
t.text :request_headers
|
|
6
|
+
t.text :request_body
|
|
7
|
+
t.string :request_url
|
|
8
|
+
t.string :request_method
|
|
9
|
+
t.text :response_headers
|
|
10
|
+
t.text :response_body
|
|
11
|
+
t.text :response_status
|
|
12
|
+
t.integer :request_spec_id
|
|
13
|
+
t.timestamps
|
|
14
|
+
end
|
|
15
|
+
add_index :recordings, :application_id, :unique => false
|
|
16
|
+
add_index :recordings, :request_spec_id, :unique => false
|
|
17
|
+
end
|
|
18
|
+
end
|
data/db/schema.rb
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
# This file is auto-generated from the current state of the database. Instead
|
|
3
|
+
# of editing this file, please use the migrations feature of Active Record to
|
|
4
|
+
# incrementally modify your database, and then regenerate this schema definition.
|
|
5
|
+
#
|
|
6
|
+
# Note that this schema.rb definition is the authoritative source for your
|
|
7
|
+
# database schema. If you need to create the application database on another
|
|
8
|
+
# system, you should be using db:schema:load, not running all the migrations
|
|
9
|
+
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
|
|
10
|
+
# you'll amass, the slower it'll run and the greater likelihood for issues).
|
|
11
|
+
#
|
|
12
|
+
# It's strongly recommended that you check this file into your version control system.
|
|
13
|
+
|
|
14
|
+
ActiveRecord::Schema.define(version: 20141119174300) do
|
|
15
|
+
|
|
16
|
+
create_table "applications", force: true do |t|
|
|
17
|
+
t.integer "user_id"
|
|
18
|
+
t.string "name"
|
|
19
|
+
t.datetime "created_at"
|
|
20
|
+
t.datetime "updated_at"
|
|
21
|
+
t.string "username", default: "anonymous"
|
|
22
|
+
t.string "password", default: "password"
|
|
23
|
+
t.boolean "record_requests", default: false
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
add_index "applications", ["user_id"], name: "index_applications_on_user_id"
|
|
27
|
+
|
|
28
|
+
create_table "recordings", force: true do |t|
|
|
29
|
+
t.integer "application_id"
|
|
30
|
+
t.text "request_headers"
|
|
31
|
+
t.text "request_body"
|
|
32
|
+
t.string "request_url"
|
|
33
|
+
t.string "request_method"
|
|
34
|
+
t.text "response_headers"
|
|
35
|
+
t.text "response_body"
|
|
36
|
+
t.text "response_status"
|
|
37
|
+
t.integer "request_spec_id"
|
|
38
|
+
t.datetime "created_at"
|
|
39
|
+
t.datetime "updated_at"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
add_index "recordings", ["application_id"], name: "index_recordings_on_application_id"
|
|
43
|
+
add_index "recordings", ["request_spec_id"], name: "index_recordings_on_request_spec_id"
|
|
44
|
+
|
|
45
|
+
create_table "request_specs", force: true do |t|
|
|
46
|
+
t.integer "user_id"
|
|
47
|
+
t.integer "application_id"
|
|
48
|
+
t.string "url"
|
|
49
|
+
t.text "note"
|
|
50
|
+
t.integer "response_id"
|
|
51
|
+
t.string "http_method", default: "GET"
|
|
52
|
+
t.string "url_type", default: "url"
|
|
53
|
+
t.text "conditions", default: "{}"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
add_index "request_specs", ["application_id"], name: "index_request_specs_on_application_id"
|
|
57
|
+
add_index "request_specs", ["user_id"], name: "index_request_specs_on_user_id"
|
|
58
|
+
|
|
59
|
+
create_table "responses", force: true do |t|
|
|
60
|
+
t.string "name"
|
|
61
|
+
t.text "content"
|
|
62
|
+
t.string "content_type"
|
|
63
|
+
t.integer "status_code", default: 200
|
|
64
|
+
t.text "headers", default: "{}"
|
|
65
|
+
t.boolean "is_template"
|
|
66
|
+
t.float "delay", default: 0.0
|
|
67
|
+
t.datetime "created_at"
|
|
68
|
+
t.datetime "updated_at"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
create_table "users", force: true do |t|
|
|
72
|
+
t.string "name"
|
|
73
|
+
t.string "email"
|
|
74
|
+
t.datetime "created_at"
|
|
75
|
+
t.datetime "updated_at"
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
end
|
data/examples/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
See example specs in `spec/requests/examples`.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<div id="fb-root"></div>
|
|
2
|
+
<script>
|
|
3
|
+
// Load the SDK Asynchronously
|
|
4
|
+
(function(d){
|
|
5
|
+
var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
|
|
6
|
+
if (d.getElementById(id)) {return;}
|
|
7
|
+
js = d.createElement('script'); js.id = id; js.async = true;
|
|
8
|
+
js.src = "//connect.facebook.net/en_US/all.js";
|
|
9
|
+
ref.parentNode.insertBefore(js, ref);
|
|
10
|
+
}(document));
|
|
11
|
+
|
|
12
|
+
// Init the SDK upon load
|
|
13
|
+
window.fbAsyncInit = function() {
|
|
14
|
+
FB.init({
|
|
15
|
+
appId : '408416075843608', // App ID
|
|
16
|
+
//channelUrl : '//'+window.location.hostname+'/channel', // Path to your Channel File
|
|
17
|
+
status : true, // check login status
|
|
18
|
+
cookie : true, // enable cookies to allow the server to access the session
|
|
19
|
+
xfbml : true // parse XFBML
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// listen for and handle auth.statusChange events
|
|
23
|
+
FB.Event.subscribe('auth.statusChange', function(response) {
|
|
24
|
+
if (response.authResponse) {
|
|
25
|
+
// user has auth'd your app and is logged into Facebook
|
|
26
|
+
FB.api('/me', function(me){
|
|
27
|
+
if (me.name) {
|
|
28
|
+
document.getElementById('auth-displayname').innerHTML = me.name;
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
document.getElementById('auth-loggedout').style.display = 'none';
|
|
32
|
+
document.getElementById('auth-loggedin').style.display = 'block';
|
|
33
|
+
} else {
|
|
34
|
+
// user has not auth'd your app, or is not logged into Facebook
|
|
35
|
+
document.getElementById('auth-loggedout').style.display = 'block';
|
|
36
|
+
document.getElementById('auth-loggedin').style.display = 'none';
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// respond to clicks on the login and logout links
|
|
41
|
+
document.getElementById('auth-loginlink').addEventListener('click', function(){
|
|
42
|
+
FB.login();
|
|
43
|
+
});
|
|
44
|
+
document.getElementById('auth-logoutlink').addEventListener('click', function(){
|
|
45
|
+
FB.logout();
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
</script>
|
|
49
|
+
|
|
50
|
+
<h1>Facebook Client-side Authentication Example</h1>
|
|
51
|
+
<div id="auth-status">
|
|
52
|
+
<div id="auth-loggedout">
|
|
53
|
+
<a href="#" id="auth-loginlink">Login</a>
|
|
54
|
+
</div>
|
|
55
|
+
<div id="auth-loggedin" style="display:none">
|
|
56
|
+
Hi, <span id="auth-displayname"></span>
|
|
57
|
+
(<a href="#" id="auth-logoutlink">logout</a>)
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<body>
|
|
3
|
+
<h1>Latest news</h1>
|
|
4
|
+
<div id="news"></div>
|
|
5
|
+
|
|
6
|
+
<script type='text/javascript' src='http://code.jquery.com/jquery-1.8.2.min.js'></script>
|
|
7
|
+
<script type='text/javascript'>
|
|
8
|
+
$(function () {
|
|
9
|
+
var url = 'http://blog.howmanyleft.co.uk/api/read/json?callback=?&type=text&num=3&filter=text';
|
|
10
|
+
$.getJSON(url, function (data) {
|
|
11
|
+
$.each(data.posts, function (idx, post) {
|
|
12
|
+
var title = post['regular-title'];
|
|
13
|
+
var href = post['url-with-slug'];
|
|
14
|
+
var body = post['regular-body'];
|
|
15
|
+
$('#news').append(
|
|
16
|
+
'<h3><a href="' + href + '">' + title + '</a></h3>' +
|
|
17
|
+
'<p>' + body + '</p>');
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
})
|
|
21
|
+
</script>
|
|
22
|
+
</body>
|
data/lib/agile_proxy.rb
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
require 'agile_proxy/version'
|
|
2
|
+
require 'agile_proxy/config'
|
|
3
|
+
require 'agile_proxy/handlers/handler'
|
|
4
|
+
require 'agile_proxy/handlers/request_handler'
|
|
5
|
+
require 'agile_proxy/handlers/stub_handler'
|
|
6
|
+
require 'agile_proxy/handlers/proxy_handler'
|
|
7
|
+
require 'agile_proxy/server'
|
|
8
|
+
require 'agile_proxy/proxy_connection'
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
module AgileProxy
|
|
2
|
+
module Api
|
|
3
|
+
#
|
|
4
|
+
# = A grape api for applications
|
|
5
|
+
#
|
|
6
|
+
# An application is a central resource for the proxy, it is the 'application under test or development'
|
|
7
|
+
#
|
|
8
|
+
# The proxy server can handle multiple applications by assigning each one a different username and password
|
|
9
|
+
# that is used when connecting to the proxy.
|
|
10
|
+
# Each application can have its own set of stubs, can be set to record or not and much much more.
|
|
11
|
+
class Applications < Grape::API
|
|
12
|
+
include Grape::Kaminari
|
|
13
|
+
helpers do
|
|
14
|
+
# We only allow selected parameters through - spec and note
|
|
15
|
+
def permitted_params
|
|
16
|
+
@permitted_params ||= declared(
|
|
17
|
+
params,
|
|
18
|
+
{ include_missing: false },
|
|
19
|
+
[:username, :password, :name, :record_requests]
|
|
20
|
+
)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Convenient access to the record specified in the id parameter
|
|
24
|
+
def record
|
|
25
|
+
current_user.applications.where(id: params[:id]).first
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Convenient access to the record parameters from a POST or a PUT, only permitted will be returned
|
|
29
|
+
def record_params
|
|
30
|
+
permitted_params.with_indifferent_access
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def default_json_spec
|
|
34
|
+
{}
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
resource :applications do
|
|
40
|
+
desc 'List all applications for the user'
|
|
41
|
+
paginate per_page: 20, max_per_page: 200
|
|
42
|
+
get do
|
|
43
|
+
authenticate!
|
|
44
|
+
scope = current_user.applications
|
|
45
|
+
{ applications: paginate(scope).as_json(default_json_spec), total: scope.count }
|
|
46
|
+
end
|
|
47
|
+
desc 'Delete all applications for the user'
|
|
48
|
+
delete do
|
|
49
|
+
authenticate!
|
|
50
|
+
scope = current_user.applications
|
|
51
|
+
scope.destroy_all
|
|
52
|
+
{ applications: [], total: 0 }
|
|
53
|
+
end
|
|
54
|
+
desc 'Create a new application for the user'
|
|
55
|
+
post do
|
|
56
|
+
authenticate!
|
|
57
|
+
current_user.applications.create!(record_params.merge user_id: current_user.id).as_json(default_json_spec)
|
|
58
|
+
end
|
|
59
|
+
desc 'Get an application by id'
|
|
60
|
+
get ':id' do
|
|
61
|
+
authenticate!
|
|
62
|
+
record.as_json(default_json_spec)
|
|
63
|
+
end
|
|
64
|
+
delete ':id' do
|
|
65
|
+
authenticate!
|
|
66
|
+
record.tap(&:destroy).as_json(default_json_spec)
|
|
67
|
+
end
|
|
68
|
+
desc 'Update a request application'
|
|
69
|
+
put ':id' do
|
|
70
|
+
authenticate!
|
|
71
|
+
record.tap { |r| r.update_attributes(record_params) }.as_json(default_json_spec)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
module AgileProxy
|
|
2
|
+
module Api
|
|
3
|
+
#
|
|
4
|
+
# = A grape API for recordings
|
|
5
|
+
#
|
|
6
|
+
# If the application is set to allow recordings, each HTTP request and response passing
|
|
7
|
+
# through the proxy server will be recorded.
|
|
8
|
+
#
|
|
9
|
+
# This API allows access to those recordings via REST
|
|
10
|
+
#
|
|
11
|
+
class Recordings < Grape::API
|
|
12
|
+
include Grape::Kaminari
|
|
13
|
+
helpers do
|
|
14
|
+
# Convenient access to the record specified in the id parameter
|
|
15
|
+
def record
|
|
16
|
+
current_application.recordings.where(id: params[:id]).first
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def default_json_spec
|
|
20
|
+
{}
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
resource :recordings do
|
|
25
|
+
desc 'List all recordings made for the application'
|
|
26
|
+
paginate per_page: 20, max_per_page: 200
|
|
27
|
+
get do
|
|
28
|
+
authenticate!
|
|
29
|
+
scope = current_application.recordings
|
|
30
|
+
{ recordings: paginate(scope).as_json(default_json_spec), total: scope.count }
|
|
31
|
+
end
|
|
32
|
+
desc 'Delete all rcordings for the application'
|
|
33
|
+
delete do
|
|
34
|
+
authenticate!
|
|
35
|
+
scope = current_application.recordings
|
|
36
|
+
scope.destroy_all
|
|
37
|
+
{ recordings: [], total: 0 }
|
|
38
|
+
end
|
|
39
|
+
desc 'Get a recording by id'
|
|
40
|
+
get ':id' do
|
|
41
|
+
authenticate!
|
|
42
|
+
record.as_json(default_json_spec)
|
|
43
|
+
end
|
|
44
|
+
delete ':id' do
|
|
45
|
+
authenticate!
|
|
46
|
+
record.tap(&:destroy).as_json(default_json_spec)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
require 'agile_proxy/model/request_spec'
|
|
2
|
+
require 'grape-kaminari'
|
|
3
|
+
module AgileProxy
|
|
4
|
+
module Api
|
|
5
|
+
#
|
|
6
|
+
# = A grape API for request specifications
|
|
7
|
+
#
|
|
8
|
+
# A 'request specification' is what is known as a 'Stub' in the UI.
|
|
9
|
+
#
|
|
10
|
+
# It defines an input and output spec for a HTTP(s) request.
|
|
11
|
+
#
|
|
12
|
+
# For example, we could say
|
|
13
|
+
# 'When http://www.mybing.com/search.html is requested with some specific query parameters, then respond with this'
|
|
14
|
+
#
|
|
15
|
+
# This API allows full CRUD access to these request specifications, but only those belonging to the logged in user.
|
|
16
|
+
#
|
|
17
|
+
class RequestSpecs < Grape::API
|
|
18
|
+
include Grape::Kaminari
|
|
19
|
+
helpers do
|
|
20
|
+
# We only allow selected parameters through - spec and note
|
|
21
|
+
def permitted_params
|
|
22
|
+
@permitted_params ||= declared(
|
|
23
|
+
params,
|
|
24
|
+
{ include_missing: false },
|
|
25
|
+
[:spec, :note, :response, :http_method, :url, :url_type, :conditions]
|
|
26
|
+
)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Convenient access to the record specified in the id parameter
|
|
30
|
+
def record
|
|
31
|
+
current_application.request_specs.where(id: params[:id]).first
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Convenient access to the record parameters from a POST or a PUT, only permitted will be returned
|
|
35
|
+
# Note that for some reason, to do with rack or grape,
|
|
36
|
+
# when we send a large body, the request_spec does not come through
|
|
37
|
+
# so, to work around this, we inject the request spec in afterwards if it is missing.
|
|
38
|
+
def record_params
|
|
39
|
+
p = permitted_params.with_indifferent_access
|
|
40
|
+
p.merge!(user_id: current_user.id, application_id: current_application.id)
|
|
41
|
+
p[:response_attributes] = p.delete(:response) if p.key?(:response)
|
|
42
|
+
p
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def default_json_spec
|
|
46
|
+
{ include: { response: { except: [:created_at, :updated_at] } } }
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
end
|
|
50
|
+
resource :request_specs do
|
|
51
|
+
desc 'List all request specifications for the application'
|
|
52
|
+
paginate per_page: 20, max_per_page: 200
|
|
53
|
+
get do
|
|
54
|
+
authenticate!
|
|
55
|
+
scope = current_application.request_specs
|
|
56
|
+
{ request_specs: paginate(scope).as_json(default_json_spec), total: scope.count }
|
|
57
|
+
end
|
|
58
|
+
delete do
|
|
59
|
+
authenticate!
|
|
60
|
+
scope = current_application.request_specs
|
|
61
|
+
scope.delete_all
|
|
62
|
+
{ request_specs: [], total: 0 }
|
|
63
|
+
end
|
|
64
|
+
desc 'Create a new request specification'
|
|
65
|
+
post do
|
|
66
|
+
authenticate!
|
|
67
|
+
current_application.request_specs.create(record_params).as_json(default_json_spec)
|
|
68
|
+
end
|
|
69
|
+
get ':id' do
|
|
70
|
+
authenticate!
|
|
71
|
+
record.as_json(default_json_spec)
|
|
72
|
+
end
|
|
73
|
+
desc 'Update a request specification'
|
|
74
|
+
put ':id' do
|
|
75
|
+
authenticate!
|
|
76
|
+
record.tap { |r| r.update_attributes(record_params) }.as_json(default_json_spec)
|
|
77
|
+
end
|
|
78
|
+
delete ':id' do
|
|
79
|
+
authenticate!
|
|
80
|
+
record.tap(&:destroy).as_json(default_json_spec)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require_relative 'request_specs'
|
|
2
|
+
require_relative 'applications'
|
|
3
|
+
require_relative 'recordings'
|
|
4
|
+
module AgileProxy
|
|
5
|
+
module Api
|
|
6
|
+
#
|
|
7
|
+
# = The API Root
|
|
8
|
+
#
|
|
9
|
+
# This is the root of the entire API for use with REST. It will not be accessed directly
|
|
10
|
+
#
|
|
11
|
+
class Root < Grape::API
|
|
12
|
+
version 'v1', vendor: 'agile-proxy'
|
|
13
|
+
format :json
|
|
14
|
+
helpers do
|
|
15
|
+
# Provides easy access to the current user.
|
|
16
|
+
# As we are currently only single user, then we just return the first user
|
|
17
|
+
def current_user
|
|
18
|
+
::AgileProxy::User.first
|
|
19
|
+
end
|
|
20
|
+
# Secured methods must call this first
|
|
21
|
+
def authenticate!
|
|
22
|
+
# Do nothing yet
|
|
23
|
+
end
|
|
24
|
+
# Provides easy access to the current application whether
|
|
25
|
+
# specified in the URL or not (defaults to the first if not)
|
|
26
|
+
def current_application
|
|
27
|
+
fail 'Application ID is missing' unless params.key?(:application_id)
|
|
28
|
+
applications = current_user.applications
|
|
29
|
+
applications.where(id: params[:application_id]).first
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
namespace 'users/:user_id' do
|
|
33
|
+
mount Api::Applications
|
|
34
|
+
namespace '/applications/:application_id' do
|
|
35
|
+
mount Api::Recordings
|
|
36
|
+
mount Api::RequestSpecs
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|