How to create a folder using alfresco-api - alfresco

I want to create a folder using ALFRESCO API, so I used this function:
public Folder createFolder(String parentFolderId, String folderName) {
Session cmisSession = getCmisSession();
Folder rootFolder = (Folder) cmisSession.getObject(parentFolderId);
Folder subFolder = null;
try {
// Making an assumption here that you probably wouldn't normally do
subFolder = (Folder) cmisSession.getObjectByPath(rootFolder.getPath() + "/" + folderName);
System.out.println("Folder already existed!");
} catch (CmisObjectNotFoundException onfe) {
Map<String, Object> props = new HashMap<String, Object>();
props.put("cmis:objectTypeId", "cmis:folder");
props.put("cmis:name", folderName);
subFolder = rootFolder.createFolder(props);
String subFolderId = subFolder.getId();
System.out.println("Created new folder: " + subFolderId);
}
return subFolder;
}
this folder was created in documentLibrary.
I do not know how to create another folder inside this new folder.
PS: this function is the one that is defined in alfresco-api-examples

The function you reference is an example helper function that will return a CMIS Folder object given the parent folder ID and folder name. If the folder does not exist, it will create a new folder and return that.
For example, if you have a folder structure like documentLibrary/folder1 and you call createFolder(documentLibraryId, "folder1") you will get a CMIS Folder object back that represents the "folder 1" folder.
If you were to call createFolder(documentLibraryId, "folder2") the folder would not be found, a new folder named "folder2" would be created, and the code would return a CMIS Folder object that represents the new "folder 2" folder.
Now that you have a CMIS Folder object, you can invoke its methods. If you want to create a new folder you can either call createFolder again, but this time pass in the new Folder's ID, like this:
Folder subFolder = createFolder(folder.id, "subfolder");
or you can use the CMIS Folder object's createFolder method, but you'll have to pass in a properties object, like this
Map<String, Object> properties = new HashMap<String, Object>();
properties.put(PropertyIds.NAME, "subfolder");
properties.put(PropertyIds.OBJECT_TYPE_ID, "cmis:folder");
Folder subFolder = folder.createFolder(properties);
For more OpenCMIS code examples, see https://chemistry.apache.org/docs/cmis-samples/samples/create-objects/index.html

Related

How to use "Azure storage blobs" for POST method in controller

