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 "trash" feature #2037

Merged
merged 8 commits into from
Sep 18, 2024
2 changes: 2 additions & 0 deletions app/graph/mutations/explainer_mutations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ class Create < Mutations::CreateMutation

class Update < Mutations::UpdateMutation
include SharedCreateAndUpdateFields

argument :trashed, GraphQL::Types::Boolean, required: false
end

class Destroy < Mutations::DestroyMutation; end
Expand Down
1 change: 1 addition & 0 deletions app/graph/mutations/fact_check_mutations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class Update < Mutations::UpdateMutation

argument :title, GraphQL::Types::String, required: false
argument :summary, GraphQL::Types::String, required: false
argument :trashed, GraphQL::Types::Boolean, required: false
end

class Destroy < Mutations::DestroyMutation; end
Expand Down
1 change: 1 addition & 0 deletions app/graph/types/explainer_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ class ExplainerType < DefaultObject
field :user, UserType, null: true
field :team, PublicTeamType, null: true
field :tags, [GraphQL::Types::String, null: true], null: true
field :trashed, GraphQL::Types::Boolean, null: true
end
1 change: 1 addition & 0 deletions app/graph/types/fact_check_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ class FactCheckType < DefaultObject
field :rating, GraphQL::Types::String, null: true
field :imported, GraphQL::Types::Boolean, null: true
field :report_status, GraphQL::Types::String, null: true
field :trashed, GraphQL::Types::Boolean, null: true
end
2 changes: 2 additions & 0 deletions app/graph/types/team_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ def tipline_messages(uid:)
argument :rating, [GraphQL::Types::String, null: true], required: false, camelize: false
argument :imported, GraphQL::Types::Boolean, required: false, camelize: false # Only for fact-checks
argument :target_id, GraphQL::Types::Int, required: false, camelize: false # Exclude articles already applied to the `ProjectMedia` with this ID
argument :trashed, GraphQL::Types::Boolean, required: false, camelize: false, default_value: false
end

def articles(**args)
Expand Down Expand Up @@ -336,6 +337,7 @@ def articles(**args)
argument :rating, [GraphQL::Types::String, null: true], required: false, camelize: false
argument :imported, GraphQL::Types::Boolean, required: false, camelize: false # Only for fact-checks
argument :target_id, GraphQL::Types::Int, required: false, camelize: false # Exclude articles already applied to the `ProjectMedia` with this ID
argument :trashed, GraphQL::Types::Boolean, required: false, camelize: false, default_value: false
end

def articles_count(**args)
Expand Down
5 changes: 5 additions & 0 deletions app/models/claim_description.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class ClaimDescription < ApplicationRecord

validates_presence_of :team
validates_uniqueness_of :project_media_id, allow_nil: true
validate :cant_apply_article_to_item_if_article_is_in_the_trash
after_commit :update_fact_check, on: [:update]
after_update :update_report_status
after_update :replace_media, unless: proc { |cd| cd.disable_replace_media }
Expand Down Expand Up @@ -115,4 +116,8 @@ def migrate_claim_and_fact_check_logs
.where.not(event: 'create').update_all(associated_id: self.project_media_id)
end
end

def cant_apply_article_to_item_if_article_is_in_the_trash
errors.add(:base, I18n.t(:cant_apply_article_to_item_if_article_is_in_the_trash)) if self.project_media && self.fact_check&.trashed
end
end
16 changes: 16 additions & 0 deletions app/models/concerns/article.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,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
after_update :schedule_for_permanent_deletion_if_sent_to_trash, if: proc { |obj| obj.is_a?(FactCheck) || obj.is_a?(Explainer) }
end

def text_fields
Expand Down Expand Up @@ -68,6 +69,13 @@ 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

def schedule_for_permanent_deletion_if_sent_to_trash
if self.trashed && !self.trashed_before_last_save
interval = CheckConfig.get('empty_trash_interval', 30, :integer)
self.class.delay_for(interval.days, { queue: 'trash', retry: 0 }).delete_permanently(self.id)
end
end

module ClassMethods
def create_tag_texts_if_needed(team_id, tags)
tags.to_a.map(&:strip).each do |tag|
Expand All @@ -87,5 +95,13 @@ def send_to_alegre(id)
::Bot::Alegre.send_field_to_similarity_index(obj.project_media, field)
end unless obj.nil?
end

def delete_permanently(id)
obj = self.find_by_id(id)
if obj && obj.trashed
obj.destroy!
obj.claim_description.destroy! if obj.is_a?(FactCheck)
Comment on lines +102 to +103
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest to swap the lines as I prefer to destroy the object itself at the end.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@melsawy good catch! I did that before but it had an issue because of the destroy dependency between claim and fact-check.

