Getting document attachments using Kentico API - kentico

I created book store site on Kentico i used only their adminstration and display the data from my website using Kentico API's but am strugled in getting attachment files related to specific document i've got document data with no problem using
TreeProvider tree = new TreeProvider(MembershipContext.AuthenticatedUser);
var documents = tree.SelectNodes("CMS.Product");
need also to get related attachment files like book PDFs.. i've tried to use
DocumentAttachment
AttachmentInfo
AttachmentInfoProvider
classes but i couldn't get the data .. I would appreciate if any one help me in that.
Actually am searching about something like GetAttachment().Where("AttachmentFile","Ënglish File")

You can filter the returned attachments based on their values in columns (CMS_Attachment table) by using a code like this:
var attachment = AttachmentInfoProvider.GetAttachments()
.WhereEquals("AttachmentName", "Englishfile")
.And()
.WhereEquals("AttachmentExtension", "jpg")
.TopN(1)
.FirstOrDefault();
if (attachment != null)
{
// attachment was found
}
This code will get one .jpg file where attachment name equals to "EnglishFile"

Solved after using something like
var Attachment = AttachmentInfoProvider.GetAttachments(226, true);

This is from Kentico documentation. This example shows how to add an attachment and modify its metadata. You can ignore that part.You will have to make it generic to work for all examples.
Kentico 9 API Links
// Creates a new instance of the Tree provider
TreeProvider tree = new TreeProvider(MembershipContext.AuthenticatedUser);
// Gets a page
TreeNode page = tree.SelectSingleNode(SiteContext.CurrentSiteName, "/Articles", "en-us");
if (page != null)
{
// Gets an attachment by file name
AttachmentInfo attachment = DocumentHelper.GetAttachment(page, "file.png", tree);
// Edits the attachment's metadata (name, title and description)
attachment.AttachmentName += " - modified";
attachment.AttachmentTitle = "Attachment title";
attachment.AttachmentDescription = "Attachment description.";
// Ensures that the attachment can be updated without supplying its binary data
attachment.AllowPartialUpdate = true;
// Saves the modified attachment into the database
AttachmentInfoProvider.SetAttachmentInfo(attachment);
}

Related

How to access document attachments from hierarchical transformation

My site has this structure:
Products
category 1
item 1
item 1 attachments
category 2
item 2
item 2 attachments
I have successfully written a hierarchical transformation that shows the data on the page at the top level. I cannot for the life of me figure out how to access the attachments for each document though.
Anyone have any idea?
If you are talking about Group attachments (this is when you have a field in your page type using the Attachments data type) then in order to access the attachments inside your transformation you need to write either a custom macro (when using Text/XML transformation) or custom transformation method. Both can be done very easily. The code itself that gets you the attachments can be like this:
public ObjectQuery<AttachmentInfo> GetAttachmentsFromField(string className, int documentID, string attachmentColumnName)
{
// get class info
var classInfo = new FormInfo(DataClassInfoProvider.GetDataClassInfo(className).ClassFormDefinition);
if (classInfo != null)
{
// get attachment field definition
var attachmentsField = classInfo.GetFormField(attachmentColumnName);
if (attachmentsField != null)
{
// get attachments strored in the field by GUID
var attachments = AttachmentInfoProvider.GetAttachments()
.WhereEquals("3CCC6E6C-56F3-42EB-8385-979973D99C55", attachmentsField.Guid)
.And()
.WhereEquals("AttachmentDocumentID", documentID);
return attachments;
}
}
return null;
}
With this it is very important to take into account that this code introduces several other SQL queries against database and therefore it should be optimized by using caching appropriately.
I suppose you mean unsorted attachments you add in Properties -> Attachments section. In this case yuo can register following control in your transformation:
<%# Register Src="~/CMSInlineControls/DocumentAttachments.ascx" TagName="DocumentAttachments" TagPrefix="cms" %>
And use it like this:
<cms:DocumentAttachments ID="ucDocAttachments" runat="server" TransformationName="cms.root.attachment" Path='<%# Eval("NodeAliasPath") %>' />
I wrote a pretty detailed blog post on this a while back. It describes very similar attributes to Enn's answer but gives great detail on why you do specific things.

Remove All Attachments from document xpages