I am creating an app where user can upload their text file and find out about its most used word.
I have tried to follow this doc to get used to the idea of using AZURE STORAGE BLOBS - https://learn.microsoft.com/en-us/azure/storage/blobs/storage-quickstart-blobs-dotnet
But I am super newbie and having a hard time figuring it out how to adapt those blobs methods for my POST method.
This my sudo - what I think I need in my controller and what needs to happen when POST method is triggered.
a.No need for DELETE or PUT, not replacing the data nor deleting in this app
b.Maybe need a GET method, but as soon as POST method is triggered, it should pass the text context to the FE component
POST method
connect with azure storage account
if it is a first time of POST, create a container to store the text file
a. how can I connect with the existing container if the new container has already been made? I found this, but this is for the old CloudBlobContainer. Not the new SDK 12 version.
.GetContainerReference($"{containerName}");
upload the text file to the container
get the chosen file's text content and return
And here is my controller.
public class HomeController : Controller
{
private IConfiguration _configuration;
public HomeController(IConfiguration Configuration)
{
_configuration = Configuration;
}
public IActionResult Index()
{
return View();
}
[HttpPost("UploadText")]
public async Task<IActionResult> Post(List<IFormFile> files)
{
if (files != null)
{
try
{
string connectionString = Environment.GetEnvironmentVariable("AZURE_STORAGE_CONNECTION_STRING");
BlobServiceClient blobServiceClient = new BlobServiceClient(connectionString);
string containerName = "textdata" + Guid.NewGuid().ToString();
BlobContainerClient containerClient = await blobServiceClient.CreateBlobContainerAsync(containerName);
//Q. How to write a if condition here so if the POST method has already triggered and container already created, just upload the data. Do not create a new container?
string fileName = //Q. how to get the chosen file name and replace with newly assignmed name?
string localFilePath = //Q. how to get the local file path so I can pass on to the FileStream?
BlobClient blobClient = containerClient.GetBlobClient(fileName);
using FileStream uploadFileStream = System.IO.File.OpenRead(localFilePath);
await blobClient.UploadAsync(uploadFileStream, true);
uploadFileStream.Close();
string data = System.IO.File.ReadAllText(localFilePath, Encoding.UTF8);
//Q. If I use fetch('Home').then... from FE component, will it receive this data? in which form will it receive? JSON?
return Content(data);
}
catch
{
//Q. how to use storageExeption for the error messages
}
finally
{
//Q. what is suitable to execute in finally? return the Content(data) here?
if (files != null)
{
//files.Close();
}
}
}
//Q. what to pass on inside of the Ok() in this scenario?
return Ok();
}
}
Q1. How can I check if the POST method has been already triggered, and created the Container? If so how can I get the container name and connect to it?
Q2. Should I give a new assigned name to the chosen file? How can I do so?
Q3. How can I get the chosen file's name so I can pass in order to process Q2?
Q4. How to get the local file path so I can pass on to the FileStream?
Q5. How to return the Content data and pass to the FE? by using fetch('Home').then... like this?
Q6. How can I use storageExeption for the error messages
Q7. What is suitable to execute in finally? return the Content(data) here?
Q8. What to pass on inside of the Ok() in this scenario?
Any help is welcomed! I know I asked a lot of Qs here. Thanks a lot!
Update: add a sample code, you can modify it as per your need.
[HttpPost]
public async Task<IActionResult> SaveFile(List<IFormFile> files)
{
if (files == null || files.Count == 0) return Content("file not selected");
string connectionString = "xxxxxxxx";
BlobServiceClient blobServiceClient = new BlobServiceClient(connectionString);
string containerName = "textdata" + Guid.NewGuid().ToString();;
BlobContainerClient containerClient = blobServiceClient.GetBlobContainerClient(containerName);
containerClient.CreateIfNotExists();
foreach (var file in files)
{
//use this line of code to get file name
string fileName = Path.GetFileName(file.FileName);
BlobClient blobClient = containerClient.GetBlobClient(fileName);
//directly read file content
using (var stream = file.OpenReadStream())
{
await blobClient.UploadAsync(stream);
}
}
//other code
return View();
}
Original answer:
When using List<IFormFile>, you should use foreach code block to iterate each file in the list.
Q2. Should I give a new assigned name to the chosen file? How can I do
so?
If you want to keep the file original name, in the foreach statement like below:
foreach (var file in myfiles)
{
Path.GetFileName(file.FileName)
//other code
}
And if you want to assign a new file name when uploaded to blob storage, you should define the new name in this line of code: BlobClient blobClient = containerClient.GetBlobClient("the new file name").
Q3. How can I get the chosen file's name so I can pass in order to
process Q2?
refer to Q2.
Q4. How to get the local file path so I can pass on to the FileStream?
You can use code like this: string localFilePath = file.FileName; to get the path, and then combine with the file name. But there is a better way, you can directly use this line of code Stream uploadFileStream = file.OpenReadStream().
Q5. How to return the Content data and pass to the FE? by using
fetch('Home').then... like this?
Not clear what's it meaning. Can you provide more details?
Q6. How can I use storageExeption for the error messages
The storageExeption does not exist in the latest version, you should install the older one.
You can refer to this link for more details.
#Ivan's answer is what the documentation seems the recommend; however, I was having a strange issue where my stream was always prematurely closed before the upload had time to complete. To anyone else who might run into this problem, going the BinaryData route helped me. Here's what that looks like:
await using var ms = new MemoryStream();
await file.CopyToAsync(ms);
var data = new BinaryData(ms.ToArray());
await blobClient.UploadAsync(data);

How to access document on alfresco?

