Skip to content

Commit

Permalink
feat(helpscout): delete old conversations
Browse files Browse the repository at this point in the history
  • Loading branch information
colinux committed Jun 13, 2024
1 parent 069cb04 commit 9d4113b
Show file tree
Hide file tree
Showing 4 changed files with 378 additions and 0 deletions.
33 changes: 33 additions & 0 deletions app/lib/helpscout/api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ class Helpscout::API
PHONES = 'phones'
OAUTH2_TOKEN = 'oauth2/token'

RATELIMIT_KEY = "helpscout-rate-limit-remaining"

def ready?
required_secrets = [
Rails.application.secrets.helpscout[:mailbox_id],
Expand Down Expand Up @@ -42,6 +44,30 @@ def create_conversation(email, subject, text, file)
call_api(:post, CONVERSATIONS, body)
end

def list_old_conversations(status, before, page: 1)
body = {
page:,
status:, # active, open, closed, pending, spam. "all" does not work
query: "(
modifiedAt:[* TO #{before.iso8601}]
)",
sortField: "modifiedAt",
sortOrder: "desc"
}

response = call_api(:get, "#{CONVERSATIONS}?#{body.to_query}")
if !response.success?
raise StandardError, "Error while listing conversations: #{response.response_code} '#{response.body}'"
end

body = parse_response_body(response)
[body[:_embedded][:conversations], body[:page]]
end

def delete_conversation(conversation_id)
call_api(:delete, "#{CONVERSATIONS}/#{conversation_id}")
end

def add_phone_number(email, phone)
query = CGI.escape("(email:#{email})")
response = call_api(:get, "#{CUSTOMERS}?mailbox=#{user_support_mailbox_id}&query=#{query}")
Expand Down Expand Up @@ -129,6 +155,13 @@ def call_api(method, path, body = nil)
body: body.to_json,
headers: headers
})
when :delete
Typhoeus.delete(url, {
body: body.to_json,
headers: headers
})
end.tap do |response|
Rails.cache.write(RATELIMIT_KEY, response.headers["X-Ratelimit-Remaining-Minute"], expires_in: 1.minute)
end
end

Expand Down
57 changes: 57 additions & 0 deletions app/tasks/maintenance/helpscout_delete_old_conversations_task.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# frozen_string_literal: true

module Maintenance
class HelpscoutDeleteOldConversationsTask < MaintenanceTasks::Task
# Delete Helpscout conversations not modified in the last 2 years, given a status.
# In order to delete all conversations, this task must be invoked 4 times
# for the 4 status: active, closed, spam, pending.
# Respects the Helpscount API rate limit (200 calls per minute).

attribute :status, :string # active, closed, spam, or pending
validates :status, presence: true

MODIFIED_BEFORE = 2.years.freeze

throttle_on do
limit = Rails.cache.read(Helpscout::API::RATELIMIT_KEY)
limit.present? && limit == 0
end

def count
_conversations, pagination = api.list_old_conversations(status, modified_before)

pagination[:totalElements]
end

# Because conversations are deleted progressively,
# ignore cursor and always pick the first page
def enumerator_builder(cursor:)
Enumerator.new do |yielder|
loop do
conversations, pagination = api.list_old_conversations(status, modified_before)
conversations.each do |conversation|
yielder.yield(conversation[:id], nil) # don't care about cursor parameter
end

# "number" is the current page (always 1 in our case)
# iterate until there are no remaining pages
break if pagination[:totalPages] == pagination[:number]
end
end
end

def process(conversation_id)
@api.delete_conversation(conversation_id)
end

private

def api
@api ||= Helpscout::API.new
end

def modified_before
MODIFIED_BEFORE.ago.utc.beginning_of_day
end
end
end
Loading

0 comments on commit 9d4113b

Please sign in to comment.