FEATURE: Import and export watched word (#12444)
Find & Replace and Autotag watched words were not completely exported and import did not work with these either. This commit changes the input and output format to CSV, which allows for a secondary column. This change is backwards compatible because a CSV file with only one column has one value per line.
This commit is contained in:
parent
fb4486d5f1
commit
437c9a554b
|
@ -1,5 +1,5 @@
|
|||
<label class="btn btn-default {{if addDisabled "disabled"}}">
|
||||
{{d-icon "upload"}}
|
||||
{{i18n "admin.watched_words.form.upload"}}
|
||||
<input class="hidden-upload-field" disabled={{addDisabled}} type="file" accept="text/plain">
|
||||
<input class="hidden-upload-field" disabled={{addDisabled}} type="file">
|
||||
</label>
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'csv'
|
||||
|
||||
class Admin::WatchedWordsController < Admin::AdminController
|
||||
skip_before_action :check_xhr, only: [:download]
|
||||
|
||||
|
@ -26,12 +28,20 @@ class Admin::WatchedWordsController < Admin::AdminController
|
|||
def upload
|
||||
file = params[:file] || params[:files].first
|
||||
action_key = params[:action_key].to_sym
|
||||
has_replacement = WatchedWord.has_replacement?(action_key)
|
||||
|
||||
Scheduler::Defer.later("Upload watched words") do
|
||||
begin
|
||||
File.open(file.tempfile, encoding: "bom|utf-8").each_line do |line|
|
||||
WatchedWord.create_or_update_word(word: line, action_key: action_key) unless line.empty?
|
||||
CSV.foreach(file.tempfile, encoding: "bom|utf-8") do |row|
|
||||
if row[0].present? && (!has_replacement || row[1].present?)
|
||||
WatchedWord.create_or_update_word(
|
||||
word: row[0],
|
||||
replacement: has_replacement ? row[1] : nil,
|
||||
action_key: action_key
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
data = { url: '/ok' }
|
||||
rescue => e
|
||||
data = failed_json.merge(errors: [e.message])
|
||||
|
@ -48,11 +58,17 @@ class Admin::WatchedWordsController < Admin::AdminController
|
|||
action = WatchedWord.actions[name]
|
||||
raise Discourse::NotFound if !action
|
||||
|
||||
content = WatchedWord.where(action: action).pluck(:word).join("\n")
|
||||
content = WatchedWord.where(action: action)
|
||||
if WatchedWord.has_replacement?(name)
|
||||
content = content.pluck(:word, :replacement).map(&:to_csv).join
|
||||
else
|
||||
content = content.pluck(:word).join("\n")
|
||||
end
|
||||
|
||||
headers['Content-Length'] = content.bytesize.to_s
|
||||
send_data content,
|
||||
filename: "#{Discourse.current_hostname}-watched-words-#{name}.txt",
|
||||
content_type: "text/plain"
|
||||
filename: "#{Discourse.current_hostname}-watched-words-#{name}.csv",
|
||||
content_type: "text/csv"
|
||||
end
|
||||
|
||||
def clear_all
|
||||
|
|
|
@ -46,6 +46,10 @@ class WatchedWord < ActiveRecord::Base
|
|||
w
|
||||
end
|
||||
|
||||
def self.has_replacement?(action)
|
||||
action == :replace || action == :tag
|
||||
end
|
||||
|
||||
def action_key=(arg)
|
||||
self.action = self.class.actions[arg.to_sym]
|
||||
end
|
||||
|
|
|
@ -8,6 +8,6 @@ class WatchedWordSerializer < ApplicationSerializer
|
|||
end
|
||||
|
||||
def include_replacement?
|
||||
action == :replace || action == :tag
|
||||
WatchedWord.has_replacement?(action)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
hello,"tag1,tag2"
|
||||
|
||||
,"tag1,tag3"
|
||||
|
||||
|
||||
world,"tag2,tag3"
|
||||
|
||||
|
||||
|
||||
test,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'csv'
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Admin::WatchedWordsController do
|
||||
|
@ -47,6 +48,23 @@ RSpec.describe Admin::WatchedWordsController do
|
|||
|
||||
expect(WatchedWord.pluck(:action).uniq).to eq([WatchedWord.actions[:flag]])
|
||||
end
|
||||
|
||||
it 'creates the words from the file' do
|
||||
post '/admin/logs/watched_words/upload.json', params: {
|
||||
action_key: 'tag',
|
||||
file: Rack::Test::UploadedFile.new(file_from_fixtures("words_tag.csv", "csv"))
|
||||
}
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(WatchedWord.count).to eq(2)
|
||||
|
||||
expect(WatchedWord.pluck(:word, :replacement)).to contain_exactly(
|
||||
['hello', 'tag1,tag2'],
|
||||
['world', 'tag2,tag3']
|
||||
)
|
||||
|
||||
expect(WatchedWord.pluck(:action).uniq).to eq([WatchedWord.actions[:tag]])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -67,6 +85,8 @@ RSpec.describe Admin::WatchedWordsController do
|
|||
block_word_1 = Fabricate(:watched_word, action: WatchedWord.actions[:block])
|
||||
block_word_2 = Fabricate(:watched_word, action: WatchedWord.actions[:block])
|
||||
censor_word_1 = Fabricate(:watched_word, action: WatchedWord.actions[:censor])
|
||||
autotag_1 = Fabricate(:watched_word, action: WatchedWord.actions[:tag], replacement: "tag1,tag2")
|
||||
autotag_2 = Fabricate(:watched_word, action: WatchedWord.actions[:tag], replacement: "tag3,tag2")
|
||||
|
||||
get "/admin/logs/watched_words/action/block/download"
|
||||
expect(response.status).to eq(200)
|
||||
|
@ -76,7 +96,15 @@ RSpec.describe Admin::WatchedWordsController do
|
|||
get "/admin/logs/watched_words/action/censor/download"
|
||||
expect(response.status).to eq(200)
|
||||
censor_words = response.body.split("\n")
|
||||
expect(censor_words).to eq([censor_word_1.word])
|
||||
expect(censor_words).to contain_exactly(censor_word_1.word)
|
||||
|
||||
get "/admin/logs/watched_words/action/tag/download"
|
||||
expect(response.status).to eq(200)
|
||||
tag_words = response.body.split("\n").map(&:parse_csv)
|
||||
expect(tag_words).to contain_exactly(
|
||||
[autotag_1.word, autotag_1.replacement],
|
||||
[autotag_2.word, autotag_2.replacement]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue