Skip to content

Commit

Permalink
5441 – Change how we create imported fact-checks when an item already…
Browse files Browse the repository at this point in the history
… exists (#2079)

## Wanted Behavior
- If the item has no fact-check: Append the fact-check to the existing ProjectMedia
- If the item already has a fact-check in a different language: Create a fact-check associated with a blank media

## Context
Importing a fact-check with a link original claim will fail when a project media with that link media already exists.

When importing, we create a project media to create the fact-check. If that project media has an original claim, we create a media as well. If the original claim is a link, we try to create a link media.

Since duplicate link medias are not permitted, if a link media with this link already exists, trying to create this new media from the same link will fail. Then creating the project media and fact-check will fail as well.

### The issue with this
We will have the project media with the link media, but will fail to create the fact-check for it, even though the partner has one. If the partner has a fact-check, we want to be able to attach it to the correct existing project media.

### A related issue
Sometimes a partner might have a fact-check for a project media, but if they have many languages, they might want to have more than one fact-check associated with that project media. Since this is currently not possible: if they have a fact-check in a different language, we want to create the fact-check associated to a blank media, instead of the link media.

References: CV2-5441
PR: 2079
  • Loading branch information
vasconsaurus authored Oct 31, 2024
1 parent 5e84771 commit 06b32dc
Show file tree
Hide file tree
Showing 5 changed files with 233 additions and 23 deletions.
15 changes: 14 additions & 1 deletion app/graph/mutations/graphql_crud_operations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,20 @@ def self.safe_save(obj, attrs, parent_names = [])
obj.send(method, value) if obj.respond_to?(method)
end
obj.disable_es_callbacks = Rails.env.to_s == "test"
obj.save_with_version!

begin
obj.save_with_version!
rescue RuntimeError => e
if e.message.include?("\"code\":#{LapisConstants::ErrorCodes::const_get('DUPLICATED')}") &&
obj.is_a?(ProjectMedia) &&
obj.set_fact_check.present? &&
obj.set_original_claim.present?
existing_pm = ProjectMedia.find(JSON.parse(e.message)['data']['id'])
obj = ProjectMedia.handle_fact_check_for_existing_claim(existing_pm,obj)
else
raise e
end
end

name = obj.class_name.underscore
{ name.to_sym => obj }.merge(
Expand Down
44 changes: 22 additions & 22 deletions app/models/concerns/project_media_creators.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,28 @@ def create_metrics_annotation
end
end

def create_claim_description_and_fact_check
cd = ClaimDescription.create!(description: self.set_claim_description, context: self.set_claim_context, project_media: self, skip_check_ability: true) unless self.set_claim_description.blank?
fc = nil
unless self.set_fact_check.blank?
fact_check = self.set_fact_check.with_indifferent_access
fc = FactCheck.create!({
title: fact_check['title'],
summary: fact_check['summary'],
language: fact_check['language'],
url: fact_check['url'],
publish_report: !!fact_check['publish_report'],
signature: Digest::MD5.hexdigest([self.set_fact_check.to_json, self.team_id].join(':')),
claim_description: cd,
report_status: (fact_check['publish_report'] ? 'published' : 'unpublished'),
rating: self.set_status,
tags: self.set_tags.to_a.map(&:strip),
skip_check_ability: true
})
end
fc
end

private

def create_team_tasks
Expand Down Expand Up @@ -236,28 +258,6 @@ def create_relationship(type = Relationship.confirmed_type)
end
end

def create_claim_description_and_fact_check
cd = ClaimDescription.create!(description: self.set_claim_description, context: self.set_claim_context, project_media: self, skip_check_ability: true) unless self.set_claim_description.blank?
fc = nil
unless self.set_fact_check.blank?
fact_check = self.set_fact_check.with_indifferent_access
fc = FactCheck.create!({
title: fact_check['title'],
summary: fact_check['summary'],
language: fact_check['language'],
url: fact_check['url'],
publish_report: !!fact_check['publish_report'],
signature: Digest::MD5.hexdigest([self.set_fact_check.to_json, self.team_id].join(':')),
claim_description: cd,
report_status: (fact_check['publish_report'] ? 'published' : 'unpublished'),
rating: self.set_status,
tags: self.set_tags.to_a.map(&:strip),
skip_check_ability: true
})
end
fc
end

def create_tags_in_background
if self.set_tags.is_a?(Array)
project_media_id = self.id
Expand Down
25 changes: 25 additions & 0 deletions app/models/project_media.rb
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,31 @@ def apply_rules_and_actions_on_update
self.team.apply_rules_and_actions(self, rule_ids)
end

def self.handle_fact_check_for_existing_claim(existing_pm,new_pm)
if existing_pm.fact_check.blank?
existing_pm.append_fact_check_from(new_pm)
return existing_pm
elsif existing_pm.fact_check.present?
if existing_pm.fact_check.language != new_pm.set_fact_check['language']
new_pm.replace_with_blank_media
return new_pm
end
end
end

def append_fact_check_from(new_pm)
self.set_claim_description = new_pm.set_claim_description
self.set_fact_check = new_pm.set_fact_check
self.create_claim_description_and_fact_check
end

def replace_with_blank_media
m = Blank.create!
self.set_original_claim = nil
self.media_id = m.id
self.save!
end

protected

def add_extra_elasticsearch_data(ms)
Expand Down
124 changes: 124 additions & 0 deletions test/controllers/graphql_controller_12_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -731,4 +731,128 @@ def teardown
assert_equal 1, pm_tags.count
assert_equal 1, fc_tags.count
end

test "should append FactCheck to ProjectMedia, if ProjectMedia already exists and does not have a FactCheck" do
Sidekiq::Testing.fake!
url = 'http://example.com'
pender_url = CheckConfig.get('pender_url_private') + '/api/medias'
response_body = '{"type":"media","data":{"url":"' + url + '","type":"item"}}'
WebMock.stub_request(:get, pender_url).with({ query: { url: url } }).to_return(body: response_body)

t = create_team
p = create_project team: t
pm = create_project_media team: t, set_original_claim: url

assert_not_nil pm

a = ApiKey.create!
b = create_bot_user api_key_id: a.id
create_team_user team: t, user: b
authenticate_with_token(a)

query = <<~GRAPHQL
mutation {
createProjectMedia(input: {
project_id: #{p.id},
media_type: "Blank",
channel: { main: 1 },
set_tags: ["tag"],
set_status: "verified",
set_claim_description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
set_original_claim: "#{url}",
set_fact_check: {
title: "Title #1",
language: "en",
}
}) {
project_media {
dbid
full_url
claim_description {
fact_check {
dbid
}
}
}
}
}
GRAPHQL

assert_no_difference 'ProjectMedia.count' do
assert_difference 'FactCheck.count' do
post :create, params: { query: query, team: t.slug }
assert_response :success
end
end

response_pm = JSON.parse(@response.body)['data']['createProjectMedia']['project_media']
fact_check = response_pm['claim_description']['fact_check']

assert_not_nil fact_check
assert_equal response_pm['dbid'], pm.id
end

test "should create a FactCheck with a Blank ProjectMedia, if ProjectMedia already exists and has a FactCheck in a different language" do
Sidekiq::Testing.fake!
url = 'http://example.com'
pender_url = CheckConfig.get('pender_url_private') + '/api/medias'
response_body = '{"type":"media","data":{"url":"' + url + '","type":"item"}}'
WebMock.stub_request(:get, pender_url).with({ query: { url: url } }).to_return(body: response_body)

t = create_team
t.settings[:languages] << 'pt'
t.save!
p = create_project team: t
pm = create_project_media team: t, set_original_claim: url
c = create_claim_description project_media: pm
fc_1 = create_fact_check claim_description: c

assert_not_nil fc_1

a = ApiKey.create!
b = create_bot_user api_key_id: a.id
create_team_user team: t, user: b
authenticate_with_token(a)

query = <<~GRAPHQL
mutation {
createProjectMedia(input: {
project_id: #{p.id},
media_type: "Blank",
channel: { main: 1 },
set_tags: ["tag"],
set_status: "verified",
set_claim_description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
set_original_claim: "#{url}",
set_fact_check: {
title: "Title #1",
language: "pt",
}
}) {
project_media {
dbid
full_url
claim_description {
fact_check {
dbid
}
}
}
}
}
GRAPHQL

assert_difference 'ProjectMedia.count' do
assert_difference 'FactCheck.count' do
post :create, params: { query: query, team: t.slug }
assert_response :success
end
end

response_pm = JSON.parse(@response.body)['data']['createProjectMedia']['project_media']
fc_2 = response_pm['claim_description']['fact_check']

assert_not_nil fc_2
assert_not_equal response_pm['dbid'], pm.id
end
end
48 changes: 48 additions & 0 deletions test/models/project_media_7_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,52 @@ def setup
assert_equal 'Claim', pm_claim.media.type
assert_equal 'This is a claim.', pm_claim.media.quote
end

test "should not create duplicate media from original claim URL as Link" do
setup_elasticsearch

# Mock Pender response for Link
link_url = 'https://example.com'
pender_url = CheckConfig.get('pender_url_private') + '/api/medias'
link_response = {
type: 'media',
data: {
url: link_url,
type: 'item'
}
}.to_json
WebMock.stub_request(:get, pender_url).with(query: { url: link_url }).to_return(body: link_response)

t = create_team
create_project team: t

assert_raise RuntimeError do
2.times { create_project_media(team: t, set_original_claim: link_url) }
end
end

test "should create duplicate media from original claim URL as UploadedImage" do
Tempfile.create(['test_image', '.jpg']) do |file|
file.write(File.read(File.join(Rails.root, 'test', 'data', 'rails.png')))
file.rewind
image_url = "http://example.com/#{file.path.split('/').last}"
WebMock.stub_request(:get, image_url).to_return(body: file.read, headers: { 'Content-Type' => 'image/jpeg' })

t = create_team
create_project team: t

assert_difference 'ProjectMedia.count', 2 do
2.times { create_project_media(team: t, set_original_claim: image_url) }
end
end
end

test "should create duplicate media from original claim URL as Claim" do
t = create_team
create_project team: t

assert_difference 'ProjectMedia.count', 2 do
2.times { create_project_media(team: t, set_original_claim: 'This is a claim.') }
end
end
end

0 comments on commit 06b32dc

Please sign in to comment.