play framework reading file from conf folder with routing - scala

I have a web application with play framework. All images used in the application are kept in public folder and are accessed with the help of a routing defined in the conf/route file. So all the images I used are present in a jar file after build. But my requirement is that the admin will be placing few images that the UI should be able to access. For obvious reasons I can ask them to add images into the jar.
My plan is to ask the admin to add images to a folder inside the conf folder and read it from there using routing (I believe its possible because currently there is a routing defined that's reading a json from the config file).
# Home page
GET / controllers.Application.index
GET /clientConfig controllers.Application.clientConfiguration
GET /testImg controllers.Application.testImg
# Map static resources from the /public folder to the /assets URL path
GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset)
Being totally new to Play framework I can't figure out a way to define routes for that and read images from a folder inside the conf folder . Any help is highly appreciated.

conf folder is a configuration folder so it's not a good idea to expose it as a public folder. For example from security perspective the application.conf or the database migration files contain sensitive data that shouldn't be accessible on any api endpoint.
What you could do is add an additional root folder to the public managed resources for example create a folder called publicImages in the root folder and add the following line to build.sbt
unmanagedResourceDirectories in Assets += baseDirectory.value / "publicImages"
Also remember that adding images to a folder on the deployed server means you won't be able to cluster, i.e. add additional nodes if/when load grows. So your best option is to use some 3rd party storage service, e.g. amazon s3 (it's pretty simple for the admin to upload images to a folder on s3)
If however you insist on adding the images to conf folder, what you could do is create a standard controller that accepts file name in its parameters (path) and stream the content of that file from the conf folder using
Play.getFile('conf/{myfile}') just make sure to enforce some security constraints like verifying no path is provided so malicious user can't traverse the machine's file system. And support only predefined 'safe' file types like images.

As LiorH said, it's usually not a good idea to expose conf folder to public. But if this is really what you want, then you can try to implement your own controller.
In your route file:
GET /configuration ConfController.loadConf(path)
In ConfController:
def loadConf(path: String) = Action {
Ok.sendFile(Play.getFile("conf$path"))
}

Related

How to remove "public" from the root directory access link?

i'am new to the hosting/c-panel stuff, and i got a laravel based app installed on my godaddy hosting, the problem is that the application require some files that are placed on the root directory of the server for example http://server.com/images/ajax-loader.gif and the file is placed just there
but when i type the link http://server.com/images/ajax-loader.gif it doesn't find it:
so i need to add a public like http://server.com/public/images/ajax-loader.gif like:
the problem is that the entire app needs to be modified to add a public for every file like that, so is there any way i can access the root folder without adding this /public/ ?
Have you contacted the hosting provider? Usually, they help with these kinds of issues.
Do other images from your 'images' directory load fine? If all images in the images directory do not load in the browser, that indicates either a permission issue or some .htaccess settings. Again needs to be checked at the hosting provider end.

How to keep application files in sails js

I am developing sails js application.I stuck with small thing.I want to keep some application files with specific folder.
Thing is when we access that folder ,Some files inside that folder can be downloadable.How can i deploy it...?
Folder called applicationData
where should i keep that folder ..? how to access that folder..?
assets
-applicationData
-images
-js
is that correct way ..? if it is correct then how can i access ..?
This is best way to access applicationData folder
sails.config.appPath + '/api/applicationData/'
when we create folder in assets it will go the .tmp/public
I suppose most suitable place in api folder

Reading files from directory in Play framework on Heroku

