Grails unable to find pdf resources when deploying war - file

I'm writing an action in controller to download pdf from webapp directory. when I run the app using run-app command, it works perfectly fine. But when I create a war, it throws error of File not found on browser. My code is as below.
def pdfDownlod ={
def pdfFileName=params.pdfFileName
def pdfFile = new File('web-app/sales/resources/pdf/'+pdfFileName)
response.setContentType("application/pdf")
response.setHeader("Content-disposition", "attachment; filename=${pdfFileName}")
response.outputStream << pdfFile?.getBytes()
response.outputStream.flush()
return
}
Please let me know the root cause of the problem and solution.
Thanks in advance.

you can try this syntax , it will work fine for you.
def pdfFile = new File(ServletContextHolder.servletContext.getRealPath('sales/resources/pdf/'+pdfFileName))
Enjoy.

That's because in your deployed war the web-app folder don't exists. To properly get resources in both dev and prod use the grailsResourceLocator bean.
Example:
class MyController {
def grailsResourceLocator
def pdfDownlod ={
def pdfFileName = params.pdfFileName
final Resource pdfFile = grailsResourceLocator.findResourceForURI('web-app/sales/resources/pdf/'+pdfFileName)
response.setContentType("application/pdf")
response.setHeader("Content-disposition", "attachment; filename=${pdfFileName}")
response.outputStream << pdfFile?.file.bytes // << already flushes!
return
}
}

Related

How to write groovy Script in Jmeter

Hello Stackoverflow Community,
I am new to Jmeter and Related Stuff.
Just Finished with Login Request and Response through Selenium WebDriver Sampler(using Java Script) .
Screen shot is also attached with this post.
All working Well.
Now i go through some articles ,they stress on using groovy script(under JSR223 Sampler) but i am not able to figure out how to convert this same Javascript(WDS sampler) in Groovy(JSR223 sampler) runnable Script.I will be very thankful for any Kind of help in this direction.
Thanks
groovy(Groovy 2.4.15/Groovy Scripting Engine 2.0) is already displayed in my JSR223 Sampler [i m using apache-jmeter-5.0 ] i run hello world program its working fine..further i have no idea abt how to play with groovy script.
Below is my code in Javascipt(selenium WDS)
WDS.sampleResult.sampleStart();
WDS.log.info("Maximo Application ---- Sample started");
var pkg = JavaImporter(org.openqa.selenium); //WebDriver classes
var support_ui = JavaImporter(org.openqa.selenium.support.ui.WebDriverWait);
var wait = new support_ui.WebDriverWait(WDS.browser, 5000);
var conditions=org.openqa.selenium.support.ui.ExpectedConditions;
var selenium_keys=JavaImporter(org.openqa.selenium.Keys);
WDS.sampleResult.getLatency();
//-----------------------------Login in Application---------------------------------------------
WDS.browser.get('http://xxxxxxxxxxxxxxx/maximo/webclient/login/login.jsp'); //opens website
WDS.log.info("Maximo Application ---- Username and Password dynamicly picked from C:/user.csv ");
//UserName
var userName = WDS.browser.findElement(pkg.By.id('username'));
WDS.log.info("Maximo Application ---- Username "+'${username}');
userName.click();
userName.sendKeys('${username}');
//Password
var password=WDS.browser.findElement(pkg.By.id("password"));
password.click();
WDS.log.info("Maximo Application ---- password "+'${password}');
password.clear();
password.sendKeys('${password}');
WDS.browser.findElement(pkg.By.id("loginbutton")).click();
WDS.log.info("Maximo Application ---- Logged by USER Name--- "+ '${username}');
WDS.sampleResult.sampleEnd();
I really Wann to switch on groovy as all coming scenarios are going to be complex
WDS_javascript
i could give you the guidance about your code.
in general, even when you are using javascript in jmeter - you are calling java methods.
groovy will do the same but in syntax it's closer to java.
so:
declare variables with def instead of var
change JavaImporter(XYZ) to import XYZ at the beginning of script
remove all java imported variables as they not needed. such as support_ui
just an example:
import org.openqa.selenium.*; //need .* to import all classes from package
import org.openqa.selenium.support.ui.WebDriverWait; //import exact class
WDS.sampleResult.sampleStart(); //code remains the same
//var pkg = JavaImporter(org.openqa.selenium); //moved to import
//var support_ui = JavaImporter(org.openqa.selenium.support.ui.WebDriverWait); //moved to import
def wait = new WebDriverWait(WDS.browser, 5000); //removed `support_ui.`
def userName = WDS.browser.findElement(By.id('username')); //removed `pkg.`
and finally just learn java & groovy

