How to load an image using its real path in Grails - html

My idea is to save the images which the user uploads outside the context path as follow:
D:\somefolder\myWeb\web-app\
D:\somefolder\imagesOutsideContextPath\
The code for that is the next (working locally):
String path = servletContext.getRealPath("/");
String parentFolder = new File(path).getParentFile().getParent();
String imagesFolder = parentFolder + "\\imagesOutsideContextPath";
Another idea (if this one doesn't work on server) would be to save the images in the current user's home folder as #HoàngLong suggested me.
But I'm not able to load the images from the view. I think this article from official documentation is not valid for that purpose. The next code desn't load anything:
<img src="D:\\somefolder\\imagesOutsideContextPath\\bestImageEver.jpg" alt="if I don't see this message, I'll be happier">
How could I use the real path instead the an url path to load these images?

There's a new plugin that makes this easy, check out http://grails.org/plugin/img-indirect

Create an action
def profileImage() {
String profilePicturePath = "${grailsApplication.config.profilePictureDirectoryPath}/${params.id}"
File file = new File(profilePicturePath)
response.contentType = URLConnection.guessContentTypeFromName(file.getName())
response.outputStream << file.bytes
response.outputStream.flush()
}
and then call this action with image name in params like:
<g:img uri="${grailsApplication.config.grails.serverURL}/controller/profileImage/${user?.profilePicture?.fileName}"/>
I have declared the image directory file in my config.groovy file like:
profilePictureDirectoryPath = '/opt/CvSurgeon/profileImages'

You can set the src to an action. With that your user will not know where your images are stored (security) and you can easily change your logic to display them.
In the action, just get your image and print the bytes. Example here.

Firstly, thank you for your reference.
It's insecure to load images using real path. The web browser should know nothing about how the pictures are saved on server, therefore not aware of the folder structure.
What I mean is that the system should use a specific URL for all your pictures, such as http://your_app/photo/user/{id}. Then to that URL, you can construct an action which gets id as a parameter, look up the photo in your file system(of course you must store the picture folder in configuration), and render the photo back.

Related

How to create alert from view model

I want to validate file. While file is invalid, i want to refresh my page and inform user that he did not upload proper file. So i have this in my
views/campaign.py
try:
wb = load_workbook(mp_file)
except BadZipfile:
return redirect('campaign_add', client_id)
The only way i know how to do it is add another attribute to client class which will be
is_error(models.BooleanField())
And then change views/campaign to
try:
client.is_error = False
wb = load_workbook(mp_file)
client.save()
except BadZipfile:
client.is_error = True
client.save()
return redirect('campaign_add', client)
And with another attribute i can add in my campaign.html file some kind of if is.error is true i'm adding some kind of windows with information about bad file after reloading page. But is there any way to do it without adding another attribute?
Ok, let's imagine that the answer is a little bit complicated than you've expected.
Modern UI's are not reloading pages just to inform about some errors with user input or upload.
So what is the best user experience here?
User is uploading some file(s) from the page.
You are sending a file via JavaScript to the dedicated API endpoint for this uploading. Let's say /workbook/uploads/. You need to create a handler for this endpoint (view)
Endpoint returns 200 OK with the empty body on success or an error, let's say 400 Bad Request with detailed JSON in the body to show to the user what's wrong.
You're parsing responses in JavaScript and show the user what's wrong
No refreshes are needed. 🙌
But the particular answer will need more code from your implementation. (view, urls, template)

Autodesk Forge - downloaded item has a different name

I'm using the https://developer.api.autodesk.com/oss/v2/buckets/:bucketKey/objects/:objectName endpoint to download an item (a Revit model) from BIM 360. Using this documentation. The file gets downloaded fine and the contents are correct however, after downloading, the file name is the GUID of the file (4aac519c-ab91-42a5-85c5-f023c82d4736.rvt) , not the 'displayName' of the file (my file.rvt) . I'm getting the file name like so:
var headervalue = resp.Headers.FirstOrDefault(x => x.Name == "Content-Disposition")?.Value;
string contentDispositionString = Convert.ToString(headervalue);
ContentDisposition contentDisposition = new ContentDisposition(contentDispositionString);
fileName = contentDisposition.FileName;
I've used the same method on another project and it's working fine. The content and the file name of the file both are correct. However somehow the endpoint is behaving differently on this project.
Any pointers what could be the issue here?
I'm not sure if this is mentioned somewhere in the documentation but I don't think you should rely on the Content-Disposition of the response headers for this. If you want to get a filename for whichever object you're downloading, you should always get it from the actual item record (obtained in the 3rd step of the tutorial you linked to).

How to access local webpage with parameters in vb?

I've scenario where i want open local web page (index.html) passing parameters in query which i can used in index.html but i'm having problem as it gives error as per below,
The system cannot find the file specified.
Vb.net Code
Dim url As String = ConfigurationManager.AppSettings("Url")
url = url & "?id=" & txtFilePath.Text
//Url example
"C:\Program Files\Products\Bella\index.html?id=232"
Process.Start(url)
i do not completely understand your question but i will try.
I do not know what the value of "Url" is, neither what the txtFilePath.text is supposed to be. but if you are trying to open a URL like
localhost/index.html?id=example
in a browser, you should use that as the first parameter.
Process.Start("IExplore.exe", url)
If you are trying to get the server to read the parameter you put into the URL, i do not know if you can make html-pages get parameters like that, maybe PHP or something else? But that should not make a difference at all for launching the browser and stuff, just a heads-up :)
But if you just want to open a static html file in a browser-window, you are, as far as i know, out of luck with passing parameters, but you SHOULD test for the existence of your file, so you are completely sure it exists in that path.
File.Exists(url)
EDIT:
Since your url is "C:\Program Files\Products\Bella\index.html?id=232" i do not believe you could pass parameters, i think it will try to find a file with the extension ".html?id=232", which obviously does not exist.
It seems there are two issues:
First:
I think the reason for the error is you need to have "file://" before the URL (as Mych mentioned in the comments) in order to access a local web page. Many browsers will automatically assume the URL should have "http://" unless you specify that it's a local file.
Depending on your browser it may add more forward slashes, but two should be sufficient to get Process.Start to recognize it.
So your URL should look like this:
"file://C:\Program Files\Products\Bella\index.html?id=232"
Second:
As far as passing a parameter to the URL the best way I have found (as jakobS suggested) you would have to use:
Process.Start("IExplore.exe", url)
'or
Process.Start("Chrome.exe", url)
or whichever browser you prefer.
So you could modify your code this way:
Dim url As String = ConfigurationManager.AppSettings("Url")
url = url & "?id=" & txtFilePath.Text
'Add "file://" to the beginning of the url.
url = "file://" & url
Process.Start("IExplore.exe", url)
That should get rid of your error and load the page with your parameters.
Hope it helps!