In my document i have multiple "Body" field which contains Rich-Text data as well as attachment files which is of type (Data Type: MIME Part).
My purpose is to only delete the attachment files from my document. I tried this,
if (document1.getAttachmentList("body").isEmpty()) {
requestScope.alist = "No attachments in body";
} else {
document1.removeAllAttachments("body");
document1.save();
requestScope.alist = "All attachments removed from body";
}
where document1 is my data source name, by this code it works properly.
But, i want to retrieve document by
var doc:NotesDocument = database.getDocumentByUNID(context.getUrlParameter("documentId"));
where it does not works.
I had even tried by this code,
var doc3:NotesDocument = database.getDocumentByUNID(context.getUrlParameter("documentId"));
var item:NotesItem =doc3.getFirstItem("$FILE");
item.remove();
doc3.save();
But, here problem is that it also deleting rich text data from document.
Is there any other solution can help me out.
Thanks in advance.
In the first working code you have a the NotesXSPDocument, but in the second example you have the NotesDocument.
may be it is an idea to convert the NotesDocument to a NotesXSPDocument so you can use the first example
To convert it in SSJS this example may help you
https://openntf.org/XSnippets.nsf/snippet.xsp?id=wrap-notesdocument-into-notesxspdocument
What is the difference between the "NotesXspDocument" and "NotesDocument" class in XPages
https://www-10.lotus.com/ldd/ddwiki.nsf/dx/xpages-notesxspdocument-vs-notesdocument.htm

Attachments Overrides existing while adding from VendorMaint graph

I am importing data and documents from third party application into Acumatica.
After importing, I am creating Vendor dynamically using below code along with attachments.
VendorMaint graph = PXGraph.CreateInstance<VendorMaint>();
VendorR row1 = null;
row1 = new VendorR();
row1.AcctName = VendorName;
row1.NoteID = noteid; // Existing - GUID created while importing
graph.BAccount.Update(row1);
If attachment already exists then it should update instead of duplicating.
In this case if Vendor already exists with files attached, then my code overrides these attachments and remove all previous files attached to that existing vendor.
I want to add the attachment instead of override the existing attachment. Any suggestion?
Try to use insert method of view:
VendorMaint graph = PXGraph.CreateInstance<VendorMaint>();
var row1 = new VendorR();
row1 = graph.BAccount.Insert(row1);
if (row1 == null) // already inserted or wasn't able to insert
{
//some logic with newly created vendor
}
else
{
//some logic with existed
}
row1.AcctName = "vendor name";
row1.NoteID = noteid; // Existing - GUID created while importing
graph.BAccount.Update(row1);
I have found the solution for the issue. Below code helps to create a new attachment and does not override any existing attachments for an existing Vendor.
// Getting the FileID of the attached file from DACClass
UploadFile uf = PXSelectJoin<UploadFile,
InnerJoin<NoteDoc, On<NoteDoc.fileID, Equal<UploadFile.fileID>>,
InnerJoin<DACClass, On<DACClass.noteID, Equal<NoteDoc.noteID>>>>,
Where<DACClass.noteID, Equal<Required<DACClass.noteID>>>>.Select(this, noteid);
if (uf != null)
{
PXNoteAttribute.SetFileNotes(graph.BAccount.Cache, graph.BAccount.Current, uf.FileID.Value);
NoteDoc doc = new NoteDoc();
doc.NoteID = uf.FileID.Value;
doc.FileID = new Guid();
graph.BAccount.Cache.Insert(doc);
}

How To find Cross References(Internal Links) In Pdf File Using ItextSharp Lib

