Tuesday, July 21, 2009

Sending document in a document library as a mail attachment

SharePoint dcument library contains "Email as a link" item in the individual items context menu that -from its name-enables you to send the link of the document using the outlook express email,



One day i asked to make a feature that can send the document itself as an attachment inside email with.

I thougt that i can make a new context menu item in the doucment library that redirect you to a page in which you can wirte your email and send the mail via smtp containing the original docuemt as an attachment,

The main issue in this idea is how to know the source docuemt in the mail page, with some crawling behind the query string of similar functionality i found that sharepoint pages uses some javascript variables that read the id of the source and the source url (to go back after sending mail.) etc..,

Now do the following steps to do so:




  1. Click Site Actions Menu the Edit Page


  2. Add Web Part choose "Content Editor Web Part".


  3. Open properties pane in the source editor cope and paste the following code inside script tag:


    function Custom_AddDocLibMenuItems(m, ctx)
    {
    var strDisplayText = ""; var strAction = ""; var strImagePath = "";
    strDisplayText = "Send Document To People";
    strAction = "window.location= '" + ctx.HttpRoot + "/_layouts/SndItmPpl.aspx?ID="+currentItemID+"&Source="+ GetSource()+"&list="+ctx.listName+"'";
    // Add our new menu item
    CAMOpt(m, strDisplayText, strAction, strImagePath);
    // add a separator to the menu
    CAMSep(m);
    // false means that the standard menu items should also be rendered
    return false;
    }
  4. From Layout property check "Hidden".
  5. the appove code add "Send Document To People" menu item to the docuemt library which open the page SndItmPpl.aspx passing source url, Item Id, parent list name to it in the query string.


  6. now copy and paste the attached SndItmPpl.aspx to your "Template" folder in the following path in your server "\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS".
  7. You can find the aspx file Here

  8. This page like the "Gmail compose mail" page but it will contain the original document by defualt.


thanks

Submitting The InfoPath From to the Current From Library Folder

Have you ever faced the case that you want to organize your form library items to folders , you may be using a submit data connection to submit your form to the library including the meta data and also to benefit from the overwrite check in the submit data connection to enable or disable overwriting forms with the same name ?. if this the

