- Post History
- Subscribe to RSS Feed
- Mark as New
- Mark as Read
- Bookmark
- Subscribe
- Printer Friendly Page
- Report Inappropriate Content
on 02-05-2015 12:32 PM
I am trying to import Word Documents to ServiceNow Knowledge Articles with out losing any images. I have tried using the Word Cleaner and SED installs without any success. Is there any fix that works?
We have our users select all, and past in to an outlook email, then send it to the instance and from there the below code for an inbound action does the rest. Not perfect but does a decent job.
[code]
var gdt = new GlideDate();
gdt.addDays(2);
//current.valid_to = gdt;
current.short_description = email.subject;
current.workflow_state = "draft";
current.topic = "General";
current.category = "";
current.roles = "knowledge_admin";
//Find and replace the image tags with the proper source.
//Get the number of attachments so the loop can be exited
//so it will stop no mater what.
var currentCount = 0;
var newBody = email.body_html;
var searchBody = email.body_html.replace(/\n/g, " ");
var regex = /<img(.*?)>/ig;
var match;
var match2;
while(match = regex.exec(searchBody)){
//Add a style float tag next to the align tag.
var alignText = match[0].replace(/align=['"]?left['"]?/gi, 'align="left" style="FLOAT: left"')
alignText = alignText.replace(/align=['"]?right['"]?/gi, 'align="right" style="FLOAT: right"')
searchBody = searchBody.replace(match[0], alignText);
var regex2 = /src=("(.)*?"|'(.)*?'|(.)*?\s+$)?/ig;
while(match2 = regex2.exec(alignText)){
findAndReplaceImage(match2[1].replace(/\s+$/,"").replace(/"+/g,"").replace(/'+/g,""));
}
currentCount += 1;
if(currentCount >= 100)
break;
}
searchBody = searchBody.replace(/<o:p>(.*?)<\/o:p>/ig, "");
currentCount = 0;
var regex2 = /<!--\[if(.*?)<!\[endif\]-->/ig;
while(match = regex2.exec(searchBody)){
searchBody = searchBody.replace(match[0], "");
currentCount += 1;
if(currentCount >= 100)
break;
}
currentCount = 0;
var regex2 = /<!\[if !vml\]>(.*?)<!\[endif\]>/ig;
while(match = regex2.exec(searchBody)){
searchBody = searchBody.replace(match[0], match[1]);
currentCount += 1;
if(currentCount >= 100)
break;
}
//gs.log("Create Morning Post: " + searchBody);
current.text = searchBody;
current.insert();
function getEmailSYSID(emailuid) {
var em = new GlideRecord('sys_email');
em.addQuery('uid', emailuid);
em.query();
if(em.next()) {
return em.sys_id;
}
return "";
}
function findAndReplaceImage(imageText){
var img = imageText;
var imgName = img.substring(4, img.search(/@/i));
var imgCode = "sys_attachment.do?sys_id=";
//Get the sys_id of the attachment
var gr = new GlideRecord("sys_attachment");
gr.addQuery("file_name", imgName);
gr.addQuery("table_sys_id", getEmailSYSID(email.uid));
gr.query();
if (gr.next()) {
imgCode += gr.sys_id;
}
searchBody = searchBody.replace(img, imgCode);
}
[/code]
Thanks Drew
I have trouble to get this going. I get some errors when I verify the script
but I think that not causing my issues:
When I execute this, the article and the attachments are created correctly, but the images are only displayed with placeholders, not the actual image.
checking the HTML, it seems as if the img sys_id is not properly inserted. Do you know why?
I think I found the issue, you're using the UID to find the email... however the UID is not unique in the system. I don't know if this should be the case, or if this has to do with all our testing.
Do you know how the UID is generated? Otherwise I will update the script also to lookup the table and the time of creation, to limit the search window...
At the time of writing this (3+ years ago) the UID of the email was the ONLY way to find the record in the table to get its sys_id. If you find a better way let me know.
Keep in mind that if you test the same email multiple times all of the attempts after the first will not have there pics attached because they were all moved to the first KB article.
thanks your last sentence saved me some trouble.
Here is the solution, just updated the 'getEmailSYSID' function a little bit.
function getEmailSYSID(emailuid) {
var em = new GlideRecord('sys_email');
em.addQuery('uid', emailuid);
em.query();
while(em.next()) {
//we execute the return only within a certain time difference between the creation of the attachment and now (in seconds)
var dif = gs.dateDiff(em.sys_created_on, gs.nowNoTZ(), true);
if(dif < 300 && dif > -300){
return em.sys_id;
}
}
return "";
}
I haven't tried, but could you not search for the message_id? is this not included when using email.message_id?
Searching the message ID mite work but I seam to remember that support told me the UID was the best method at the time.
Hey how did you get the code to show formatted?
On the right upper side of the reply box you have 'use advanced editor'
and then you have more options, one of em called 'insert'
Well, thank you again I'll play a bit around with the message_id later, but this seems now to work perfectly!
Perhaps you can update your correct answer.
Kind Regards
Michel
Hi,
We are facing the same issue that images are not getting displayed. sys_id is bla@nk in the image src
Were you able to find any fix for this issue.
Thanks
As explained, I updated the getEmailSYSID() function of his initial script, just see my comment above. Replace the initial function with my updated one and it should work.
Hi,
We have applied the same script which you updated in the function getEmailSYSID()
The function getEmailSYSID() is getting called but no records are returned by the query.
Although Querying the sys_email table manually with emailUID is returning the correct email.
FYI the instance is domain separated.
I guess it's this one
var dif = gs.dateDiff(em.sys_created_on, gs.nowNoTZ(), true);
I used 'gs.nowNoTZ()' because it's in the same format as 'sys_created_on'... but it may be different for other locale settings. Add a log just before that variable:
gs.log(em.subject + " - created: " + em.sys_created_on + " - nowNoTZ: " + gs.nowNoTZ());
Does the 'sys_created_on' date match the nowNoTZ()?
If not, you need to play around with the GlideDateTime: https://wiki.servicenow.com/index.php?title=GlideDateTime
To be honest, I don't think that this method is really proper, but it works for us and I currently have no time to play around. As already mentioned, a much better method for querying the email in my opinion probably the 'message_id'. So if you want, try to adapt the script to be able to grab not only the 'uid' but also the 'message_id', something like:
function getEmailSYSID(emailuid, emailmsgid) {
var em = new GlideRecord('sys_email');
em.addQuery('uid', emailuid);
em.addQuery('message_id', emailmsgid);
em.query();
while(em.....
Have you found a cleaner way to do this process? I will need to do hundreds if not thousands and was hoping someone found an easier method of uploading the content.
Many Thanks for any assistance you can provide.
Well once I implemented this with my corrections it worked pretty well. We have used this now for a lot of articles and not even once did we encounter major issues. Some minor displacements, but they are quickly fixed once imported.
Hi,
I copy paste the above script in the inbound action.
When I am sending an email from my outlook with the attachment(Word doc), its create a incident rather then knowledge article.
Can you please help me in this.
I am new in service now.
I want to copy the content of "word doc" to the knowledge article.
Thanks
You did most probably reference the wrong table on the inbound action.
Please take also my improvements to the script into count. I discussed them a little further below.
Hi Michel,
No, I have also used the same table name.
The way I designed the script you have to open the word doc and paste the content into the email and send just the email to the system with the proper subject so the system recognizes that the inbound action should run.
I tried to use the code in an Eureka release and doesn't work, and I receive errors like these ones
Error processing inbound action 'Insert Knowledge'
org.mozilla.javascript.EvaluatorException: The undefined value has no properties. (<refname>; line 22)
I send the email from an Outlook email client, pasting in the body of the email the text from a word document.
Is this code having issue for Eureka releases?
I have Eureka Patch 4 installed and the script is working fine as far as I can tell.
Dubya
I'm defining the Inbound emal action in this way:
I am getting this kind of errors
Error processing inbound action 'Insert Knowledge'
org.mozilla.javascript.EvaluatorException: The undefined value has no properties. (<refname>; line 22)
When i send the email to my DEV instance, I am watching the target pointing to the incident table, despite the inbound action is defined to point to the kb_knowledge and also the error below
What you think could be wrong with my inbound email action?
thanks!
Jesus
Whats on line 22 and 43? What was the content of the message that you sent?
I attached a text file that is the code used as the body in the message
thanks!
I send a new message and I watched more details about the error, the issue is in the following code,
I think something is not activated in my instance and that is why an object is not recognized.
I still receive error for new inbound email messages
thanks!
worker.0 WARNING *** WARNING *** Javascript compiler exception: The undefined value has no properties. (<refname>; line 43) in:
var gdt = new GlideDate();
gdt.addDays(2);
//current.valid_to = gdt;
current.short_description = email.subject;
current.workflow_state = "draft";
current.topic = "General";
current.category = "";
current.roles = "knowledge_admin";
//Find and replace the image tags with the proper source.
//Get the number of attachments so the loop can be exited
//so it will stop no mater what.
var currentCount = 0;
var newBody = email.body_html;
var searchBody = email.body_html.replace(/\n/g, " ");
...
you corrected the thrown exception errors on 4 of the lines in the script.
example on your line 18 with the part:
while(match == regex.exec(searchBody)){
the actual script is
while(match = regex.exec(searchBody)){
I know it throws an errors, but that's somehow required for the script to work. Because later you're going to use the value in the variable 'match' that has been set in line 18... If somebody has any idea how to formulate this correctly, you're welcome to help out.
Here is the full script that I use:
var gdt = new GlideDate();
gdt.addDays(2);
//current.valid_to = gdt;
var desc = email.subject;
desc = desc.replace("Knowledge:","");
current.short_description = desc.trim();
current.workflow_state = "draft";
current.topic = "General";
//current.category = "";
current.roles = "knowledge";
//Find and replace the image tags with the proper source.
//Get the number of attachments so the loop can be exited
//so it will stop no mater what.
var currentCount = 0;
var newBody = email.body_html;
var searchBody = email.body_html.replace(/\n/g, " ");
var regex = /<img(.*?)>/ig;
var match;
var match2;
while(match = regex.exec(searchBody)){
//Add a style float tag next to the align tag.
var alignText = match[0].replace(/align=['"]?left['"]?/gi, 'align="left" style="FLOAT: left"');
alignText = alignText.replace(/align=['"]?right['"]?/gi, 'align="right" style="FLOAT: right"');
searchBody = searchBody.replace(match[0], alignText);
var regex2 = /src=("(.)*?"|'(.)*?'|(.)*?\s+$)?/ig;
while(match2 = regex2.exec(alignText)){
findAndReplaceImage(match2[1].replace(/\s+$/,"").replace(/"+/g,"").replace(/'+/g,""));
}
currentCount += 1;
if(currentCount >= 100)
break;
}
searchBody = searchBody.replace(/<o:p>(.*?)<\/o:p>/ig, "");
currentCount = 0;
var regex2 = /<!--\[if(.*?)<!\[endif\]-->/ig;
while(match = regex2.exec(searchBody)){
searchBody = searchBody.replace(match[0], "");
currentCount += 1;
if(currentCount >= 100)
break;
}
currentCount = 0;
var regex2 = /<!\[if !vml\]>(.*?)<!\[endif\]>/ig;
while(match = regex2.exec(searchBody)){
searchBody = searchBody.replace(match[0], match[1]);
currentCount += 1;
if(currentCount >= 100)
break;
}
//gs.log("Create Morning Post: " + searchBody);
current.text = searchBody;
current.insert();
event.state="stop_processing";
function getEmailSYSID(emailuid) {
var em = new GlideRecord('sys_email');
em.addQuery('uid', emailuid);
em.query();
while(em.next()) {
//we execute the return only within a certain time difference between the creation of the attachment and now (in seconds)
var dif = gs.dateDiff(em.sys_created_on, gs.nowNoTZ(), true);
//gs.log("difference: " + dif + "eid: " + em.sys_id + " uid: " + em.uid); //debug
if(dif < 300 && dif > -300){
//gs.log('passed dif if: ' + em.sys_id + " uid: " + em.uid); //debug
return em.sys_id;
}
}
return "";
}
function findAndReplaceImage(imageText){
var img = imageText;
var imgName = img.substring(4, img.search(/@/i));
var imgCode = "sys_attachment.do?sys_id=";
//Get the sys_id of the attachment
var gr = new GlideRecord("sys_attachment");
gr.addQuery("file_name", imgName);
gr.addQuery("table_sys_id", getEmailSYSID(email.uid));
gr.query();
if (gr.next()) {
imgCode += gr.sys_id;
}
searchBody = searchBody.replace(img, imgCode);
}
Michel
thanks for the code fixed, this is working fine, also the images are displayed in the KB articles
lot of thanks!
Jesus
I have this working (for me) based on Drew's update at the bottom of the post. I can see the knowledge base article as it was sent in from email, ie graphics in line and not as attachments, however my service desk team cannot and they have knowledge and knowledge admin roles whereas I'm an administrator.
Should they have a particular role to be able to view?
EDIT **
NB I checked the script and the knowledge role is mentioned which as I said earlier they already have and I assigned one of them the admin role and it made no difference despite using the same browser(s).
If you impersonate them on your computer does it work?
Sorry for delay, appears to be working all right and also works for other docs where you can copy all and paste into email.
Thanks
HI together
I'm facing a similar issue:
On the prod Instance on Dublin Release the obove code works great.
On the dev Instance Eureka Patch 7 the obove code doesn't generate the pictures as attachment and displayes it wrong:
Did you find a solution for this?
On Dublin we faced the same problem than Angus. I (as an admin) can copy & paste pictures and the itil users with knowledge_admin and image_admin role can't.
Thanks
From your screen shot it does not look like the images are attached to the KB article. Are you sure the images showed up at the instance as part of the message?
Wow, I feel so left out of the answer...
Hi Drew
no they aren't. In Dublin they get attached. I think I know the root cause. There are two users for my email adress in the system. My admin user and my itil user have the same email adress. So it's more or less coincidence which user is chosen when I send an email to the system. The itil user didn't posess the knowledge role. I this caused it.
I have to think about the problem of the duplicate users.
Thank you for your question. It broght me the solution.
BR
Christina
We are in the start of going over to ServiceNow and this script will help us alot and save many hours of importing KB-articles into the system 😃
This document was generated from the following discussion: Import of Word Documents to ServiceNow Knowledge base
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi,
I want to import the word documents directly in the SNOW instance and map it to the knowledge articles not through inbound actions. Is that possible?
Please help.
Thanks,
Sivaranjani.