Upload to Amazon S3 using Boto3 and return public url

Iam trying to upload files to s3 using Boto3 and make that uploaded file public and return it as a url.
class UtilResource(BaseZMPResource):
class Meta(BaseZMPResource.Meta):
queryset = Configuration.objects.none()
resource_name = 'util_resource'
allowed_methods = ['get']
def post_list(self, request, **kwargs):
fileToUpload = request.FILES
# write code to upload to amazone s3
# see: https://boto3.readthedocs.org/en/latest/reference/services/s3.html
self.session = Session(aws_access_key_id=settings.AWS_KEY_ID,
aws_secret_access_key=settings.AWS_ACCESS_KEY,
region_name=settings.AWS_REGION)
client = self.session.client('s3')
client.upload_file('zango-static','fileToUpload')
url = "some/test/url"
return self.create_response(request, {
'url': url // return's public url of uploaded file
})
I searched whole documentation I couldn't find any links which describes how to do this can someone explain or provide any resource where I can find the soultion?
I'm in the same situation.
Not able to find anything in the Boto3 docs beyond generate_presigned_url which is not what I need in my case since I have public readable S3 Objects.
The best I came up with is:
bucket_location = boto3.client('s3').get_bucket_location(Bucket=s3_bucket_name)
object_url = "https://s3-{0}.amazonaws.com/{1}/{2}".format(
bucket_location['LocationConstraint'],
s3_bucket_name,
key_name)
You might try posting on the boto3 github issues list for a better solution.
I had the same issue.
Assuming you know the bucket name where you want to store your data, you can then use the following:
import boto3
from boto3.s3.transfer import S3Transfer
credentials = {
'aws_access_key_id': aws_access_key_id,
'aws_secret_access_key': aws_secret_access_key
}
client = boto3.client('s3', 'us-west-2', **credentials)
transfer = S3Transfer(client)
transfer.upload_file('/tmp/myfile', bucket, key,
extra_args={'ACL': 'public-read'})
file_url = '%s/%s/%s' % (client.meta.endpoint_url, bucket, key)
The best solution I found is still to use the generate_presigned_url, just that the Client.Config.signature_version needs to be set to botocore.UNSIGNED.
The following returns the public link without the signing stuff.
config = Config(signature_version=botocore.UNSIGNED)
config.signature_version = botocore.UNSIGNED
boto3.client('s3', config=config).generate_presigned_url('get_object', ExpiresIn=0, Params={'Bucket': bucket, 'Key': key})
The relevant discussions on the boto3 repository are:
https://github.com/boto/boto3/issues/110
https://github.com/boto/boto3/issues/169
https://github.com/boto/boto3/issues/1415
Somebody who wants to build up a direct URL for the public accessible object to avoid using generate_presigned_url for some reason.
Please build URL with urllib.parse.quote_plus considering whitespace and special character issue.
My object key: 2018-11-26 16:34:48.351890+09:00.jpg
please note whitespace and ':'
S3 public link in aws console: https://s3.my_region.amazonaws.com/my_bucket_name/2018-11-26+16%3A34%3A48.351890%2B09%3A00.jpg
Below code was OK for me
import boto3
s3_client = boto3.client
bucket_location = s3_client.get_bucket_location(Bucket='my_bucket_name')
url = "https://s3.{0}.amazonaws.com/{1}/{2}".format(bucket_location['LocationConstraint'], 'my_bucket_name', quote_plus('2018-11-26 16:34:48.351890+09:00.jpg')
print(url)
Going through the existing answers and their comments, I did the following and works well for special cases of file names like having whitespaces, having special characters (ASCII), corner cases. E.g. file names of the form: "key=value.txt"
import boto3
import botocore
config = botocore.client.Config(signature_version=botocore.UNSIGNED)
object_url = boto3.client('s3', config=config).generate_presigned_url('get_object', ExpiresIn=0, Params={'Bucket': s3_bucket_name, 'Key': key_name})
print(object_url)
For Django, if you use Django storages with boto3 the code below does exactly what you want:
default_storage.url(name=f.name)
I used an f-string for the same
import boto3
#s3_client = boto3.session.Session(profile_name='sssss').client('s3')
s3_client=boto3.client('s3')
s3_bucket_name = 'xxxxx'
s3_website_URL= f"http://{s3_bucket_name}.s3-website.{s3_client.get_bucket_location(Bucket=s3_bucket_name)['LocationConstraint']}.amazonaws.com"

App Engine Credential issue

I have an app engine app which imports a jar. In that jar I am using
GoogleClientSecrets.load()
to load client_secrets.json file for authentication with BigQuery. Apparently, App Engine does not like me reading a file from some location on my disk when I deploy the app on localhost. I am assuming if I put the credentials in WEBINF folder it will work but haven't tested it but then it would be easy for anyone to access the file. Where is the best place to put credentials and how would one access them from App Engine app?
Thank you for your help!
The suggestions helped to solve the problem when it comes to reading a file. What about writing to a file? I am using FileCredentialStore which stores credential file.
I believe this line is causing a problem:
FileCredentialStore variantStoreCredentialManager = new FileCredentialStore(expectedClientFile,jsonFactory);
and the error is
java.security.AccessControlException: access denied ("java.io.FilePermission" file path "write")
public Bigquery createAuthorizedClient() throws IOException {
Credential authorization = new GoogleCredential();
if ( clientID == null ) {
authorization = createWebAuthenticatedClientCredential();
} else {
String expectedFileLocation = CREDENTIAL_FILE_PATH;
File expectedClientFile = new File(expectedFileLocation);
if ( ! expectedClientFile.exists() ) {
// this is a known issue, the credential store will blow up if the file doesn't exist. So create it with an
// empty json ( { } )
createClientFile(expectedClientFile);
}
FileCredentialStore variantStoreCredentialManager = new FileCredentialStore(expectedClientFile,jsonFactory);
GoogleCredential.Builder credentialBuilder = new GoogleCredential.Builder();
credentialBuilder.setJsonFactory(jsonFactory);
credentialBuilder.setClientSecrets(clientSecrets);
credentialBuilder.setTransport(transport);
authorization = credentialBuilder.build();
boolean loadedSuccessfully = variantStoreCredentialManager.load(clientID,authorization);
if ( ! loadedSuccessfully ) {
authorization = createWebAuthenticatedClientCredential();
variantStoreCredentialManager.store(clientID, authorization);
}
}
return new Bigquery(transport, jsonFactory, authorization);
}
No, contents of /WEB-INF folder is private to application code and is not accessible via HTTP (= servlet container does not honour requests that try to access data in WEB-INF folder).
Use this snippet to read contents of a file inside a /WEB-INF folder:
InputStream is = getServletContext().getResourceAsStream("/WEB-INF/"+filename);
Then read a stream using one of the methods for reading InputStreams.

Unable to download file from blobstore

I have successfully uploaded a file to blobstore using this code.
But I am unable to download it.
What I am doing is:
`class PartnerFileDownloadHandler(blobstore_handlers.BlobstoreDownloadHandler):
def get(self, blob_key):
resource = str(urllib.unquote(blob_key))
logging.info('I am here.') //This gets printed successfully.
blob_info = blobstore.BlobInfo.get(blob_key)
logging.info(blob_info) //This gets logged too.
self.send_blob(blob_info)`
I have also tried:
blobstore.BlobReader(blob_key).read()
and I get file data in string form but I can not write it to file, as local file system can not be accessed from within a handler, I guess.
The way I am uploading a file is the only way in my project so I can not use the usual way specified in the Google's official tutorial. Also The file I am uploading to blobstore is not present at my local file syatem, I pick it from a URL, perhaps this is the problem why I am not able to download the file.
Any suggestions?
Thanks
Perhaps you should use resource instead of blob_key from your code sample?
class PartnerFileDownloadHandler(blobstore_handlers.BlobstoreDownloadHandler):
def get(self, blob_key):
resource = str(urllib.unquote(blob_key))
self.send_blob(resource)
you can use DownloadHandler as this:
from mimetypes import guess_type
def mime_type(filename):
return guess_type(filename)[0]
class Thumbnailer(blobstore_handlers.BlobstoreDownloadHandler):
def get(self , blob_key):
if blob_key:
blob_info = blobstore.get(blob_key)
if blob_info:
save_as1 = blob_info.filename
mime_type=mime_type(blob_info.filename)
self.send_blob(blob_info,content_type=mime_type,save_as=save_as1)

Grails create downloadable file on the fly

Briefly: I can make a file, save it in the file system and then make a page with a link to that file, but what if I want a page with links to many files which may not all need to be generated?
So my user clicks a link on the list page like:
<g:link action="gimmeAFile" id="${myThingieInstance.id}">${fieldValue(bean: myThingieInstance, field: "id")}</g:link>
Right now I have a controller that looks like this:
def gimmeAFile = {
def lotsaLines = []
//Do a ton of stuff that has lotsaLines.add(resultStrings) all over
def fileName = "blahblah-${dateOrSomething}.csv"
def dumbFile = new File('web-app/tmpfiles/'+fileName).withWriter {out ->
lotsaLines.each{
out.println it
}
}
[fileName:fileName]
}
And then they go to gimmeAFile.gsp which has the link to actually download the file:
Download Report
How do I make a link on the list viewer that will create and download the file without dragging the user to an extra screen. NOTE: I cannot have the files pre-generated, so I need to figure out how to link to a file that isnt there yet. I'm thinking something like render() at the end of the controller. Can I make the gimmeAFile controller just give the file instead of making a page with a link to the file?
OK so to clarify this is what I finally figured out based on Kaleb's answer. Thankyou SO!!
def gimmeAFile = {
def lotsaLines = []
//Do a ton of stuff that has lotsaLines.add(resultStrings) all over
def fileName = "blahblah-${dateOrSomething}.csv"
def dumbFile = new File('web-app/tmpfiles/'+fileName).withWriter {out ->
lotsaLines.each{
out.println it
}
}
def openAgain = new File('web-app/tmpfiles/'+fileName)
response.setContentType("text/csv")
response.setHeader("Content-disposition", "filename=${fileName}")
response.outputStream << openAgain.getBytes()
response.outputStream.flush()
return
}
You can create a view that just gets the bytes of the file and writes out to the response:
response.contentType = 'image/jpeg' // or whatever content type your resources are
response.outputStream << file.getBytes()
response.outputStream.flush()
Is that what you're trying to do?
Another option which is a bit nicer, you can just render the file, straight from your controller's action:
render(file: theFile, contentType: 'your/contentType')
See also: http://grails.org/doc/latest/ref/Controllers/render.html
(I've found that if you add the fileName option, it prompts the user to download the file.)

Resources