Requirement: Adding Parent folders, Child folders and Their files to Document and Library from Particular location.
Case-1: If Folder is already exists then get that id and add file
( Here I am using
addFileEntry(repositoryId, folderId,sourceFileName, mimeType, title, description, changeLog, is, size, serviceContext) of DLAppServiceUtil class ).
Case-2: If Folder is not exits add folder then add file
(Here I am using for adding folder
addFolder() method of DLAppServiceUtil class)
My case its gives slow performance. That is the problem.
Which version of Liferay are you using?
The current trend is the following in 6.1+ (well, when it is correctly implemented, but you can build more or less on this with the new DLApp implementation):
Locate the parent folder id. Use the default from the DLFolderConstancts if you don't have any.
Assume the folder exists and try to get it.
It will throw you a NoSuch***Exception if not found. If this is the case, create the folder by hand
You could do something like this:
private Folder getOrCreateFolder(final ServiceContext serviceContext,
final long userId, final Group group, String folderName)
throws PortalException, SystemException {
final long parentFolderId = DLFolderConstants.DEFAULT_PARENT_FOLDER_ID;
final long repositoryId = group.getGroupId();
try {
final Folder prev = DLAppLocalServiceUtil.getFolder(
repositoryId, parentFolderId, folderName);
return prev;
} catch (final NoSuchFolderException e) {
final Folder newFolder = DLAppLocalServiceUtil.addFolder(userId,
repositoryId, parentFolderId, folderName,
"My cool new folder", serviceContext);
return newFolder;
}
}
The docs and stuff are absolutely leaky about why you call the addFolder() that way, take a look on the portal source. It's not that trivial but isn't that hard to get used to either.
Related
I'm currently facing to an issue using the Elevated Mode used in a Feature.
I have created a custome SharePoint security role (contribute role without the Delete right).
The goal of my SharePoint feature is the following:
When uploading a file to a SP Site, the name of the file needs to be renamed using the meta-data's selected. When uploading a file, a second form is asking the user to defined 3 or 4 meta-data's.
To rename the file, i have developed the following code:
Public override void ItemAdded(SPItemEventProperties properties)
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
CallFunctionToUpdate();
});
}
Public override void ItemUpdated(SPItemEventProperties properties)
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
CallFunctionToUpdate();
});
}
Public void CallFunctionToUpdate()
{
try
{
this.EventFiringEnabled = false;
using (SPWeb newWeb = newSite.OpenWeb(_properties.RelativeWebUrl))
{
SPListItem item = newWeb.Lists[_properties.ListId].GetItemById(_properties.ListItem.ID);
newFileName = FilenameManagementHelper.GenerateFilename(properties.ListItem);
currentName = properties.ListItem["Name"].ToString();
var extension = Path.GetExtension(currentName);
if (item["Title"] == null || item["Title"].ToString() != newFileName)
{
item["Title"] = newFileName;
item["Editor"] = new SPFieldUserValue(properties.OpenWeb(), properties.OpenWeb().CurrentUser.ID, properties.OpenWeb().CurrentUser.LoginName);
item.SystemUpdate();
}
if (currentName.Substring(0, currentName.Length - extension.Length) != newFileName)
{
SPList list = newWeb.Lists[_properties.List.Title];
string destUrl = list.RootFolder.Url + "/" + newFileName + extension;
SPFile fileToMove = list.Items[_properties.ListItemUniqueId].File;
SPFolder folder = newWeb.GetFolder(list.RootFolder.Url);
byte[] bin = fileToMove.OpenBinary();
folder.Files.Add(destUrl, bin, fileToMove.Properties, true);
fileToMove.Delete(); newWeb.Lists[list.RootFolder.Url].Update();
}
}
}
catch (Exception ex)
{
DocumentDiagnosticService.LogError(CategoryID.Error, string.Format("Error {0} for the file name - {1}", ex.Message, currentName));
}
finally
{
this.EventFiringEnabled = true;
}
}
Before renaming the file name, I'm updating the field (meta-data's) title and Editor. The second step will move the file (with the meta-data's and the history associated to the uploaded file)
I'm using the Elevated Mode because the user with a restricted Security role cannot delete. In the code developed I'm moving the file renamed and deleting the old file uploaded.
I found that approach because I need to keep the versioning. Updating directly the name of the file (like for the title) is not allowed and that's losing the history. Ex: A file will be uploaded, the name of the file will be updated using the Meta-data's. For the first version, there is no issue. Uploading a second file with the same meta-data's as there is already an existing file with the same name, that will generate an error. Using the Files.Add, that will oerride the current file and will keep the history.
My issue in this case: When the user is uploading the file, the fields Title and Editor are correctly replaced. Than is moving the file, renaming the field Name and deleting the old version. At this moment, the Modify by field is coming the SharePoint Sys Admin all the time.
How can i keep the Modifiy by with the name of the person who is uploading the file ?
EDIT:
Using the following code:
SPList list = newWeb.Lists[_properties.List.Title];
string destUrl = list.RootFolder.Url + "/" + newFileName + extension;
SPFile fileToMove = list.Items[_properties.ListItemUniqueId].File;
SPFolder folder = newWeb.GetFolder(list.RootFolder.Url);
byte[] bin = fileToMove.OpenBinary();
folder.Files.Add(destUrl, bin, fileToMove.Properties, true);
fileToMove.Delete();
Allow me to move the file with the meta-data's selected during the upload. I still have the versioning if a current version is already uploaded BUT the Modified By is SysAdmin.
Using the following code:
SPList list = newWeb.Lists[_properties.List.Title];
string destUrl = list.RootFolder.Url + "/" + newFileName + extension;
SPFile fileToMove = list.Items[_properties.ListItemUniqueId].File;
SPFolder folder = newWeb.GetFolder(list.RootFolder.Url);
byte[] bin = fileToMove.OpenBinary();
SPUser author = fileToMove.Author;
folder.Files.Add(destUrl, bin, author, author, DateTime.Now, DateTime.Now);
fileToMove.Delete();
Allow me to move the file and keep the history if i already have a version. I can now get the Modified By field filled by the real user who is uploading and not the SysAdmin BUT I'm losing the meta-data's selected during the upload.
Thank you for your support,
Fix.
Use item.Update() instead of SystemUpdate(). It should retain the identity of logged in user.
Thank you for your support.
I have solved my issue by using the following code:
folder.Files.Add(destUrl, bin, fileToMove.Properties, author, author, DateTime.Now, DateTime.Now, true);
Now, I have the Modified By value filled with the user who is uploading, the meta-data's are still there and the versioning too.
I am attempting to create a set of folders that comes in from a flat file in the manner of.
X/Y/Z
and I would like to create a directory for each of these but my memory of recursion has got me in knotts.
here is my code can someone advise.
public void CreateDirectory(SPFolderCollection oWeb, string folder)
{
SPFolder theFolder = oWeb.Add(folder);
theFolder.Update();
}
public void FolderCreator(SPWeb oWeb)
{
StreamReader reader = new StreamReader(this.txtFolders.Text);
while (reader.Peek() != -1)
{
string folderLine = reader.ReadLine();
if (folderLine.Contains("/"))
{
SPFolderCollection collection = oWeb.Folders["Documents"].SubFolders[folderLine.Split('/')[0]].SubFolders;
CreateDirectory(collection, folderLine);
}
SPFolderCollection newCollection = oWeb.Folders["Documents"].SubFolders;
CreateDirectory(newCollection, folderLine);
}
}
This does not work I am looking for it to do recrusion so if I pass
ABC/DEF/GHI
and
ABC/DEF
it will go and create the folders appropriately.
But I am stuck as how to do that.
The SPFileCollection.Add() methods allow you to pass in the full relative path of a file. So this may be an option assuming you aren't just generating a folder structure, which you may be doing, in which case this won't really work unless you create a temporary file and then delete it to keep the folder path.
web.Files.Add("/sites/somesite/shared documents/foldera/folderb/folderc/somefile.txt", stream);
Here i know the source folder path.But i want to search a particular folder like "MANAGERS" in the list of directories for files.Could we do this type of operation in C# Windows Application?Please help me regarding this.
You can use the DirectoryInfo class.
DirectoryInfo di = new DirectoryInfo(mySourceFolder);
DirectoryInfo[] diArr = di.GetDirectories();
foreach (DirectoryInfo dri in diArr)
{
if(dri.Name.ToUpperInvariant() == "MANAGERS")
{
FileInfo[] fiArr = di.GetFiles(); // get a list of files in directory
}
}
I have created a web part which renders a button, on click of this button I want to access the directory of the other machine in LAN. Once I get the access to this Directory I will create a nested directories inside it with different extensions of files, but the problem is when I tries to access this folder by UNC Path it is giving me error like "Could not find a part of the path '\comp01\ibc'". Here comp01 is the computer name which is situated in LAN and ibc is a shared folder on that machine.
Following is the code for button click,
void _btnBackup_Click(object sender, EventArgs e)
{
try
{
//UNC Path --> \\In-Wai-Svr2\IBC
if (!string.IsNullOrEmpty(UncPath))
{
SPSite currentSite = SPControl.GetContextSite(this.Context);
SPWeb parentWeb = currentSite.OpenWeb();
string dir = Path.GetDirectoryName(UncPath);
//If IBC folder does not exist then create it.
if(!Directory.Exists(dir))
Directory.CreateDirectory(dir);
IterateThroughChildren(parentWeb, UncPath);
}
else
{
_lblMessage.Text = "UNC Path should not be empty";
}
}
catch(Exception ex)
{
_lblMessage.Text = ex.Message;
}
}
For UNC paths you need to specify it like this:
either use a C# string literal
String path = #"\\comp01\ibc";
or escape the string like
String path = "\\\\comp01\\ibc"
Try that.
basic overview...
i have a site setup in iis...
- "mysite" (wwwroot\mysite) under that there are 2 virtual directory applications
- "uploads" (\uploadfiles)
- "app" (wwwroot\myapp)
I also have a subdomain that is set up as a different site in iis...
- "beta.mysite" (wwwroot\mysitebeta) under that there are 2 virtual directory
- "uploads" (\uploadfiles)
- "app" (wwwroot\myappbeta)
the sub domain is working fine.... i can type in https://beta.mysite.com/app ... and it brings up the beta site log in perfectly fine.... the problem is, when i click on any of the buttons that create a post back... it reverts to https://www.mysite.com/app...
all of the links display the correct relative path to their files.... and if i type in https://beta.mysite.com/app/dir/page.aspx... it will actually go to that page on the beta site, all the links are going to the right spots... its just the postbacks that are killing me...
Have you tried setting a different application pool for these two websites? Looks like it's trying to be "smart" and concludes that the two virtual directories are actually the same website.
If all else fails, you could rewrite the postback URL in the FORM-tag that ASP.NET generates manually. Using an App_Browsers file and a ControlAdapter are probably the cleanest way of doing that.
I have an example of such a ControlAdapter implementation, though it is intended to work with URL rewriting to prevent reverting to the actual behind-the-scenes URL on postback. However, I think it would work for your problem out-of-the-box
public class FormRewriterControlAdapter : System.Web.UI.Adapters.ControlAdapter
{
protected override void Render(HtmlTextWriter writer)
{
base.Render(new RewriteFormHtmlTextWriter(writer));
}
}
public class RewriteFormHtmlTextWriter : HtmlTextWriter
{
private const string contextItemKey = "FormActionWritten";
public RewriteFormHtmlTextWriter(HtmlTextWriter writer) : base(writer)
{
InnerWriter = writer.InnerWriter;
}
public RewriteFormHtmlTextWriter(System.IO.TextWriter writer) : base(writer)
{
base.InnerWriter = writer;
}
public override void WriteAttribute(string name, string value, bool fEncode)
{
// If the attribute we are writing is the "action" attribute, and we are not on a sub-control,
// then replace the value to write with the raw URL of the request - which ensures that we'll
// preserve the PathInfo value on postback scenarios
if (name == "action" && !HttpContext.Current.Items.Contains(contextItemKey))
{
// Use the Request.RawUrl property to retrieve the un-rewritten URL
value = HttpContext.Current.Request.RawUrl;
HttpContext.Current.Items[contextItemKey] = true;
}
base.WriteAttribute(name, value, fEncode);
}
}
Form.browser file:
<browsers>
<browser refID="Default">
<controlAdapters>
<adapter controlType="System.Web.UI.HtmlControls.HtmlForm" adapterType="FormRewriterControlAdapter" />
</controlAdapters>
</browser>
</browsers>