Permanent links to thumbnails in Google Drive API

I'm using Google Drive API (PHP) to upload some photos to my Drive. When a file is uploaded, a Google_DriveFile object is returned in the response to confirm the successful transfer. It includes a field called thumbnailLink, accessible through the getThumbnailLink getter. Its content may look like this:
https://lh4.googleusercontent.com/dqVdU195R4_0ZtWxsJlhW1Fr2K30xa2hH3V1KV4UrTBl9QkhOSR0ZqN9HoB-TjEQv8SIJw=s220
Until today, I was sure that the link doesn't change by itself over time. However, when I tried to display a thumbnail of a photo I have on my Drive, using a cached address I keep in my local database, I got a 403 error - you can see it under the mentioned link. I asked the API for the current link to the thumbnail and it's now completely different.
It happened to me only once but for multiple files, i.e. all the files I had on my Drive suddenly got new thumbnail links.
Is there a way to quickly retrieve a thumbnail of a document (preferably, a photo) by some constant value or to be sure that it won't change? The perfect solution would be to access the thumbnail under a link that includes the document's id instead of some hash that may change.
Try this:
https://drive.google.com/thumbnail?authuser=0&sz=w320&id=[fileid]
Where:
sz is a size, where you may use as w (width), as h (height)
fileid is a file id. You may find it in "share" menu by right click in Google Drive UI.
I have gone through the API Documentation as they have provided:
Important: Thumbnails are invalidated each time the content of the file changes. When supplying thumbnails, it is important to upload new thumbnails each time the content is modified.
According to the information it means that a new Thumbnail is only generated only when the contents of the file are modifided. But in your case it is really weired thing and the contents are not changed but the thumbnail are Changed. As from documentation there is no batch process thing avaiable but another way around is available i.e. Web Hook
According to the Documentation there is web hook available i.e. Files:Watch process through which one can track the changes are made to file. Thus, it means every time contents are changed then hook would run and you can change the cache of the image thumbnail.
HTTP request can be sent to request the watching the files changing
POST https://www.googleapis.com/drive/v2/files/fileId/watch
Here fileID means the ID provided after loading the file.
In the request body, supply data with the following structure:
id ==> string (A UUID or similar unique string that identifies
this channel.)
token# ==> string (An arbitrary string delivered to the target address with
each notification delivered over this channel).
expiration# => long (Date and time of notification channel expiration,
expressed as a Unix timestamp, in milliseconds.)
type ==> string (The type of delivery mechanism used for this channel.
The only option is web_hook.)
address => string (The address where notifications are delivered
for this channel.)
# Optional.
If the contents get changed then new Thumbnail is generated and hook will notify you address and through your address you can fetch new information.
Here is another solution. Let's say we store only GDrive ID of the images or PDFs (google generate thumbs for many file types).
we can send request to gDrive to get valid thumbnail since looks like thumbs will expire even if there is no changes to the file.
In this case each thumbnail inside Angular component. If you use something else you can create array of links and iterate through it to create proper thumb links.
Here is the code:
const thumb = () => {
if (this.item.DriveId) {
this.getThumb(this.item.DriveId, this.authToken)
.then(response => {
console.log(`response from service ${response}`);
// Set thumbnail width size to 300px or any other width if needed
this.item.externalThumbnailId = response.slice(0, -3) + 300;
})
//here we can handle cases when API limit exceeded 10 req in a sec
.catch(e => {
if(e.data.error.message == 'User Rate Limit Exceeded'){
console.log('Failed to load thumb. trying one more time');
setTimeout(thumb, 1000);
} else {
console.log(e);
}
});
}
};
//call this function on component load.
thumb();
Another solution will be to write some backend script that updates thumbs in DB records.

WebMatrix - Server.MapPath issues

I am having an issue with the server.mappath method. My current code is:
var imageroot = Server.MapPath("~/Images/Property/");
var foldername = rPropertyId.ToString();
var path = Path.Combine(imageroot, foldername);
When I upload this path into my database, I expect to see the following URL:
/images/property/1/filename.jpg
But what I actually see is this URL:
C:\Users\gavin\Dropbox\My Web Sites\StayInFlorida\Images\Property\1\filename.jpg
How do I get around this? I'm assuming I have to change the MapPath method, but I've tried a few things but I've had no luck.
The Server.MapPath method returns a file system path. What you want is a (relative) URL. Paths and URLs are completely different things. Typically, you need a path if you want to manage files in your server side code, and you need a URL is you are providing access to those files to visitors via hyperlinks. URLs can be constructed from strings:
var url = string.Format("/Images/Property/{0}/{1}", rProprtyId, filename)