case you will face to problems.


  1. Submit using data connection sumbits only to the root folder

  2. Overwrite check can only check for dublicated forms in the current directory (so you can't guarantee uniqunuess in the form library entierly)

Solution


The solution for the first problem is to handle the submit event and update the url for the Main Submit data connection with the current working directory.


The Solution for second problem is to search all the folders inside the the form library for the field you want to be unique which will be shown in the Title Field, if it exists before cancel submittion.


The Code


1- Add New Submit Data Connecntion to your form library
2- From Submit Options Choose to run custom code when sumbiting the form.
3- This will open the code behind project for this form template, Add the following variables to the FormState dictionary




private string RootFolder
{
get { return FormState["RootFolder"].ToString(); }
set { FormState["RootFolder"] = value; }
}
private Guid SiteID
{
get{return (Guid)FormState["SiteID"];}
set{FormState["SiteID"] = value;}
}
private Guid WebID
{
get{return (Guid)FormState["WebID"];}
set{FormState["WebID"] = value;}
}

private Boolean ProjectExist
{
get{return (Boolean)FormState["ProjectExist"];}
set{FormState["ProjectExist"] = value;}
}


4- You need to handle the load event to read the current folder.
Note that you should handle the two cases if the form is opend in the browser or usnig the infopath client




void FormEvents_Loading(object sender, LoadingEventArgs e)
{
XPathNavigator xnDoc = this.MainDataSource.CreateNavigator();
if (this.New) // New Request
{
char[] splitter = new char[] { '/' };
// Read The Root folder from the url if form shown in browser
if (Application.Environment.IsBrowser)
{
string[] all = e.InputParameters["SaveLocation"].Trim(splitter).Split(splitter);
RootFolder = all[all.Length - 1];
}
else // if the form shown in the infopath read the folder from the uri
{
string strUri = this.Template.Uri.ToString();
string strPath = strUri.Substring(0, strUri.IndexOf("Forms") - 1);
RootFolder = strPath.Substring(strPath.LastIndexOf("/") + 1);
}
XPathNavigator isNew =
xnDoc.SelectSingleNode("/my:myFields/my:New", this.NamespaceManager);
isNew.SetValue("1");
XPathNavigator root = xnDoc.SelectSingleNode("/my:myFields/my:root", this.NamespaceManager);
root.SetValue(RootFolder);
}
else // Modification To Existing Item
{
XPathNavigator isNew =
xnDoc.SelectSingleNode("/my:myFields/my:New", this.NamespaceManager);
isNew.SetValue("0");
}
}


5- Before sumbitting the form you will need the following:


  • Get the current folder.

  • Loop inside all the fodler in our form library to search for the choosen field to be unique if it is existing before.
    Note that you should run the search method with elavated privilages to get the results regardless of the current logged user permissions.

  • Concatenate the current folder to the Main Submit connention folder.

  • Then Submit your form.




public void FormEvents_Submit(object sender, SubmitEventArgs e)
{
SPWeb contextWeb = SPContext.Current.Web;
SiteID = contextWeb.Site.ID;
WebID = contextWeb.ID;
// Invoke the CheckAvailablity method with elavated privilage to
// get the search results regardless the privilages of the logged user
// becuse we search subfolders that may include special permissions
SPSecurity.CodeToRunElevated codeToRunElevated = new SPSecurity.CodeToRunElevated(CheckAvailablity);
SPSecurity.RunWithElevatedPrivileges(codeToRunElevated);
try
{
FileSubmitConnection dc =
(FileSubmitConnection)this.DataConnections["SharePoint Library Submit"];
if (ProjectExist)
{
throw new Exception("The Project Name Exists before, It must be unique.");
}
if (dc != null)
{
string listName = "listname";
if (RootFolder != listName)
{
dc.FolderUrl = dc.FolderUrl + "/" + RootFolder;
}
else
{
dc.FolderUrl = dc.FolderUrl;
}
dc.Execute();
e.CancelableArgs.Cancel = false;
}
}
catch (Exception ex)
{
e.CancelableArgs.Message = @"There was a problem submitting the
form: " + ex.Message;
e.CancelableArgs.Cancel = true;
}
}




///


/// This Method Used to search for the filed that should be unique inside all the folders
/// for the form library because of the limitation for the (built in overwrite check)
/// that can gurantee uniquiness only in the current folder
///

void CheckAvailablity()
{
// Read The Current List by opening the web explicitly
// to get rid of "Operation is not valid due to the current state of the object"
// if we used SPContext.Current.Web directly
SPSite site = new SPSite(SiteID);
SPWeb web = site.OpenWeb(WebID);
SPList list = web.Lists["listname"];
XPathNavigator xnDoc = this.MainDataSource.CreateNavigator();
XPathNavigator pName =
xnDoc.SelectSingleNode("/my:myFields/my:project_name", this.NamespaceManager);
string projectName = pName.Value;
SPQuery q = new SPQuery();
q.Query = @"" + projectName + "";
// Search in the root folder first
bool found = false;
SPListItemCollection outerColl = list.GetItems(q);
if (outerColl.Count > 0)
{
found = true;
}
else
{
// then search inside subfolders
foreach (SPListItem flder in list.Folders)
{
q.Folder = flder.Folder;
SPListItemCollection coll = list.GetItems(q);
if (coll.Count > 0)
{
found = true;
break;
}
}
}
ProjectExist = found;
}



I hope this helps, and Appreciate any comments

Monday, July 20, 2009

Pre-build / Post-build Events

In many cases your solution contains many projects that its output in the form of dll, after building your solution you may do some routine work by copying your dlls into a separate fodler without the need to change the defult bin\debug folder.

The Solution is to use Post-build events to copy your output dll into your seprate folder.

Steps:

  1. Open your project properties page.
  2. Select Build Events tab.
  3. Write yuor command in the Post-build Events dialouge.
  4. Click Edit-Post build to use Macros.
  5. Use the sample command copy "$(TargetPath)" "$(SolutionDir)\Dlls\$(TargetFileName)"





Visual Studio 2008 macros are essentially environment variables contained within parentheses, preceded by the $ symbol—much like Perl.


The Following is a table of all available macros:





I hope this hepls
Thanks