From 70195632f87cd8fb2bc547653c4c57e7c7a97525 Mon Sep 17 00:00:00 2001 From: NMerz Date: Sun, 29 Nov 2020 15:19:10 -0500 Subject: [PATCH] Store Profile Picture on AWS Save the profile picture to AWS so that the user need not retrieve it every time. --- Lambdas/Lists/Picture/src/Picture.java | 34 +++++ Lambdas/Lists/Picture/src/PictureGET.java | 12 ++ Lambdas/Lists/Picture/src/PictureGetter.java | 34 +++++ Lambdas/Lists/Picture/src/PicturePUT.java | 11 ++ Lambdas/Lists/Picture/src/PicturePutter.java | 28 +++++ .../com/example/listify/MainActivity.java | 116 +++++++++++++++++- .../com/example/listify/data/Picture.java | 24 ++++ 7 files changed, 254 insertions(+), 5 deletions(-) create mode 100644 Lambdas/Lists/Picture/src/Picture.java create mode 100644 Lambdas/Lists/Picture/src/PictureGET.java create mode 100644 Lambdas/Lists/Picture/src/PictureGetter.java create mode 100644 Lambdas/Lists/Picture/src/PicturePUT.java create mode 100644 Lambdas/Lists/Picture/src/PicturePutter.java create mode 100644 Listify/app/src/main/java/com/example/listify/data/Picture.java diff --git a/Lambdas/Lists/Picture/src/Picture.java b/Lambdas/Lists/Picture/src/Picture.java new file mode 100644 index 0000000..f4e5fae --- /dev/null +++ b/Lambdas/Lists/Picture/src/Picture.java @@ -0,0 +1,34 @@ +import java.sql.ResultSet; +import java.sql.SQLException; + +public class Picture { + String base64EncodedImage; + + public Picture(ResultSet rs) { + try { + this.base64EncodedImage = rs.getString("base64image"); + } catch (SQLException throwables) { + throwables.printStackTrace(); + this.base64EncodedImage = null; + } + } + + public Picture(String base64EncodedImage) { + this.base64EncodedImage = base64EncodedImage; + } + + @Override + public String toString() { + return "Picture{" + + "base64EncodedImage='" + base64EncodedImage + '\'' + + '}'; + } + + public String getBase64EncodedImage() { + return base64EncodedImage; + } + + public void setBase64EncodedImage(String base64EncodedImage) { + this.base64EncodedImage = base64EncodedImage; + } +} diff --git a/Lambdas/Lists/Picture/src/PictureGET.java b/Lambdas/Lists/Picture/src/PictureGET.java new file mode 100644 index 0000000..e5787dd --- /dev/null +++ b/Lambdas/Lists/Picture/src/PictureGET.java @@ -0,0 +1,12 @@ +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.RequestHandler; + +import java.util.Map; + +public class PictureGET implements RequestHandler, Object> { + + public Object handleRequest(Map inputMap, Context unfilled) { + return BasicHandler.handleRequest(inputMap, unfilled, PictureGetter.class); + } + +} \ No newline at end of file diff --git a/Lambdas/Lists/Picture/src/PictureGetter.java b/Lambdas/Lists/Picture/src/PictureGetter.java new file mode 100644 index 0000000..136e926 --- /dev/null +++ b/Lambdas/Lists/Picture/src/PictureGetter.java @@ -0,0 +1,34 @@ +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; + +public class PictureGetter implements CallHandler { + private final Connection connection; + private final String cognitoID; + + private final String GET_ITEM = "SELECT * FROM Pictures WHERE cognitoID = ?;"; + + public PictureGetter(Connection connection, String cognitoID) { + this.connection = connection; + this.cognitoID = cognitoID; + } + + @Override + public Object conductAction(Map bodyMap, HashMap queryMap, String cognitoID) throws SQLException { + PreparedStatement statement = connection.prepareStatement(GET_ITEM); + if (!queryMap.get("id").toString().equals("profile")) { + throw new IllegalArgumentException("Only profile pictures are currently supported."); + } + statement.setString(1, cognitoID); + System.out.println(statement); + ResultSet queryResults = statement.executeQuery(); + queryResults.first(); + System.out.println(queryResults); + Picture retrievedPicture = new Picture(queryResults); +// System.out.println(retrievedPicture); + return retrievedPicture; + } +} \ No newline at end of file diff --git a/Lambdas/Lists/Picture/src/PicturePUT.java b/Lambdas/Lists/Picture/src/PicturePUT.java new file mode 100644 index 0000000..43fc914 --- /dev/null +++ b/Lambdas/Lists/Picture/src/PicturePUT.java @@ -0,0 +1,11 @@ +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.RequestHandler; + +import java.util.Map; + +public class PicturePUT implements RequestHandler, Object> { + + public Object handleRequest(Map inputMap, Context unfilled) { + return BasicHandler.handleRequest(inputMap, unfilled, PicturePutter.class); + } +} diff --git a/Lambdas/Lists/Picture/src/PicturePutter.java b/Lambdas/Lists/Picture/src/PicturePutter.java new file mode 100644 index 0000000..fadff15 --- /dev/null +++ b/Lambdas/Lists/Picture/src/PicturePutter.java @@ -0,0 +1,28 @@ +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; + +public class PicturePutter implements CallHandler { + + private Connection connection; + private String cognitoID; + + public PicturePutter(Connection connection, String cognitoID) { + this.connection = connection; + this.cognitoID = cognitoID; + } + + final private String STORE_PICTURE_SQL = "REPLACE INTO Pictures(cognitoID, base64image) VALUES(?, ?);"; + + public Object conductAction(Map bodyMap, HashMap queryString, String cognitoID) throws SQLException { + PreparedStatement storePicture = connection.prepareStatement(STORE_PICTURE_SQL); + storePicture.setString(1, cognitoID); + storePicture.setString(2, bodyMap.get("base64EncodedImage").toString()); + System.out.println(storePicture); + storePicture.executeUpdate(); + connection.commit(); + return null; + } +} \ No newline at end of file diff --git a/Listify/app/src/main/java/com/example/listify/MainActivity.java b/Listify/app/src/main/java/com/example/listify/MainActivity.java index e19570d..7bbaf0c 100644 --- a/Listify/app/src/main/java/com/example/listify/MainActivity.java +++ b/Listify/app/src/main/java/com/example/listify/MainActivity.java @@ -1,12 +1,16 @@ package com.example.listify; import android.app.AlertDialog; +import android.content.Context; import android.content.Intent; +import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.provider.MediaStore; +import android.util.Base64; +import android.util.Base64OutputStream; import android.util.Log; import android.view.MenuItem; import android.view.View; @@ -24,12 +28,12 @@ import androidx.navigation.ui.AppBarConfiguration; import androidx.navigation.ui.NavigationUI; import com.amplifyframework.auth.AuthException; import com.example.listify.data.List; +import com.example.listify.data.Picture; import com.example.listify.ui.LoginPage; import com.google.android.material.navigation.NavigationView; import org.json.JSONException; -import java.io.File; -import java.io.IOException; +import java.io.*; import java.text.SimpleDateFormat; import java.time.Instant; import java.util.Date; @@ -169,9 +173,22 @@ public class MainActivity extends AppCompatActivity implements CreateListDialogF TextView emailView = navigationView.getHeaderView(0).findViewById(R.id.textViewEmailSidebar); emailView.setText(am.getEmail()); - - ImageView profilePicture = navigationView.getHeaderView(0).findViewById(R.id.imageViewProfilePicture); - profilePicture.setOnClickListener(new View.OnClickListener() { + Properties configs = new Properties(); + try { + configs = AuthManager.loadProperties(this, "android.resource://" + getPackageName() + "/raw/auths.json"); + } catch (IOException | JSONException e) { + e.printStackTrace(); + } + Requestor requestor = new Requestor(am, configs.getProperty("apiKey")); + SynchronousReceiver profilePictureReceiver = new SynchronousReceiver<>(); + ImageView profilePictureView = navigationView.getHeaderView(0).findViewById(R.id.imageViewProfilePicture); + try { + requestor.getObject("profile", Picture.class, profilePictureReceiver); + profilePictureView.setImageURI(Uri.fromFile(saveImage(profilePictureReceiver.await().getBase64EncodedImage()))); + } catch (Exception e) { + e.printStackTrace(); + } + profilePictureView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -223,27 +240,116 @@ public class MainActivity extends AppCompatActivity implements CreateListDialogF }); } + //From: https://stackoverflow.com/questions/30005815/convert-encoded-base64-image-to-file-object-in-android + private File saveImage(final String imageData) throws IOException { + final byte[] imgBytesData = android.util.Base64.decode(imageData, + android.util.Base64.DEFAULT); + + final File file = File.createTempFile("profilePicture", null, this.getCacheDir()); + final FileOutputStream fileOutputStream; + try { + fileOutputStream = new FileOutputStream(file); + } catch (FileNotFoundException e) { + e.printStackTrace(); + return null; + } + + final BufferedOutputStream bufferedOutputStream = new BufferedOutputStream( + fileOutputStream); + try { + bufferedOutputStream.write(imgBytesData); + } catch (IOException e) { + e.printStackTrace(); + return null; + } finally { + try { + bufferedOutputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return file; + } + protected void onActivityResult (int requestCode, int resultCode, Intent data) { Uri selectedImage = null; + Properties configs = new Properties(); + try { + configs = AuthManager.loadProperties(this, "android.resource://" + getPackageName() + "/raw/auths.json"); + } catch (IOException | JSONException e) { + e.printStackTrace(); + } + Requestor requestor = new Requestor(am, configs.getProperty("apiKey")); switch (requestCode){ case CAMERA_CAPTURE: Log.i("Profile Picture", "Pulling image file at " + this.newImageFileLocation.getAbsolutePath()); selectedImage = Uri.fromFile(this.newImageFileLocation); + try { + requestor.putObject(new Picture(fileToString(this.newImageFileLocation))); + } catch (JSONException | IOException jsonException) { + jsonException.printStackTrace(); + } + break; case IMAGE_SELECT: if ((data == null) || (data.getData() == null)) { return; } selectedImage = data.getData(); + try { + requestor.putObject(new Picture(fileToString(new File(getRealPathFromUri(this, selectedImage))))); + } catch (JSONException | IOException exception) { + exception.printStackTrace(); + } break; } MainActivity.super.onActivityResult(requestCode, resultCode, data); + if (selectedImage == null) { + return; + } NavigationView navigationView = findViewById(R.id.nav_view); + ImageView profilePicture = navigationView.getHeaderView(0).findViewById(R.id.imageViewProfilePicture); profilePicture.setImageURI(selectedImage); + + } + + //From: https://stackoverflow.com/questions/20028319/how-to-convert-content-media-external-images-media-y-to-file-storage-sdc + private static String getRealPathFromUri(Context context, Uri contentUri) { + Cursor cursor = null; + try { + String[] proj = { MediaStore.Images.Media.DATA }; + cursor = context.getContentResolver().query(contentUri, proj, null, null, null); + int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); + cursor.moveToFirst(); + return cursor.getString(column_index); + } finally { + if (cursor != null) { + cursor.close(); + } + } + } + + //From: https://stackoverflow.com/questions/27784230/convert-a-file-100mo-in-base64-on-android + private String fileToString(File toStringify) throws IOException { + InputStream inputStream = new FileInputStream(toStringify.getAbsolutePath()); + byte[] buffer = new byte[8192]; + int bytesRead; + ByteArrayOutputStream output = new ByteArrayOutputStream(); + Base64OutputStream output64 = new Base64OutputStream(output, Base64.DEFAULT); + try { + while ((bytesRead = inputStream.read(buffer)) != -1) { + output64.write(buffer, 0, bytesRead); + } + } catch (IOException e) { + e.printStackTrace(); + } + output64.close(); + + return output.toString(); } //getOutputImageFile from https://developer.android.com/guide/topics/media/camera diff --git a/Listify/app/src/main/java/com/example/listify/data/Picture.java b/Listify/app/src/main/java/com/example/listify/data/Picture.java new file mode 100644 index 0000000..59578cb --- /dev/null +++ b/Listify/app/src/main/java/com/example/listify/data/Picture.java @@ -0,0 +1,24 @@ +package com.example.listify.data; + +public class Picture { + String base64EncodedImage; + + public Picture(String base64EncodedImage) { + this.base64EncodedImage = base64EncodedImage; + } + + @Override + public String toString() { + return "Picture{" + + "base64EncodedImage='" + base64EncodedImage + '\'' + + '}'; + } + + public String getBase64EncodedImage() { + return base64EncodedImage; + } + + public void setBase64EncodedImage(String base64EncodedImage) { + this.base64EncodedImage = base64EncodedImage; + } +}