I created a project alfresco amp.
To add a document, I run this Test class:
public class Test {
public static void main(String[] args) throws UnsupportedEncodingException {
Map<String, String> sessionParameters = new HashMap<String, String>();
sessionParameters.put(SessionParameter.USER, "admin");
sessionParameters.put(SessionParameter.PASSWORD, "admin");
sessionParameters.put(SessionParameter.ATOMPUB_URL, "http://localhost:8080/alfresco/api/-default-/public/cmis/versions/1.1/atom");
sessionParameters.put(SessionParameter.BINDING_TYPE, BindingType.ATOMPUB.value());
SessionFactory sessionFactory = SessionFactoryImpl.newInstance();
Session lSession = sessionFactory.getRepositories(sessionParameters).get(0).createSession();
Folder root = lSession.getRootFolder();
Map<String, Object> folderProperties = new HashMap<String, Object>();
folderProperties.put(PropertyIds.OBJECT_TYPE_ID, "cmis:folder");
folderProperties.put(PropertyIds.NAME, "oo");
Folder newFolder = root.createFolder(folderProperties);
Map<String, Object> lProperties = new HashMap<String, Object>();
String name = "lol.txt";
lProperties.put(PropertyIds.OBJECT_TYPE_ID, "cmis:document");
lProperties.put(PropertyIds.NAME, name);
byte[] content = "CMIS Testdata One".getBytes();
InputStream stream = new ByteArrayInputStream(content);
ContentStream contentStream = new ContentStreamImpl(name, new BigInteger(content), "text/plain", stream);
Document newContent1 = newFolder.createDocument(lProperties, contentStream, null);
System.out.println("Document created: " + newContent1.getId());
}
}
The document is created with success; I got: Document created: e3184105-e59e-4b8a-88e7-9442942433a4;1.0
My problem is how can I access to this document (With which url can I access to that document).
Please help?.
It looks like you've created a document and you now want to know what URL to use to get to it. You have many options, some of which include...
Use the Alfresco web app's download URL:
http://localhost:8080/alfresco/s/api/node/workspace/SpacesStore/dac36aab-dd49-4abc-a4bc-0e0d5729c9ad/content;cm%3Acontent
Use the Share web app's download URL:
http://localhost:8080/share/proxy/alfresco/slingshot/node/content/workspace/SpacesStore/dac36aab-dd49-4abc-a4bc-0e0d5729c9ad/test.txt
Use the CMIS URL (AtomPub binding):
http://localhost:8080/alfresco/api/-default-/public/cmis/versions/1.1/atom/content/test.txt?id=dac36aab-dd49-4abc-a4bc-0e0d5729c9ad%3B1.0
Use the CMIS URL (Browser binding):
http://localhost:8080/alfresco/api/-default-/public/cmis/versions/1.1/browser/root?objectId=dac36aab-dd49-4abc-a4bc-0e0d5729c9ad%3B1.0&cmisselector=content
Write your own URL handler that fetches the input stream via CMIS and returns that stream to the requester. Assuming you are using something like Spring MVC, the code for that might look like:
public InputStream download(String objectId) {
Session session = getSession();
CmisObject obj = session.getObject(objectId);
Document doc = null;
if (obj.getBaseTypeId().equals(BaseTypeId.CMIS_DOCUMENT)) {
doc = (Document) obj;
}
return doc.getContentStream().getStream();
}
Each of the above options assumes a test file in a test folder named "test.txt" with an Alfresco Node Reference of:
workspace://SpacesStore/dac36aab-dd49-4abc-a4bc-0e0d5729c9ad
And a CMIS Object ID of:
dac36aab-dd49-4abc-a4bc-0e0d5729c9ad;1.0

How to write to static file in asp.net core?

I'm making an example to write to static file (.txt).
I've tried:
public IActionResult Index()
{
string dt = DateTimeOffset.Now.ToString("ddMMyyyy");
string path = Path.Combine(_environment.WebRootPath, $"Logs/{dt}");
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
string filePath = Path.Combine(_environment.WebRootPath, $"Logs/{dt}/{dt}.txt");
using (FileStream fs = System.IO.File.Create(filePath))
{
AddText(fs, "foo");
AddText(fs, "bar\tbaz");
}
return View();
}
private void AddText(FileStream fs, string value)
{
byte[] info = new System.Text.UTF8Encoding(true).GetBytes(value);
fs.Write(info, 0, info.Length);
}
But it created everything inside wwwroot folder instead of the root of project.
I want to create the text file here:
Where can I edit?
UPDATE:
This is how I define _environment:
public class HomeController : Controller
{
private readonly IHostingEnvironment _environment;
public HomeController(IHostingEnvironment environment)
{
_environment = environment;
}
}
The problem is that you are using IHostingEnvironment.WebRootPath to determine the root folder. This property is the absolute path to the directory that contains the web-servable application content files - i.e. the wwwroot folder. Instead you should use the IHostingEnvironment.ContentRootPath property which will give you the absolute path to the directory that contains the application.
For example:
var contentRoot = _environment.ContentRootPath;
var webRoot = _environment.WebRootPath;
//contentRoot = "C:\Projects\YourWebApp"
//webRoot = "C:\Projects\YourWebApp\wwwroot"
You could use WebRootPath and navigate to it's parent directory, but if for some reason you choose to move wwwroot somewhere else, your code may break. Much better to use a method that will give you the correct path every time in every project.
Instead of
string filePath = Path.Combine(_environment.WebRootPath, $"Logs/{dt}/{dt}.txt");
use
var folder = new System.IO.DirectoryInfo(_environment.WebRootpath).Parent.FullName;
var filePath = Path.Combine(folder, $"Logs/{dt}/{dt}.txt");

How to get Html of any view by it's full file location

public string GetRazorViewAsString(string filePath, object model = null)
{
var resultString = new StringWriter();
var context = new HttpContextWrapper(HttpContext.Current);
var routeData = new RouteData();
// Creatign the controller context
var controllerContext = new ControllerContext(new RequestContext(context, routeData), new DummyController());
// Rebdering the view and getting the html to resultString
var razor = new RazorView(controllerContext, filePath, null, false, null);
razor.Render(new ViewContext(controllerContext, razor, new ViewDataDictionary(model), new TempDataDictionary(), resultString), resultString);
// Returning the generated html
return resultString.ToString();
}
public class DummyController : Controller { }
Currently, we are using above code for generating HTML for a view.
In that, view path is a virtual path.
Now, we are planning to move the views outside of the project. So keeping virtual path is not possible now.
Is there any way of creating HTML by taking full path of the view
You can implement a VirtualPathProvider. Create a class that inherits from VirtualPathProvider, then override two methods:
FileExists
GetFile
These methods accept a virtual path argument, which you can then map to some location on disk. Your controllers will be unaware that this provider exists (they continue to use virtual paths for views). You may need to also implement a VirtualFile.
For more information, see http://www.umbraworks.net/bl0g/rebuildall/2009/11/17/ASP_NET_MVC_and_virtual_views. This blog post is sourcing views from a database, but you can adapt it to source views from anywhere.

