Grails Generating a zip file for the user to download - model-view-controller

I am a newbie to grails currently working on a web-app project that works with users uploading pictures. Users can create a "hunt" with a list of prompts. Each "prompt" is the objective for participants (eg: upload pictures of your favorite candy.) Basically the web-app is a "scavenger hunt" tool for Photographers to socially share their work.
Right now, I am having trouble trying write a function in my user controller to generate a zip file with all of the pictures that the user has uploaded. This is what my controller function looks like at the moment.
I used this example I found to start.
Generating a zip file.
def downloadAlbum(){
ByteArrayOutputStream baos = new ByteArrayOutputStream()
ZipOutputStream zipFile = new ZipOutputStream(baos)
//Instance of a user domain class
def userInstance = User.findByLogin(auth.user())
//pictures are uploaded to a prompt and stored as a photoInstance
//this line of code gets the actual file stored as byte[]
photoInstance.myFile = image.getBytes()
//select all photos that belong to the user and store them into a list
def photoInstanceList = userInstance ? Photo.findAllByMyUser(userInstance) : []
//Mapping
[userInstance: userInstance, photoInstanceList: photoInstanceList]
photoInstanceList.each {photo ->
if (photoInstance.myFile != "") {
File file = new File(photoInstance.myFile)
zipFile.putNextEntry(new ZipEntry(Photo.title+".jpeg"))
file.withInputStream { i ->
zipFile << i
}
zipFile.closeEntry()
}
}
zipFile.finish()
response.setHeader("Content-disposition", "filename=\"${login}.zip\"")
response.contentType = "application/zip"
response.outputStream << baos.toByteArray()
response.outputStream.flush()
}
I then use this code in the User view to generate a link that calls the function in the user controller. Am I close? Is there some missing piece in my code?
By the way, This is the first question I have ever written on Stack Overflow. I appreciate the time that you have taken to read this entry. If anything is not clear enough, please where I can improve this question. I am using grails 2.1.1
Thank you for your time!!

If the above code has been copied as is here, shouldn't we be using photo.title instead of Photo.title in the below line
zipFile.putNextEntry(new ZipEntry(Photo.title+".jpeg"))

Related

How to list all children in Google Drive's appfolder and read file contents with Xamarin / c#?

