From 1ff3a229dc983a486dbb69d6437d7a3556869372 Mon Sep 17 00:00:00 2001 From: Caio Almeida <117518+caiosba@users.noreply.github.com> Date: Sat, 16 Sep 2023 17:23:59 -0300 Subject: [PATCH] Fixing "PG::UntranslatableCharacter" error when storing some Pender data annotations PostgreSQL doesn't support null characters in a JSON column, so these characters need to be removed before storing. Fixes CV2-3582. --- app/models/annotations/dynamic.rb | 1 + test/controllers/graphql_controller_3_test.rb | 73 ++++++++++--------- test/models/media_test.rb | 10 +++ 3 files changed, 48 insertions(+), 36 deletions(-) diff --git a/app/models/annotations/dynamic.rb b/app/models/annotations/dynamic.rb index 9200bdfa3a..956e7615db 100644 --- a/app/models/annotations/dynamic.rb +++ b/app/models/annotations/dynamic.rb @@ -98,6 +98,7 @@ def create_field(name, value) f.skip_check_ability = true f.disable_es_callbacks = self.disable_es_callbacks || value.blank? f.field_name = name + value.gsub!('\u0000', '') if value.is_a?(String) # Avoid PG::UntranslatableCharacter exception f.value = value f.annotation_id = self.id f diff --git a/test/controllers/graphql_controller_3_test.rb b/test/controllers/graphql_controller_3_test.rb index c34f80f865..519fcc414a 100644 --- a/test/controllers/graphql_controller_3_test.rb +++ b/test/controllers/graphql_controller_3_test.rb @@ -343,42 +343,43 @@ def setup test "should set smooch user slack channel url in background" do Sidekiq::Testing.fake! do - u = create_user - t = create_team - create_team_user team: t, user: u, role: 'admin' - p = create_project team: t - author_id = random_string - set_fields = { smooch_user_data: { id: author_id }.to_json, smooch_user_app_id: 'fake', smooch_user_id: 'fake' }.to_json - d = create_dynamic_annotation annotated: p, annotation_type: 'smooch_user', set_fields: set_fields - Sidekiq::Worker.drain_all - assert_equal 0, Sidekiq::Worker.jobs.size - authenticate_with_token - url = random_url - query = 'mutation { updateDynamicAnnotationSmoochUser(input: { clientMutationId: "1", id: "' + d.graphql_id + '", set_fields: "{\"smooch_user_slack_channel_url\":\"' + url + '\"}" }) { project { dbid } } }' - post :create, params: { query: query } - assert_response :success - assert_equal url, d.reload.get_field_value('smooch_user_slack_channel_url') - # check that cache key exists - key = "SmoochUserSlackChannelUrl:Team:#{d.team_id}:#{author_id}" - assert_equal url, Rails.cache.read(key) - # test using a new mutation `smoochBotAddSlackChannelUrl` - Sidekiq::Worker.drain_all - assert_equal 0, Sidekiq::Worker.jobs.size - url2 = random_url - query = 'mutation { smoochBotAddSlackChannelUrl(input: { clientMutationId: "1", id: "' + d.id.to_s + '", set_fields: "{\"smooch_user_slack_channel_url\":\"' + url2 + '\"}" }) { annotation { dbid } } }' - post :create, params: { query: query } - assert_response :success - assert Sidekiq::Worker.jobs.size > 0 - assert_equal url, d.reload.get_field_value('smooch_user_slack_channel_url') - # execute job and check that url was set - Sidekiq::Worker.drain_all - assert_equal url2, d.get_field_value('smooch_user_slack_channel_url') - # check that cache key exists - assert_equal url2, Rails.cache.read(key) - # call mutation with non existing id - query = 'mutation { smoochBotAddSlackChannelUrl(input: { clientMutationId: "1", id: "99999", set_fields: "{\"smooch_user_slack_channel_url\":\"' + url2 + '\"}" }) { annotation { dbid } } }' - post :create, params: { query: query } - assert_response :success + u = create_user + t = create_team + create_team_user team: t, user: u, role: 'admin' + p = create_project team: t + author_id = random_string + set_fields = { smooch_user_data: { id: author_id }.to_json, smooch_user_app_id: 'fake', smooch_user_id: 'fake' }.to_json + d = create_dynamic_annotation annotated: p, annotation_type: 'smooch_user', set_fields: set_fields + Sidekiq::Worker.drain_all + assert_equal 0, Sidekiq::Worker.jobs.size + authenticate_with_token + url = random_url + query = 'mutation { updateDynamicAnnotationSmoochUser(input: { clientMutationId: "1", id: "' + d.graphql_id + '", set_fields: "{\"smooch_user_slack_channel_url\":\"' + url + '\"}" }) { project { dbid } } }' + post :create, params: { query: query } + assert_response :success + Sidekiq::Worker.drain_all + assert_equal url, d.reload.get_field_value('smooch_user_slack_channel_url') + # check that cache key exists + key = "SmoochUserSlackChannelUrl:Team:#{d.team_id}:#{author_id}" + assert_equal url, Rails.cache.read(key) + # test using a new mutation `smoochBotAddSlackChannelUrl` + Sidekiq::Worker.drain_all + assert_equal 0, Sidekiq::Worker.jobs.size + url2 = random_url + query = 'mutation { smoochBotAddSlackChannelUrl(input: { clientMutationId: "1", id: "' + d.id.to_s + '", set_fields: "{\"smooch_user_slack_channel_url\":\"' + url2 + '\"}" }) { annotation { dbid } } }' + post :create, params: { query: query } + assert_response :success + assert Sidekiq::Worker.jobs.size > 0 + assert_equal url, d.reload.get_field_value('smooch_user_slack_channel_url') + # execute job and check that url was set + Sidekiq::Worker.drain_all + assert_equal url2, d.get_field_value('smooch_user_slack_channel_url') + # check that cache key exists + assert_equal url2, Rails.cache.read(key) + # call mutation with non existing id + query = 'mutation { smoochBotAddSlackChannelUrl(input: { clientMutationId: "1", id: "99999", set_fields: "{\"smooch_user_slack_channel_url\":\"' + url2 + '\"}" }) { annotation { dbid } } }' + post :create, params: { query: query } + assert_response :success end end diff --git a/test/models/media_test.rb b/test/models/media_test.rb index 61b67775b3..19be8cc974 100644 --- a/test/models/media_test.rb +++ b/test/models/media_test.rb @@ -593,4 +593,14 @@ def setup l = create_valid_media assert_equal '', l.picture end + + test "should sanitize link data before storing" do + pender_url = CheckConfig.get('pender_url_private') + '/api/medias' + url = random_url + response = { type: 'media', data: { url: url, type: 'item', title: "Foo \u0000 bar" } } + WebMock.stub_request(:get, pender_url).with({ query: { url: url } }).to_return(body: response.to_json) + assert_difference 'Link.count' do + create_media url: url + end + end end