fix(app-store): address review sync comments
This commit is contained in:
@@ -4,9 +4,23 @@ class Inboxes::FetchAppStoreReviewsJob < ApplicationJob
|
||||
def perform(channel)
|
||||
return unless channel.account.feature_enabled?(:channel_app_store)
|
||||
|
||||
synced_until = sync_reviews(channel)
|
||||
return if synced_until.blank?
|
||||
|
||||
channel.update!(last_synced_at: synced_until)
|
||||
rescue StandardError => e
|
||||
ChatwootExceptionTracker.new(e, account: channel.account).capture_exception
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def sync_reviews(channel)
|
||||
failed = false
|
||||
synced_dates = []
|
||||
|
||||
channel.fetch_reviews.each do |review_payload|
|
||||
::AppStore::ReviewBuilder.new(review_payload: review_payload, channel: channel).perform
|
||||
synced_dates << parsed_review_created_at(review_payload)
|
||||
rescue StandardError => e
|
||||
failed = true
|
||||
ChatwootExceptionTracker.new(e, account: channel.account).capture_exception
|
||||
@@ -14,8 +28,12 @@ class Inboxes::FetchAppStoreReviewsJob < ApplicationJob
|
||||
|
||||
return if failed
|
||||
|
||||
channel.update!(last_synced_at: Time.current)
|
||||
rescue StandardError => e
|
||||
ChatwootExceptionTracker.new(e, account: channel.account).capture_exception
|
||||
synced_dates.compact.max
|
||||
end
|
||||
|
||||
def parsed_review_created_at(review_payload)
|
||||
Time.zone.parse(review_payload.dig('review', 'attributes', 'createdDate').to_s)
|
||||
rescue StandardError
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
@@ -51,7 +51,7 @@ class AppStore::ReviewBuilder
|
||||
end
|
||||
|
||||
def rating
|
||||
attributes['rating'].to_i
|
||||
attributes['rating'].to_i.clamp(0, 5)
|
||||
end
|
||||
|
||||
def created_at
|
||||
|
||||
@@ -4,7 +4,15 @@ require 'rails_helper'
|
||||
|
||||
RSpec.describe Inboxes::FetchAppStoreReviewsJob do
|
||||
let(:channel) { create(:channel_app_store, last_synced_at: nil) }
|
||||
let(:review_payload) { { 'review' => { 'id' => 'review-1' }, 'response' => nil } }
|
||||
let(:review_payload) do
|
||||
{
|
||||
'review' => {
|
||||
'id' => 'review-1',
|
||||
'attributes' => { 'createdDate' => '2026-05-20T10:00:00-00:00' }
|
||||
},
|
||||
'response' => nil
|
||||
}
|
||||
end
|
||||
let(:review_builder) { instance_double(AppStore::ReviewBuilder, perform: true) }
|
||||
|
||||
before do
|
||||
@@ -24,7 +32,23 @@ RSpec.describe Inboxes::FetchAppStoreReviewsJob do
|
||||
described_class.perform_now(channel)
|
||||
|
||||
expect(review_builder).to have_received(:perform)
|
||||
expect(channel.reload.last_synced_at).to be_present
|
||||
expect(channel.reload.last_synced_at).to eq(Time.zone.parse('2026-05-20T10:00:00-00:00'))
|
||||
end
|
||||
|
||||
it 'updates the sync timestamp to the latest fetched review date' do
|
||||
older_payload = review_payload.deep_dup
|
||||
newer_payload = review_payload.deep_dup
|
||||
older_payload['review']['id'] = 'review-1'
|
||||
older_payload['review']['attributes']['createdDate'] = '2026-05-20T10:00:00-00:00'
|
||||
newer_payload['review']['id'] = 'review-2'
|
||||
newer_payload['review']['attributes']['createdDate'] = '2026-05-20T11:00:00-00:00'
|
||||
|
||||
allow(channel).to receive(:fetch_reviews).and_return([newer_payload, older_payload])
|
||||
allow(AppStore::ReviewBuilder).to receive(:new).and_return(review_builder)
|
||||
|
||||
described_class.perform_now(channel)
|
||||
|
||||
expect(channel.reload.last_synced_at).to eq(Time.zone.parse('2026-05-20T11:00:00-00:00'))
|
||||
end
|
||||
|
||||
it 'captures per-review errors and continues syncing' do
|
||||
|
||||
@@ -74,6 +74,18 @@ RSpec.describe AppStore::ReviewBuilder do
|
||||
expect(review_message.content).to include('★★★★☆ (4/5)')
|
||||
end
|
||||
|
||||
it 'clamps the review rating before building the message content' do
|
||||
invalid_rating_payload = review_payload.deep_dup
|
||||
invalid_rating_payload['review']['attributes']['rating'] = 7
|
||||
invalid_rating_payload['response'] = nil
|
||||
|
||||
described_class.new(review_payload: invalid_rating_payload, channel: channel).perform
|
||||
|
||||
review_message = inbox.conversations.last.messages.incoming.find_by(source_id: 'review-1')
|
||||
expect(review_message.content).to include('★★★★★ (5/5)')
|
||||
expect(review_message.content_attributes['app_store']).to include('rating' => 5)
|
||||
end
|
||||
|
||||
it 'falls back to current time when Apple timestamps are blank' do
|
||||
blank_timestamp_payload = review_payload.deep_dup
|
||||
blank_timestamp_payload['review']['attributes']['createdDate'] = ''
|
||||
|
||||
Reference in New Issue
Block a user