end
end
end
end
10 changes: 9 additions & 1 deletion app/models/explainer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class Explainer < ApplicationRecord
validate :language_in_allowed_values, unless: proc { |e| e.language.blank? }

after_save :update_paragraphs_in_alegre
after_update :detach_explainer_if_trashed

def notify_bots
# Nothing to do for Explainer
Expand Down Expand Up @@ -57,7 +58,8 @@ def self.get_exported_data(query, team)
end

def self.update_paragraphs_in_alegre(id, previous_paragraphs_count, timestamp)
explainer = Explainer.find(id)
explainer = Explainer.find_by_id(id)
return if explainer.nil?

# Skip if the explainer was saved since this job was created (it means that there is a more recent job)
return if explainer.updated_at.to_f > timestamp
Expand Down Expand Up @@ -131,4 +133,10 @@ def language_in_allowed_values
allowed_languages << 'und'
errors.add(:language, I18n.t(:"errors.messages.invalid_article_language_value")) unless allowed_languages.include?(self.language)
end

def detach_explainer_if_trashed
if self.trashed && !self.trashed_before_last_save
self.project_medias = []
end
end
end
5 changes: 5 additions & 0 deletions app/models/explainer_item.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class ExplainerItem < ApplicationRecord

validates_presence_of :explainer, :project_media
validate :same_team
validate :cant_apply_article_to_item_if_article_is_in_the_trash

def version_metadata(_changes)
{ explainer_title: self.explainer.title }.to_json
Expand All @@ -17,4 +18,8 @@ def version_metadata(_changes)
def same_team
errors.add(:base, I18n.t(:explainer_and_item_must_be_from_the_same_team)) unless self.explainer&.team_id == self.project_media&.team_id
end

def cant_apply_article_to_item_if_article_is_in_the_trash
errors.add(:base, I18n.t(:cant_apply_article_to_item_if_article_is_in_the_trash)) if self.explainer&.trashed
end
end
9 changes: 9 additions & 0 deletions app/models/fact_check.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class FactCheck < ApplicationRecord

after_save :update_report, unless: proc { |fc| fc.skip_report_update || !DynamicAnnotation::AnnotationType.where(annotation_type: 'report_design').exists? || fc.project_media.blank? }
after_save :update_item_status, if: proc { |fc| fc.saved_change_to_rating? }
after_update :detach_claim_if_trashed

def text_fields
['fact_check_title', 'fact_check_summary']
Expand Down Expand Up @@ -143,4 +144,12 @@ def set_initial_rating
default_rating = self.claim_description.team.verification_statuses('media', nil)['default']
self.rating = pm_rating || default_rating
end

def detach_claim_if_trashed
if self.trashed && !self.trashed_before_last_save
cd = self.claim_description
cd.project_media = nil
cd.save!
end
end
end
6 changes: 6 additions & 0 deletions app/models/team.rb
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,9 @@ def filtered_explainers(filters = {})
# Filter by date
query = query.where(updated_at: Range.new(*format_times_search_range_filter(JSON.parse(filters[:updated_at]), nil))) unless filters[:updated_at].blank?

# Filter by trashed
query = query.where(trashed: !!filters[:trashed])

# Filter by text
query = self.filter_by_keywords(query, filters, 'Explainer') if filters[:text].to_s.size > 2

Expand Down Expand Up @@ -534,6 +537,9 @@ def filtered_fact_checks(filters = {})
# Filter by report status
query = query.where('fact_checks.report_status' => [filters[:report_status]].flatten.map(&:to_s)) unless filters[:report_status].blank?

# Filter by trashed
query = query.where('fact_checks.trashed' => !!filters[:trashed])

# Filter by text
query = self.filter_by_keywords(query, filters) if filters[:text].to_s.size > 2

Expand Down
1 change: 1 addition & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -830,6 +830,7 @@ en:
send_on_must_be_in_the_future: can't be in the past.
cant_delete_default_folder: The default folder can't be deleted
explainer_and_item_must_be_from_the_same_team: Explainer and item must be from the same workspace.
cant_apply_article_to_item_if_article_is_in_the_trash: This article is in the trash so it can't be added to this media cluster. Please first restore it from the trash.
shared_feed_imported_media_already_exist: |-
No media eligible to be imported into your workspace.
The media selected to import already exist in your workspace in the following items:
Expand Down
6 changes: 6 additions & 0 deletions db/migrate/20240913210101_add_trashed_to_articles.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class AddTrashedToArticles < ActiveRecord::Migration[6.1]
def change
add_column :fact_checks, :trashed, :boolean, default: false, index: true
add_column :explainers, :trashed, :boolean, default: false, index: true
end
end
4 changes: 3 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 2024_08_13_155311) do
ActiveRecord::Schema.define(version: 2024_09_13_210101) do

# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
Expand Down Expand Up @@ -324,6 +324,7 @@
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.string "tags", default: [], array: true
t.boolean "trashed", default: false
t.index ["tags"], name: "index_explainers_on_tags", using: :gin
t.index ["team_id"], name: "index_explainers_on_team_id"
t.index ["user_id"], name: "index_explainers_on_user_id"
Expand All @@ -344,6 +345,7 @@
t.integer "report_status", default: 0
t.string "rating"
t.boolean "imported", default: false
t.boolean "trashed", default: false
t.index ["claim_description_id"], name: "index_fact_checks_on_claim_description_id", unique: true
t.index ["imported"], name: "index_fact_checks_on_imported"
t.index ["language"], name: "index_fact_checks_on_language"
Expand Down
7 changes: 6 additions & 1 deletion lib/relay.idl
Original file line number Diff line number Diff line change
Expand Up @@ -8265,6 +8265,7 @@ type Explainer implements Node {
team: PublicTeam
team_id: Int
title: String
trashed: Boolean
updated_at: String
url: String
user: User
Expand Down Expand Up @@ -8418,6 +8419,7 @@ type FactCheck implements Node {
summary: String
tags: [String]
title: String
trashed: Boolean
updated_at: String
url: String
user: User
Expand Down Expand Up @@ -13167,10 +13169,11 @@ type Team implements Node {
tags: [String]
target_id: Int
text: String
trashed: Boolean = false
updated_at: String
user_ids: [Int]
): ArticleUnionConnection
articles_count(article_type: String, imported: Boolean, language: [String], publisher_ids: [Int], rating: [String], report_status: [String], standalone: Boolean, tags: [String], target_id: Int, text: String, updated_at: String, user_ids: [Int]): Int
articles_count(article_type: String, imported: Boolean, language: [String], publisher_ids: [Int], rating: [String], report_status: [String], standalone: Boolean, tags: [String], target_id: Int, text: String, trashed: Boolean = false, updated_at: String, user_ids: [Int]): Int
available_newsletter_header_types: JsonStringType
avatar: String
check_search_spam: CheckSearch
Expand Down Expand Up @@ -15590,6 +15593,7 @@ input UpdateExplainerInput {
language: String
tags: [String]
title: String
trashed: Boolean
url: String
}

Expand Down Expand Up @@ -15620,6 +15624,7 @@ input UpdateFactCheckInput {
summary: String
tags: [String]
title: String
trashed: Boolean
url: String
}

Expand Down
2 changes: 1 addition & 1 deletion lib/sample_data.rb
Original file line number Diff line number Diff line change
Expand Up @@ -899,7 +899,7 @@ def create_claim_description(options = {})
description: random_string,
context: random_string,
user: options[:user] || create_user,
project_media: options[:project_media] || create_project_media
project_media: options.has_key?(:project_media) ? options[:project_media] : create_project_media
}.merge(options))
end

Expand Down
76 changes: 76 additions & 0 deletions public/relay.json
Original file line number Diff line number Diff line change
Expand Up @@ -44795,6 +44795,20 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "trashed",
"description": null,
"args": [

],
"type": {
"kind": "SCALAR",
"name": "Boolean",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "updated_at",
"description": null,
Expand Down Expand Up @@ -45621,6 +45635,20 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "trashed",
"description": null,
"args": [

],
"type": {
"kind": "SCALAR",
"name": "Boolean",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "updated_at",
"description": null,
Expand Down Expand Up @@ -69084,6 +69112,18 @@
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "trashed",
"description": null,
"type": {
"kind": "SCALAR",
"name": "Boolean",
"ofType": null
},
"defaultValue": "false",
"isDeprecated": false,
"deprecationReason": null
}
],
"type": {
Expand Down Expand Up @@ -69265,6 +69305,18 @@
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "trashed",
"description": null,
"type": {
"kind": "SCALAR",
"name": "Boolean",
"ofType": null
},
"defaultValue": "false",
"isDeprecated": false,
"deprecationReason": null
}
],
"type": {
Expand Down Expand Up @@ -85404,6 +85456,18 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "trashed",
"description": null,
"type": {
"kind": "SCALAR",
"name": "Boolean",
"ofType": null
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "clientMutationId",
"description": "A unique identifier for the client performing the mutation.",
Expand Down Expand Up @@ -85584,6 +85648,18 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "trashed",
"description": null,
"type": {
"kind": "SCALAR",
"name": "Boolean",
"ofType": null
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "clientMutationId",
"description": "A unique identifier for the client performing the mutation.",
Expand Down
Loading
Loading