Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Articles data model and API changes #1903

Merged
merged 58 commits into from
Jul 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
15a8707
[WIP] Sort explainers on GraphQL API
caiosba May 24, 2024
0753c41
Adding filters to explainers
caiosba May 27, 2024
f3722af
Merge branch 'develop' into epic/CV2-4441-articles
caiosba May 28, 2024
7451913
Explainers data model and API updates (#1901)
caiosba May 28, 2024
dc697b0
Merge branch 'develop' into epic/CV2-4441-articles
caiosba May 29, 2024
ff938ed
Updates for fact-check data model and API (#1904)
caiosba May 30, 2024
7f842ff
Merge branch 'develop' into epic/CV2-4441-articles
caiosba May 30, 2024
e4f87a3
Merge remote-tracking branch 'origin/develop' into epic/CV2-4441-arti…
brianfleming Jun 4, 2024
4b21b67
Merge branch 'develop' into epic/CV2-4441-articles
caiosba Jun 5, 2024
5b47a18
Merge branch 'develop' into epic/CV2-4441-articles
caiosba Jun 5, 2024
17ae359
Merge branch 'develop' into epic/CV2-4441-articles
melsawy Jun 10, 2024
d7f51e4
CV2-4665: index report information in fact check (#1909)
melsawy Jun 11, 2024
fcf75ba
Merge branch 'develop' into epic/CV2-4441-articles
caiosba Jun 11, 2024
e9f795a
Merge branch 'develop' into epic/CV2-4441-articles
caiosba Jun 12, 2024
06a12cf
Merge branch 'develop' into epic/CV2-4441-articles
caiosba Jun 14, 2024
e3c69c4
Merge branch 'develop' into epic/CV2-4441-articles
caiosba Jun 20, 2024
96a7a4f
CV2-4665: filter by report information
melsawy Jun 22, 2024
943440a
Merge branch 'develop' into epic/CV2-4441-articles
melsawy Jun 22, 2024
a3192a1
Merge branch 'epic/CV2-4441-articles' of github.com:meedan/check-api …
melsawy Jun 22, 2024
e0c8128
Some changes to articles API and data model (#1933)
caiosba Jun 23, 2024
53c61e1
Small refactoring
caiosba Jun 23, 2024
e8e1d83
Merge remote-tracking branch 'origin/develop' into epic/CV2-4441-arti…
brianfleming Jun 24, 2024
5a4d4ad
Fixing two things reported by frontend team
caiosba Jun 24, 2024
5d81dea
Merge branch 'epic/CV2-4441-articles' of github.com:meedan/check-api …
caiosba Jun 24, 2024
b6f838b
Merge remote-tracking branch 'origin/develop' into epic/CV2-4441-arti…
brianfleming Jun 25, 2024
817b831
List standalone fact-checks
caiosba Jun 26, 2024
11d6af2
Merge branch 'develop' into epic/CV2-4441-articles
caiosba Jun 27, 2024
e5afacb
Fixing search by text for explainers
caiosba Jun 29, 2024
a11c066
Merge branch 'develop' into epic/CV2-4441-articles
caiosba Jul 2, 2024
28b1283
Merge branch 'develop' into epic/CV2-4441-articles
caiosba Jul 6, 2024
86e2d2e
Merge branch 'develop' into epic/CV2-4441-articles
caiosba Jul 8, 2024
c54936f
Ticket CV2-4889: Expose number of articles for an item in GraphQL (#1…
caiosba Jul 10, 2024
88546eb
Add fact_check_id field to ProjectMediaType
amoedoamorim Jul 11, 2024
21820a6
Adding field `explainer_items` to `ProjectMediaType`
caiosba Jul 11, 2024
14018f1
Exposing fact-check report_status in GraphQL
caiosba Jul 14, 2024
c936681
Reverting changes to schema
caiosba Jul 14, 2024
0f15496
Adding unique index to explainer_items
caiosba Jul 14, 2024
eadd525
Adding unique index to explainer_items
caiosba Jul 14, 2024
44b6454
Fixing language validation for fact-check
caiosba Jul 14, 2024
c92ef6b
Merge branch 'develop' into epic/CV2-4441-articles
caiosba Jul 14, 2024
4df9d1b
Add "imported" field to fact-checks (#1951)
caiosba Jul 14, 2024
20e4b4d
Fixing test
caiosba Jul 14, 2024
7a5d3df
CV2-4879: add rake task to set team_id for ClaimDescription (#1954)
melsawy Jul 15, 2024
aa51c00
CV2-4901 fact check article list not displaying rating (#1952)
melsawy Jul 15, 2024
b3f3158
Merge branch 'develop' into epic/CV2-4441-articles
caiosba Jul 15, 2024
1858e82
Always set claim description team based on project media
caiosba Jul 16, 2024
46fc1fd
Always set claim description team based on project media
caiosba Jul 16, 2024
734f949
4880 – Seeds Script: Create standalone claim descriptions and fact-ch…
vasconsaurus Jul 16, 2024
895df70
Merge remote-tracking branch 'origin/develop' into epic/CV2-4441-arti…
brianfleming Jul 16, 2024
5346b05
Set initial rating for fact-check
caiosba Jul 16, 2024
83a3cee
Merge branch 'epic/CV2-4441-articles' of github.com:meedan/check-api …
caiosba Jul 16, 2024
3fb0ed9
Fixing test
caiosba Jul 16, 2024
8a201eb
Fix
caiosba Jul 17, 2024
33e04d7
Return team for fact check mutations
caiosba Jul 19, 2024
664c292
Merge branch 'develop' into epic/CV2-4441-articles
caiosba Jul 20, 2024
c09dc10
Return total number of articles (regardless the type)
caiosba Jul 22, 2024
c4c1df0
Adding missing test
caiosba Jul 22, 2024
f345782
Fixing conflict [skip ci]
caiosba Jul 22, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions app/graph/mutations/claim_description_mutations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,12 @@ module SharedCreateAndUpdateFields
included do
argument :description, GraphQL::Types::String, required: false
argument :context, GraphQL::Types::String, required: false, as: :claim_context
argument :project_media_id, GraphQL::Types::Int, required: false, camelize: false
end
end

class Create < Mutations::CreateMutation
include SharedCreateAndUpdateFields

argument :project_media_id, GraphQL::Types::Int, required: true, camelize: false
end

class Update < Mutations::UpdateMutation
Expand Down
11 changes: 11 additions & 0 deletions app/graph/mutations/explainer_item_mutations.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module ExplainerItemMutations
MUTATION_TARGET = 'explainer_item'.freeze
PARENTS = ['explainer', 'project_media'].freeze

class Create < Mutations::CreateMutation
argument :explainer_id, GraphQL::Types::Int, required: true
argument :project_media_id, GraphQL::Types::Int, required: true
end

class Destroy < Mutations::DestroyMutation; end
end
3 changes: 2 additions & 1 deletion app/graph/mutations/explainer_mutations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ module SharedCreateAndUpdateFields
extend ActiveSupport::Concern

included do
argument :title, GraphQL::Types::String, required: true
argument :title, GraphQL::Types::String, required: false
argument :description, GraphQL::Types::String, required: false
argument :url, GraphQL::Types::String, required: false
argument :language, GraphQL::Types::String, required: false
argument :tags, [GraphQL::Types::String, null: true], required: false
end
end

Expand Down
4 changes: 3 additions & 1 deletion app/graph/mutations/fact_check_mutations.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
module FactCheckMutations
MUTATION_TARGET = 'fact_check'.freeze
PARENTS = ['claim_description'].freeze
PARENTS = ['claim_description', 'team'].freeze

module SharedCreateAndUpdateFields
extend ActiveSupport::Concern

included do
argument :url, GraphQL::Types::String, required: false
argument :language, GraphQL::Types::String, required: false
argument :tags, [GraphQL::Types::String, null: true], required: false
argument :rating, GraphQL::Types::String, required: false
end
end

Expand Down
1 change: 1 addition & 0 deletions app/graph/types/article_union.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ class ArticleUnion < BaseUnion
description 'A union type of all article types we can handle'
possible_types(
ExplainerType,
FactCheckType,
)
end
2 changes: 1 addition & 1 deletion app/graph/types/claim_description_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class ClaimDescriptionType < DefaultObject

def fact_check(report_status: nil)
ability = context[:ability] || Ability.new
status = object.project_media.report_status
status = object.project_media&.report_status
can_read = ability.can?(:read, object) || status == 'published'
(can_read && (!report_status || status == report_status)) ? object.fact_check : nil
end
Expand Down
10 changes: 10 additions & 0 deletions app/graph/types/explainer_item_type.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class ExplainerItemType < DefaultObject
description 'Explainer item type'

implements GraphQL::Types::Relay::Node

field :explainer_id, GraphQL::Types::Int, null: false
field :project_media_id, GraphQL::Types::Int, null: false
field :explainer, ExplainerType, null: false
field :project_media, ProjectMediaType, null: false
end
9 changes: 2 additions & 7 deletions app/graph/types/explainer_type.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
class ExplainerType < DefaultObject
description "Explainer type"
description 'Explainer type'

implements GraphQL::Types::Relay::Node

Expand All @@ -12,10 +12,5 @@ class ExplainerType < DefaultObject
field :team_id, GraphQL::Types::Int, null: true
field :user, UserType, null: true
field :team, PublicTeamType, null: true

field :tags, TagType.connection_type, null: true

def tags
Tag.where(annotation_type: 'tag', annotated_type: object.class.name, annotated_id: object.id)
end
field :tags, [GraphQL::Types::String, null: true], null: true
end
4 changes: 4 additions & 0 deletions app/graph/types/fact_check_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,8 @@ class FactCheckType < DefaultObject
field :language, GraphQL::Types::String, null: true
field :user, UserType, null: true
field :claim_description, ClaimDescriptionType, null: true
field :tags, [GraphQL::Types::String, null: true], null: true
field :rating, GraphQL::Types::String, null: true
field :imported, GraphQL::Types::Boolean, null: true
field :report_status, GraphQL::Types::String, null: true
end
3 changes: 3 additions & 0 deletions app/graph/types/mutation_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,7 @@ class MutationType < BaseObject

field :createApiKey, mutation: ApiKeyMutations::Create
field :destroyApiKey, mutation: ApiKeyMutations::Destroy

field :createExplainerItem, mutation: ExplainerItemMutations::Create
field :destroyExplainerItem, mutation: ExplainerItemMutations::Destroy
end
15 changes: 15 additions & 0 deletions app/graph/types/project_media_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class ProjectMediaType < DefaultObject

field :media_id, GraphQL::Types::Int, null: true
field :user_id, GraphQL::Types::Int, null: true
field :fact_check_id, GraphQL::Types::Int, null: true
field :url, GraphQL::Types::String, null: true
field :full_url, GraphQL::Types::String, null: true
field :quote, GraphQL::Types::String, null: true
Expand Down Expand Up @@ -370,4 +371,18 @@ def is_secondary
field :similar_items, ProjectMediaType.connection_type, null: true

field :media_slug, GraphQL::Types::String, null: true

field :fact_check, FactCheckType, null: true

field :explainers, ExplainerType.connection_type, null: true

field :explainer_items, ExplainerItemType.connection_type, null: true

field :articles_count, GraphQL::Types::Int, null: true

def articles_count
count = object.explainers.count
count += 1 if object.fact_check
count
end
end
60 changes: 57 additions & 3 deletions app/graph/types/team_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -288,10 +288,64 @@ def tipline_messages(uid:)

field :articles, ::ArticleUnion.connection_type, null: true do
argument :article_type, GraphQL::Types::String, required: true, camelize: false
end

def articles(article_type:)
object.explainers if article_type == 'explainer'
# Sort and pagination
argument :offset, GraphQL::Types::Int, required: false, default_value: 0
argument :sort, GraphQL::Types::String, required: false, default_value: 'title'
argument :sort_type, GraphQL::Types::String, required: false, camelize: false, default_value: 'ASC'

# Filters
argument :user_ids, [GraphQL::Types::Int, null: true], required: false, camelize: false
argument :tags, [GraphQL::Types::String, null: true], required: false, camelize: false
argument :language, [GraphQL::Types::String, null: true], required: false, camelize: false
argument :updated_at, GraphQL::Types::String, required: false, camelize: false # JSON
argument :text, GraphQL::Types::String, required: false, camelize: false # Search by text
argument :standalone, GraphQL::Types::Boolean, required: false, camelize: false # Not applied to any item (fact-checks only)
argument :publisher_ids, [GraphQL::Types::Int, null: true], required: false, camelize: false
argument :report_status, [GraphQL::Types::String, null: true], required: false, camelize: false
argument :rating, [GraphQL::Types::String, null: true], required: false, camelize: false
argument :imported, GraphQL::Types::Boolean, required: false, camelize: false # Only for fact-checks
end

def articles(**args)
sort = args[:sort].to_s
order = [:title, :language, :updated_at, :id].include?(sort.downcase.to_sym) ? sort.downcase.to_sym : :title
order_type = args[:sort_type].to_s.downcase.to_sym == :desc ? :desc : :asc
articles = Explainer.none
if args[:article_type] == 'explainer'
articles = object.filtered_explainers(args)
elsif args[:article_type] == 'fact-check'
articles = object.filtered_fact_checks(args)
end
articles.offset(args[:offset].to_i).order(order => order_type)
end

field :articles_count, GraphQL::Types::Int, null: true do
argument :article_type, GraphQL::Types::String, required: false, camelize: false

# Filters
argument :user_ids, [GraphQL::Types::Int, null: true], required: false, camelize: false
argument :tags, [GraphQL::Types::String, null: true], required: false, camelize: false
argument :language, [GraphQL::Types::String, null: true], required: false, camelize: false
argument :updated_at, GraphQL::Types::String, required: false, camelize: false # JSON
argument :text, GraphQL::Types::String, required: false, camelize: false # Search by text
argument :standalone, GraphQL::Types::Boolean, required: false, camelize: false # Not applied to any item (fact-checks only)
argument :publisher_ids, [GraphQL::Types::Int, null: true], required: false, camelize: false
argument :report_status, [GraphQL::Types::String, null: true], required: false, camelize: false
argument :rating, [GraphQL::Types::String, null: true], required: false, camelize: false
argument :imported, GraphQL::Types::Boolean, required: false, camelize: false # Only for fact-checks
end

def articles_count(**args)
count = nil
if args[:article_type] == 'explainer'
count = object.filtered_explainers(args).count
elsif args[:article_type] == 'fact-check'
count = object.filtered_fact_checks(args).count
elsif args[:article_type].blank?
count = object.filtered_explainers(args).count + object.filtered_fact_checks(args).count
end
count
end

field :api_key, ApiKeyType, null: true do
Expand Down
5 changes: 3 additions & 2 deletions app/models/ability.rb
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,10 @@ def collaborator_perms
v_obj = obj.item_type.constantize.find(obj.item_id) if obj.item_type == 'ProjectMedia'
!v_obj.nil? and v_obj.team_id == @context_team.id and v_obj.media.user_id = @user.id
end
can [:create, :update, :read, :destroy], FactCheck, { claim_description: { project_media: { team_id: @context_team.id } } }
can [:create, :update, :read, :destroy], FactCheck, { claim_description: { team_id: @context_team.id } }
can [:create, :update, :read, :destroy], Explainer, team_id: @context_team.id
can [:create, :update, :read], ClaimDescription, { project_media: { team_id: @context_team.id } }
can [:create, :update, :read], ClaimDescription, { team_id: @context_team.id }
can [:create, :update, :read, :destroy], ExplainerItem, { project_media: { team_id: @context_team.id } }
end

def bot_permissions
Expand Down
24 changes: 21 additions & 3 deletions app/models/claim_description.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
class ClaimDescription < ApplicationRecord
include Article

belongs_to :project_media
before_validation :set_team, on: :create
belongs_to :project_media, optional: true
belongs_to :team
has_one :fact_check, dependent: :destroy

accepts_nested_attributes_for :fact_check, reject_if: proc { |attributes| attributes['summary'].blank? }

validates_presence_of :project_media
validates_uniqueness_of :project_media_id
validates_presence_of :team
validates_uniqueness_of :project_media_id, allow_nil: true
after_commit :update_fact_check, on: [:update]

# To avoid GraphQL conflict with name `context`
alias_attribute :claim_context, :context
Expand All @@ -32,4 +35,19 @@ def article_elasticsearch_data(action = 'create_or_update')
}
self.index_in_elasticsearch(data)
end

private

def set_team
team = (self.project_media&.team || Team.current)
self.team = team unless team.nil?
end

def update_fact_check
fact_check = self.fact_check
if fact_check && self.project_media_id
fact_check.updated_at = Time.now
fact_check.save!
end
end
end
20 changes: 19 additions & 1 deletion app/models/concerns/article.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ module Article

after_commit :update_elasticsearch_data, :send_to_alegre, :notify_bots, on: [:create, :update]
after_commit :destroy_elasticsearch_data, on: :destroy
after_save :create_tag_texts_if_needed
end

def text_fields
Expand Down Expand Up @@ -46,14 +47,15 @@ def notify_bots
'ClaimDescription' => 'save_claim_description',
'FactCheck' => 'save_fact_check'
}[self.class.name]
BotUser.enqueue_event(event, self.project_media.team_id, self)
BotUser.enqueue_event(event, self.project_media.team_id, self) unless self.project_media.nil?
end

protected

def index_in_elasticsearch(data)
# touch project media to update `updated_at` date
pm = self.project_media
return if pm.nil?
pm = ProjectMedia.find_by_id(pm.id)
unless pm.nil?
updated_at = Time.now
Expand All @@ -64,9 +66,25 @@ def index_in_elasticsearch(data)
end
end

def create_tag_texts_if_needed
self.class.delay.create_tag_texts_if_needed(self.team_id, self.tags) if self.respond_to?(:tags) && !self.tags.blank?
end

module ClassMethods
def create_tag_texts_if_needed(team_id, tags)
tags.each do |tag|
next if TagText.where(text: tag, team_id: team_id).exists?
tag_text = TagText.new
tag_text.text = tag
tag_text.team_id = team_id
tag_text.skip_check_ability = true
tag_text.save!
end
end

def send_to_alegre(id)
obj = self.find_by_id(id)
return if obj.project_media.nil?
obj.text_fields.each do |field|
::Bot::Alegre.send_field_to_similarity_index(obj.project_media, field)
end unless obj.nil?
Expand Down
2 changes: 2 additions & 0 deletions app/models/concerns/project_media_associations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ module ProjectMediaAssociations
has_one :claim_description, dependent: :destroy
belongs_to :source, optional: true
has_many :tipline_requests, as: :associated
has_many :explainer_items
has_many :explainers, through: :explainer_items
has_annotations
end
end
12 changes: 11 additions & 1 deletion app/models/concerns/project_media_cached_fields.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ def title_or_description_update
model: FactCheck,
affected_ids: proc { |fc| [fc.claim_description.project_media] },
events: {
save: :recalculate
save: :recalculate,
destroy: :recalculate
}
}

Expand Down Expand Up @@ -176,6 +177,11 @@ def title_or_description_update
}
]

cached_field :fact_check_id,
start_as: nil,
recalculate: :recalculate_fact_check_id,
update_on: [FACT_CHECK_EVENT]

cached_field :fact_check_title,
start_as: nil,
recalculate: :recalculate_fact_check_title,
Expand Down Expand Up @@ -540,6 +546,10 @@ def recalculate_last_seen
[v1, v2].max.to_i
end

def recalculate_fact_check_id
self.claim_description&.fact_check&.id
end

def recalculate_fact_check_title
self.claim_description&.fact_check&.title
end
Expand Down
4 changes: 4 additions & 0 deletions app/models/concerns/project_media_getters.rb
Original file line number Diff line number Diff line change
Expand Up @@ -209,4 +209,8 @@ def get_creator_name
def team_avatar
self.team.avatar
end

def fact_check
self.claim_description&.fact_check
end
end
4 changes: 4 additions & 0 deletions app/models/concerns/team_associations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,8 @@ def check_search_unconfirmed
def check_search_spam
check_search_filter({ 'archived' => CheckArchivedFlags::FlagCodes::SPAM })
end

def fact_checks
FactCheck.joins(:claim_description).where('claim_descriptions.team_id' => self.id)
end
end
4 changes: 3 additions & 1 deletion app/models/explainer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ class Explainer < ApplicationRecord
belongs_to :team

has_annotations
has_many :explainer_items
has_many :project_medias, through: :explainer_items

before_validation :set_team
validates_format_of :url, with: URI.regexp, allow_blank: true, allow_nil: true
validates_presence_of :team
validates_presence_of :team, :title, :description
validate :language_in_allowed_values, unless: proc { |e| e.language.blank? }

def notify_bots
Expand Down
Loading