Copy folders when copying list items from source to destination - sharepoint

This is my code to copy files in a list from source to destination. Using the code below I am only able to copy files but not folders. Any ideas on how can I copy the folders and the files within those folders?
using (SPSite objSite = new SPSite(URL))
{
using (SPWeb objWeb = objSite.OpenWeb())
{
SPList objSourceList = null;
SPList objDestinationList = null;
try
{
objSourceList = objWeb.Lists["Source"];
}
catch(Exception ex)
{
Console.WriteLine("Error opening source list");
Console.WriteLine(ex.Message);
}
try
{
objDestinationList = objWeb.Lists["Destination"];
}
catch (Exception ex)
{
Console.WriteLine("Error opening destination list");
Console.WriteLine(ex.Message);
}
string ItemURL = string.Empty;
if (objSourceList != null && objDestinationList != null)
{
foreach (SPListItem objSourceItem in objSourceList.Items)
{
ItemURL = string.Format(#"{0}/Destination/{1}", objDestinationList.ParentWeb.Url, objSourceItem.Name);
objSourceItem.CopyTo(ItemURL);
objSourceItem.UnlinkFromCopySource();
}
}
}
}
Thanks

This is what worked for me. I had to move folders from spweb to another.
private static void RecursiveCopy(SPList objSourceList, SPFolder objSourceFolder, SPFolder objDestinationFolder)
{
SPListItemCollection objItems = ((SPDocumentLibrary)objSourceList).GetItemsInFolder(objSourceList.DefaultView, objSourceFolder);
foreach (SPListItem objItem in objItems)
{
//If it's a file copy it.
if (objItem.FileSystemObjectType == SPFileSystemObjectType.File)
{
byte[] fileBytes = objItem.File.OpenBinary();
string DestinationURL = string.Format(#"{0}/{1}", objDestinationFolder.Url, objItem.File.Name);
//Copy the file.
SPFile objDestinationFile = objDestinationFolder.Files.Add(DestinationURL, fileBytes, true);
objDestinationFile.Update();
}
else
{
string dirURL = string.Format(#"{0}/{1}", objDestinationFolder.Url, objItem.Folder.Name);
SPFolder objNewFolder = objDestinationFolder.SubFolders.Add(dirURL);
objNewFolder.Update();
//Copy all the files in the sub folder
RecursiveCopy(objSourceList, objItem.Folder, objNewFolder);
}
}
}
public static void CopyListItems(string SourceSiteURL, string DestinationSiteURL, string ListName)
{
string DestinationURL = string.Empty;
using (SPSite SourceSite = new SPSite(SourceSiteURL))
{
using (SPWeb SourceWeb = SourceSite.OpenWeb())
{
using (SPSite DestinationSite = new SPSite(DestinationSiteURL))
{
using (SPWeb DestinationWeb = DestinationSite.OpenWeb())
{
DestinationWeb.AllowUnsafeUpdates = true;
//Get the QA Forms Document libarary from the source web
SPList objSourceList = SourceWeb.Lists[ListName];
SPList objDestinationList = null;
try
{
objDestinationList = DestinationWeb.Lists[ListName];
}
catch
{
//Create a list in the destination web
DestinationWeb.Lists.Add(ListName, string.Empty, SPListTemplateType.DocumentLibrary);
}
objDestinationList = DestinationWeb.Lists[ListName];
//Recursively copy all the files and folders
RecursiveCopy(objSourceList, objSourceList.RootFolder, objDestinationList.RootFolder);
DestinationWeb.Update();
DestinationWeb.AllowUnsafeUpdates = false;
}
}
}
}
}
this copies all the files and folders recursively.
Hope it helps someone.

If you are copying to a destination that is located within the same SPWeb, you can try the following.
using (SPSite site = new SPSite("http://urltosite"))
{
using (SPWeb web = site.OpenWeb())
{
//get the folder from the source library
SPFolder sourceFolder = web.GetFolder("Documents/Folder 1");
//get the folder to the destination
SPFolder destinationFolder = web.GetFolder("New Library");
sourceFolder.CopyTo(destinationFolder.ServerRelativeUrl + "/" + sourceFolder.Name);
}
}
Sadly I don't think this works when copying a folder to a different SPWeb or SPSite.

SPList.Items only returns non-folder items. You can use SPList.Folders to iterate all of the folders in a list. So if you did the same foreach loop, only using:
foreach (SPListItem objSourceFolderItem in objSourceList.Folders)
You would then get all of the folders. To properly move the folder and all of its contents, you would use objSourceFolderItem.Folder.CopyTo(ItemUrl).
I've tried this using a list with only one level of folders (pair it with a foreach loop to get all of the items in the root folder), and it worked for me in SP2007. I believe SPList.Folders gets all of the folders in the entire list, not just the ones in the root folder, so if you end up breaking the list with a multi-level folder system, then an alternative to try might be:
foreach (SPFolder objSourceFolderItem in objSourceList.RootFolder.SubFolders)
Since those are already SPFolder objects, you can just use objSourceFolderItem.CopyTo(ItemUrl).

Related

Copying existing files into a server SharePoint

I'm facing of difficulties to change a files into CSV and save it into local environment. How can I achieve this? Try to look around but seem like not what I'm looking for.
I'm running on SharePoint 2010. Before this, this code only grab data from SharePoint and turn it into xlsx and update it into our web.
private static void GenerateSPGroupUsersReport() //
{
Log("Generate Sharepoint Group Users Report");
DataSet dsSecurityReport = new DataSet();
string ConnectedWebURL = ConfigurationManager.AppSettings["SPGroupUsersWebURL"];
//string[] strURL = ConnectedWebURL.Split(';');
DataTable dTblSPGroupUser = new DataTable();
dTblSPGroupUser.Columns.Add("SiteURL", typeof(string));
dTblSPGroupUser.Columns.Add("SharepointGroup", typeof(string));
dTblSPGroupUser.Columns.Add("User", typeof(string));
// Hafees add 10/22/2019
dTblSPGroupUser.Columns.Add("UserLanID", typeof(string));
dTblSPGroupUser.Columns.Add("Email", typeof(string));
SPSite site = new SPSite(ConnectedWebURL);
SPWebApplication webApp = site.WebApplication;
foreach (SPSite s in webApp.Sites)
{
SPGroupCollection groupCol = s.RootWeb.SiteGroups;
foreach (SPGroup group in groupCol)
{
// Hafees include group.Users, user.Email
foreach (SPUser user in group.Users)
{
dTblSPGroupUser.Rows.Add(s.Url, group.Name, user.Name, user.LoginName, user.Email);
}
//bool contains = dTblSPGroupUser.AsEnumerable().Any(rowC => group.Name == rowC.Field<string>("SharepointGroup"));
//if (!contains)
//{
// foreach (SPUser user in group.Users)
// {
// dTblSPGroupUser.Rows.Add(s.Url, group.Name, user.Name);
// }
//}
}
}
DataSet dsSPGroup = new DataSet();
dsSPGroup.Tables.Add(dTblSPGroupUser);
SaveIntoSPLibrary(site, dsSPGroup, "GroupUsers_" + ConnectedWebURL.Replace("http://", "").Replace("https://", "").Replace(":", "-").Trim());
Log("Generate Sharepoint Group Users Report Complete");
}
// This is where I generate the group of user report.
private static void SaveIntoSPLibrary(SPSite site, DataSet ds, string fileName)
{
string UIResourceServerRelativeWebURL = ConfigurationManager.AppSettings["UIResourceServerRelativeWebURL"];
using (SPWeb web = site.OpenWeb(UIResourceServerRelativeWebURL))
{
byte[] byteArray = GenerateExcelFile(ds);
string CustomReportLibrary = ConfigurationManager.AppSettings["CustomReportLibrary"];
string strFileName = String.Format(fileName + ".{0}.xlsx", DateTime.Today.ToString("yyyyMMdd"));
Log("Saving into SP Library. " + CustomReportLibrary + strFileName);
web.AllowUnsafeUpdates = true;
SPFile file = web.Files.Add(CustomReportLibrary + strFileName, byteArray, true);
file.Item["Year"] = DateTime.Now.ToString("yyyy");
file.Item["Month"] = string.Format("{0}. {1}", DateTime.Now.Month, DateTime.Now.ToString("MMMM"));
file.Item.Update();
file.Update();
web.AllowUnsafeUpdates = false;
}
}
// This is where the files save into xlsx and update it into SharePoint Library.
I try to do a copy of SaveIntoLibrary with abit of modification, I change to CSV files and create a new configurationManager which it will point into my local directory. But seem I'm wrong at somewhere. The files still didn't get into my local directory. Please advice.
You should export the DataTable report data to local CSV,
Check the code in this thread, this will output the csv file so you could save to your local.
var dataTable = GetData();
StringBuilder builder = new StringBuilder();
List<string> columnNames = new List<string>();
List<string> rows = new List<string>();
foreach (DataColumn column in dataTable.Columns)
{
columnNames.Add(column.ColumnName);
}
builder.Append(string.Join(",", columnNames.ToArray())).Append("\n");
foreach (DataRow row in dataTable.Rows)
{
List<string> currentRow = new List<string>();
foreach (DataColumn column in dataTable.Columns)
{
object item = row[column];
currentRow.Add(item.ToString());
}
rows.Add(string.Join(",", currentRow.ToArray()));
}
builder.Append(string.Join("\n", rows.ToArray()));
Response.Clear();
Response.ContentType = "text/csv";
Response.AddHeader("Content-Disposition", "attachment;filename=myfilename.csv");
Response.Write(builder.ToString());
Response.End();

Processing Multiple sub-directories and all files in each directory

Hoping someone can help me here, I'm not very familiar with working with directories. My application compresses files and stores them in a media directory as well as stores them in the database, This works well if I create the directory and actually call each file separately.
But I would like to make it dynamic, and process all folders under the install folder, For every directory under this directory I would like to process each directory and all the files within that directory.
What I have tried:
public class SetupFiles : ISetupFiles
{
private readonly ISession _session;
private readonly IFileService _fileService;
private readonly IFileProvider _fileProvider;
public SetupFiles(ISession session, IFileService fileService, IFileProvider fileProvider)
{
_session = session;
_fileService = fileService;
_fileProvider = fileProvider;
}
public void Setup()
{
string installPath = ("install/images/");
_session.Transact(session =>
{
DirectoryInfo dir = new DirectoryInfo(installPath);
DirectoryInfo[] subdirectories = dir.GetDirectories();
foreach (var subdirectory in subdirectories)
{
string currentDirName = Directory.GetCurrentDirectory();
var directory = new MediaCategory
{
Name = subdirectory.Name.ToString().ToUpper(),
UrlSegment = subdirectory.Name.Trim().ToLower(),
};
session.Save(directory);
string[] pngFiles = Directory.GetFiles(currentDirName, "*.png", SearchOption.AllDirectories);
string[] jpgFiles = Directory.GetFiles(currentDirName, "*.jpg", SearchOption.AllDirectories);
string[] gifFiles = Directory.GetFiles(currentDirName, "*.gif", SearchOption.AllDirectories);
string[] pdfFiles = Directory.GetFiles(currentDirName, "*.pdf", SearchOption.AllDirectories);
foreach (var currentPngFile in pngFiles)
{
var fileStream = _fileProvider.GetFileInfo(currentPngFile).CreateReadStream();
MediaFile dbpngFile = _fileService.AddFile(fileStream, Path.GetFileName(currentPngFile), "image/png", fileStream.Length, directory);
}
foreach (var currentJpgFile in jpgFiles)
{
var fileStream = _fileProvider.GetFileInfo(currentJpgFile).CreateReadStream();
MediaFile dbjpgFile = _fileService.AddFile(fileStream, Path.GetFileName(currentJpgFile), "image/jpg", fileStream.Length, directory);
}
foreach (var currentGifFile in gifFiles)
{
var fileStream = _fileProvider.GetFileInfo(currentGifFile).CreateReadStream();
MediaFile dbgifFile = _fileService.AddFile(fileStream, Path.GetFileName(currentGifFile), "image/gif", fileStream.Length, directory);
}
foreach (var currentPdfFile in pdfFiles)
{
var fileStream = _fileProvider.GetFileInfo(currentPdfFile).CreateReadStream();
MediaFile dbgifFile = _fileService.AddFile(fileStream, Path.GetFileName(currentPdfFile), "file/pdf", fileStream.Length, directory);
}
}
});
}
But for some reason, I get an error that it can not find the directory.
Any help would be greatly appreciated.
int the Line DirectoryInfo[] subdirectories = dir.GetDirectories(); dir shows the directory but GetDirectories() returns NULL.
I must have had a Brain Fart. lol With help from #ciubotariu-florin I was able to get past this issue.
For anyone else with this issue, wwwroot is an environment folder and is part of web root from IIS config. So to work with Directory() and or DirectoryInfo() you must use IHostingEnvironment this allows you to use IHostingEnvironment.WebRootPath so changing my path from
string installPath = ("install/images/");
to
string installPath = Path.Combine(_env.WebRootPath, "install/images/").ToLower();
solved my issues.

Safely return all lists in site collection that match criteria

I'm using the following code to get all "Announcement" lists in a Web Applications site collection.
Unfortunately, sometimes the current user does not have permission to that site and the page fails with an exception, even inside the try block.
What would be the right way to do the following safely for all users, where even an anonymous user would just get no results?
static public List<SPListMeta> AllSiteAnnouncementsLists()
{
var returnList = new List<SPListMeta>();
foreach (SPSite oSiteCollection in SPContext.Current.Web.Site.WebApplication.Sites)
{
var collWebs = oSiteCollection.AllWebs;
try
{
foreach (SPWeb oWebsite in collWebs)
{
using (oWebsite)
{
var collSiteLists = oWebsite.GetListsOfType(SPBaseType.GenericList);
returnList.AddRange(from SPList oList in collSiteLists where oList.Title == "Announcements" select new SPListMeta(oList));
}
}
}
catch
{
}
}
return returnList;
}
Try give your code the right permission to execute.
using Microsoft.Sharepoint.Administrator;
SPSecurity.RunWithElevatedPrivileges(delegate(){
// Your source code goes here
});
To get all items of the specific list type from the site collection you have to use SPSiteDataQuery. Each user will get only those items they have permissions.
SPWeb web = SPContext.Current.Web;
SPSiteDataQuery query = new SPSiteDataQuery();
//Ask for all lists created from the announcement template.
query.Lists = "<Lists ServerTemplate=\"104\" />";
// Get the Title field. Define here all you need.
query.ViewFields = "<FieldRef Name=\"Title\" />";
// Set the sort order.
query.Query = "<OrderBy>" +
"<FieldRef Name=\"Title\" />" +
"</OrderBy>";
// Query all Web sites in this site collection.
query.Webs = "<Webs Scope=\"SiteCollection\" />";
DataTable dt = web.GetSiteData(query);
DataView dv = new DataView(dt);
This is what ended up working for me, though I do not know if it is the best way to do this.
static public List<SPListMeta> AllSiteAnnouncementsLists()
{
var returnList = new List<SPListMeta>();
var collWebs = SPContext.Current.Web.Site.WebApplication.Sites[0].OpenWeb().GetSubwebsForCurrentUser();
if(SPContext.Current.Site.RootWeb.DoesUserHavePermissions(SPBasePermissions.Open))
{
var collSiteLists = SPContext.Current.Site.RootWeb.GetListsOfType(SPBaseType.GenericList);
returnList.AddRange(from SPList oList in collSiteLists
where oList.DoesUserHavePermissions(SPBasePermissions.ViewListItems)
&& oList.BaseTemplate == SPListTemplateType.Announcements
select new SPListMeta(oList));
}
foreach (SPWeb oWebsite in collWebs)
{
returnList.AddRange(WebRecursion.GetListsForCurrentWeb(oWebsite, SPListTemplateType.Announcements));
foreach (SPWeb oSubSite in oWebsite.Webs)
{
returnList.AddRange(WebRecursion.GetListsForCurrentWeb(oSubSite, SPListTemplateType.Announcements));
}
}
return returnList;
}
public static List<SPListMeta> GetListsForCurrentWeb(SPWeb oWebsite, SPListTemplateType type)
{
var returnList = new List<SPListMeta>();
if (oWebsite.DoesUserHavePermissions(SPBasePermissions.Open))
{
using (oWebsite)
{
var collSiteLists = oWebsite.Lists;
returnList.AddRange(from SPList oList in collSiteLists
where oList.DoesUserHavePermissions(SPBasePermissions.ViewListItems)
&& oList.BaseTemplate == type
select new SPListMeta(oList));
}
}
return returnList;
}

ListViewWebPart

I'm using listviewwebpart to display contents of SPFolder (subfolder inside a list) to display its contents.
Beolw is the code to implement the same :
protected override void CreateChildControls()
{
try
{
base.CreateChildControls();
webPart = new ListViewWebPart();
using (var site = new SPSite(SPContext.Current.Web.Url))
using (var web = site.OpenWeb())
{
clientName = DataLogic.Client.GetClientName(Constants.Session.Client_ClientID);
var library = web.Lists["Account"];
webPart.ListName = library.ID.ToString("B").ToUpper();
webPart.ListId = library.ID;
SPFolder folder = web.GetFolder("/Account/" + clientName);
if (folder.Item != null)
{
SPContentTypeId folderctid = folder.Item.ContentType.Id;
//set the folder url
SetPrivateFieldValue(webPart, "rootFolder", folder.Url);
SetPrivateFieldValue(webPart, "folderCtId", folderctid.ToString());
webPart.ListViewXml = library.DefaultView.GetViewXml();
webPart.ChromeType = PartChromeType.None;
this.mainSec.Controls.Add(webPart);
}
else
{
lblWarning.Text = "There is no document library associated with client " + clientName;
}
}
}
catch (Exception ex)
{
}
}
private static void SetPrivateFieldValue(object obj, string fieldName, string val)
{
FieldInfo fi = obj.GetType().GetField(fieldName, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
fi.SetValue(obj, val);
}
The contents display correctly but the toolbar is the parent list's toolbar and not the folder's toolbar.
How can i modify the toolbar context to load the context of the spfolder?

Adding description to WebPartPage when creating the page

I am following this (http://msdn.microsoft.com/en-us/library/ms450826.aspx) method to add a webpartpage (samplewpp.aspx) and it works. However, I need to add one line description as well. How?
You need to add a Content Editor Web Part (CEWP) to the page and then add your description to this. The CEWP allows you to put text/html onto a page.
To do this programatically then follow something like this code by Razi bin Rais :-
AddAndFillCEWP("http://server","/" ,"/Pages/blank.aspx","this text is adding via code","Header","CEWP WebPart");
private void AddAndFillCEWP(string siteUrl, string webName, string pageUrl, string textCEWP, string zoneId, string title)
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite spSiteTest = new SPSite(siteUrl))
{
using (SPWeb web = spSiteTest.OpenWeb(webName))
{
try
{
web.AllowUnsafeUpdates = true;
SPFile file = web.GetFile(pageUrl);
if (null != file)
{
using (SPLimitedWebPartManager mgr = file.GetLimitedWebPartManager(PersonalizationScope.Shared))
{
if (null != mgr)
{
//create new webpart object
ContentEditorWebPart contentEditor = new ContentEditorWebPart();
//set properties of new webpart object
contentEditor.ZoneID = zoneId;
contentEditor.Title = title;
contentEditor.ChromeState = System.Web.UI.WebControls.WebParts.PartChromeState.Normal;
contentEditor.ChromeType = System.Web.UI.WebControls.WebParts.PartChromeType.TitleAndBorder;
//Add content to CEWP
XmlDocument xmlDoc = new XmlDocument();
XmlElement xmlElement = xmlDoc.CreateElement("Root");
xmlElement.InnerText = textCEWP;
contentEditor.Content = xmlElement;
contentEditor.Content.InnerText = xmlElement.InnerText;
//Add it to the zone
mgr.AddWebPart(contentEditor, contentEditor.ZoneID, 0);
web.Update();
}
}
}
}
finally
{
web.AllowUnsafeUpdates = false;
}
}
}
});
}

Resources