twitter.rb 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. class ExternalCredential::Twitter
  2. def self.app_verify(params)
  3. register_webhook(params)
  4. end
  5. def self.request_account_to_link(credentials = {}, app_required = true)
  6. external_credential = ExternalCredential.find_by(name: 'twitter')
  7. raise Exceptions::UnprocessableEntity, 'No twitter app configured!' if !external_credential && app_required
  8. if external_credential
  9. if credentials[:consumer_key].blank?
  10. credentials[:consumer_key] = external_credential.credentials['consumer_key']
  11. end
  12. if credentials[:consumer_secret].blank?
  13. credentials[:consumer_secret] = external_credential.credentials['consumer_secret']
  14. end
  15. end
  16. raise Exceptions::UnprocessableEntity, 'No consumer_key param!' if credentials[:consumer_key].blank?
  17. raise Exceptions::UnprocessableEntity, 'No consumer_secret param!' if credentials[:consumer_secret].blank?
  18. consumer = OAuth::Consumer.new(
  19. credentials[:consumer_key],
  20. credentials[:consumer_secret], {
  21. site: 'https://api.twitter.com'
  22. }
  23. )
  24. begin
  25. request_token = consumer.get_request_token(oauth_callback: ExternalCredential.callback_url('twitter'))
  26. rescue => e
  27. if e.message == '403 Forbidden'
  28. raise "#{e.message}, maybe credentials wrong or callback_url for application wrong configured."
  29. end
  30. raise e
  31. end
  32. {
  33. request_token: request_token,
  34. authorize_url: request_token.authorize_url,
  35. }
  36. end
  37. def self.link_account(request_token, params)
  38. external_credential = ExternalCredential.find_by(name: 'twitter')
  39. raise Exceptions::UnprocessableEntity, 'No twitter app configured!' if !external_credential
  40. raise Exceptions::UnprocessableEntity, 'No request_token for session found!' if !request_token
  41. raise Exceptions::UnprocessableEntity, 'Invalid oauth_token given!' if request_token.params[:oauth_token] != params[:oauth_token]
  42. access_token = request_token.get_access_token(oauth_verifier: params[:oauth_verifier])
  43. client = TwitterSync.new(
  44. consumer_key: external_credential.credentials[:consumer_key],
  45. consumer_secret: external_credential.credentials[:consumer_secret],
  46. access_token: access_token.token,
  47. access_token_secret: access_token.secret,
  48. )
  49. client_user = client.who_am_i
  50. # check if account already exists
  51. Channel.where(area: 'Twitter::Account').each do |channel|
  52. next if !channel.options
  53. next if !channel.options['user']
  54. next if !channel.options['user']['id']
  55. next if channel.options['user']['id'].to_s != client_user.id.to_s && channel.options['user']['screen_name'] != client_user.screen_name
  56. channel.options['user']['id'] = client_user.id.to_s
  57. channel.options['user']['screen_name'] = client_user.screen_name
  58. channel.options['user']['name'] = client_user.name
  59. # update access_token
  60. channel.options['auth']['external_credential_id'] = external_credential.id
  61. channel.options['auth']['oauth_token'] = access_token.token
  62. channel.options['auth']['oauth_token_secret'] = access_token.secret
  63. channel.save!
  64. subscribe_webhook(
  65. channel: channel,
  66. client: client,
  67. external_credential: external_credential,
  68. )
  69. return channel
  70. end
  71. # create channel
  72. channel = Channel.create!(
  73. area: 'Twitter::Account',
  74. options: {
  75. adapter: 'twitter',
  76. user: {
  77. id: client_user.id.to_s,
  78. screen_name: client_user.screen_name,
  79. name: client_user.name,
  80. },
  81. auth: {
  82. external_credential_id: external_credential.id,
  83. oauth_token: access_token.token,
  84. oauth_token_secret: access_token.secret,
  85. },
  86. sync: {
  87. limit: 20,
  88. search: [],
  89. mentions: {},
  90. direct_messages: {},
  91. track_retweets: false
  92. }
  93. },
  94. active: true,
  95. created_by_id: 1,
  96. updated_by_id: 1,
  97. )
  98. subscribe_webhook(
  99. channel: channel,
  100. client: client,
  101. external_credential: external_credential,
  102. )
  103. channel
  104. end
  105. def self.webhook_url
  106. "#{Setting.get('http_type')}://#{Setting.get('fqdn')}#{Rails.configuration.api_path}/channels_twitter_webhook"
  107. end
  108. def self.register_webhook(params)
  109. request_account_to_link(params, false)
  110. raise Exceptions::UnprocessableEntity, 'No consumer_key param!' if params[:consumer_key].blank?
  111. raise Exceptions::UnprocessableEntity, 'No consumer_secret param!' if params[:consumer_secret].blank?
  112. raise Exceptions::UnprocessableEntity, 'No oauth_token param!' if params[:oauth_token].blank?
  113. raise Exceptions::UnprocessableEntity, 'No oauth_token_secret param!' if params[:oauth_token_secret].blank?
  114. return if params[:env].blank?
  115. env_name = params[:env]
  116. client = TwitterSync.new(
  117. consumer_key: params[:consumer_key],
  118. consumer_secret: params[:consumer_secret],
  119. access_token: params[:oauth_token],
  120. access_token_secret: params[:oauth_token_secret],
  121. )
  122. # needed for verify callback
  123. Cache.write('external_credential_twitter', {
  124. consumer_key: params[:consumer_key],
  125. consumer_secret: params[:consumer_secret],
  126. access_token: params[:oauth_token],
  127. access_token_secret: params[:oauth_token_secret],
  128. })
  129. # verify if webhook is already registered
  130. begin
  131. webhooks = client.webhooks_by_env_name(env_name)
  132. rescue
  133. begin
  134. webhooks = client.webhooks
  135. raise "Unable to get list of webooks. You use the wrong 'Dev environment label', only #{webhooks.inspect} available."
  136. rescue => e
  137. raise "Unable to get list of webooks. Maybe you do not have an Twitter developer approval right now or you use the wrong 'Dev environment label': #{e.message}"
  138. end
  139. end
  140. webhook_id = nil
  141. webhook_valid = nil
  142. webhooks.each do |webhook|
  143. next if webhook[:url] != webhook_url
  144. webhook_id = webhook[:id]
  145. webhook_valid = webhook[:valid]
  146. end
  147. # if webhook is already registered
  148. # - in case if webhook is invalid, just send a new verification request
  149. # - in case if webhook is valid return
  150. if webhook_id
  151. if webhook_valid == false
  152. client.webhook_request_verification(webhook_id, env_name, webhook_url)
  153. end
  154. params[:webhook_id] = webhook_id
  155. return params
  156. end
  157. # delete already registered webhooks
  158. webhooks.each do |webhook|
  159. client.webhook_delete(webhook[:id], env_name)
  160. end
  161. # register new webhook
  162. response = client.webhook_register(env_name, webhook_url)
  163. params[:webhook_id] = response[:id]
  164. params
  165. end
  166. def self.subscribe_webhook(channel:, client:, external_credential:)
  167. env_name = external_credential.credentials[:env]
  168. webhook_id = external_credential.credentials[:webhook_id]
  169. Rails.logger.debug { "Starting Twitter subscription for webhook_id #{webhook_id} and Channel #{channel.id}" }
  170. client.webhook_subscribe(env_name)
  171. channel.options['subscribed_to_webhook_id'] = webhook_id
  172. channel.save!
  173. true
  174. end
  175. end