twitter.rb 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  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. client_user_id = client_user.id
  51. # check if account already exists
  52. Channel.where(area: 'Twitter::Account').each do |channel|
  53. next if !channel.options
  54. next if !channel.options['user']
  55. next if !channel.options['user']['id']
  56. next if channel.options['user']['id'] != client_user_id && channel.options['user']['screen_name'] != client_user.screen_name
  57. channel.options['user']['id'] = client_user_id
  58. channel.options['user']['screen_name'] = client_user.screen_name
  59. channel.options['user']['name'] = client_user.name
  60. # update access_token
  61. channel.options['auth']['external_credential_id'] = external_credential.id
  62. channel.options['auth']['oauth_token'] = access_token.token
  63. channel.options['auth']['oauth_token_secret'] = access_token.secret
  64. channel.save!
  65. subscribe_webhook(
  66. channel: channel,
  67. client: client,
  68. external_credential: external_credential,
  69. )
  70. return channel
  71. end
  72. # create channel
  73. channel = Channel.create!(
  74. area: 'Twitter::Account',
  75. options: {
  76. adapter: 'twitter',
  77. user: {
  78. id: client_user_id,
  79. screen_name: client_user.screen_name,
  80. name: client_user.name,
  81. },
  82. auth: {
  83. external_credential_id: external_credential.id,
  84. oauth_token: access_token.token,
  85. oauth_token_secret: access_token.secret,
  86. },
  87. sync: {
  88. limit: 20,
  89. search: [],
  90. mentions: {},
  91. direct_messages: {},
  92. track_retweets: false
  93. }
  94. },
  95. active: true,
  96. created_by_id: 1,
  97. updated_by_id: 1,
  98. )
  99. subscribe_webhook(
  100. channel: channel,
  101. client: client,
  102. external_credential: external_credential,
  103. )
  104. channel
  105. end
  106. def self.webhook_url
  107. "#{Setting.get('http_type')}://#{Setting.get('fqdn')}#{Rails.configuration.api_path}/channels_twitter_webhook"
  108. end
  109. def self.register_webhook(params)
  110. request_account_to_link(params, false)
  111. raise Exceptions::UnprocessableEntity, 'No consumer_key param!' if params[:consumer_key].blank?
  112. raise Exceptions::UnprocessableEntity, 'No consumer_secret param!' if params[:consumer_secret].blank?
  113. raise Exceptions::UnprocessableEntity, 'No oauth_token param!' if params[:oauth_token].blank?
  114. raise Exceptions::UnprocessableEntity, 'No oauth_token_secret param!' if params[:oauth_token_secret].blank?
  115. return if params[:env].blank?
  116. env_name = params[:env]
  117. client = TwitterSync.new(
  118. consumer_key: params[:consumer_key],
  119. consumer_secret: params[:consumer_secret],
  120. access_token: params[:oauth_token],
  121. access_token_secret: params[:oauth_token_secret],
  122. )
  123. # needed for verify callback
  124. Cache.write('external_credential_twitter', {
  125. consumer_key: params[:consumer_key],
  126. consumer_secret: params[:consumer_secret],
  127. access_token: params[:oauth_token],
  128. access_token_secret: params[:oauth_token_secret],
  129. })
  130. # verify if webhook is already registered
  131. begin
  132. webhooks = client.webhooks_by_env_name(env_name)
  133. rescue => e
  134. begin
  135. webhooks = client.webhooks
  136. raise "Unable to get list of webooks. You use the wrong 'Dev environment label', only #{webhooks.inspect} available."
  137. rescue => e
  138. 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}"
  139. end
  140. end
  141. webhook_id = nil
  142. webhook_valid = nil
  143. webhooks.each do |webhook|
  144. next if webhook[:url] != webhook_url
  145. webhook_id = webhook[:id]
  146. webhook_valid = webhook[:valid]
  147. end
  148. # if webhook is already registered
  149. # - in case if webhook is invalid, just send a new verification request
  150. # - in case if webhook is valid return
  151. if webhook_id
  152. if webhook_valid == false
  153. client.webhook_request_verification(webhook_id, env_name, webhook_url)
  154. end
  155. params[:webhook_id] = webhook_id
  156. return params
  157. end
  158. # delete already registered webhooks
  159. webhooks.each do |webhook|
  160. client.webhook_delete(webhook[:id])
  161. end
  162. # register new webhook
  163. response = client.webhook_register(env_name, webhook_url)
  164. params[:webhook_id] = response[:id]
  165. params
  166. end
  167. def self.subscribe_webhook(channel:, client:, external_credential:)
  168. env_name = external_credential.credentials[:env]
  169. webhook_id = external_credential.credentials[:webhook_id]
  170. Rails.logger.debug { "Starting Twitter subscription for webhook_id #{webhook_id} and Channel #{channel.id}" }
  171. client.webhook_subscribe(env_name)
  172. channel.options['subscribed_to_webhook_id'] = webhook_id
  173. channel.save!
  174. true
  175. end
  176. end