I'm trying to work with text files in the apps folder.
Here's my GoogleApiClient constructor:
googleApiClient = new GoogleApiClient.Builder(this)
.AddApi(DriveClass.API)
.AddScope(DriveClass.ScopeFile)
.AddScope(DriveClass.ScopeAppfolder)
.UseDefaultAccount()
.AddConnectionCallbacks(this)
.EnableAutoManage(this, this)
.Build();
I'm connecting with:
googleApiClient.Connect()
And after:
OnConnected()
I need to list all files inside the app folder. Here's what I got so far:
IDriveFolder appFolder = DriveClass.DriveApi.GetAppFolder(googleApiClient);
IDriveApiMetadataBufferResult result = await appFolder.ListChildrenAsync(googleApiClient);
Which is giving me the files metadata.
But after that, I don't know how to read them, edit them or save new files. They are text files created with my app's previous version (native).
I'm following the google docs for drive but the Xamarin API is a lot different and has no docs or examples. Here's the API I'm using: https://components.xamarin.com/view/googleplayservices-drive
Edit:
Here is an example to read file contents from the guide:
DriveFile file = ...
file.open(mGoogleApiClient, DriveFile.MODE_READ_ONLY, null)
.setResultCallback(contentsOpenedCallback);
First I can't find anywhere in the guide what "DriveFile file = ..." means. How do I get this instance? DriveFile seems to be a static class in this API.
I tried:
IDriveFile file = DriveClass.DriveApi.GetFile(googleApiClient, metadata.DriveId);
This has two problems, first it complains that GetFile is deprecated but doesn't say how to do it properly. Second, the file doesn't have an "open" method.
Any help is appreciated.
The Xamarin binding library wraps the Java Drive library (https://developers.google.com/drive/), so all the guides/examples for the Android-based Drive API work if you keep in mind the Binding's Java to C# transformations:
get/set methods -> properties
fields -> properties
listeners -> events
static nested class -> nested class
inner class -> nested class with an instance constructor
So you can list the AppFolder's directory and files by recursively using the Metadata when the drive item is a folder.
Get Directory/File Tree Example:
await Task.Run(() =>
{
async void GetFolderMetaData(IDriveFolder folder, int depth)
{
var folderMetaData = await folder.ListChildrenAsync(_googleApiClient);
foreach (var driveItem in folderMetaData.MetadataBuffer)
{
Log.Debug(TAG, $"{(driveItem.IsFolder ? "(D)" : "(F)")}:{"".PadLeft(depth, '.')}{driveItem.Title}");
if (driveItem.IsFolder)
GetFolderMetaData(driveItem.DriveId.AsDriveFolder(), depth + 1);
}
}
GetFolderMetaData(DriveClass.DriveApi.GetAppFolder(_googleApiClient), 0);
});
Output:
[SushiHangover.FlightAvionics] (D):AppDataFolder
[SushiHangover.FlightAvionics] (F):.FlightInstrumentationData1.json
[SushiHangover.FlightAvionics] (F):.FlightInstrumentationData2.json
[SushiHangover.FlightAvionics] (F):.FlightInstrumentationData3.json
[SushiHangover.FlightAvionics] (F):AppConfiguration.json
Write a (Text) File Example:
using (var contentResults = await DriveClass.DriveApi.NewDriveContentsAsync(_googleApiClient))
using (var writer = new OutputStreamWriter(contentResults.DriveContents.OutputStream))
using (var changeSet = new MetadataChangeSet.Builder()
.SetTitle("AppConfiguration.txt")
.SetMimeType("text/plain")
.Build())
{
writer.Write("StackOverflow Rocks\n");
writer.Write("StackOverflow Rocks\n");
writer.Close();
await DriveClass.DriveApi.GetAppFolder(_googleApiClient).CreateFileAsync(_googleApiClient, changeSet, contentResults.DriveContents);
}
Note: Substitute a IDriveFolder for DriveClass.DriveApi.GetAppFolder to save a file in a subfolder of the AppFolder.
Read a (text) File Example:
Note: driveItem in the following example is an existing text/plain-based MetaData object that is found by recursing through the Drive contents (see Get Directory/File list above) or via creating a query (Query.Builder) and executing it via DriveClass.DriveApi.QueryAsync.
var fileContexts = new StringBuilder();
using (var results = await driveItem.DriveId.AsDriveFile().OpenAsync(_googleApiClient, DriveFile.ModeReadOnly, null))
using (var inputStream = results.DriveContents.InputStream)
using (var streamReader = new StreamReader(inputStream))
{
while (streamReader.Peek() >= 0)
fileContexts.Append(await streamReader.ReadLineAsync());
}
Log.Debug(TAG, fileContexts.ToString());

How to Grab an image file from Parse

So i've tried looking over the documentation and cant make heads or tails of it... so i'm hoping someone here can help:
so i've created a ParseFile with an image stored in a byte[]. I've saved this parsefile and then assigned it into a parseObject. I have then saved the parseObject
profilePicFile = new ParseFile( "profilePic.png", bytes);
Task saveProfilePic = profilePicFile.SaveAsync();
yield return saveProfilePic;
user["Profile_Pic"] = profilePicFile;
Task updateUser = user.SaveAsync();
Then i've made a temporary button just to check that this works. I've assigned it a new script. Basically when I hit the button, I just want it to grab the user, and its profile_pic and tell me if there is something there.
ParseObject receivedUser = new ParseObject("ReceivedUser");
ParseQuery<ParseObject> query = ParseObject.GetQuery("User");
query.GetAsync("DwRfTQ66tA").ContinueWith(t =>
{
receivedUser = t.Result;
});
if (receivedUser.IsDataAvailable == true) {
print ("getting data");
byte[] data = receivedUser.Get<byte[]> ("Profile_Pic");
} else {
print ("no user");
}
}
Am I doing this right? Do i need to re-initialise anything? Do I need to add the other script component to this or use Getcomponent to get the user data? (I dont think so since the ParseUser object is supposed to be a static right?). Or does this script need to re-log in to grab data from Parse?
currently the error i'm getting is KeyNotFoundException.
I deff have a User Class on parse and a Profile_Pic column. I'm using the object ID as the reference. Is this correct?
Instead of
ParseObject.GetQuery("User")
you should be using:
ParseUser.Query

How to use imgscalr using Grails

