I'm querying the graph api using this URL:
https://graph.microsoft.com/v1.0/sites/{siteID}/drives/{driveID}/root/children
which is giving me the webURL
"https://MY DOMAIN.sharepoint.com/sites/{SITE}/{FILENAME}.url
Is there any way to get the value that the shortcut item points to, as opposed to downloading a .url file?
I think Get url address from url file answers half of my question, however, I'm unable to get the contents of the url as a File type object to be able to read through it.
I'm getting each of the quicklinks and adding them to a list via ReadAsStringAsync
public static async Task<List<QuickLinkViewModel>> GetQuickLinksAsync (dynamic quicklinksJson)
{
List<QuickLinkViewModel> quickLinks = new List<QuickLinkViewModel>();
var quickLink = quicklinksJson.value;
string title;
HttpClient client = new HttpClient();
byte[] reply;
foreach (var q in quickLink)
{
reply = await client.GetByteArrayAsync(q.webUrl);
title = q.name;
title = System.IO.Path.GetFileNameWithoutExtension(title);
quickLinks.Add(new QuickLinkViewModel
{
Title = title,
webUrl = q.webUrl
});
}
return quickLinks;
}
When I run this I'm getting the error:
The best overloaded method match for
'System.Net.Http.HttpClient.GetByteArrayAsync(string)' has some
invalid arguments
.url file is not supported to be previewed in SharePoint. So the webUrl format in the query results of Microsoft Graph is different from other files. Other files can be previewed through this webUrl. The .url file will be downloaded directly through webUrl.
You can download it and open it with the edit tool to see the value that the shortcut item points to.
The content of .url file:
[InternetShortcut]
URL={the value that the shortcut item points to}
UPDATE:
If you want to get the content of the .url file in your code, you need to call another Graph endpoint: GET /drives/{drive-id}/items/{item-id}/content. See reference here. Use client.DownloadString to read the content in C#.
Here is a simple example (Please note that I didn't implement the authorization process here, just put the Authorization herder for convenience):
Related
I was trying to convert .docx file to .pdf using drive api, which sounds reasonable since you can do it manually.
Here is my code:
FilesResource.CreateMediaUpload request;
using (var stream = new System.IO.FileStream(#"test.docx",
System.IO.FileMode.Open))
{
request = driveService.Files.Create(
fileMetadata, stream, "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
request.Fields = ""id, webViewLink, webContentLink, size";
var x = request.Upload();
Console.WriteLine(x);
}
var file = request.ResponseBody;
Afterwards, I am getting id of this file and trying to do:
var downloadRequest = driveService.Files.Export(file.Id, "application/pdf");
which fails with error: "Export only supports Google Docs"
Ofc! I suppose it hasn't yet become "Google DOC", however, this format is supported for conversion as mentioned here and here.
Ok, I've noticed if you go to the drive and open the file manually it will become google doc file and also will get new ID. The export on this ID will work just fine. However, doing something manually isn't acceptable approach for our needs.
Tried another approach, you can use direct link with &export=pdf parameter to convert google doc file.
https://docs.google.com/document/d/FILE_ID/export?format=doc
But passing FILEID to that link doesn't work in this case(works with "DOC" file just fine) Tried doing something similiar to stackoverflow answer. No way.
So. Is there any way to trigger File to become Google DOC and wait till it converts? Is there any other way?
Thanks in advance!
Thanks to #bash.d I was able to convert from docx to pdf.
Actually one have to use v2 of API and its "Insert" method.
https://developers.google.com/drive/v2/reference/files/insert#examples
use the code from this link and specify
request.Convert = true;
after that I used
var downloadRequest = driveService.Files.Export(file.Id, "application/pdf");
and voilà! It worked! Takes about 30 seconds to convert file in my case.
In short, I need to detect a webpage's GET requests programmatically.
The long story is that my company is currently trying to write a small installer for a piece of proprietary software that installs another piece of software.
To get this other piece of software, I realize it's as simple as calling the download link through C#'s lovely WebClient class (Dir is just the Temp directory in AppData/Local):
using (WebClient client = new WebClient())
{
client.DownloadFile("[download link]", Dir.FullName + "\\setup.exe");
}
However, the page which the installer comes from does is not a direct download page. The actual download link is subject to change (our company's specific installer might be hosted on a different download server another time around).
To get around this, I realized that I can just monitor the GET requests the page makes and dynamically grab the URL from there.
So, I know I'm going to do, but I was just wondering, is there was a built-in part of the language that allows you to see what requests a page has made? Or do I have to write this functionality myself, and what would be a good starting point?
I think I'd do it like this. First download the HTML contents of the download page (the page that contains the link to download the file). Then scrape the HTML to find the download link URL. And finally, download the file from the scraped address.
using (WebClient client = new WebClient())
{
// Get the website HTML.
string html = client.DownloadString("http://[website that contains the download link]");
// Scrape the HTML to find the download URL (see below).
// Download the desired file.
client.DownloadFile(downloadLink, Dir.FullName + "\\setup.exe");
}
For scraping the download URL from the website I'd recommend using the HTML Agility Pack. See here for getting started with it.
I think you have to write your own "mediahandler", which returns a HttpResponseMessage.
e.g. with webapi2
[HttpGet]
[AllowAnonymous]
[Route("route")]
public HttpResponseMessage GetFile([FromUri] string path)
{
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new StreamContent(new FileStream(path, FileMode.Open, FileAccess.Read));
string fileName = Path.GetFileNameWithoutExtension(path);
string disposition = "attachment";
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue(disposition) { FileName = fileName + Path.GetExtension(absolutePath) };
result.Content.Headers.ContentType = new MediaTypeHeaderValue(MimeMapping.GetMimeMapping(Path.GetExtension(path)));
return result;
}
I'm downloading and saving images from URL. The image can be of any format.
Right click on the image, select Properties and then the Details tab. There is a Comments field. I would like to add text in that field while saving the image . Is it possible.
using (WebClient webClient = new WebClient())
{
webClient.DownloadFile("http://www.example.com/1.jpg", "1.jpg");
}
The property system in Windows has a complex story, you can find more information about it here: Extracting Windows File Properties (Custom Properties) C#
You could try it with the Microsoft.WindowsAPICodePack.Shell nuget package:
var file = ShellFile.FromFilePath("your image.jpg");
using (var writer = file.Properties.GetPropertyWriter())
{
writer.WriteProperty(file.Properties.System.Comment, "hello");
}
But, in the case of images, the shell may not be able to write extra properties on the file itself (most imaging codecs except JPG don't support such a 'comments' metadata). What I suggest in this case is use this CodeFluentRuntime nuget package's CompoundStorage class, here is an example:
static void Main(string[] args)
{
var storage = new CompoundStorage("your image.png", false); // open for write
storage.Properties.Comments = "hello"; // change well-known "comments" property
storage.CommitChanges();
}
It will work and write the property information not stricly on the file, but on NTFS (it works also on pure plain .txt files for example). If you read the file again and browse all properties, like this, you should see it:
static void Main(string[] args)
{
var storage = new CompoundStorage("consent.png"); // open for read
foreach (var prop in storage.Properties)
{
Console.WriteLine(prop.Name + "=" + prop.Value);
}
}
Now, the problem is, with recent versions of Windows, the shell property sheet you show in your question will not display the Comments property (for example, I'm running on Windows 10 and I don't see it although it's properly written). Unfortunately, there is not many other options for images files.
You can use this reference link to solved your problem.
http://www.codeproject.com/Articles/3615/File-Information-using-C
I have problem with browse button and switching to file dialog. I cannot use my file path control and just send there my string with file path and file itself, as it's readonly and in fact some behind control is my input filepath.
Here's my code
driver.FindElement(By.Id("browseButton")).Click();
driver.SwitchTo().ActiveElement().SendKeys(filepath);
Above code fills my control for file path, as i can see that on UI. But my open file dialog is still opened and i do not know how to close it and submit my upload.
Uploading files in Selenium can be a pain, to say the least. The real problem comes from the fact that it does not support dialog boxes such as file upload and download.
I go over this in an answer to another question, so I will just copy/paste my answer from there here. The code examples should actually be relevant in your case, since you are using C#:
Copied from previous answer on question here:
Selenium Webdriver doesn't really support this. Interacting with non-browser windows (such as native file upload dialogs and basic auth dialogs) has been a topic of much discussion on the WebDriver discussion board, but there has been little to no progress on the subject.
I have, in the past, been able to work around this by capturing the underlying request with a tool such as Fiddler2, and then just sending the request with the specified file attached as a byte blob.
If you need cookies from an authenticated session, WebDriver.magage().getCookies() should help you in that aspect.
edit: I have code for this somewhere that worked, I'll see if I can get ahold of something that you can use.
public RosterPage UploadRosterFile(String filePath){
Face().Log("Importing Roster...");
LoginRequest login = new LoginRequest();
login.username = Prefs.EmailLogin;
login.password = Prefs.PasswordLogin;
login.rememberMe = false;
login.forward = "";
login.schoolId = "";
//Set up request data
String url = "http://www.foo.bar.com" + "/ManageRoster/UploadRoster";
String javaScript = "return $('#seasons li.selected') .attr('data-season-id');";
String seasonId = (String)((IJavaScriptExecutor)Driver().GetBaseDriver()).ExecuteScript(javaScript);
javaScript = "return Foo.Bar.data.selectedTeamId;";
String teamId = (String)((IJavaScriptExecutor)Driver().GetBaseDriver()).ExecuteScript(javaScript);
//Send Request and parse the response into the new Driver URL
MultipartForm form = new MultipartForm(url);
form.SetField("teamId", teamId);
form.SetField("seasonId", seasonId);
form.SendFile(filePath,LoginRequest.sendLoginRequest(login));
String response = form.ResponseText.ToString();
String newURL = StaticBaseTestObjs.RemoveStringSubString("http://www.foo.bar.com" + response.Split('"')[1].Split('"')[0],"amp;");
Face().Log("Navigating to URL: "+ newURL);
Driver().GoTo(new Uri(newURL));
return this;
}
Where MultiPartForm is:
MultiPartForm
And LoginRequest/Response:
LoginRequest
LoginResponse
The code above is in C#, but there are equivalent base classes in Java that will do what you need them to do to mimic this functionality.
The most important part of all of that code is the MultiPartForm.SendFile method, which is where the magic happens.
One of the many ways to do that is to remove the disable attribute and then use typical selenium SendKeys() to accomplish that
public void test(string path)
{
By byId = By.Id("removeAttribute");
const string removeAttribute = #"document.getElementById('browseButton').removeAttribute('disabled');";
((IJavaScriptExecutor)Driver).ExecuteScript(removeAttribute);
driver.FindElement(byId).Clear();
driver.FindElement(byId).SendKeys(path);
}
You can use this Auto IT Script to Handle File Upload Option.
Auto IT Script for File Upload:
AutoItSetOption("WinTitleMatchMode","2") ; set the select mode to
Do
Sleep ("1000")
until WinExists("File Upload")
WinWait("File Upload")
WinActivate("File Upload")
ControlFocus("File Upload","","Edit1")
Sleep(2000)
ControlSetText("File Upload" , "", "Edit1", $CmdLineRaw)
Sleep(2000)
ControlClick("File Upload" , "","Button1");
Build and Compile the above code and place the EXE in a path and call it when u need it.
Call this Once you click in the Browse Button.
Process p = System.Diagnostics.Process.Start(txt_Browse.Text + "\\File Upload", DocFileName);
p.WaitForExit();
Using Sitecore 6.5, when images are rendered on a web page, a URL such as the one below is used
~/media/OSS/Images/MyImage
But if you add an image from the library in a content editor a path such as below is used
~/media/1CFDDC34C94E460FAA2B1518DCA22360.PNG
This makes sense as it's trying to use a meaningful path when rendered for the web.
We would like to use the first media image path to add images in the content editor in HTML view rather than the default second method. This is because we are actually taking some html files and automatically adding them in to Sitecore via a script and we can change the image paths to a location in the media library if the first image format is used by using a convention so the images should appear in the newly created items. We have now idea about a media library image ID.
The first format does appear to work as images are rendered in the content editor design editor and when the page is rendered but Sitecore marks these as broken links in the Content Editor. Are any ideas on whether we are safe to use this format?
You may want to avoid hard coding paths to media in the rich text field. The second "dynamic link" is an important feature of Sitecore in that it keeps a connection between the media and item in the Links database. This safeguards you if you ever delete or move the media.
Since it sounds like you are importing content from an external source and you already have a means of detecting the image paths, I would recommend (if possible) that you upload the images programmatically and insert the dynamic links.
Below is a function that you can call for uploading to the Media Library and getting back the media item:
Example usage:
var file = AddFile("/assets/images/my-image.jpg", "/sitecore/media library/images/example", "my-image");
The code:
private MediaItem AddFile(string relativeUrl, string sitecorePath, string mediaItemName)
{
var extension = Path.GetExtension(relativeUrl);
var localFilename = #"c:\temp\" + mediaItemName + extension;
using (var client = new WebClient())
{
client.DownloadFile("http://yourdomain.com" + relativeUrl, localFilename);
}
// Create the options
var options = new MediaCreatorOptions
{
FileBased = false,
IncludeExtensionInItemName = false,
KeepExisting = false,
Versioned = false,
Destination = sitecorePath + "/" + mediaItemName,
Database = Factory.GetDatabase("master")
};
// Now create the file
var creator = new MediaCreator();
var mediaItem = creator.CreateFromFile(localFilename, options);
return mediaItem;
}
As for generating the dynamic link to the media, I actually haven't found a Sitecore method to do this, so I resorted to the following code:
var extension = !String.IsNullOrEmpty(Settings.Media.RequestExtension)
? Settings.Media.RequestExtension
: ((MediaItem)item).Extension;
var dynamicMediaUrl = String.Format(
"{0}{1}.{2}",
MediaManager.MediaLinkPrefix,
item.ID.ToShortID(),
extension);
No it will not cause any rendering issue apart from the broken links notification as you noted. Also when you select an image in the editor and select to edit the media folder will be at the root rather than at the image itself. But as Derek has noted, the use of dynamic links is an important feature to make sure your links do not break if something is moved or deleted.
I would add to his answer that since you are adding the text via a script you can detect images in the text using HtmlAgilityPack (already used in Sitecore) or FizzlerEx (more similar to jQuery syntax), use the code he provided to upload the images to the media library, grab the GUID and replace the src. Something along the lines of:
string content = "<whatever your html to go in the rich text field>";
HtmlDocument doc = new HtmlDocument();
doc.Load(content);
foreach(HtmlNode img in doc.DocumentElement.SelectNodes("//img[starts-with(#src, '/media/')]")
{
HtmlAttribute attr = img["src"];
Item scMediaItem = UploadLocalMedia(attr.Value);
attr.Value = GetDynamicMediaUrl(scMediaItem);
}