app/services/open_humans_service.rb
# frozen_string_literal: true
class OpenHumansService
# used to do the interfacing w/ Open Humans
BASE_API_URL = 'https://www.openhumans.org/api/direct-sharing/project'
BOUNDARY = '0P3NSNPH34RT50PENHUM4N5'
def initialize(user)
@user = user
@oh_profile = @user.open_humans_profile || OpenHumansProfile.new(user_id: @user.id)
end
def authenticate(code)
# lets convert
get_access_tokens(code)
set_open_humans_ids
# delete old files if there are any
begin
delete_opensnp_id
end
upload_opensnp_id
end
def get_access_tokens(code)
# authenticate w/ our client id/secret against API
# post with the key the user provided us with.
url = URI.parse('https://www.openhumans.org/oauth2/token/')
req = Net::HTTP::Post.new(url.request_uri)
req.basic_auth ENV.fetch('OH_CLIENT_ID'), ENV.fetch('OH_CLIENT_SECRET')
req.set_form_data('grant_type' => 'authorization_code',
'code' => code,
'redirect_uri' => OH_REDIRECT_URL)
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = (url.scheme == 'https')
response = http.request(req)
update_tokens(JSON.parse(response.body))
end
def refresh_token
url = URI.parse('https://www.openhumans.org/oauth2/token/')
req = Net::HTTP::Post.new(url.request_uri)
req.set_form_data('grant_type' => 'refresh_token',
'refresh_token' => @oh_profile.refresh_token)
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = (url.scheme == 'https')
response = http.request(req)
update_tokens(JSON.parse(response.body))
end
def set_open_humans_ids
uri = URI.parse(BASE_API_URL + '/exchange-member/')
uri_params = { access_token: @oh_profile.access_token }
uri.query = URI.encode_www_form(uri_params)
res = Net::HTTP.get_response(uri)
res_json = JSON.parse(res.body)
@oh_profile.project_member_id = res_json['project_member_id']
@oh_profile.open_humans_user_id = res_json['username']
@oh_profile.save
end
def upload_opensnp_id
base_url = BASE_API_URL + '/files/upload/?access_token='
uri = URI.parse(base_url + @oh_profile.access_token)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = (uri.scheme == 'https')
upload = Net::HTTP::Post.new(uri.request_uri)
upload.content_type = "multipart/form-data; BOUNDARY=#{BOUNDARY}"
upload.body = generate_form_body
http.request(upload)
end
def delete_opensnp_id
base_url = BASE_API_URL + '/files/delete/?access_token='
url = URI.parse(base_url + @oh_profile.access_token)
req = Net::HTTP::Post.new(url.request_uri)
req.set_form_data(project_member_id: @oh_profile.project_member_id, all_files: true)
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = (url.scheme == 'https')
http.request(req)
end
private
def update_tokens(tokens)
@oh_profile.expires_in = Time.current + tokens['expires_in']
@oh_profile.access_token = tokens['access_token']
@oh_profile.refresh_token = tokens['refresh_token']
@oh_profile.save
end
def generate_json
{ user_name: @user.name,
user_id: @user.id,
has_sequence: @user.has_sequence,
user_uri: "https://opensnp.org/users/#{@user.id}" }
end
def generate_metadata
metadata = generate_json
metadata['tags'] = ['opensnp']
metadata['description'] = "links to openSNP user #{@user.id}"
metadata
end
def generate_form_body
metadata = generate_metadata
file_content = generate_json
<<-POST_BODY.strip_heredoc
--#{BOUNDARY}\r
Content-Disposition: form-data; name="project_member_id"\r\n\r
#{@oh_profile.project_member_id}\r
--#{BOUNDARY}\r
Content-Disposition: form-data; name="metadata"\r\n\r
#{metadata.to_json}\r
--#{BOUNDARY}\r
Content-Disposition: form-data; name="data_file"; filename="#{@user.id}.json"\r\n\r
#{file_content.to_json}\r
--#{BOUNDARY}--\r\n\r
POST_BODY
end
end