I have a directory with deep structure (lot of sub-directories and files) that I read from my play application. On my PC I read the directory using -
val directory = Play.getFile("directory")
for(file <- directory.listFiles) {
val lines = Source.fromFile(file).getLines()
}
This works perfectly on my PC but not on Heroku. On Heroku I get a NPE on line#2 (above code) which means that the directory object is not getting made.
This suggestion of a similar issue suggests that I could put my directory in public and read it as using the Play.resource API. But I DONT want to put my directory in public. And I have a need to list the contents of a directory as it could be changing... how can I do this in Play on Heroku?
As this suggests,in order to make Play.getFile("location_from_project_root") (or any other similar one) working in production environment, you have to explicitly ask from play to add the directory where you put the file ,to the dist.
Ex:
You want to access a file Project_Root/resources/mtFile.json, (inside /resources folder you created), you can use Play.getFile("/resources/mtFile.json")method.
But in order to make it works in any production environment, you have to add /resources folder to the dist. Otherwise that file will not be there. In order to do that you have to add these lines into your build.sbt file.
import com.typesafe.sbt.packager.MappingsHelper._
mappings in Universal ++= directory(baseDirectory.value / "resources")
Now, if you take a dist using activator dist command you can see that a directory called /resources has added into the root of the dist. Now Play.getFile("/resources/mtFile.json") should work in production environment.
Play.getFile(relativePath) retrieves a file relative to the current app's root path. Current app's root path may not be same on your PC and Heroku.
One more thing: Your statement that the directory object is not getting made is not true. listFiles operation is throwing NPE in your case.
Try this to get a list of files from your directory:
val listOfFilesInDirectory: List[java.io.File] = Option(getClass.getResource("/directory")).map(_.toURI).map(new java.io.File(_)).map(_.listFiles).flatten.toList
You can put your files under your conf folder, so that the files are not publicly available. Then use :
Play.resource("conf/directory"): Option[URL]
or
Play.resourceAsStream("conf/directory"): Option[InputStream]

Servlet cannot find the file I'm trying to open

I read that the servlets map the current location based on the url. Clicking a button from my Home.jsp page directs me to my servlet, ExcelUploader. The URL when said button is clicked is
http://localhost:8080/ServletExample/ExcelUploader
I'm trying to open an excel file located in the same folder as my JSP. so that means I have to move one folder up relative to the url above. I have this in my servlet:
InputStream inp = new FileInputStream("../OpenMe.xls");
However I'm still getting a
java.io.FileNotFoundException: ..\OpenMe.xls (The system cannot find the file specified)
This is how my project is setup:
The FileInputStream operates on the local disk file system relative to the working directory and knows absolutely nothing about the fact that it's invoked from a Java EE web application. Any relative path you pass to it is relative to the folder which was been opened at the moment the command to start the server is executed. This is often the server's own installation folder, but in case of an IDE this can also be project's own root folder. This variable is not controllable from inside your Java code. You should not be relying on that.
You've stored the file as a resource of the public webcontent. So it's available as a webcontent resource by ServletContext#getResourceAsStream() which returns an InputStream. If you have absolutely a legitimate reason to invoke the servlet by its URL instead of just using the file's own URL http://localhost:8080/ServletExample/OpenMe.xls, then you should be getting at as follows:
InputStream input = getServletContext().getResourceAsStream("/OpenMe.xls");
// ...
If your intent is indeed to restrict the file's access to by the servlet only, you might want to consider to move the file into the /WEB-INF folder, so that the enduser can never open it directly by entering the file's own URL. You only need to change the resource path accordingly.
InputStream input = getServletContext().getResourceAsStream("/WEB-INF/OpenMe.xls");
// ...
You should not be using getRealPath() as suggested by the other answer. This won't work when the servletcontainer is configured to expand the WAR file into memory instead of into local disk file system, which is often the case in 3rd party hosts. It would return null then.
See also:
getResourceAsStream() vs FileInputStream
Paths for files that live in the webtree have to be "translated" using getRealPath before they are usable, like this:
File excelFile = new File(getServletContext().getRealPath("/OpenMe.xls"));
While you're at it, using the default package isn't a good idea, create a package for your files.

Configuration and content management with automated deployment tools for ZF based app

I am trying to automate deployments of a particular project and a bit lost as to who to handle config file as well as user assets.
(Application is based on Zend Framework based btw).
Main application folder is structured as follows:
./app
./config.ini <----- config file
./modules
./controllers
./models
./views
./libs
./public
That config file is where all the configs are stored.
So 'app' folder contains whole bunch of code in PHP and 'public' contains whole bunch of code in JavaScript, HTML/CSS and stuff like that(web accessible basically).
If I follow Capistrano's model, where each package is expanded into it's own folder that is then symlinked to, how do I handle that config.ini file?
What about all the user content that is uploaded into ./public folder?
Thanks!
The Capistrano approach to this is to have a structure like this on your remote server:
releases/
20100901172311/
20101001101232/
[...]
current/ (symlink to current release)
shared/
in the shared directory you include your config file and any user generated content (e.g. shared/files). Then on each deployment, once you've checked out the code you automatically create symlinks from the checkout into your relevant shared directories. E.g.:
releases/20101001101232/public/files -> shared/files
releases/20101001101232/application/configs/config.ini -> shared/config.ini
that way, when a user uploads a file to public/files it is actually being stored in shared/files.