I've just begun using Groovy and Grails the last few days. I don't have any prior experience of Java, so you'll have to excuse this (probably) very basic question. I've searched Google and Stack Overflow and haven't found anything that helps me with the actually installation.
I have got an image upload working, and I am storing the file on the server. I used a IBM Grails tutorial to guide me through it. That works fine.
I would also like to resize the file in a large, medium, and small format. I wanted to use imgscalr for this, but I cant get it to work. I have downloaded version 4.2 which contains various .jar files. Do I need to put these somewhere on the server and reference them? The only thing I've done is add these lines to buildConfig.groovy
dependencies {
// specify dependencies here under either 'build', 'compile', 'runtime', 'test' or 'provided' scopes eg.
// runtime 'mysql:mysql-connector-java:5.1.20'
compile 'org.imgscalr:imgscalr-lib:4.2'
}
and import org.imgscalr.Scalr.* in my PhotoController.Groovy
Here's my code for saving the file onto the server, I would also like to resize and save the image.
def save() {
def photoInstance = new Photo(params)
// Handle uploaded file
def uploadedFile = request.getFile('photoFile')
if(!uploadedFile.empty) {
println "Class: ${uploadedFile.class}"
println "Name: ${uploadedFile.name}"
println "OriginalFileName: ${uploadedFile.originalFilename}"
println "Size: ${uploadedFile.size}"
println "ContentType: ${uploadedFile.contentType}"
def webRootDir = servletContext.getRealPath("/")
def originalPhotoDir = new File(webRootDir, "/images/photographs/original")
originalPhotoDir.mkdirs()
uploadedFile.transferTo(new File(originalPhotoDir, uploadedFile.originalFilename))
BufferedImage largeImg = Scalr.resize(uploadedFile, 1366);
def largePhotoDir = new File(webRootDir, "/images/photographs/large")
largePhotoDir.mkdirs()
photoInstance.photoFile = uploadedFile.originalFilename
}
if (!photoInstance.hasErrors() && photoInstance.save()) {
flash.message = "Photo ${photoInstance.id} created"
redirect(action:"list")
}
else {
render(view:"create", model:[photoInstance: photoInstance])
}
}
The error I'm getting is No such property: Scalr for class: garethlewisweb.PhotoController
I'm obviously doing something very wrong. Any guidance appreciated.
This is the first google result for "How to use imgscalr in grails" and I was surprised with the lack of informations and examples when googling it. Although the first answer is close, there's still a few mistakes to be corrected.
To anyone that ended here like me through google, heres a more detailed example of how to correctly use this nice plugin:
First, declare the plugin in your BuildConfig.groovy file:
dependencies {
// specify dependencies here under either 'build', 'compile', 'runtime', 'test' or 'provided' scopes eg.
// runtime 'mysql:mysql-connector-java:5.1.20'
compile 'org.imgscalr:imgscalr-lib:4.2'
}
Then, after installed, just paste this piece of code in your controller, in the action that receives the multi-part form with the image uploaded.
def create() {
def userInstance = new User(params)
//saving image
def imgFile = request.getFile('myFile')
def webRootDir = servletContext.getRealPath("/")
userInstance.storeImageInFileSystem(imgFile, webRootDir)
(...)
}
Inside my domain, I implemented this storeImageInFileSystem method, that will resize the image and store it in the filesystem. But first, import this to the file:
import org.imgscalr.Scalr
import java.awt.image.BufferedImage
import javax.imageio.ImageIO
And then, implement the method:
def storeImageInFileSystem(imgFile, webRootDir){
if (!imgFile.empty)
{
def defaultPath = "/images/userImages"
def systemDir = new File(webRootDir, defaultPath)
if (!systemDir.exists()) {
systemDir.mkdirs()
}
def imgFileDir = new File( systemDir, imgFile.originalFilename)
imgFile.transferTo( imgFileDir )
def imageIn = ImageIO.read(imgFileDir);
BufferedImage scaledImage = Scalr.resize(imageIn, 200); //200 is the size of the image
ImageIO.write(scaledImage, "jpg", new File( systemDir, imgFile.originalFilename )); //write image in filesystem
(...)
}
}
This worked well for me. Change any details as the need, like the system diretory or the size of the image.
Instead of
import org.imgscalr.Scalr.*
You want
import org.imgscalr.Scalr
import javax.imageio.ImageIO
Then resize needs a BufferedImage (looking at the JavaDocs), so try:
def originalPhotoDir = new File(webRootDir, "/images/photographs/original")
originalPhotoDir.mkdirs()
def originalPhotoFile = new File(originalPhotoDir, uploadedFile.originalFilename)
uploadedFile.transferTo( originalPhotoFile )
// Load the image
BufferedImage originalImage = ImageIO.read( originalPhotoFile )
// Scale it
BufferedImage largeImg = Scalr.resize(uploadedFile, 1366);
// Make the destination folder
def largePhotoDir = new File(webRootDir, "/images/photographs/large" )
largePhotoDir.mkdirs()
// Write the large image out
ImageIO.write( largeImg, 'png', new File( largePhotoDir, uploadedFile.originalFilename )
Of course, you'll have to watch for files overwriting already existing images
Put the jar file(s) in the 'lib' directory of your Grails application. You may then delete that line from BuildConfig.groovy

Generate a pdf file and send after querying database for a pass mark

My project is almost done, and thanks to stackoverflow. Now that I have managed to capture Users details and their certificates, I am looking for a way to generate pdf which I will send to those who passed.
I am not looking for the code at the moment. I have an asp.net mvc 3 application which shows Certificates details for my students. Now I want the certificates to be generated then sent by email, all this automated.
First I would like help on how I can generate a pdf from database values and sending the generated pdf wont be a problem.
Using iTextSharp, this code will create and serve a PDF:
public FileStreamResult DownloadPDF()
{
MemoryStream workStream = new MemoryStream();
using(Document document = new Document())
{
PdfWriter.GetInstance(document, workStream).CloseStream = false;
document.Open();
document.SetPageSize(PageSize.LETTER);
document.SetMargins(12, 12, 8, 7);
document.NewPage();
// Create a new Paragraph object with the text, "Hello, World!"
var welcomeParagraph = new Paragraph("Hello, World!");
// Add the Paragraph object to the document
document.Add(welcomeParagraph);
// This is where your data would go
document.Close();
}
workStream.Position = 0;
FileStreamResult fileResult = new FileStreamResult(workStream, "application/pdf");
fileResult.FileDownloadName = "test.pdf";
return fileResult;
}
For more information see Creating PDF Documents with ASP.NET and iTextSharp
There are a lot of tutorials online, but this should get you started.

BackgroundTransferRequest WP7

I am using the Background Transfer to upload Photographs to my Web Service. As the Photograph uploads can consume significant time and memory, I thought it might be a nice idea to use the background transfer request to accomplish this. After the photo is uploaded, I want to obtain the Id of the uploaded photo and then use it for post-processing. However, it turns out I can't do that in a background transfer request.
Per my understanding, Background Transfer works using the following logic ONLY:
You have to obtain the file you want to upload and then save/copy it to your app's Isolated Storage under the folder: shared/transfers. This is extremely important. Apparently, using file in a different location didn't work for me. Maybe it isn't the shared/transfers as much as it is a 'relative' path. But I would stick to the same conventions.
After you have saved the file in that location, your background request can be created based on that. It doesn't look like you can pass POST CONTENT other than the file contents, so any other parameters like file name, mime type etc. will need to be passed as QUERY String parameters only. I can understand this, but it would've been nice if I could pass both as POST Content. I don't think HTTP has a limitation on how this works.
Here is some code for creating a request using Hammock:
string url = App.ZineServiceAuthority + "articles/save-blob?ContainerName={0}&MimeType={1}&ZineId={2}&Notes={3}&IsPrivate={4}&FileName={5}";
url = String.Format(url, userId, "image/jpg", ZineId, txtStatus.Text, true, UploadFileName);
var btr = new BackgroundTransferRequest(new Uri(url, UriKind.Absolute));
btr.TransferPreferences = TransferPreferences.AllowCellularAndBattery;
btr.Method = "POST";
btr.Headers.Add("token", IsolatedStorageHelper.GetTravzineToken());
btr.UploadLocation = new Uri(#"/shared\transfers/" + UploadFileName, UriKind.Relative);
btr.TransferStatusChanged += new EventHandler<BackgroundTransferEventArgs>(btr_TransferStatusChanged);
btr.TransferProgressChanged += new EventHandler<BackgroundTransferEventArgs>(btr_TransferProgressChanged);
BackgroundTransferService.Add(btr);
In my case, I am literally passing all the necessary parameters using the query string. On a successful save, my Web Service returns back the Id of the Photo I just uploaded. However:
There is NO way (or at least I know of) to obtain and evaluate the RESPONSE. The Background Transfer Request Event handlers do not expose a RESPONSE.
Here are my event handlers:
void btr_TransferProgressChanged(object sender, BackgroundTransferEventArgs e)
{
bool isUploading = e.Request.TotalBytesToSend > 0 ? true : false;
lblStatus.Text = isUploading ? "Uploading" + e.Request.BytesSent.ToString() + " sent" : "Done";
}
void btr_TransferStatusChanged(object sender, BackgroundTransferEventArgs e)
{
if (e.Request.TransferStatus == TransferStatus.Completed)
{
using (IsolatedStorageFile iso =
IsolatedStorageFile.GetUserStoreForApplication())
{
if (iso.FileExists(e.Request.UploadLocation.OriginalString))
iso.DeleteFile(e.Request.UploadLocation.OriginalString);
}
BackgroundTransferService.Remove(e.Request);
if (null != e.Request.TransferError)
{
MessageBox.Show(e.Request.TransferError.Message);
}
else
{
lblStatus.Text = "Done baby done";
}
}
}
So now my question is, how does anyone do any sort of POST Processing in such scenarios?
Can anyone please tell me the line of thought behind designing such an inflexible class?
Any thoughts on how I could get around this issue would be appreciated.
Also, does anyone have any working examples of a homegrown BackgroundTransfer?
Haven't tried it but why not set a download location like this:
btr.DownloadLocation = "myDownloadFile.html";
btr.UploadLocation = "myUploadFile.jpg";
...
If the request is completed read the file "myDownloadFile.html" where your response has been stored and delete it afterwards.

Resources