so I am working on a school project in which we have designed a web application that takes in much user info and creates a pdf then should display that pdf to the user so they can print it off or save it. We are using Play! Framework 2.1.3 as our framework and server and Java for the server side. I create the pdf with Apache's PDFbox library. Every thing works as it should in development mode ie launching it on a localhost with plays run command. the issue is when we put it up to the server and launch with plays start command I it seems to take a snapshot of the directory (or at least the assets/public folder) which is where I am housing the output.pdf file/s (i have attempted to move the file elsewhere but that still seems to result in a 404 error). Initially I believed this to be something with liunx machine we were deploying to which was creating a caching problem and have tried many of the tricks to defeat the browser from caching the pdf
like using javascript to append on a time stamp to the filename,
using this cache-control directive in the play! documentation,
"assets.cache./public/stylesheets/output.pdf"="max-age=0",
then I tried to just save the pdf as a different filename each time and pass back the name of that file and call it directly through the file structure in the HTML
which also works fine with the run command but not the start.
finally I came to the conclusion that when the start command is issued it balls up the files so only the files that are there when the start command is issued can be seen.
I read the documentation here
http://www.playframework.com/documentation/2.1.x/Production
which then I noticed this part
When you run the start command, Play forks a new JVM and runs the
default Netty HTTP server. The standard output stream is redirected to
the Play console, so you can monitor its status.
so it looks like the fact that it forks a new JVM is what is causing my pain.
so my question really is can this be gotten around in some way that a web app can create and display a pdf form? (if I cannot get this to work my only solution
that I can see is that I will have to simulate the form with HTML and fill it out from there) --which I really think is a bad way to do this.
this seems like something that should have a solution but I cannot seem to find or come up with one please help.
i have looked here:
http://www.playframework.com/documentation/2.1.x/JavaStream
the answer may be in there but Im not getting it to work I am pretty novice with this Play! Framework still
You are trying to deliver the generated PDF file to the user by placing it in the assets directory, and putting a link to it in the HTML. This works in development mode because Play finds the assets in the directory. It won't work in production because the project is wrapped up into a jar file when you do play dist, and the contents of the jar file can't be modified by the Play application. (In dev mode, Play has a classpath entry for the directory. In production, the classpath points to the jar file).
You are on the right lines with JavaStream. The way forward is:
Generate the PDF somewhere in your local filesystem (I recommend the temp directory).
Write a new Action in your Application object that opens the file you generated, and serves it instead of a web page.
Check out the Play docs for serving files. This approach also has the advantage that you can specify the filename that the user sees. There is an overloaded function Controller.ok(File file, String filename) for doing this. (When you generate the file, you should give it a unique name, otherwise each request will overwrite the file from a previous request. But you don't want the user to see the unique name).
Related
I can't get the Google API to find my service account's credentials. I downloaded the necessary JSON file with the right name into the proper place, and I'm using Python code straight off the API documentation:
import gspread
gc = gspread.service_account()
sh = gc.open("Example spreadsheet (I'll replace this with my actual sheet name later)")
print(sh.sheet1.get('A1'))
The code stops at gc = gspread.service_account() with a FileNotFoundError. I discovered via an error message that this is because it's looking at the complete wrong file path (I think it's thinking I'm on a Mac when I'm actually on a Windows PC??). Overriding the file name, i.e.
gc = gspread.service_account(filename="insert\actual\path\here.json"),
does not work either, which is the mystifying part. I copied that path straight out of my file explorer, doubled the backslashes so Unicode doesn't try to escape it all (that happened once), tried every modification on the file path I could think of (%APPDATA%\gspread\service_account.json instead of the whole thing, etc.) - what could be going wrong?
Edit: #mods, feel free to close the question! I found the issue, which is that I was using the Repl.it online coding environment instead of a local one. I ported everything over to IDLE and it worked fine. I strongly suspect Repl.it just couldn't access my local files at all (I also tried it on Repl.it with a random screenshot in a different place, and it threw the same error).
I have a WebAPI service, written in ASP.NET (not Core), for which I am trying to generate documentation, in order to allow other devs to use it. I found Swashbuckle, and installed it. Then, since I also use OData for some of my services, I added Swashbuckle.OData. Then, I modified the CustomProvider setting in SwaggerConfig to use the ODataSwaggerProvider. I also set ResolveConflictingActions(apiDescriptions => apiDescriptions.First()) because I had a few Actions with the same URL path, differing only by query string (I'll need to address that later). So far so good.
Then, I tested it. I started my web app, then added "/swagger/" to then end. I got a message stating that it was loading the resource info. However, after several minutes, I got a browser error debug popup, stating "Error: Not enough storage is available to complete this operation." It asks if I want to debug, and if I do, it takes me to the debugger in IE (the browser I'm using). The only code in the stack is either from jquery-1-8-0-min-js or swagger-ui-min-js (this part confuses me, as there is no "swagger-ui-min-js" file in my project; I'm assuming it's embedded in the dll). There is no part of the stack trace that floats back up to my code, and all the code there is minified, so it's very difficult to debug.
However, I do know that it is at least partially working, as three of the controllers do show up in the resulting page after you close the error popup. You can navigate through them, and all the GETs, POSTs, PUTs, and DELETEs seem to be there, and you can test them.
Is it the case that whenever you navigate to the "/swagger/" url, Swagger hits all the URLs in the service, in order to generate the documentation? I'm wondering if maybe it is hitting an action that is taking a particularly long time to run, or possibly its generated documentation is taking too much disk space (I have plenty of space on my disk, but maybe it is referring to RAM?).
Anyway, even if that were not an issue, how can I get it to generate something, some kind of document file, that I can send off to someone? I see no new files added to my folders, so it would seem that it re-does the whole process every time you navigate to the swagger URL.
When I tried the Chrome browser, I no longer had the issue (I was using IE11 before). Not sure what the problem was, but this was the workaround.
I am developing an application in ServiceStack and am trying to sort out deployment on AppHarbor, however for some reason my web.config transforms are not being applied.
I had originally a Web.AppHarbor.config file and changed the Environment Setting to "AppHarbor" - once this failed to work after several updates, I gave up and changed the Environment setting to "Release" and copied the desired transformations into the Web.Release.Config file.
App gets deployed OK but config settings do not reflect the values in the transform file (I verify this by login on with twitter and seeing the callback url for Twitter Auth still tries to redirect me to localhost, which is one of the settings I change in my transform file)
I have also tried the transform tester tool and all works as expected.
Manually publishing the web application to a local folder correctly applies the transformations according to the selected configuration
Does anyone have this working? Is there something obvious I'm missing?
Thanks
It sounds like the Web.Release.config file is not included in the build output. You need to set the Build Action attribute to Content to include it in the build output.
You can confirm whether the file is included in the output by downloading the build from the log page.
I stumbled across this post because I was seeing the same lack of action myself. Upon closer inspection (about 15 times that is) of my Web.Release.config I realized one of the nodes in my config file was not marked xdt:Transform="Replace". Unsurprisingly it did nothing when deployed.
I have had some experience writing container-bound scripts, but am totally new to web apps.
How do I debug (e.g. look at variable values, step through code etc) a web app? In a container bound script it was easy, because I could set breakpoints, use the apps script debugger - how do I go about this in a web page e.g. when I execute a doPost?
In his excellent book "Google Script", James Ferreira advocates setting up your own development environment with three browser windows; one for the code, one for the live view (in Publish, Deploy as web app, you are provided with a "latest code" link that will update the live view to the latest save when it is refreshed), and one for a spreadsheet that logs errors (using try/catch wrapped around bits of code you want to keep an eye on).
In Web Apps, even the most basic debugging of variables through Logger.log() does not work!
A great solution to have at least simple variable logging available is Peter Herrmann's BetterLog for Apps Script. It allows you to log into a spreadsheet (the same as your working spreadsheet or a separate one).
Installation is very simple - just add an external resource (see the Github readme) and a single line of code to override the standard Logger object:
Logger = BetterLog.useSpreadsheet('your-spreadsheet-key-goes-here');
Remember, that the spreedsheet that you give here as a parameter will be used for the logging output and thus must be writable by anybody!
BetterLog will create a new sheet called "Log" in the given spreadsheet and will write each log call into a separate row of that sheet.
So, for me, I debug the front-end using inspector, I haven't found a way to step through code yet, but you can use 'debugger' in your javascript (along with console.log) to stop the code and check variables.
to debug the backend, what I've been doing is to write my functions like
function test_doSomething(){
payload = "{item1: 100, item2: 200}" //<- copy paste from log file
backend_doSomething(payload)
}
function backend_doSomething(payload){
Logger.log(payload)
params = JSON.parse(payload)
...
}
Then after refreshing your project on the backend, you can look at executions, grab the payload from the log file, and paste it into your test_doSomething() function.
From there, you are re-creating the call that you want to debug and you can run that, stepping through the backend code as usual.
What is the best practice when serving files from the Zend Framework MVC? These files have to be served from the MVC as they are protected.
I know you can read in the file and place it into the Response object but this seems like a bad practice as you would be reading the entire file into memory then serving it. Right now I usually do:
header('Content-type: image/jpeg');
fpassthru(fopen($path, 'rb'));
exit;
But this also doesn't seem right as I'm stopping the execution of the script. Any suggestions?
I see nothing wrong with just exit(); What you will need to be careful of is any output buffering layers you may have on (gzip compression, etc). Large files could blow up those buffers pretty quick, so you'll want to close them out and potentially 'chunk' your output with a fopen/fread loop.
I would suggest building a super-simple script for retrieving files based on ticket system like in CMS you generate ticket to DB - filename, unique-hash and than redirect to the super-simple file-retieving script (file.php?hash=asd52ad3as1g5). It will get the hash from query and based on it fetch the real filename and push that to output as you have written using fpassthru. The hash need to be unique and hard to guess...
You could try using the X-Sendfile header. It is supported by lighttpd and newer versions of apache. Basically the webserver will replace the output of the script with the file you specified. The downside being that it is specific to the configuration of the webserver, so you may be on a host that doesn't support it.