ASP.NET- using System.IO.File.Delete() to delete file(s) from directory inside wwwroot?

I have a ASP.NET SOAP web service whose web method creates a PDF file, writes it to the "Download" directory of the applicaton, and returns the URL to the user. Code:
//Create the map images (MapPrinter) and insert them on the PDF (PagePrinter).
MemoryStream mstream = null;
FileStream fs = null;
try
{
//Create the memorystream storing the pdf created.
mstream = pgPrinter.GenerateMapImage();
//Convert the memorystream to an array of bytes.
byte[] byteArray = mstream.ToArray();
//return byteArray;
//Save PDF file to site's Download folder with a unique name.
System.Text.StringBuilder sb = new System.Text.StringBuilder(Global.PhysicalDownloadPath);
sb.Append("\\");
string fileName = Guid.NewGuid().ToString() + ".pdf";
sb.Append(fileName);
string filePath = sb.ToString();
fs = new FileStream(filePath, FileMode.CreateNew);
fs.Write(byteArray, 0, byteArray.Length);
string requestURI = this.Context.Request.Url.AbsoluteUri;
string virtPath = requestURI.Remove(requestURI.IndexOf("Service.asmx")) + "Download/" + fileName;
return virtPath;
}
catch (Exception ex)
{
throw new Exception("An error has occurred creating the map pdf.", ex);
}
finally
{
if (mstream != null) mstream.Close();
if (fs != null) fs.Close();
//Clean up resources
if (pgPrinter != null) pgPrinter.Dispose();
}
Then in the Global.asax file of the web service, I set up a Timer in the Application_Start event listener. In the Timer's ElapsedEvent listener I look for any files in the Download directory that are older than the Timer interval (for testing = 1 min., for deployment ~20 min.) and delete them. Code:
//Interval to check for old files (milliseconds), also set to delete files older than now minus this interval.
private static double deleteTimeInterval;
private static System.Timers.Timer timer;
//Physical path to Download folder. Everything in this folder will be checked for deletion.
public static string PhysicalDownloadPath;
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
deleteTimeInterval = Convert.ToDouble(System.Configuration.ConfigurationManager.AppSettings["FileDeleteInterval"]);
//Create timer with interval (milliseconds) whose elapse event will trigger the delete of old files
//in the Download directory.
timer = new System.Timers.Timer(deleteTimeInterval);
timer.Enabled = true;
timer.AutoReset = true;
timer.Elapsed += new System.Timers.ElapsedEventHandler(OnTimedEvent);
PhysicalDownloadPath = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath + "Download";
}
private static void OnTimedEvent(object source, System.Timers.ElapsedEventArgs e)
{
//Delete the files older than the time interval in the Download folder.
var folder = new System.IO.DirectoryInfo(PhysicalDownloadPath);
System.IO.FileInfo[] files = folder.GetFiles();
foreach (var file in files)
{
if (file.CreationTime < DateTime.Now.AddMilliseconds(-deleteTimeInterval))
{
string path = PhysicalDownloadPath + "\\" + file.Name;
System.IO.File.Delete(path);
}
}
}
This works perfectly, with one exception. When I publish the web service application to inetpub\wwwroot (Windows 7, IIS7) it does not delete the old files in the Download directory. The app works perfect when I publish to IIS from a physical directory not in wwwroot. Obviously, it seems IIS places some sort of lock on files in the web root. I have tested impersonating an admin user to run the app and it still does not work. Any tips on how to circumvent the lock programmatically when in wwwroot? The client will probably want the app published to the root directory.
Your problem may be related to the fact that IIS reloads the Web Service Application if the directory or files contained in the main folder changes.
Try creating / deleting files in a temporary folder which is outside the root folder of your application (be aware of permissions on the folder to allow IIS to read/write files).
Instead of writing directly to the file system, why not use isolated storage?
http://msdn.microsoft.com/en-us/library/system.io.isolatedstorage.isolatedstorage.aspx
This should solve any location or permission based issues that you are having
I forgot to come back and answer my question.
I had to give the IIS_IUSRS group Modify permissions to the directory where I was reading/writing files.
Thanks to all those who answered.

Resources