We're changing the labels on our Ideas Exchange, and would like to find a way to bulk edit the already existing threads to the new labels.
For example, there are a lot of threads that have the label "Company." This label will be changed to "Companies." Is there a way to edit all of the threads that have the "Company" labels to be "Companies"?
thanks!
Yes, I do it all the time using the API in a script. Put the following code in a .rb file and run the script according to the instructions in the code. If you have questions, feel free to contact me kim.groneman@microfocus.com
# encoding: UTF-8
require 'rexml/document'
require 'logger'
require 'time'
# Ruby script for adding and removing labels inside messages
# Requirements: Ruby, Curl, restapi.enableRefererCheck set to false on the Lithium instance (in order to authenticate with another session ID)
# Usage: ruby update-labels.rb -h <hostname> -s <session ID> <CSV-filename> [> <logfile>]
# Tested with ruby 1.9.3p551(centos),2.2.6p396(win) and curl 7.39.0(centos),7.50.0(win)
# Author: Lithium migration team, Boyana Dobrinska (boyanna.dobrinska@lithium.com)
$log = Logger.new(STDOUT)
#function to output log data on both screen and file if redirected by command line
def echo(output_text, fileonly=0)
if $stdout.tty? && (fileonly==1) then return end
$log.info output_text
if !$stdout.tty? && (fileonly!=1) then
$stderr.puts output_text
end
end
$hostname = "" #full instance hostname URL eg. http://migration3.stage.lithium.com/
$sessionid = "" #Lithium cookie session ID
$filename = "" #CSV filename with the source, target node movement pairs
#checking command line agruments
ARGV.each do|a|
if $hostname == "?" then
$hostname = a
next
end
if $sessionid == "?" then
$sessionid = a
next
end
if a == "-h" then
$hostname = "?"
elsif a == "-s" then
$sessionid = "?"
else
$filename = a.encode('utf-8','windows-1252')
end
end
if $filename.empty? || $hostname.length<4 || $sessionid.length<4 then
$stderr.puts "Usage: ruby #{$PROGRAM_NAME} -h <hostname> -s <session ID> <CSV-filename> [> <logfile>]"
$stderr.puts "Example: ruby #{$PROGRAM_NAME} -h http://migration3.stage.lithium.com/ -s E5F00635A34824446A2854A9D6B1D117 update-labels-test.csv > todays-test.log"
exit
end
#creating the rest urls from the hostname url
REST_URL = "#{$hostname}#{$hostname[-1]!="/" ? "/" : ""}restapi/vc" #ADDING THE REST PART TO THE BASE URL
count_actions = 0
count_errors = 0
start_time = Time.now
begin
echo "STARTING THE PROCESS"
echo "*** VERBOSE MODE *** NO CHANGES WILL BE WRITTEN TO THE COMMUNITY" if $verbose == 1
echo " INSTANCE: #{$hostname}"
echo " SESSIONID: #{$sessionid}"
echo "SOURCE FILE: #{$filename}"
#check file exists
if !File.exist?($filename) then
echo "WARN: FILE '#{$filename}' DOESN'T EXIST."
count_errors += 1
exit
end
#check for authenticated admin
restcall="curl -s -S --retry 15 -k " \
+" --cookie \"LiSESSIONID=#{$sessionid}\" " \
+" #{REST_URL}/authentication/sessions/current/user/roles"
#puts restcall
curl = %x[#{restcall}]
#puts curl
if $?.exitstatus !=0 then
echo "WARN: HTTP communication failed for rest call: #{restcall}. Exit status: #{$?.exitstatus}."
count_errors += 1
exit
end
begin
doc = REXML::Document.new(curl)
rescue REXML::ParseException => msg
echo "WARN: XML Parsing Failed: #{msg.message} (Line:#{msg.backtrace.inspect.match(/(.rb:)(\d+):/)[2]})"
echo "WARN: XML for parsing:\n#{curl}"
count_errors += 1
exit
end
if doc.elements["response"].nil? || (doc.elements["response"].attributes["status"] != "success") then
echo "WARN: REST call failed."
echo "WARN: REST response:\n#{curl}"
count_errors += 1
exit
end
if !/<name type="string">Administrator<\/name>/.match(curl)
echo "WARN: The user doesn't have the Administrator role. Exiting."
count_errors += 1
exit
end
echo "Authentication success."
REGPAT = /^\s*([0-9]+?)\s*,\s*(ADD|REMOVE)\s*,\s*([^,]+)/i #regular expression to match a proper CSV file record
count_lines = 0
#reading the csv
file = File.new($filename, "r:UTF-8")
while (line = file.gets)
count_lines+=1
if match = line.match(REGPAT) then
topicid, action, label = match.captures
else
echo "WARN: LINE NOT MATCHING REGEXP: line #{count_lines} content: #{line}"
break if count_lines > 1 #only one bad line is allowed, usually the last line in the file may be empty
next
end
topicid = topicid.strip
action = action.strip.downcase
label = label.strip
echo "line: #{count_lines}, topic '#{topicid}': #{action} '#{label}'"
#check the message
restcall="curl -s -S --retry 15 -k " \
+" --cookie \"LiSESSIONID=#{$sessionid}\" "\
+" #{REST_URL}/messages/id/#{topicid}"
#echo restcall
curl = %x[#{restcall}]
#echo curl
if $?.exitstatus !=0 then
echo "WARN: HTTP communication failed for message #{rootmsg}. Rest call: #{restcall}. Exit status: #{$?.exitstatus}."
count_errors += 1
next #change to exit if you need hard stop on such error
end
begin
doc = REXML::Document.new(curl)
rescue REXML::ParseException => msg
echo "WARN: XML Parsing Failed: #{msg.message} (Line:#{msg.backtrace.inspect.match(/(.rb:)(\d+):/)[2]})"
echo "WARN: XML for parsing:\n#{curl}"
count_errors += 1
next #change to exit if you need hard stop on such error
end
if doc.elements["response"].nil? || (doc.elements["response"].attributes["status"] != "success") then
echo "WARN: REST call failed."
echo "WARN: REST response:\n#{curl}"
count_errors += 1
next #change to exit if you need hard stop on such error
end
author = doc.elements["response/message/author"].attributes["href"].to_s.strip
labels, newlabels = ""
labelfound = false
doc.elements.each("response/message/labels/label") do |labelitem|
labelfound = true if labelitem.elements["text"].text == label
labels += (", " + labelitem.elements["text"].text)
end
labels[0..1] = "" if labels[0] = ","
#echo labels
case action
when 'remove'
if not labelfound then
echo "WARN: Label '#{label}' not found inside the existing '#{labels}'."
count_errors += 1
next #change to exit if you need hard stop on such error
end
newlabels = labels.gsub(label,"")
when 'add'
if labelfound then
echo "WARN: Label '#{label}' already present."
count_errors += 1
next #change to exit if you need hard stop on such error
end
newlabels = labels + (labels == "" ? "" : ",") + label
else
echo "WARN: Unknown action type. This should never happen."
exit
end
#echo newlabels
#updating the message
restcall="curl -s -S --retry 15 -k " \
+" #{REST_URL}/messages/id/#{topicid}/edit "\
+" --cookie \"LiSESSIONID=#{$sessionid}\" "\
+" --form \"restapi.response_style=view\" "\
+ (author != "" ? " --form \"credentials.identity_user=#{author}\" " : "") \
+" --form \"label.labels=#{newlabels.gsub(/(["`$])/, '\\\\\1')}\" "
#echo restcall
curl = %x[#{restcall}]
#echo curl
if $?.exitstatus !=0 then
echo "WARN: HTTP communication failed for message #{rootmsg}. Rest call: #{restcall}. Exit status: #{$?.exitstatus}."
count_errors += 1
next #change to exit if you need hard stop on such error
end
begin
doc = REXML::Document.new(curl)
rescue REXML::ParseException => msg
echo "WARN: XML Parsing Failed: #{msg.message} (Line:#{msg.backtrace.inspect.match(/(.rb:)(\d+):/)[2]})"
echo "WARN: XML for parsing:\n#{curl}"
count_errors += 1
next #change to exit if you need hard stop on such error
end
if doc.elements["response"].nil? || (doc.elements["response"].attributes["status"] != "success") then
echo "WARN: REST call failed."
echo "WARN: REST response:\n#{curl}"
count_errors += 1
next #change to exit if you need hard stop on such error
end
echo "Updated #{doc.elements["response/message"].attributes["view_href"].to_s.strip}."
count_actions += 1
end
file.close
echo "TOTAL OF #{count_actions} ACTIONS PERFORMED, #{count_errors} ERRORS ENCOUNTERED."
echo "THE PROCESS TOOK #{Time.at(Time.now - start_time).gmtime.strftime('%R:%S')} HOURS."
echo "PROCESS COMPLETED."
end
The input csv file looks like this:
post ID, add,label
postID,remove,label
I always set the following before running the script otherwise errors will happen and/or you'll tick a lot of people off with a flurry of subscription emails:
Welcome to the Technology board!
Curious about our platform? Looking to connect on social technology? You've come to the right place!