Hi I am using ItextSharp For searching Cross References(Internal Links) In pdf file. I already done with External Links.
Please Post If u have any solutions.
//Get the current page
PdfDictionary PageDictionary = R.GetPageN(page);
//Get all of the annotations for the current page
PdfArray Annots = PageDictionary.GetAsArray(PdfName.ANNOTS);
//Make sure we have something
if ((Annots == null) || (Annots.Length == 0))
// return null;
{
Console.WriteLine("nothing");
}
//Loop through each annotation
if (Annots != null)
{
foreach (PdfObject A in Annots.ArrayList)
{
//Convert the itext-specific object as a generic PDF object
PdfDictionary AnnotationDictionary = (PdfDictionary)PdfReader.GetPdfObject(A);
//Make sure this annotation has a link
if (!AnnotationDictionary.Get(PdfName.SUBTYPE).Equals(PdfName.LINK))
continue;
//Make sure this annotation has an ACTION
if (AnnotationDictionary.Get(PdfName.A) == null)
continue;
//Get the ACTION for the current annotation
PdfDictionary AnnotationAction = AnnotationDictionary.GetAsDict(PdfName.A);
// PdfDictionary AnnotationAction = (PdfDictionary)AnnotationDictionary.Get(PdfName.A);
//Test if it is a URI action (There are tons of other types of actions, some of which might mimic URI, such as JavaScript, but those need to be handled seperately)
if (AnnotationAction.Get(PdfName.S).Equals(PdfName.URI))
{
PdfString Destination = AnnotationAction.GetAsString(PdfName.URI);
string url1 = Destination.ToString();
}
}
}
You've already done most of the work. Please take a look at the following screen shot:
You see the /Annots array of a page. You are already parsing that array in your code and you skip all annotations that aren't of the /Subtype /Link or don't have an /A key, which is excellent.
Currently you're only looking for values of /S that are of type /URI. You say you're already done with external links, but that's not true: you should also lok for entries where /S is /GoToR (remote goto). If you want internal links, you need to look for /S values equal to /GoTo, /GoToE, and (in the future) /GoToDp. Maybe you also want to remove the /JavaScript actions, because they can also be used to jump to a specific page.
Please download The ABC of PDF and take a look at table 3.11 for more info. (The book is available for free.)

Programmatically Edit Infopath Form Fields?

