crowdkit 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +16 -0
- data/Gemfile.lock +97 -0
- data/LICENSE.txt +20 -0
- data/README.md +178 -0
- data/Rakefile +54 -0
- data/VERSION +1 -0
- data/crowdkit.gemspec +122 -0
- data/lib/crowdkit.rb +77 -0
- data/lib/crowdkit/api.rb +171 -0
- data/lib/crowdkit/api/arguments.rb +187 -0
- data/lib/crowdkit/api/factory.rb +29 -0
- data/lib/crowdkit/api/request_methods.rb +70 -0
- data/lib/crowdkit/api/response_wrapper.rb +122 -0
- data/lib/crowdkit/client.rb +36 -0
- data/lib/crowdkit/client/account.rb +7 -0
- data/lib/crowdkit/client/jobs.rb +56 -0
- data/lib/crowdkit/client/judgments.rb +9 -0
- data/lib/crowdkit/client/poll.rb +48 -0
- data/lib/crowdkit/client/statuses.rb +14 -0
- data/lib/crowdkit/client/units.rb +54 -0
- data/lib/crowdkit/client/workers.rb +13 -0
- data/lib/crowdkit/client/worksets.rb +27 -0
- data/lib/crowdkit/config.rb +62 -0
- data/lib/crowdkit/core_ext/array.rb +7 -0
- data/lib/crowdkit/core_ext/hash.rb +30 -0
- data/lib/crowdkit/core_ext/sawyer.rb +7 -0
- data/lib/crowdkit/error.rb +198 -0
- data/lib/crowdkit/middleware/raise_error.rb +14 -0
- data/lib/crowdkit/ssl_certs/cacerts.pem +3868 -0
- data/lib/crowdkit/version.rb +3 -0
- data/spec/crowdkit/client/account_spec.rb +19 -0
- data/spec/crowdkit/client/jobs_spec.rb +275 -0
- data/spec/crowdkit/client/judgments_spec.rb +30 -0
- data/spec/crowdkit/client/statuses_spec.rb +30 -0
- data/spec/crowdkit/client/units_spec.rb +266 -0
- data/spec/crowdkit/client/workers_spec.rb +33 -0
- data/spec/crowdkit/client/worksets_spec.rb +113 -0
- data/spec/crowdkit/client_spec.rb +55 -0
- data/spec/crowdkit_spec.rb +139 -0
- data/spec/fixtures/account.json +7 -0
- data/spec/fixtures/jobs/copy.json +79 -0
- data/spec/fixtures/jobs/job.json +1 -0
- data/spec/fixtures/jobs/order.json +53 -0
- data/spec/fixtures/jobs/search.json +1 -0
- data/spec/fixtures/judgments/index.json +46 -0
- data/spec/fixtures/judgments/show.json +16 -0
- data/spec/fixtures/root.json +1 -0
- data/spec/fixtures/statuses/index.json +25 -0
- data/spec/fixtures/statuses/status.json +12 -0
- data/spec/fixtures/units/copy.json +34 -0
- data/spec/fixtures/units/index.json +1502 -0
- data/spec/fixtures/units/poll/normal.json +902 -0
- data/spec/fixtures/units/poll/small.json +602 -0
- data/spec/fixtures/units/show.json +34 -0
- data/spec/fixtures/upload.csv +25 -0
- data/spec/fixtures/worksets/index.json +20 -0
- data/spec/fixtures/worksets/show.json +9 -0
- data/spec/spec_helper.rb +53 -0
- data/spec/support/base.rb +11 -0
- metadata +218 -0
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Crowdkit::Client::Workers do
|
4
|
+
context "flag" do
|
5
|
+
let!(:request_stub) { stub_put("/workers/1/flag").to_return(status: 204) }
|
6
|
+
before { client.workers(worker_id: 1).flag(reason: 'Because') }
|
7
|
+
|
8
|
+
it "requests" do
|
9
|
+
expect(request_stub).to have_been_requested
|
10
|
+
end
|
11
|
+
|
12
|
+
it "response" do
|
13
|
+
expect(client.last_response.status).to eq(204)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "blows up without reason" do
|
17
|
+
expect { client.workers(worker_id: 1).flag }.to raise_error Crowdkit::ValidationError
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context "deflag" do
|
22
|
+
let!(:request_stub) { stub_put("/workers/2/deflag").to_return(status: 204) }
|
23
|
+
before { client.workers(worker_id: 2).deflag }
|
24
|
+
|
25
|
+
it "requests" do
|
26
|
+
expect(request_stub).to have_been_requested
|
27
|
+
end
|
28
|
+
|
29
|
+
it "response" do
|
30
|
+
expect(client.last_response.status).to eq(204)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Crowdkit::Client::Worksets do
|
4
|
+
context "show" do
|
5
|
+
let!(:request_stub) { stub_get("/worksets/1").to_return(fixture_response("worksets/show.json")) }
|
6
|
+
|
7
|
+
context "requests" do
|
8
|
+
it "gets made" do
|
9
|
+
client.worksets.get(1)
|
10
|
+
expect(request_stub).to have_been_requested
|
11
|
+
end
|
12
|
+
|
13
|
+
it "has find alias" do
|
14
|
+
client.worksets.find(1)
|
15
|
+
expect(request_stub).to have_been_requested
|
16
|
+
end
|
17
|
+
|
18
|
+
it "blows up without id" do
|
19
|
+
expect { client.worksets.get }.to raise_error Crowdkit::ValidationError
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context "response" do
|
24
|
+
it "parses" do
|
25
|
+
expect(client.worksets.get(1).id).to eq(1)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context "list" do
|
31
|
+
let!(:request_stub) { stub_get("/jobs/1/worksets").to_return(fixture_response("worksets/index.json")) }
|
32
|
+
|
33
|
+
context "requests" do
|
34
|
+
it "gets made" do
|
35
|
+
client.worksets(job_id: 1).list
|
36
|
+
expect(request_stub).to have_been_requested
|
37
|
+
end
|
38
|
+
|
39
|
+
it "has all alias" do
|
40
|
+
client.worksets.all(job_id: 1)
|
41
|
+
expect(request_stub).to have_been_requested
|
42
|
+
end
|
43
|
+
|
44
|
+
it "blows up without job_id" do
|
45
|
+
expect { client.worksets.list }.to raise_error Crowdkit::ValidationError
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context "response" do
|
50
|
+
it "parses" do
|
51
|
+
expect(client.worksets(job_id: 1).list.length).to eq(2)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
context "statuses" do
|
58
|
+
shared_examples_for "statuses" do
|
59
|
+
it "requests" do
|
60
|
+
expect(request_stub).to have_been_requested
|
61
|
+
end
|
62
|
+
|
63
|
+
it "response" do
|
64
|
+
expect(client.last_response.status).to eq(204)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context "flag" do
|
69
|
+
it_behaves_like "statuses" do
|
70
|
+
let!(:request_stub) { stub_put("/worksets/1/flag").to_return(status: 204) }
|
71
|
+
before { client.worksets(workset_id: 1).flag(reason: 'Because') }
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context "deflag" do
|
76
|
+
it_behaves_like "statuses" do
|
77
|
+
let!(:request_stub) { stub_put("/worksets/1/deflag").to_return(status: 204) }
|
78
|
+
before { client.worksets(workset_id: 1).deflag(reason: 'Because') }
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context "reject" do
|
83
|
+
it_behaves_like "statuses" do
|
84
|
+
let!(:request_stub) { stub_put("/worksets/1/reject").to_return(status: 204) }
|
85
|
+
before { client.worksets(workset_id: 1).reject(reason: 'Too bad!') }
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context "approve" do
|
90
|
+
it_behaves_like "statuses" do
|
91
|
+
let!(:request_stub) { stub_put("/worksets/1/approve").to_return(status: 204) }
|
92
|
+
before { client.worksets(workset_id: 1).approve(reason: 'Cool!') }
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context "bonus" do
|
98
|
+
let!(:request_stub) { stub_put("/worksets/1/bonus").to_return(status: 204) }
|
99
|
+
before { client.worksets(workset_id: 1).bonus(amount: 10) }
|
100
|
+
|
101
|
+
it "requests" do
|
102
|
+
expect(request_stub).to have_been_requested
|
103
|
+
end
|
104
|
+
|
105
|
+
it "response" do
|
106
|
+
expect(client.last_response.status).to eq(204)
|
107
|
+
end
|
108
|
+
|
109
|
+
it "blows up without amount" do
|
110
|
+
expect { client.worksets(workset_id: 1).bonus }.to raise_error Crowdkit::ValidationError
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'open-uri'
|
3
|
+
describe Crowdkit::Client do
|
4
|
+
context 'root' do
|
5
|
+
let!(:request_stub) { stub_get("").to_return(fixture_response("root.json")) }
|
6
|
+
|
7
|
+
it "requests the resource" do
|
8
|
+
client.root
|
9
|
+
expect(request_stub).to have_been_requested
|
10
|
+
end
|
11
|
+
|
12
|
+
it "provides links" do
|
13
|
+
expect(client.root.rels.size).to eq(2)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context "pagination" do
|
18
|
+
let!(:first_page) { stub_get("/jobs").to_return(fixture_response("jobs/search.json", 200, { Link: '<https://api.crowdflower.com/v2/jobs?page=2>; rel="last", <https://api.crowdflower.com/v2/jobs?page=2>; rel="next"'})) }
|
19
|
+
let!(:last_page) { stub_get("/jobs?page=2").to_return(fixture_response("jobs/search.json", 200, { Link: '<https://api.crowdflower.com/v2/jobs>; rel="first", <https://api.crowdflower.com/v2/jobs>; rel="prev"'}))}
|
20
|
+
|
21
|
+
it "auto paginates with a block" do
|
22
|
+
client.config.auto_paginate = true
|
23
|
+
total_jobs = 0
|
24
|
+
client.jobs.list { |job| total_jobs += 1 }
|
25
|
+
expect(total_jobs).to eq(10)
|
26
|
+
expect(first_page).to have_been_requested
|
27
|
+
expect(last_page).to have_been_requested
|
28
|
+
end
|
29
|
+
|
30
|
+
it "auto paginates without a block" do
|
31
|
+
client.config.auto_paginate = true
|
32
|
+
expect(client.jobs.list.to_a.length).to eq(10)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "auto paginates with options" do
|
36
|
+
expect(client.config.auto_paginate).to be_falsey
|
37
|
+
expect(client.jobs.list(auto_pagination: true).to_a.length).to eq(10)
|
38
|
+
expect(client.auto_pagination).to be_falsey
|
39
|
+
end
|
40
|
+
|
41
|
+
it "next page" do
|
42
|
+
expect(client.jobs.list.next_page.length).to eq(5)
|
43
|
+
expect(last_page).to have_been_requested
|
44
|
+
end
|
45
|
+
|
46
|
+
it "prev page" do
|
47
|
+
client.jobs.list.next_page.prev_page
|
48
|
+
expect(first_page).to have_been_requested.twice
|
49
|
+
end
|
50
|
+
|
51
|
+
it "missing page" do
|
52
|
+
expect(client.jobs.list.first_page).to be_falsey
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Crowdkit do
|
4
|
+
context "configuration" do
|
5
|
+
context "defaults" do
|
6
|
+
specify "connection_options" do
|
7
|
+
expect(Crowdkit.config.connection_options).to include({
|
8
|
+
headers: {
|
9
|
+
accept: "application/json",
|
10
|
+
user_agent: "Crowdkit Ruby Gem #{Crowdkit::VERSION}"
|
11
|
+
}
|
12
|
+
})
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context "stack" do
|
17
|
+
specify "default" do
|
18
|
+
expect(Crowdkit.config.stack.handlers.first).to eq(Faraday::Request::TokenAuthentication)
|
19
|
+
end
|
20
|
+
|
21
|
+
context "overrides" do
|
22
|
+
before(:each) do
|
23
|
+
Crowdkit.reset!
|
24
|
+
end
|
25
|
+
|
26
|
+
it "modifies existing stack" do
|
27
|
+
Crowdkit.configure do |c|
|
28
|
+
c.stack.insert_before(Faraday::Request::TokenAuthentication, Crowdkit)
|
29
|
+
end
|
30
|
+
expect(Crowdkit.config.stack.handlers.first).to eq Crowdkit
|
31
|
+
end
|
32
|
+
|
33
|
+
it "overrides stack" do
|
34
|
+
Crowdkit.configure do |c|
|
35
|
+
c.stack do |builder|
|
36
|
+
builder.use Crowdkit
|
37
|
+
end
|
38
|
+
end
|
39
|
+
expect(Crowdkit.config.stack.handlers.first).to eq Crowdkit
|
40
|
+
end
|
41
|
+
|
42
|
+
it "use custom adapter" do
|
43
|
+
Crowdkit.configure(adapter: :typhoeus)
|
44
|
+
expect(Crowdkit.config.stack.handlers.last).to eq Faraday::Adapter::Typhoeus
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context "non defaults" do
|
50
|
+
shared_examples "overrides" do
|
51
|
+
specify "user_agent" do
|
52
|
+
expect(client.config.user_agent).to eq("Foo")
|
53
|
+
end
|
54
|
+
|
55
|
+
specify "nested connection_options" do
|
56
|
+
expect(client.config.connection_options).to include({
|
57
|
+
headers: {
|
58
|
+
accept: "application/json",
|
59
|
+
user_agent: "Foo"
|
60
|
+
}
|
61
|
+
})
|
62
|
+
end
|
63
|
+
|
64
|
+
specify "logging" do
|
65
|
+
expect(client.config.stack.handlers.first).to eq(Faraday::Response::Logger)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context "global" do
|
70
|
+
let(:client) do
|
71
|
+
Crowdkit
|
72
|
+
end
|
73
|
+
|
74
|
+
before(:each) do
|
75
|
+
Crowdkit.reset!
|
76
|
+
Crowdkit.configure(debug: true, user_agent: "Foo")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context "block" do
|
81
|
+
let(:client) do
|
82
|
+
Crowdkit.new do |c|
|
83
|
+
c.debug = true
|
84
|
+
c.user_agent = "Foo"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
it_behaves_like "overrides"
|
89
|
+
end
|
90
|
+
|
91
|
+
context "opts" do
|
92
|
+
let(:client) do
|
93
|
+
Crowdkit.new({debug: true, user_agent: "Foo"})
|
94
|
+
end
|
95
|
+
|
96
|
+
it_behaves_like "overrides"
|
97
|
+
end
|
98
|
+
|
99
|
+
context "env" do
|
100
|
+
around(:each) do |example|
|
101
|
+
Crowdkit.reset!
|
102
|
+
ENV["CROWDKIT_USER_AGENT"] = "Foo"
|
103
|
+
ENV["CROWDKIT_DEBUG"] = "true"
|
104
|
+
example.run
|
105
|
+
ENV["CROWDKIT_USER_AGENT"] = nil
|
106
|
+
ENV["CROWDKIT_DEBUG"] = nil
|
107
|
+
end
|
108
|
+
|
109
|
+
let(:client) do
|
110
|
+
Crowdkit
|
111
|
+
end
|
112
|
+
|
113
|
+
it_behaves_like "overrides"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
context "client proxy" do
|
119
|
+
context "unconfigured" do
|
120
|
+
specify "exception" do
|
121
|
+
expect { Crowdkit.do_get("/foo") }.to raise_error Crowdkit::Unauthorized
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context "rate limits" do
|
127
|
+
let!(:soft_request_stub) { stub_get(/jobs\/soft/).to_return(body: 'rate limit exceeded', status: 429) }
|
128
|
+
let!(:hard_request_stub) { stub_get(/jobs\/hard/).to_return(body: 'rate limit exceeded', status: 403) }
|
129
|
+
|
130
|
+
it "retries once on hard" do
|
131
|
+
expect { client.jobs.get("hard") }.to raise_error(Crowdkit::Forbidden)
|
132
|
+
end
|
133
|
+
|
134
|
+
it "raises error on soft" do
|
135
|
+
expect { client.jobs.get("soft") }.to raise_error(Crowdkit::TooManyRequests)
|
136
|
+
expect(soft_request_stub).to have_been_requested.times(2)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
{
|
2
|
+
"id":12,
|
3
|
+
"created_at":"2014-06-12T23:24:05Z",
|
4
|
+
"updated_at":"2014-06-12T23:24:05Z",
|
5
|
+
"state":"unordered",
|
6
|
+
"tags":[],
|
7
|
+
"title":"Some really awesome job that is so very very cool",
|
8
|
+
"stats":{
|
9
|
+
"units_count":0,
|
10
|
+
"new_units_count":0,
|
11
|
+
"judgments_count":0,
|
12
|
+
"needed_judgments_count":0,
|
13
|
+
"golds_count":0,
|
14
|
+
"cost":0.0,
|
15
|
+
"allocated_funds":0.0
|
16
|
+
},
|
17
|
+
"user":{
|
18
|
+
"id":1,
|
19
|
+
"name":"cf_internal user",
|
20
|
+
"account_balance":0.0,
|
21
|
+
"allocated_funds":0.0,
|
22
|
+
"email":"cf_internal@crowdflower.com"
|
23
|
+
},
|
24
|
+
"_links":{
|
25
|
+
"self":{
|
26
|
+
"href":"https://api.crowdflower.dev/v2/jobs/12"
|
27
|
+
},
|
28
|
+
"units":{
|
29
|
+
"href":"https://api.crowdflower.dev/v2/jobs/12/units/{unit_id}",
|
30
|
+
"templated":true
|
31
|
+
},
|
32
|
+
"judgments":{
|
33
|
+
"href":"https://api.crowdflower.dev/v2/jobs/12/judgments/{judgment_id}",
|
34
|
+
"templated":true
|
35
|
+
}
|
36
|
+
},
|
37
|
+
"definition":{
|
38
|
+
"cml":"<p>I don't have any data this is a survey</p>\n<cml:checkboxes label=\"How cool is this?\" class=\"\" validates=\"required\">\n <cml:checkbox label=\"Category A\"/>\n <cml:checkbox label=\"Category B\"/>\n <cml:checkbox label=\"Category C\"/>\n </cml:checkboxes>",
|
39
|
+
"instructions":"Well you've got to do this awesome shit, and then later do that cool stuff"
|
40
|
+
},
|
41
|
+
"contributor_settings":{
|
42
|
+
"assignment_ttl_in_minutes":30,
|
43
|
+
"excluded_countries":[],
|
44
|
+
"included_countries":[],
|
45
|
+
"channels":[]
|
46
|
+
},
|
47
|
+
"quality_settings":{
|
48
|
+
"test_questions_per_assignment":0,
|
49
|
+
"reject_at":70,
|
50
|
+
"after_gold":10,
|
51
|
+
"variable_judgments_mode":"none"
|
52
|
+
},
|
53
|
+
"job_settings":{
|
54
|
+
"judgments_per_unit":3,
|
55
|
+
"units_per_assignment":5,
|
56
|
+
"pages_per_assignment":1,
|
57
|
+
"language":"en",
|
58
|
+
"explicit_content":false,
|
59
|
+
"payment_cents":5,
|
60
|
+
"public_data":false
|
61
|
+
},
|
62
|
+
"api_settings":{
|
63
|
+
"auto_order":false
|
64
|
+
},
|
65
|
+
"report_settings":{
|
66
|
+
"include_unfinished":true
|
67
|
+
},
|
68
|
+
"current_status":{
|
69
|
+
"id":"3d05fc4a1501dcebfb836434d8fc5cce",
|
70
|
+
"percent_complete":0,
|
71
|
+
"state":"queued",
|
72
|
+
"name":"Unit Copy",
|
73
|
+
"_links":{
|
74
|
+
"self":{
|
75
|
+
"href":"https://api.crowdflower.com/v2/statuses/3d05fc4a1501dcebfb836434d8fc5cce"
|
76
|
+
}
|
77
|
+
}
|
78
|
+
}
|
79
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"id":1,"created_at":"2014-02-07T16:43:29Z","updated_at":"2014-02-07T16:45:00Z","state":"unordered","tags":[],"title":"Some really awesome job that is so very very cool","stats":{"units_count":1,"new_units_count":1,"judgments_count":0,"needed_judgments_count":0,"golds_count":0},"user":{"id":1,"name":"cf_internal user","email":"cf_internal@crowdflower.com"},"_links":{"self":{"href":"https://api.crowdflower.dev/v2/jobs/1"},"units":{"href":"https://api.crowdflower.dev/v2/jobs/1/units/{unit_id}","templated":true},"judgments":{"href":"https://api.crowdflower.dev/v2/jobs/1/judgments/{judgment_id}","templated":true}},"definition":{"cml":"<p>I don't have any data this is a survey</p>\n<cml:checkboxes label=\"How cool is this?\" class=\"\" validates=\"required\">\n <cml:checkbox label=\"Category A\"/>\n <cml:checkbox label=\"Category B\"/>\n <cml:checkbox label=\"Category C\"/>\n </cml:checkboxes>","instructions":"Well you've got to do this awesome shit, and then later do that cool stuff"},"contributor_settings":{"assignment_ttl_in_minutes":30,"excluded_countries":[],"included_countries":[],"channels":[]},"quality_settings":{"test_questions_per_assignment":0,"reject_at":70,"after_gold":10,"variable_judgments_mode":"none"},"job_settings":{"judgments_per_unit":3,"units_per_assignment":5,"pages_per_assignment":1,"language":"en","explicit_content":false,"payment_cents":5,"public_data":false},"api_settings":{"auto_order":false},"report_settings":{"include_unfinished":true}}
|
@@ -0,0 +1,53 @@
|
|
1
|
+
{
|
2
|
+
"created_at":"2014-06-13T22:14:11Z",
|
3
|
+
"units_count":5,
|
4
|
+
"amount":10.0,
|
5
|
+
"id":1822,
|
6
|
+
"job":{
|
7
|
+
"id":9408,
|
8
|
+
"created_at":"2014-06-13T22:14:11Z",
|
9
|
+
"updated_at":"2014-06-13T22:14:11Z",
|
10
|
+
"state":"running",
|
11
|
+
"project_number":"PN001",
|
12
|
+
"tags":[],
|
13
|
+
"alias":"foo1",
|
14
|
+
"title":"Fantastic Job",
|
15
|
+
"stats":{
|
16
|
+
"units_count":5,
|
17
|
+
"new_units_count":5,
|
18
|
+
"judgments_count":0,
|
19
|
+
"needed_judgments_count":0,
|
20
|
+
"golds_count":0,
|
21
|
+
"cost":0.0,
|
22
|
+
"allocated_funds":0.0
|
23
|
+
},
|
24
|
+
"_links":{
|
25
|
+
"self":{
|
26
|
+
"href":"https://api.crowdflower.test/v2/jobs/9408"
|
27
|
+
}
|
28
|
+
}
|
29
|
+
},
|
30
|
+
"user":{
|
31
|
+
"id":18548,
|
32
|
+
"name":"Willy Beetus",
|
33
|
+
"account_balance":10.0,
|
34
|
+
"allocated_funds":10.0,
|
35
|
+
"email":"person1@crowdflower.com"
|
36
|
+
},
|
37
|
+
"current_status":{
|
38
|
+
"id":"9e61a51bad819441e3d5fcfc6045b555",
|
39
|
+
"percent_complete":0,
|
40
|
+
"state":"queued",
|
41
|
+
"name":"Unit Ordering",
|
42
|
+
"_links":{
|
43
|
+
"self":{
|
44
|
+
"href":"https://api.crowdflower.com/v2/statuses/9e61a51bad819441e3d5fcfc6045b555"
|
45
|
+
}
|
46
|
+
}
|
47
|
+
},
|
48
|
+
"_links":{
|
49
|
+
"self":{
|
50
|
+
"href":"https://api.crowdflower.test/v2/orders/1822"
|
51
|
+
}
|
52
|
+
}
|
53
|
+
}
|