-
Notifications
You must be signed in to change notification settings - Fork 1
/
interventions_gateway_api.rb
170 lines (136 loc) · 4.07 KB
/
interventions_gateway_api.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
require 'sinatra/base'
require 'ostruct'
require 'rollbar/middleware/sinatra'
require_relative 'lib/sugar'
require_relative 'lib/credential'
require_relative 'lib/version'
require_relative 'lib/env'
require 'pry' if Env.local?
SORTED_MESSAGE_KEYS = %w(message project_id user_id).freeze
OPTIONAL_MESSAGE_KEYS = %w(workflow_id).freeze
SORTED_SUBJECT_QUEUE_KEYS = %w(project_id subject_ids user_id workflow_id).freeze
INTERVENTION_EVENT = { event: 'intervention' }.freeze
MESSAGE_EVENT_TYPE = { event_type: 'message' }.freeze
SUBJECT_QUEUE_EVENT_TYPE = { event_type: 'subject_queue' }.freeze
class InterventionsGatewayApi < Sinatra::Base
use Rollbar::Middleware::Sinatra
attr_reader :credential
configure :production, :staging, :development do
enable :logging
end
before do
content_type 'application/json'
if request.post?
setup_credentials
unless valid_credentials
error_response(401, 'invalid credentials, please check your token details')
end
end
end
# {
# "message": "All of your contributions really help."
# "project_id": "5733",
# "user_id": "6"
# }
post '/messages' do
json = JSON.parse(request.body.read.to_s)
payload_attributes = json.keys.sort.dup
non_optional_attributes = payload_attributes - OPTIONAL_MESSAGE_KEYS
has_required_attributes = (SORTED_MESSAGE_KEYS - non_optional_attributes).empty?
has_unknown_attributes = !(non_optional_attributes - SORTED_MESSAGE_KEYS).empty?
valid_payload = has_required_attributes && !has_unknown_attributes
unless valid_payload
error_response(
422,
'message requires message, project_id and user_id attributes'
)
end
message = Message.new(json)
authorize(message) do
sugar_client.experiment(message.to_h)
end
end
# {
# "project_id": "3434",
# "subject_ids": ["1", "2"],
# "user_id": "23",
# "workflow_id": "21"
# }
post '/subject_queues' do
json = JSON.parse(request.body.read.to_s)
valid_payload = SORTED_SUBJECT_QUEUE_KEYS == json.keys.sort
unless valid_payload
error_response(422, 'subject_queues requires project_id, subject_ids, user_id and workflow_id attributes')
end
subject_queue_req = SubjectQueue.new(json)
authorize(subject_queue_req) do
sugar_client.experiment(subject_queue_req.to_h)
end
end
# add a default health check end point
get '/' do
{status: 'ok', version: VERSION, commit_id: Env.commit_id}.to_json
end
# sinkhole 404 & 400 responses
error Sinatra::NotFound do
error_response(404, 'Not Found')
end
error Sinatra::BadRequest do
error_response(400, 'Bad Request')
end
private
def sugar_client
@sugar_client ||= Sugar.new(
ENV['SUGAR_HOST'],
ENV['SUGAR_USERNAME'],
ENV['SUGAR_PASSWORD']
)
end
def setup_credentials
authorization = request.env['HTTP_AUTHORIZATION']
match = /\ABearer (.*)\Z/.match(authorization)
if match
auth = match[1]
@credential = Credential.new(auth)
end
end
def valid_credentials
return false unless credential
credential.logged_in? && !credential.expired?
end
def authorize(message)
if credential.accessible_project?(message.project_id)
yield
success_response(message.user_id, message.uuid)
else
error_response(403, 'You do not have access to this project')
end
end
def success_response(user_id, uuid)
{
status: "ok",
message: "payload sent to user_id: #{user_id}",
uuid: uuid
}.to_json
end
def error_response(status_code, message)
halt status_code, { errors: [message] }.to_json
end
class Intervention < OpenStruct
def initialize(params)
uuid_added = params.merge(uuid: SecureRandom.uuid)
full_payload = uuid_added.merge(INTERVENTION_EVENT)
super(full_payload)
end
end
class Message < Intervention
def initialize(params)
super(params.merge(MESSAGE_EVENT_TYPE))
end
end
class SubjectQueue < Intervention
def initialize(params)
super(params.merge(SUBJECT_QUEUE_EVENT_TYPE))
end
end
end