I have a form library in my share point site. Programmatically I need to fill some fields. Can I do that? If any one know please provide me some sample code. First I need to retrieve the infopath document and then I need to fill the fields.
What axel_c posted is pretty dang close. Here's some cleaned up and verified working code...
public static void ChangeFields()
{
//Open SharePoint site
using (SPSite site = new SPSite("http://<SharePoint_Site_URL>"))
{
using (SPWeb web = site.OpenWeb())
{
//Get handle for forms library
SPList formsLib = web.Lists["FormsLib"];
if (formsLib != null)
{
foreach (SPListItem item in formsLib.Items)
{
XmlDocument xml = new XmlDocument();
//Open XML file and load it into XML document
using (Stream s = item.File.OpenBinaryStream())
{
xml.Load(s);
}
//Do your stuff with xml here. This is just an example of setting a boolean field to false.
XmlNodeList nodes = xml.GetElementsByTagName("my:SomeBooleanField");
foreach (XmlNode node in nodes)
{
node.InnerText = "0";
}
//Get binary data for new XML
byte[] xmlData = System.Text.Encoding.UTF8.GetBytes(xml.OuterXml);
using (MemoryStream ms = new MemoryStream(xmlData))
{
//Write data to SharePoint XML file
item.File.SaveBinary(ms);
}
}
}
}
}
}
The Infopath document is just a regular XML file, the structure of which matches the data sources you defined in the Infopath form.
You just need to access the file via the SharePoint object model, modify it using standard methods (XmlDocument API) and then write it back to the SharePoint list. You must be careful to preserve the structure and insert valid data or you won't be able to open the form using Infopath.
You should really check out a book on SharePoint if you plan to do any serious development. Infopath is also a minefield.
Object model usage examples: here, here and here. The ridiculously incomplete MSDN reference documentation is here.
EDIT: here is some example code. I haven't done SharePoint for a while so I'm not sure this is 100% correct, but it should give you enough to get started:
// Open SharePoint site
using (SPSite site = new SPSite("http://<SharePoint_Site_URL>"))
{
using (SPWeb web = site.OpenWeb())
{
// Get handle for forms library
SPList formsLib = web.Lists["FormsLib"];
if (formsLib != null)
{
SPListItem itm = formsLib.Items["myform.xml"];
// Open xml and load it into XML document
using (Stream s = itm.File.OpenBinary ())
{
MemoryStream ms;
byte[] xmlData;
XmlDocument xml = new XmlDocument ();
xml.Load (s);
s.Close ();
// Do your stuff with xml here ...
// Get binary data for new XML
xmlData = System.Text.Encoding.UTF8.GetBytes (xml.DocumentElement.OuterXml);
ms = new MemoryStream (xmlData);
// Write data to sharepoint item
itm.File.SaveBinary (ms);
ms.Close ();
itm.Update ();
}
}
web.Close();
}
site.Close();
}
It depends a bit on your available tool set, skills and exact requirements.
There are 2 main ways of pre populating data inside an InfoPath form.
Export the relevant fields as part of the form's publishing process. The fields will then become columns on the Document / Forms library from where you can manipulate them either manually, via a Workflow or wherever your custom code is located.
Directly manipulate the form using code similar to what was provided by Axel_c previously. The big question here is: what will trigger this code? An event receiver on the Document Library, a SharePoint Designer Workflow, a Visual Studio workflow etc?
If you are trying to do this from a SharePoint Designer workflow then have a look at the Workflow Power Pack for SharePoint. It allows C# and VB code to be embedded directly into the workflow without the need for complex Visual Studio development. An example of how to query InfoPath data from a workflow can be found here. If you have some development skills you should be able to amend it to suit your needs.
I also recommend the site www.infopathdev.com, they have excellent and active forums. You will almost certainly find an answer to your question there.
Thanks for the sample code, #axel_c and #Jeff Burt
Below is just the same code from Jeff Burt modified for a file in Document set which I needed. If you don't already have the Document Set reference, you can check out this site on how to grab one:
http://howtosharepoint.blogspot.com/2010/12/programmatically-create-document-set.html
Also, the codes will open the .xml version of the infopath form and not the .xsn template version which you might run into.
Thanks again everyone...
private void ChangeFields(DocumentSet docSet)
{
string extension = "";
SPFolder documentsetFolder = docSet.Folder;
foreach (SPFile file in documentsetFolder.Files)
{
extension = Path.GetExtension(file.Name);
if (extension != ".xml") //check if it's a valid xml file
return;
XmlDocument xml = new XmlDocument();
//Open XML file and load it into XML document, needs to be .xml file not .xsn
using (Stream s = file.OpenBinaryStream())
{
xml.Load(s);
}
//Do your stuff with xml here. This is just an example of setting a boolean field to false.
XmlNodeList nodes = xml.GetElementsByTagName("my:fieldtagname");
foreach (XmlNode node in nodes)
{
node.InnerText = "xyz";
}
//Get binary data for new XML
byte[] xmlData = System.Text.Encoding.UTF8.GetBytes(xml.OuterXml);
using (MemoryStream ms = new MemoryStream(xmlData))
{
//Write data to SharePoint XML file
file.SaveBinary(ms);
}
}
}
I had this issue and resolved it with help from Jeff Burt / Axel_c's posts.
I was trying to use the XMLDocument.Save([stream]) and SPItem.File.SaveBinary([stream]) methods to write an updated InfoPath XML file back to a SharePoint library. It appears that XMLDocument.Save([stream]) writes the file back to SharePoint with the wrong encoding, regardless of what it says in the XML declaration.
When trying to open the updated InfoPath form I kept getting the error "a calculation in the form has not been completed..."
I've written these two functions to get and update and InfoPath form. Just manipulate the XML returned from ReadSPFiletoXMLdocument() in the usual way and send it back to your server using WriteXMLtoSPFile().
private System.Xml.XmlDocument ReadSPFiletoXMLdocument(SPListItem item)
{
//get SharePoint file XML
System.Xml.XmlDocument xDoc = new System.Xml.XmlDocument();
try
{
using (System.IO.Stream xmlStream = item.File.OpenBinaryStream())
{
xDoc.Load(xmlStream);
}
}
catch (Exception ex)
{
//put your own error handling here
}
return xDoc;
}
private void WriteXMLtoSPFile(SPListItem item, XmlDocument xDoc)
{
byte[] xmlData = System.Text.Encoding.UTF8.GetBytes(xDoc.OuterXml);
try
{
using (System.IO.MemoryStream outStream = new System.IO.MemoryStream(xmlData))
{
item.File.SaveBinary(outStream);
}
}
catch (Exception ex)
{
//put your own error handling here
}
}

Resources