| @@ -10,7 +10,7 @@ class TouchWebhookJob < ApplicationJob | |||||
| return if issue.nil? || sender.nil? | return if issue.nil? || sender.nil? | ||||
| issue.project.webhooks.each do |webhook| | issue.project.webhooks.each do |webhook| | ||||
| next unless webhook.events["events"]["issues"] | next unless webhook.events["events"]["issues"] | ||||
| @webhook_task = Webhook::EventClient.new(webhook, issue, sender,"issues","issues").do_request | |||||
| _, _, @webhook_task = Webhook::IssueClient.new(webhook, issue, sender,"issues",).do_request | |||||
| Rails.logger.info "Touch Webhook Response result: #{@webhook_task.response_content}" | Rails.logger.info "Touch Webhook Response result: #{@webhook_task.response_content}" | ||||
| end | end | ||||
| when 'IssueUpdate' | when 'IssueUpdate' | ||||
| @@ -20,7 +20,7 @@ class TouchWebhookJob < ApplicationJob | |||||
| return if issue.nil? || sender.nil? || !changes.is_a?(Hash) | return if issue.nil? || sender.nil? || !changes.is_a?(Hash) | ||||
| issue.project.webhooks.each do |webhook| | issue.project.webhooks.each do |webhook| | ||||
| next unless webhook.events["events"]["issues"] | next unless webhook.events["events"]["issues"] | ||||
| @webhook_task = Webhook::EventClient.new(webhook, issue, sender, "issues", "issues",changes.stringify_keys).do_request | |||||
| _, _, @webhook_task = Webhook::IssueClient.new(webhook, issue, sender, "issues", changes.stringify_keys).do_request | |||||
| Rails.logger.info "Touch Webhook Response result: #{@webhook_task.response_content}" | Rails.logger.info "Touch Webhook Response result: #{@webhook_task.response_content}" | ||||
| end | end | ||||
| @@ -31,18 +31,18 @@ class TouchWebhookJob < ApplicationJob | |||||
| return if issue.nil? || sender.nil? | return if issue.nil? || sender.nil? | ||||
| issue.project.webhooks.each do |webhook| | issue.project.webhooks.each do |webhook| | ||||
| next unless webhook.events["events"]["issue_assign"] | next unless webhook.events["events"]["issue_assign"] | ||||
| @webhook_task = Webhook::EventClient.new(webhook, issue, sender, "issues", "issue_assign",{assigner_ids: assigner_ids}).do_request | |||||
| _, _, @webhook_task = Webhook::IssueClient.new(webhook, issue, sender, "issue_assign",{assigner_ids: assigner_ids}.stringify_keys).do_request | |||||
| Rails.logger.info "Touch Webhook Response result: #{@webhook_task.response_content}" | Rails.logger.info "Touch Webhook Response result: #{@webhook_task.response_content}" | ||||
| end | end | ||||
| when 'IssueLable' | |||||
| when 'IssueLabel' | |||||
| issue_id, sender_id, issue_tag_ids = args[0], args[1], args[2] | issue_id, sender_id, issue_tag_ids = args[0], args[1], args[2] | ||||
| issue = Issue.find_by_id issue_id | issue = Issue.find_by_id issue_id | ||||
| sender = User.find_by_id sender_id | sender = User.find_by_id sender_id | ||||
| return if issue.nil? || sender.nil? | return if issue.nil? || sender.nil? | ||||
| issue.project.webhooks.each do |webhook| | issue.project.webhooks.each do |webhook| | ||||
| next unless webhook.events["events"]["issue_label"] | next unless webhook.events["events"]["issue_label"] | ||||
| @webhook_task = Webhook::EventClient.new(webhook, issue, sender, "issues", "issue_label",{issue_tag_ids: issue_tag_ids}).do_request | |||||
| _, _, @webhook_task = Webhook::IssueClient.new(webhook, issue, sender, "issue_label",{issue_tag_ids: issue_tag_ids}.stringify_keys).do_request | |||||
| Rails.logger.info "Touch Webhook Response result: #{@webhook_task.response_content}" | Rails.logger.info "Touch Webhook Response result: #{@webhook_task.response_content}" | ||||
| end | end | ||||
| @@ -53,37 +53,22 @@ class TouchWebhookJob < ApplicationJob | |||||
| sender = User.find_by_id sender_id | sender = User.find_by_id sender_id | ||||
| return if issue.nil? || sender.nil? || comment.nil? | return if issue.nil? || sender.nil? || comment.nil? | ||||
| changes = { | |||||
| id: comment.id, | |||||
| user: comment.user.to_builder.target!, | |||||
| body: comment.notes, | |||||
| created_on: comment.created_on, | |||||
| updated_on: comment.updated_on, | |||||
| } | |||||
| issue.project.webhooks.each do |webhook| | issue.project.webhooks.each do |webhook| | ||||
| next unless webhook.events["events"]["issue_comment"] | next unless webhook.events["events"]["issue_comment"] | ||||
| @webhook_task = Webhook::EventClient.new(webhook, issue, sender, "issue_comment", "issue_comment",changes.stringify_keys).do_request | |||||
| _, _, @webhook_task = Webhook::IssueCommentClient.new(webhook, issue, comment, sender, "issue_comment").do_request | |||||
| Rails.logger.info "Touch Webhook Response result: #{@webhook_task.response_content}" | Rails.logger.info "Touch Webhook Response result: #{@webhook_task.response_content}" | ||||
| end | end | ||||
| when 'PullRequestComment' | when 'PullRequestComment' | ||||
| issue_id, sender_id, comment_id = args[0], args[1], args[2] | |||||
| issue = Issue.find_by_id issue_id | |||||
| comment = issue.comment_journals.find_by_id comment_id | |||||
| pull_id, sender_id, comment_id = args[0], args[1], args[2] | |||||
| pull = PullRequest.find_by_id pull_id | |||||
| comment = pull.issue.comment_journals.find_by_id comment_id | |||||
| sender = User.find_by_id sender_id | sender = User.find_by_id sender_id | ||||
| return if issue.nil? || sender.nil? || comment.nil? | |||||
| changes = { | |||||
| id: comment.id, | |||||
| user: comment.user.to_builder.target!, | |||||
| body: comment.notes, | |||||
| created_on: comment.created_on, | |||||
| updated_on: comment.updated_on, | |||||
| } | |||||
| issue.project.webhooks.each do |webhook| | |||||
| return if pull.nil? || sender.nil? || comment.nil? | |||||
| pull.project.webhooks.each do |webhook| | |||||
| next unless webhook.events["events"]["pull_request_comment"] | next unless webhook.events["events"]["pull_request_comment"] | ||||
| @webhook_task = Webhook::EventClient.new(webhook, issue, sender, "issue_comment", "pull_request_comment",changes.stringify_keys).do_request | |||||
| _, _, @webhook_task = Webhook::PullCommentClient.new(webhook, pull, comment, sender, "pull_request_comment").do_request | |||||
| Rails.logger.info "Touch Webhook Response result: #{@webhook_task.response_content}" | Rails.logger.info "Touch Webhook Response result: #{@webhook_task.response_content}" | ||||
| end | end | ||||
| end | end | ||||
| @@ -272,5 +272,9 @@ class Journal < ApplicationRecord | |||||
| send_details | send_details | ||||
| end | end | ||||
| def to_builder | |||||
| Jbuilder.new do |journal| | |||||
| journal.(self, :id, :notes, :comments_count) | |||||
| end | |||||
| end | |||||
| end | end | ||||
| @@ -117,4 +117,18 @@ class PullRequest < ApplicationRecord | |||||
| JSON.parse file_names | JSON.parse file_names | ||||
| end | end | ||||
| def to_builder | |||||
| Jbuilder.new do |pull| | |||||
| pull.(self, :id, :gitea_number, :title, :body, :base, :head, :is_original, :comments_count) | |||||
| pull.created_at self.created_at.strftime("%Y-%m-%d %H:%M") | |||||
| pull.updated_at self.updated_at.strftime("%Y-%m-%d %H:%M") | |||||
| pull.user self.user.to_builder | |||||
| if self.fork_project.present? | |||||
| pull.fork_project self.fork_project.to_builder | |||||
| else | |||||
| pull.fork_project nil | |||||
| end | |||||
| end | |||||
| end | |||||
| end | end | ||||
| @@ -6,19 +6,27 @@ module Webhook::Client | |||||
| # hmac.update(message) | # hmac.update(message) | ||||
| # sha1 = hmac.digest.unpack('H*').first | # sha1 = hmac.digest.unpack('H*').first | ||||
| attr_reader :uuid, :event, :http_method, :content_type, :url, :secret, :payload_content | |||||
| attr_accessor :request_content, :response_content | |||||
| attr_reader :uuid, :event, :http_method, :content_type, :url, :secret, :payload_content, :webhook | |||||
| attr_accessor :request_content, :response_content, :webhook_task | |||||
| def initialize(opts) | def initialize(opts) | ||||
| @uuid = opts[:uuid] | @uuid = opts[:uuid] | ||||
| @event = opts[:event] | @event = opts[:event] | ||||
| @http_method = opts[:http_method] | |||||
| @content_type = opts[:content_type] | |||||
| @url = opts[:url] | |||||
| @secret = opts[:secret] | |||||
| @webhook = opts[:webhook] | |||||
| @http_method = @webhook.http_method | |||||
| @content_type = @webhook.content_type | |||||
| @url = @webhook.url | |||||
| @secret = @webhook.secret | |||||
| @payload_content = opts[:payload_content] | @payload_content = opts[:payload_content] | ||||
| @request_content = {} | @request_content = {} | ||||
| @response_content = {} | @response_content = {} | ||||
| @webhook_task = Gitea::WebhookTask.create( | |||||
| hook_id: @webhook.id, | |||||
| uuid: @uuid, | |||||
| payload_content: @payload_content, | |||||
| event_type: @event, | |||||
| is_delivered: true | |||||
| ) | |||||
| end | end | ||||
| def do_request | def do_request | ||||
| @@ -41,13 +49,21 @@ module Webhook::Client | |||||
| @request_content["http_method"] = @http_method | @request_content["http_method"] = @http_method | ||||
| @request_content["headers"] = headers | @request_content["headers"] = headers | ||||
| response = RestClient::Request.execute(method: trans_http_method, url: @url, headers: headers, payload: payload_content) {|response, request, result| response } | |||||
| response = RestClient::Request.execute(method: trans_http_method, url: @url, headers: headers, payload: @webhook_task.read_attribute_before_type_cast("payload_content")) {|response, request, result| response } | |||||
| @response_content["status"] = response.code | @response_content["status"] = response.code | ||||
| @response_content["headers"] = response.headers | @response_content["headers"] = response.headers | ||||
| @response_content["body"] = response.body.to_json | @response_content["body"] = response.body.to_json | ||||
| return @request_content, @response_content | |||||
| @webhook_task.update_attributes({ | |||||
| delivered: Time.now.to_i * 1000000000, | |||||
| is_succeed: @response_content["status"] < 300, | |||||
| request_content: @request_content, | |||||
| response_content: @response_content | |||||
| }) | |||||
| return @request_content, @response_content, @webhook_task | |||||
| end | end | ||||
| def request_content | def request_content | ||||
| @@ -58,6 +74,10 @@ module Webhook::Client | |||||
| @response_content | @response_content | ||||
| end | end | ||||
| def webhook_task | |||||
| @webhook_task | |||||
| end | |||||
| private | private | ||||
| def signatureSHA1 | def signatureSHA1 | ||||
| hmac = OpenSSL::HMAC.new(@secret, OpenSSL::Digest::SHA1.new) | hmac = OpenSSL::HMAC.new(@secret, OpenSSL::Digest::SHA1.new) | ||||
| @@ -1,130 +0,0 @@ | |||||
| class Webhook::EventClient | |||||
| include Webhook::Client | |||||
| attr_accessor :webhook, :issue, :sender | |||||
| attr_accessor :webhook_task | |||||
| def initialize(webhook, issue, sender, event, event_type, changes={}) | |||||
| @webhook = webhook | |||||
| @issue = issue | |||||
| @sender = sender | |||||
| @event = event | |||||
| @event_type = event_type | |||||
| @changes = changes | |||||
| # 创建webhook task | |||||
| @webhook_task = Gitea::WebhookTask.create( | |||||
| hook_id: @webhook.id, | |||||
| uuid: SecureRandom.uuid, | |||||
| payload_content: payload_content, | |||||
| event_type: @event_type, | |||||
| is_delivered: true | |||||
| ) | |||||
| # 构建client参数 | |||||
| super({ | |||||
| uuid: @webhook_task.uuid, | |||||
| event: @event, | |||||
| http_method: @webhook.http_method, | |||||
| content_type: @webhook.content_type, | |||||
| url: @webhook.url, | |||||
| secret: @webhook.secret, | |||||
| payload_content: @webhook_task.read_attribute_before_type_cast("payload_content") | |||||
| }) | |||||
| end | |||||
| def do_request | |||||
| request_content, response_content = super | |||||
| @webhook_task.update_attributes({ | |||||
| delivered: Time.now.to_i * 1000000000, | |||||
| is_succeed: response_content["status"] < 300, | |||||
| request_content: request_content, | |||||
| response_content: response_content | |||||
| }) | |||||
| @webhook_task | |||||
| end | |||||
| def payload_content | |||||
| case @event_type | |||||
| when "issues" | |||||
| issue_payload_content | |||||
| when "issue_assign" | |||||
| issue_assign_payload_content | |||||
| when "issue_label" | |||||
| issue_label_payload_content | |||||
| when "issue_comment" | |||||
| issue_comment_payload_content | |||||
| when "pull_request_comment" | |||||
| pull_request_comment_payload_content | |||||
| end | |||||
| end | |||||
| def issue_payload_content | |||||
| if @changes.blank? | |||||
| { | |||||
| "action": "opened", | |||||
| "number": @issue.project_issues_index, | |||||
| "issue": JSON.parse(@issue.to_builder.target!), | |||||
| "project": JSON.parse(@issue.project.to_builder.target!), | |||||
| "sender": JSON.parse(@sender.to_builder.target!) | |||||
| } | |||||
| else | |||||
| { | |||||
| "action": "edited", | |||||
| "number": @issue.project_issues_index, | |||||
| "changes": @changes, | |||||
| "issue": JSON.parse(@issue.to_builder.target!), | |||||
| "project": JSON.parse(@issue.project.to_builder.target!), | |||||
| "sender": JSON.parse(@sender.to_builder.target!) | |||||
| } | |||||
| end | |||||
| end | |||||
| def issue_assign_payload_content | |||||
| { | |||||
| "action": @changes["assigner_ids"].blank? ? "unassigned" : "assigned", | |||||
| "number": @issue.project_issues_index, | |||||
| "issue": JSON.parse(@issue.to_builder.target!), | |||||
| "assignees": @issue.assignees.map(&:to_builder.target!), | |||||
| "project": JSON.parse(@issue.project.to_builder.target!), | |||||
| "sender": JSON.parse(@sender.to_builder.target!) | |||||
| } | |||||
| end | |||||
| def issue_label_payload_content | |||||
| { | |||||
| "action": @changes["issue_tag_ids"].blank? ? "label_cleared" : "label_updated", | |||||
| "number": @issue.project_issues_index, | |||||
| "issue": JSON.parse(@issue.to_builder.target!), | |||||
| "project": JSON.parse(@issue.project.to_builder.target!), | |||||
| "sender": JSON.parse(@sender.to_builder.target!) | |||||
| } | |||||
| end | |||||
| def issue_comment_payload_content | |||||
| { | |||||
| "action": "created", | |||||
| "number": @issue.project_issues_index, | |||||
| "issue": JSON.parse(@issue.to_builder.target!), | |||||
| "comment": @changes, | |||||
| "project": JSON.parse(@issue.project.to_builder.target!), | |||||
| "sender": JSON.parse(@sender.to_builder.target!) | |||||
| } | |||||
| end | |||||
| def pull_request_comment_payload_content | |||||
| { | |||||
| "action": "created", | |||||
| "number": @issue.project_issues_index, | |||||
| "issue": JSON.parse(@issue.to_builder.target!), | |||||
| "comment": @changes, | |||||
| "project": JSON.parse(@issue.project.to_builder.target!), | |||||
| "sender": JSON.parse(@sender.to_builder.target!) | |||||
| } | |||||
| end | |||||
| end | |||||
| @@ -0,0 +1,75 @@ | |||||
| class Webhook::IssueClient | |||||
| include Webhook::Client | |||||
| attr_accessor :webhook, :issue, :sender, :event, :changes | |||||
| attr_accessor :webhook_task | |||||
| def initialize(webhook, issue, sender, event, changes={}) | |||||
| @webhook = webhook | |||||
| @issue = issue | |||||
| @sender = sender | |||||
| @event = event | |||||
| @changes = changes | |||||
| # 构建client参数 | |||||
| super({ | |||||
| uuid: SecureRandom.uuid, | |||||
| event: @event, | |||||
| webhook: @webhook, | |||||
| payload_content: payload_content | |||||
| }) | |||||
| end | |||||
| def payload_content | |||||
| case @event | |||||
| when "issues" | |||||
| issue_payload_content | |||||
| when "issue_assign" | |||||
| issue_assign_payload_content | |||||
| when "issue_label" | |||||
| issue_label_payload_content | |||||
| end | |||||
| end | |||||
| def issue_payload_content | |||||
| if @changes.blank? | |||||
| { | |||||
| "action": "opened", | |||||
| "number": @issue.project_issues_index, | |||||
| "issue": JSON.parse(@issue.to_builder.target!), | |||||
| "project": JSON.parse(@issue.project.to_builder.target!), | |||||
| "sender": JSON.parse(@sender.to_builder.target!) | |||||
| } | |||||
| else | |||||
| { | |||||
| "action": "edited", | |||||
| "number": @issue.project_issues_index, | |||||
| "changes": @changes, | |||||
| "issue": JSON.parse(@issue.to_builder.target!), | |||||
| "project": JSON.parse(@issue.project.to_builder.target!), | |||||
| "sender": JSON.parse(@sender.to_builder.target!) | |||||
| } | |||||
| end | |||||
| end | |||||
| def issue_assign_payload_content | |||||
| { | |||||
| "action": @changes["assigner_ids"].blank? ? "unassigned" : "assigned", | |||||
| "number": @issue.project_issues_index, | |||||
| "issue": JSON.parse(@issue.to_builder.target!), | |||||
| "project": JSON.parse(@issue.project.to_builder.target!), | |||||
| "sender": JSON.parse(@sender.to_builder.target!) | |||||
| } | |||||
| end | |||||
| def issue_label_payload_content | |||||
| { | |||||
| "action": @changes["issue_tag_ids"].blank? ? "label_cleared" : "label_updated", | |||||
| "number": @issue.project_issues_index, | |||||
| "issue": JSON.parse(@issue.to_builder.target!), | |||||
| "project": JSON.parse(@issue.project.to_builder.target!), | |||||
| "sender": JSON.parse(@sender.to_builder.target!) | |||||
| } | |||||
| end | |||||
| end | |||||
| @@ -0,0 +1,37 @@ | |||||
| class Webhook::IssueCommentClient | |||||
| include Webhook::Client | |||||
| attr_accessor :webhook, :issue, :journal, :sender, :event | |||||
| def initialize(webhook, issue, journal, sender, event) | |||||
| @webhook = webhook | |||||
| @issue = issue | |||||
| @journal = journal | |||||
| @sender = sender | |||||
| @event = event | |||||
| # 构建client参数 | |||||
| super({ | |||||
| uuid: SecureRandom.uuid, | |||||
| event: @event, | |||||
| webhook: @webhook, | |||||
| payload_content: payload_content | |||||
| }) | |||||
| end | |||||
| private | |||||
| def payload_content | |||||
| { | |||||
| "action": "created", | |||||
| "issue": JSON.parse(@issue.to_builder.target!), | |||||
| "journal": JSON.parse(@journal.to_builder.target!), | |||||
| "project": JSON.parse(@issue.project.to_builder.target!), | |||||
| "sender": JSON.parse(@sender.to_builder.target!), | |||||
| "is_pull": false | |||||
| } | |||||
| end | |||||
| end | |||||
| @@ -1,55 +0,0 @@ | |||||
| class Webhook::IssueCreateClient | |||||
| include Webhook::Client | |||||
| attr_accessor :webhook, :issue, :sender | |||||
| attr_accessor :webhook_task | |||||
| def initialize(webhook, issue, sender) | |||||
| @webhook = webhook | |||||
| @issue = issue | |||||
| @sender = sender | |||||
| # 创建webhook task | |||||
| @webhook_task = Gitea::WebhookTask.create( | |||||
| hook_id: @webhook.id, | |||||
| uuid: SecureRandom.uuid, | |||||
| payload_content: payload_content, | |||||
| event_type: "issues", | |||||
| is_delivered: true | |||||
| ) | |||||
| # 构建client参数 | |||||
| super({ | |||||
| uuid: @webhook_task.uuid, | |||||
| event: "issues", | |||||
| http_method: @webhook.http_method, | |||||
| content_type: @webhook.content_type, | |||||
| url: @webhook.url, | |||||
| secret: @webhook.secret, | |||||
| payload_content: @webhook_task.read_attribute_before_type_cast("payload_content") | |||||
| }) | |||||
| end | |||||
| def do_request | |||||
| request_content, response_content = super | |||||
| @webhook_task.update_attributes({ | |||||
| delivered: Time.now.to_i * 1000000000, | |||||
| is_succeed: response_content["status"] < 300, | |||||
| request_content: request_content, | |||||
| response_content: response_content | |||||
| }) | |||||
| @webhook_task | |||||
| end | |||||
| def payload_content | |||||
| { | |||||
| "action": "opened", | |||||
| "number": @issue.project_issues_index, | |||||
| "issue": JSON.parse(@issue.to_builder.target!), | |||||
| "project": JSON.parse(@issue.project.to_builder.target!), | |||||
| "sender": JSON.parse(@sender.to_builder.target!) | |||||
| } | |||||
| end | |||||
| end | |||||
| @@ -1,57 +0,0 @@ | |||||
| class Webhook::IssueUpdateClient | |||||
| include Webhook::Client | |||||
| attr_accessor :webhook, :issue, :sender, :changes | |||||
| attr_accessor :webhook_task | |||||
| def initialize(webhook, issue, sender, changes={}) | |||||
| @webhook = webhook | |||||
| @issue = issue | |||||
| @sender = sender | |||||
| @changes = changes | |||||
| # 创建webhook task | |||||
| @webhook_task = Gitea::WebhookTask.create( | |||||
| hook_id: @webhook.id, | |||||
| uuid: SecureRandom.uuid, | |||||
| payload_content: payload_content, | |||||
| event_type: "issues", | |||||
| is_delivered: true | |||||
| ) | |||||
| # 构建client参数 | |||||
| super({ | |||||
| uuid: @webhook_task.uuid, | |||||
| event: "issues", | |||||
| http_method: @webhook.http_method, | |||||
| content_type: @webhook.content_type, | |||||
| url: @webhook.url, | |||||
| secret: @webhook.secret, | |||||
| payload_content: @webhook_task.read_attribute_before_type_cast("payload_content") | |||||
| }) | |||||
| end | |||||
| def do_request | |||||
| request_content, response_content = super | |||||
| @webhook_task.update_attributes({ | |||||
| delivered: Time.now.to_i * 1000000000, | |||||
| is_succeed: response_content["status"] < 300, | |||||
| request_content: request_content, | |||||
| response_content: response_content | |||||
| }) | |||||
| @webhook_task | |||||
| end | |||||
| def payload_content | |||||
| { | |||||
| "action": "edited", | |||||
| "number": @issue.project_issues_index, | |||||
| "changes": @changes, | |||||
| "issue": JSON.parse(@issue.to_builder.target!), | |||||
| "project": JSON.parse(@issue.project.to_builder.target!), | |||||
| "sender": JSON.parse(@sender.to_builder.target!) | |||||
| } | |||||
| end | |||||
| end | |||||
| @@ -0,0 +1,36 @@ | |||||
| class Webhook::PullCommentClient | |||||
| include Webhook::Client | |||||
| attr_accessor :webhook, :pull, :journal, :sender, :event | |||||
| def initialize(webhook, pull, journal, sender, event) | |||||
| @webhook = webhook | |||||
| @pull = pull | |||||
| @journal = journal | |||||
| @sender = sender | |||||
| @event = event | |||||
| # 构建client参数 | |||||
| super({ | |||||
| uuid: SecureRandom.uuid, | |||||
| event: @event, | |||||
| webhook: @webhook, | |||||
| payload_content: payload_content | |||||
| }) | |||||
| end | |||||
| private | |||||
| def payload_content | |||||
| { | |||||
| "action": "created", | |||||
| "number": @pull.gitea_number, | |||||
| "pull_request": JSON.parse(@pull.to_builder.target!), | |||||
| "comment": JSON.parse(@journal.to_builder.target!), | |||||
| "project": JSON.parse(@pull.project.to_builder.target!), | |||||
| "sender": JSON.parse(@sender.to_builder.target!), | |||||
| "is_pull": true | |||||
| } | |||||
| end | |||||
| end | |||||