From 8653b9a0352f63e87e8f872f6c15d1750519a417 Mon Sep 17 00:00:00 2001 From: NMerz Date: Sat, 14 Nov 2020 11:40:42 -0500 Subject: [PATCH 01/11] Try storing serialized search object Does not seem to be the best solution (https://stackoverflow.com/questions/17662236/java-write-object-to-mysql-each-field-or-serialized-byte-array) and does not entirely work, but saving it for posterity because there are some interesting changes here --- .../Lists/ItemSearch/src/ItemSearcher.java | 14 ++++- .../SearchHistory/src/SearchHistory.java | 39 +++++++++++++ .../SearchHistory/src/SearchHistoryGET.java | 11 ++++ .../src/SearchHistoryGetter.java | 31 ++++++++++ .../SearchHistory/src/SearchHistoryPUT.java | 11 ++++ .../src/SearchHistoryPutter.java | 34 +++++++++++ .../src/SearchHistoryUpdate.java | 56 +++++++++++++++++++ Lambdas/Lists/pom.xml | 5 ++ .../java/com/example/listify/Requestor.java | 21 ++++++- .../example/listify/data/SearchHistory.java | 23 ++++++++ 10 files changed, 243 insertions(+), 2 deletions(-) create mode 100644 Lambdas/Lists/SearchHistory/src/SearchHistory.java create mode 100644 Lambdas/Lists/SearchHistory/src/SearchHistoryGET.java create mode 100644 Lambdas/Lists/SearchHistory/src/SearchHistoryGetter.java create mode 100644 Lambdas/Lists/SearchHistory/src/SearchHistoryPUT.java create mode 100644 Lambdas/Lists/SearchHistory/src/SearchHistoryPutter.java create mode 100644 Lambdas/Lists/SearchHistory/src/SearchHistoryUpdate.java create mode 100644 Listify/app/src/main/java/com/example/listify/data/SearchHistory.java diff --git a/Lambdas/Lists/ItemSearch/src/ItemSearcher.java b/Lambdas/Lists/ItemSearch/src/ItemSearcher.java index a3a7381..eef6cc4 100644 --- a/Lambdas/Lists/ItemSearch/src/ItemSearcher.java +++ b/Lambdas/Lists/ItemSearch/src/ItemSearcher.java @@ -1,3 +1,6 @@ +import com.amazonaws.services.lambda.AWSLambdaClientBuilder; +import com.amazonaws.services.lambda.model.InvokeRequest; + import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -18,13 +21,22 @@ public class ItemSearcher implements CallHandler { } @Override - public Object conductAction(Map body, HashMap queryParams, String s) throws SQLException { + public Object conductAction(Map body, HashMap queryParams, String cognitoID) throws SQLException { PreparedStatement getItemMatches = connection.prepareStatement(GET_ITEM_MATCHES); getItemMatches.setString(1, "%" + queryParams.get("id") + "%"); System.out.println(getItemMatches); ResultSet searchResults = getItemMatches.executeQuery(); ItemSearch searchResultsObject = new ItemSearch(searchResults); System.out.println(searchResultsObject); + InvokeRequest invokeRequest = new InvokeRequest(); + invokeRequest.setFunctionName("SearchHistoryUpdate"); + invokeRequest.setPayload("{" + + " \"newSearch\": \"" + queryParams.get("id") + "\"," + + " \"cognitoID\": \""+ cognitoID + "\"" + + "}"); + invokeRequest.setInvocationType("Event"); + System.out.println(invokeRequest); + AWSLambdaClientBuilder.defaultClient().invoke(invokeRequest); return searchResultsObject; } } diff --git a/Lambdas/Lists/SearchHistory/src/SearchHistory.java b/Lambdas/Lists/SearchHistory/src/SearchHistory.java new file mode 100644 index 0000000..b29e10d --- /dev/null +++ b/Lambdas/Lists/SearchHistory/src/SearchHistory.java @@ -0,0 +1,39 @@ +import java.io.Serializable; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; + +public class SearchHistory implements Serializable { + ArrayList searches; + + public SearchHistory(ArrayList searches) { + this.searches = searches; + } + + public SearchHistory() { + this.searches = new ArrayList<>(); + } + + public SearchHistory(ResultSet row) throws SQLException { + this.searches = (ArrayList) row.getObject("historyObject"); + } + + public ArrayList getSearches() { + return searches; + } + + public void setSearches(ArrayList searches) { + this.searches = searches; + } + + public void addSearch(String newSearch) { + searches.add(newSearch); + } + + @Override + public String toString() { + return "SearchHistory{" + + "searches=" + searches + + '}'; + } +} diff --git a/Lambdas/Lists/SearchHistory/src/SearchHistoryGET.java b/Lambdas/Lists/SearchHistory/src/SearchHistoryGET.java new file mode 100644 index 0000000..4c696b3 --- /dev/null +++ b/Lambdas/Lists/SearchHistory/src/SearchHistoryGET.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 SearchHistoryGET implements RequestHandler, Object> { + + public Object handleRequest(Map inputMap, Context unfilled) { + return BasicHandler.handleRequest(inputMap, unfilled, SearchHistoryGetter.class); + } +} diff --git a/Lambdas/Lists/SearchHistory/src/SearchHistoryGetter.java b/Lambdas/Lists/SearchHistory/src/SearchHistoryGetter.java new file mode 100644 index 0000000..13319cd --- /dev/null +++ b/Lambdas/Lists/SearchHistory/src/SearchHistoryGetter.java @@ -0,0 +1,31 @@ +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 SearchHistoryGetter implements CallHandler { + + private Connection connection; + private String cognitoID; + + public SearchHistoryGetter(Connection connection, String cognitoID) { + this.connection = connection; + this.cognitoID = cognitoID; + } + + final private String SELECT_HISTORY = "SELECT * from SearchHistory WHERE userID = ?;"; + + public Object conductAction(Map bodyMap, HashMap queryString, String cognitoID) throws SQLException { + PreparedStatement select_history = connection.prepareStatement(SELECT_HISTORY); + select_history.setString(1, cognitoID); + System.out.println(select_history); + ResultSet searchHistory = select_history.executeQuery(); + if (!searchHistory.first()) { + return new SearchHistory(); + } + System.out.println(new SearchHistory(searchHistory)); + return new SearchHistory(searchHistory); + } +} \ No newline at end of file diff --git a/Lambdas/Lists/SearchHistory/src/SearchHistoryPUT.java b/Lambdas/Lists/SearchHistory/src/SearchHistoryPUT.java new file mode 100644 index 0000000..28d5019 --- /dev/null +++ b/Lambdas/Lists/SearchHistory/src/SearchHistoryPUT.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 SearchHistoryPUT implements RequestHandler, Object> { + + public Object handleRequest(Map inputMap, Context unfilled) { + return BasicHandler.handleRequest(inputMap, unfilled, SearchHistoryPutter.class); + } +} diff --git a/Lambdas/Lists/SearchHistory/src/SearchHistoryPutter.java b/Lambdas/Lists/SearchHistory/src/SearchHistoryPutter.java new file mode 100644 index 0000000..a18a2ff --- /dev/null +++ b/Lambdas/Lists/SearchHistory/src/SearchHistoryPutter.java @@ -0,0 +1,34 @@ +import com.google.gson.Gson; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; + +public class SearchHistoryPutter implements CallHandler { + + private Connection connection; + private String cognitoID; + + public SearchHistoryPutter(Connection connection, String cognitoID) { + this.connection = connection; + this.cognitoID = cognitoID; + } + + final private String STORE_HISTORY = "REPLACE INTO SearchHistory(userID, historyObject) VALUES(?, ?);"; + + public Object conductAction(Map bodyMap, HashMap queryString, String cognitoID) throws SQLException { + final String searchHistoryJson = new Gson().toJson(bodyMap); + System.out.println(searchHistoryJson); + SearchHistory toStore = new Gson().fromJson(searchHistoryJson, SearchHistory.class); + System.out.println(toStore); + PreparedStatement store_history = connection.prepareStatement(STORE_HISTORY); + store_history.setString(1, cognitoID); + store_history.setObject(2, toStore.searches); + System.out.println(store_history); + store_history.executeUpdate(); + connection.commit(); + return null; + } +} \ No newline at end of file diff --git a/Lambdas/Lists/SearchHistory/src/SearchHistoryUpdate.java b/Lambdas/Lists/SearchHistory/src/SearchHistoryUpdate.java new file mode 100644 index 0000000..70671aa --- /dev/null +++ b/Lambdas/Lists/SearchHistory/src/SearchHistoryUpdate.java @@ -0,0 +1,56 @@ +import com.amazonaws.services.lambda.AWSLambdaClientBuilder; +import com.amazonaws.services.lambda.model.InvokeRequest; +import com.amazonaws.services.lambda.model.InvokeResult; +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.RequestHandler; +import com.google.gson.Gson; + +import java.util.InputMismatchException; +import java.util.Map; + +public class SearchHistoryUpdate implements RequestHandler, Object> { + + public Object handleRequest(Map inputMap, Context unfilled) { + String cognitoID = (String) inputMap.get("cognitoID"); + System.out.println(cognitoID); + String newSearch = (String) inputMap.get("newSearch"); + System.out.println(newSearch); + InvokeRequest invokeRequest = new InvokeRequest(); + invokeRequest.setFunctionName("SearchHistoryGET"); + invokeRequest.setPayload("{" + + " \"body\": {" + + " }," + + " \"params\": {" + + " \"querystring\": {" + + " }" + + " }," + + " \"context\": {" + + " \"sub\": \""+ cognitoID + "\"" + + " }" + + "}"); + System.out.println(invokeRequest); + InvokeResult searchHistoryResult = AWSLambdaClientBuilder.defaultClient().invoke(invokeRequest); + System.out.println(searchHistoryResult); + if (searchHistoryResult.getStatusCode() != 200) { + throw new InputMismatchException("Could not find a search history for the specified usr"); + } + System.out.println(new String(searchHistoryResult.getPayload().array())); + SearchHistory priorSearchHistory = new Gson().fromJson(new String(searchHistoryResult.getPayload().array()), SearchHistory.class); + priorSearchHistory.addSearch(newSearch); + invokeRequest.setFunctionName("SearchHistoryPUT"); + System.out.println("New search history: " + new Gson().toJson(priorSearchHistory)); + invokeRequest.setPayload("{" + + " \"body\":" + new Gson().toJson(priorSearchHistory) + "," + + " \"params\": {" + + " \"querystring\": {" + + " }" + + " }," + + " \"context\": {" + + " \"sub\": \""+ cognitoID + "\"" + + " }" + + "}"); + invokeRequest.setInvocationType("Event"); + System.out.println(invokeRequest); + AWSLambdaClientBuilder.defaultClient().invoke(invokeRequest); + return null; } +} diff --git a/Lambdas/Lists/pom.xml b/Lambdas/Lists/pom.xml index b148d2c..4725165 100644 --- a/Lambdas/Lists/pom.xml +++ b/Lambdas/Lists/pom.xml @@ -94,6 +94,11 @@ jackson-dataformat-xml 2.8.5 + + com.fasterxml.jackson.core + jackson-annotations + 2.11.3 + com.fasterxml.jackson.core jackson-databind diff --git a/Listify/app/src/main/java/com/example/listify/Requestor.java b/Listify/app/src/main/java/com/example/listify/Requestor.java index b2df019..ed149c3 100644 --- a/Listify/app/src/main/java/com/example/listify/Requestor.java +++ b/Listify/app/src/main/java/com/example/listify/Requestor.java @@ -60,6 +60,25 @@ public class Requestor { launchCall(deleteRequest, null, classType, failureHandler); } + public void putObject(Object toPost) throws JSONException { + putObject(toPost, (RequestErrorHandler) null); + } + + public void putObject(Object toPost, RequestErrorHandler failureHandler) throws JSONException { + putObject(toPost, null, failureHandler); + } + + public void putObject(Object toPost, Receiver idReceiver) throws JSONException { + putObject(toPost, idReceiver, null); + } + + public void putObject(Object toPut, Receiver idReceiver, RequestErrorHandler failureHandler) throws JSONException { + String putURL = DEV_BASEURL + "/" + toPut.getClass().getSimpleName(); + Request putRequest = buildBaseRequest(putURL, "PUT", new Gson().toJson(toPut)); + launchCall(putRequest, idReceiver, Integer.class, failureHandler); + } + + public void postObject(Object toPost) throws JSONException { postObject(toPost, (RequestErrorHandler) null); } @@ -85,7 +104,7 @@ public class Requestor { String responseString = response.body().string(); if (receiver != null) { if (classType == null) { - Log.e("Requestor Contract Error", "classType while receiver populated"); + Log.e("Requestor Contract Error", "no/null classType while receiver populated"); } try { receiver.acceptDelivery(new Gson().fromJson(responseString, classType)); diff --git a/Listify/app/src/main/java/com/example/listify/data/SearchHistory.java b/Listify/app/src/main/java/com/example/listify/data/SearchHistory.java new file mode 100644 index 0000000..dace88d --- /dev/null +++ b/Listify/app/src/main/java/com/example/listify/data/SearchHistory.java @@ -0,0 +1,23 @@ +package com.example.listify.data; + +import java.util.ArrayList; + +public class SearchHistory { + ArrayList searches; + + public SearchHistory(ArrayList searches) { + this.searches = searches; + } + + public ArrayList getSearches() { + return searches; + } + + public void setSearches(ArrayList searches) { + this.searches = searches; + } + + public void addSearch(String newSearch) { + searches.add(newSearch); + } +} From 3afaad89ea4e0874a98493fcc025fda746106756 Mon Sep 17 00:00:00 2001 From: NMerz Date: Sat, 14 Nov 2020 12:05:50 -0500 Subject: [PATCH 02/11] Use plain table search history This is easier, clearer, faster for inters, and ultimately not really much less space efficient than trying to store this in a serialized nor unreasonably slow for retrievals. Food for thought: Would this might be well-suited to a nosql database? --- .../Lists/ItemSearch/src/ItemSearcher.java | 14 ++++- .../SearchHistory/src/SearchHistory.java | 6 +- ...HistoryPUT.java => SearchHistoryPOST.java} | 4 +- .../src/SearchHistoryUpdate.java | 56 ------------------- ...yPutter.java => SearchHistoryUpdater.java} | 16 ++---- .../com/example/listify/MainActivity.java | 16 ++++-- .../example/listify/data/SearchHistory.java | 7 +++ 7 files changed, 40 insertions(+), 79 deletions(-) rename Lambdas/Lists/SearchHistory/src/{SearchHistoryPUT.java => SearchHistoryPOST.java} (72%) delete mode 100644 Lambdas/Lists/SearchHistory/src/SearchHistoryUpdate.java rename Lambdas/Lists/SearchHistory/src/{SearchHistoryPutter.java => SearchHistoryUpdater.java} (53%) diff --git a/Lambdas/Lists/ItemSearch/src/ItemSearcher.java b/Lambdas/Lists/ItemSearch/src/ItemSearcher.java index eef6cc4..e24ebdf 100644 --- a/Lambdas/Lists/ItemSearch/src/ItemSearcher.java +++ b/Lambdas/Lists/ItemSearch/src/ItemSearcher.java @@ -29,10 +29,18 @@ public class ItemSearcher implements CallHandler { ItemSearch searchResultsObject = new ItemSearch(searchResults); System.out.println(searchResultsObject); InvokeRequest invokeRequest = new InvokeRequest(); - invokeRequest.setFunctionName("SearchHistoryUpdate"); + invokeRequest.setFunctionName("SearchHistoryPOST"); invokeRequest.setPayload("{" + - " \"newSearch\": \"" + queryParams.get("id") + "\"," + - " \"cognitoID\": \""+ cognitoID + "\"" + + " \"body\": {" + + " \"searchTerm\": \"" + queryParams.get("id") + "\"" + + " }," + + " \"params\": {" + + " \"querystring\": {" + + " }" + + " }," + + " \"context\": {" + + " \"sub\": \"" + cognitoID + "\"" + + " }" + "}"); invokeRequest.setInvocationType("Event"); System.out.println(invokeRequest); diff --git a/Lambdas/Lists/SearchHistory/src/SearchHistory.java b/Lambdas/Lists/SearchHistory/src/SearchHistory.java index b29e10d..f319150 100644 --- a/Lambdas/Lists/SearchHistory/src/SearchHistory.java +++ b/Lambdas/Lists/SearchHistory/src/SearchHistory.java @@ -15,7 +15,11 @@ public class SearchHistory implements Serializable { } public SearchHistory(ResultSet row) throws SQLException { - this.searches = (ArrayList) row.getObject("historyObject"); + this.searches = new ArrayList<>(); + row.beforeFirst(); + while (row.next()) { + this.searches.add(row.getString("search")); + } } public ArrayList getSearches() { diff --git a/Lambdas/Lists/SearchHistory/src/SearchHistoryPUT.java b/Lambdas/Lists/SearchHistory/src/SearchHistoryPOST.java similarity index 72% rename from Lambdas/Lists/SearchHistory/src/SearchHistoryPUT.java rename to Lambdas/Lists/SearchHistory/src/SearchHistoryPOST.java index 28d5019..6b05141 100644 --- a/Lambdas/Lists/SearchHistory/src/SearchHistoryPUT.java +++ b/Lambdas/Lists/SearchHistory/src/SearchHistoryPOST.java @@ -3,9 +3,9 @@ import com.amazonaws.services.lambda.runtime.RequestHandler; import java.util.Map; -public class SearchHistoryPUT implements RequestHandler, Object> { +public class SearchHistoryPOST implements RequestHandler, Object> { public Object handleRequest(Map inputMap, Context unfilled) { - return BasicHandler.handleRequest(inputMap, unfilled, SearchHistoryPutter.class); + return BasicHandler.handleRequest(inputMap, unfilled, SearchHistoryUpdater.class); } } diff --git a/Lambdas/Lists/SearchHistory/src/SearchHistoryUpdate.java b/Lambdas/Lists/SearchHistory/src/SearchHistoryUpdate.java deleted file mode 100644 index 70671aa..0000000 --- a/Lambdas/Lists/SearchHistory/src/SearchHistoryUpdate.java +++ /dev/null @@ -1,56 +0,0 @@ -import com.amazonaws.services.lambda.AWSLambdaClientBuilder; -import com.amazonaws.services.lambda.model.InvokeRequest; -import com.amazonaws.services.lambda.model.InvokeResult; -import com.amazonaws.services.lambda.runtime.Context; -import com.amazonaws.services.lambda.runtime.RequestHandler; -import com.google.gson.Gson; - -import java.util.InputMismatchException; -import java.util.Map; - -public class SearchHistoryUpdate implements RequestHandler, Object> { - - public Object handleRequest(Map inputMap, Context unfilled) { - String cognitoID = (String) inputMap.get("cognitoID"); - System.out.println(cognitoID); - String newSearch = (String) inputMap.get("newSearch"); - System.out.println(newSearch); - InvokeRequest invokeRequest = new InvokeRequest(); - invokeRequest.setFunctionName("SearchHistoryGET"); - invokeRequest.setPayload("{" + - " \"body\": {" + - " }," + - " \"params\": {" + - " \"querystring\": {" + - " }" + - " }," + - " \"context\": {" + - " \"sub\": \""+ cognitoID + "\"" + - " }" + - "}"); - System.out.println(invokeRequest); - InvokeResult searchHistoryResult = AWSLambdaClientBuilder.defaultClient().invoke(invokeRequest); - System.out.println(searchHistoryResult); - if (searchHistoryResult.getStatusCode() != 200) { - throw new InputMismatchException("Could not find a search history for the specified usr"); - } - System.out.println(new String(searchHistoryResult.getPayload().array())); - SearchHistory priorSearchHistory = new Gson().fromJson(new String(searchHistoryResult.getPayload().array()), SearchHistory.class); - priorSearchHistory.addSearch(newSearch); - invokeRequest.setFunctionName("SearchHistoryPUT"); - System.out.println("New search history: " + new Gson().toJson(priorSearchHistory)); - invokeRequest.setPayload("{" + - " \"body\":" + new Gson().toJson(priorSearchHistory) + "," + - " \"params\": {" + - " \"querystring\": {" + - " }" + - " }," + - " \"context\": {" + - " \"sub\": \""+ cognitoID + "\"" + - " }" + - "}"); - invokeRequest.setInvocationType("Event"); - System.out.println(invokeRequest); - AWSLambdaClientBuilder.defaultClient().invoke(invokeRequest); - return null; } -} diff --git a/Lambdas/Lists/SearchHistory/src/SearchHistoryPutter.java b/Lambdas/Lists/SearchHistory/src/SearchHistoryUpdater.java similarity index 53% rename from Lambdas/Lists/SearchHistory/src/SearchHistoryPutter.java rename to Lambdas/Lists/SearchHistory/src/SearchHistoryUpdater.java index a18a2ff..625c6db 100644 --- a/Lambdas/Lists/SearchHistory/src/SearchHistoryPutter.java +++ b/Lambdas/Lists/SearchHistory/src/SearchHistoryUpdater.java @@ -1,31 +1,25 @@ -import com.google.gson.Gson; - import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.HashMap; import java.util.Map; -public class SearchHistoryPutter implements CallHandler { +public class SearchHistoryUpdater implements CallHandler { private Connection connection; private String cognitoID; - public SearchHistoryPutter(Connection connection, String cognitoID) { + public SearchHistoryUpdater(Connection connection, String cognitoID) { this.connection = connection; this.cognitoID = cognitoID; } - final private String STORE_HISTORY = "REPLACE INTO SearchHistory(userID, historyObject) VALUES(?, ?);"; + final private String UPDATE_HISTORY = "INSERT INTO SearchHistory(userID, search) VALUES(?, ?);"; public Object conductAction(Map bodyMap, HashMap queryString, String cognitoID) throws SQLException { - final String searchHistoryJson = new Gson().toJson(bodyMap); - System.out.println(searchHistoryJson); - SearchHistory toStore = new Gson().fromJson(searchHistoryJson, SearchHistory.class); - System.out.println(toStore); - PreparedStatement store_history = connection.prepareStatement(STORE_HISTORY); + PreparedStatement store_history = connection.prepareStatement(UPDATE_HISTORY); store_history.setString(1, cognitoID); - store_history.setObject(2, toStore.searches); + store_history.setObject(2, bodyMap.get("searchTerm")); System.out.println(store_history); store_history.executeUpdate(); connection.commit(); 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 881ce02..ec0c89b 100644 --- a/Listify/app/src/main/java/com/example/listify/MainActivity.java +++ b/Listify/app/src/main/java/com/example/listify/MainActivity.java @@ -16,19 +16,15 @@ import androidx.navigation.Navigation; import androidx.navigation.ui.AppBarConfiguration; import androidx.navigation.ui.NavigationUI; import com.amplifyframework.auth.AuthException; -import com.example.listify.data.Item; -import com.example.listify.data.ItemSearch; import com.example.listify.data.List; -import com.example.listify.data.ListEntry; +import com.example.listify.data.SearchHistory; import com.example.listify.ui.LoginPage; import com.google.android.material.navigation.NavigationView; import org.json.JSONException; import java.io.IOException; import java.time.Instant; -import java.util.Arrays; import java.util.Properties; -import java.util.Random; import static com.example.listify.SplashActivity.showSplash; @@ -108,7 +104,14 @@ public class MainActivity extends AppCompatActivity implements CreateListDialogF } Requestor requestor = new Requestor(authManager, configs.getProperty("apiKey")); - + SynchronousReceiver historyReceiver = new SynchronousReceiver<>(); + requestor.getObject("N/A", SearchHistory.class, historyReceiver, historyReceiver); + try { + System.out.println(historyReceiver.await()); + } catch (Exception e) { + e.printStackTrace(); + } + /* List testList = new List(-1, "New List", "user filled by lambda", Instant.now().toEpochMilli()); ListEntry entry = new ListEntry(1, 4, Math.abs(new Random().nextInt()), Instant.now().toEpochMilli(),false); @@ -139,6 +142,7 @@ public class MainActivity extends AppCompatActivity implements CreateListDialogF } catch (Exception receiverError) { receiverError.printStackTrace(); } + */ } //------------------------------------------------------------------------------------------// diff --git a/Listify/app/src/main/java/com/example/listify/data/SearchHistory.java b/Listify/app/src/main/java/com/example/listify/data/SearchHistory.java index dace88d..1d29594 100644 --- a/Listify/app/src/main/java/com/example/listify/data/SearchHistory.java +++ b/Listify/app/src/main/java/com/example/listify/data/SearchHistory.java @@ -20,4 +20,11 @@ public class SearchHistory { public void addSearch(String newSearch) { searches.add(newSearch); } + + @Override + public String toString() { + return "SearchHistory{" + + "searches=" + searches + + '}'; + } } From 82272a9a2934dc6986d55b62213b0307611bf03c Mon Sep 17 00:00:00 2001 From: NMerz Date: Sat, 14 Nov 2020 12:46:33 -0500 Subject: [PATCH 03/11] Set permission param Ensure permssion parameter is getting set when sharing a list --- Lambdas/Lists/ListShare/src/ListSharer.java | 14 ++-- .../java/com/example/listify/ListPage.java | 19 ++---- .../ShoppingListsSwipeableAdapter.java | 2 +- .../com/example/listify/data/ListShare.java | 64 ++++++++++++++++++- 4 files changed, 76 insertions(+), 23 deletions(-) diff --git a/Lambdas/Lists/ListShare/src/ListSharer.java b/Lambdas/Lists/ListShare/src/ListSharer.java index 0997818..f5488a7 100644 --- a/Lambdas/Lists/ListShare/src/ListSharer.java +++ b/Lambdas/Lists/ListShare/src/ListSharer.java @@ -22,7 +22,7 @@ public class ListSharer implements CallHandler { } final private String CHECK_ACCESS = "SELECT * from ListSharee WHERE listID = ? AND userID = ?;"; - final private String SHARE_LIST = "INSERT INTO ListSharee(listID, userID) VALUES(?, ?);"; + final private String SHARE_LIST = "INSERT INTO ListSharee(listID, userID, permissionLevel) VALUES(?, ?, ?);"; public Object conductAction(Map bodyMap, HashMap queryString, String cognitoID) throws SQLException { PreparedStatement checkAccess = connection.prepareStatement(CHECK_ACCESS); @@ -52,15 +52,17 @@ public class ListSharer implements CallHandler { throw new InputMismatchException("Could not find specified user to share with"); } String shareWithSub = new String(invokeResult.getPayload().array()).replace("\"", ""); - checkAccess.setString(2, shareWithSub); - checkAccessRS = checkAccess.executeQuery(); - if (checkAccessRS.next()) { - throw new InputMismatchException("The specified user already has access"); - } +// checkAccess.setString(2, shareWithSub); +// checkAccessRS = checkAccess.executeQuery(); +// if (checkAccessRS.next()) { +// throw new InputMismatchException("The specified user already has access"); +// } PreparedStatement shareList = connection.prepareStatement(SHARE_LIST); shareList.setInt(1, listID); shareList.setString(2, shareWithSub); + Integer permissionLevel = Integer.parseInt(bodyMap.get("permissionLevel").toString()); + shareList.setInt(3, permissionLevel); shareList.executeUpdate(); connection.commit(); return null; diff --git a/Listify/app/src/main/java/com/example/listify/ListPage.java b/Listify/app/src/main/java/com/example/listify/ListPage.java index 1efd025..454d32a 100644 --- a/Listify/app/src/main/java/com/example/listify/ListPage.java +++ b/Listify/app/src/main/java/com/example/listify/ListPage.java @@ -5,23 +5,14 @@ import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; import android.util.Log; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; +import android.view.*; import android.widget.*; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; - import com.bumptech.glide.Glide; - -import com.example.listify.data.Chain; -import com.example.listify.data.Item; -import com.example.listify.data.List; -import com.example.listify.data.ListEntry; -import com.example.listify.data.ListShare; +import com.example.listify.data.*; +import org.json.JSONException; import java.io.IOException; import java.text.DecimalFormat; @@ -30,8 +21,6 @@ import java.util.HashMap; import java.util.Map; import java.util.Properties; -import org.json.JSONException; - import static com.example.listify.MainActivity.am; public class ListPage extends AppCompatActivity implements Requestor.Receiver { @@ -125,7 +114,7 @@ public class ListPage extends AppCompatActivity implements Requestor.Receiver { public void onClick(DialogInterface dialog, int which) { EditText sharedEmailText = (EditText) codeView.findViewById(R.id.editTextTextSharedEmail); String sharedEmail = sharedEmailText.getText().toString(); - ListShare listShare = new ListShare(listID, sharedEmail); + ListShare listShare = new ListShare(listID, sharedEmail, "Read, Edit, Delete"); try { requestor.postObject(listShare); } diff --git a/Listify/app/src/main/java/com/example/listify/adapter/ShoppingListsSwipeableAdapter.java b/Listify/app/src/main/java/com/example/listify/adapter/ShoppingListsSwipeableAdapter.java index 892f2f0..9ad540a 100644 --- a/Listify/app/src/main/java/com/example/listify/adapter/ShoppingListsSwipeableAdapter.java +++ b/Listify/app/src/main/java/com/example/listify/adapter/ShoppingListsSwipeableAdapter.java @@ -129,7 +129,7 @@ public class ShoppingListsSwipeableAdapter extends BaseAdapter { public void onClick(DialogInterface dialog, int which) { EditText sharedEmailText = (EditText) codeView.findViewById(R.id.editTextTextSharedEmail); String sharedEmail = sharedEmailText.getText().toString(); - ListShare listShare = new ListShare(curList.getItemID(), sharedEmail); + ListShare listShare = new ListShare(curList.getItemID(), sharedEmail, "Read, Edit, Delete"); try { requestor.postObject(listShare); } diff --git a/Listify/app/src/main/java/com/example/listify/data/ListShare.java b/Listify/app/src/main/java/com/example/listify/data/ListShare.java index 406f286..bcc5226 100644 --- a/Listify/app/src/main/java/com/example/listify/data/ListShare.java +++ b/Listify/app/src/main/java/com/example/listify/data/ListShare.java @@ -1,12 +1,65 @@ package com.example.listify.data; +import com.example.listify.BuildConfig; + +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; + public class ListShare { Integer listID; String shareWithEmail; + Integer permissionLevel; - public ListShare(Integer listID, String shareWithEmail) { + private static final Map keysToPerms; + static { + //All keys should be a prime number > 1 + HashMap keysToPermsTemp = new HashMap<>(); + keysToPermsTemp.put(2, "Read"); + keysToPermsTemp.put(3, "Edit"); + keysToPermsTemp.put(5, "Delete"); + keysToPerms = Collections.unmodifiableMap(keysToPermsTemp); + } + + public ListShare(Integer listID, String shareWithEmail, Integer permissionLevel) { this.listID = listID; this.shareWithEmail = shareWithEmail; + this.permissionLevel = permissionLevel; + } + + public ListShare(Integer listID, String shareWithEmail, String permissions) { + this.listID = listID; + this.shareWithEmail = shareWithEmail; + permissionLevel = 1; + for (Map.Entry keytoPermEntry: keysToPerms.entrySet()) { + if (permissions.contains(keytoPermEntry.getValue())) { + permissionLevel *= keytoPermEntry.getKey(); + } + } + } + + @Override + public String toString() { + StringBuilder toReturn = new StringBuilder("ListShare{" + + "listID=" + listID + + ", shareWithEmail='" + shareWithEmail + '\'' + + ", permissionLevel=" + permissionLevel + + " [Permissions: "); + + int permissionLevelCopy = permissionLevel; + for (Object permissionObject : keysToPerms.keySet().stream().sorted(Comparator.reverseOrder()).toArray()) { + Integer permissionInteger = (Integer) permissionObject; + if (permissionLevelCopy % permissionInteger == 0) { + permissionLevelCopy /= permissionInteger; + toReturn.append(keysToPerms.get(permissionInteger)).append(","); + } + } + if (BuildConfig.DEBUG && permissionLevelCopy != 1) { + throw new AssertionError("Assertion failed"); + } + toReturn.append("]}"); + return toReturn.toString(); } public Integer getListID() { @@ -24,4 +77,13 @@ public class ListShare { public void setShareWithEmail(String shareWithEmail) { this.shareWithEmail = shareWithEmail; } + + public Integer getPermissionLevel() { + return permissionLevel; + } + + public void setPermissionLevel(Integer permissionLevel) { + this.permissionLevel = permissionLevel; + } + } From 954b52dc0a5014626d94d80afb453531259caea6 Mon Sep 17 00:00:00 2001 From: NMerz Date: Sat, 14 Nov 2020 14:29:48 -0500 Subject: [PATCH 04/11] Stricter access checking Properly restrict access to list actions to only authorized users. --- Lambdas/Lists/List/src/ListAdder.java | 3 +- Lambdas/Lists/List/src/ListDeleter.java | 5 +++ Lambdas/Lists/List/src/ListGetter.java | 10 ++++- Lambdas/Lists/List/src/ListPermissions.java | 41 +++++++++++++++++++ .../Lists/ListEntry/src/ListEntryAdder.java | 23 ++++++++--- .../Lists/ListEntry/src/ListEntryDeleter.java | 24 ++++++++++- Lambdas/Lists/ListShare/src/ListSharer.java | 10 +++-- Lambdas/Lists/User/src/UserGetter.java | 23 ++++++++--- .../java/com/example/listify/ListPage.java | 2 +- .../ShoppingListsSwipeableAdapter.java | 2 +- .../com/example/listify/data/ListShare.java | 16 ++++---- 11 files changed, 132 insertions(+), 27 deletions(-) create mode 100644 Lambdas/Lists/List/src/ListPermissions.java diff --git a/Lambdas/Lists/List/src/ListAdder.java b/Lambdas/Lists/List/src/ListAdder.java index 03fd809..b94af67 100644 --- a/Lambdas/Lists/List/src/ListAdder.java +++ b/Lambdas/Lists/List/src/ListAdder.java @@ -9,7 +9,7 @@ public class ListAdder implements CallHandler { private String cognitoID; private final String LIST_CREATE = "INSERT INTO List (name, owner, lastUpdated) VALUES (?, ?, ?);"; - private final String LIST_ACCESS_GRANT = "INSERT INTO ListSharee(listID, userID) VALUES(?, ?);"; + private final String LIST_ACCESS_GRANT = "INSERT INTO ListSharee(listID, userID, permissionLevel) VALUES(?, ?, ?);"; public ListAdder(Connection connection, String cognitoID) { this.connection = connection; @@ -31,6 +31,7 @@ public class ListAdder implements CallHandler { PreparedStatement accessGrant = connection.prepareStatement(LIST_ACCESS_GRANT); accessGrant.setInt(1, newID); accessGrant.setString(2, cognitoID); + accessGrant.setInt(3, ListPermissions.getAll()); System.out.println(accessGrant); accessGrant.executeUpdate(); connection.commit(); diff --git a/Lambdas/Lists/List/src/ListDeleter.java b/Lambdas/Lists/List/src/ListDeleter.java index 820f65f..f3761e9 100644 --- a/Lambdas/Lists/List/src/ListDeleter.java +++ b/Lambdas/Lists/List/src/ListDeleter.java @@ -37,6 +37,11 @@ public class ListDeleter implements CallHandler { ResultSet userLists = accessCheck.executeQuery(); if (!userLists.next()) { throw new AccessControlException("User does not have access to list"); + } else { + Integer permissionLevel = userLists.getInt("permissionLevel"); + if (!ListPermissions.hasPermission(permissionLevel, "Delete")) { + throw new AccessControlException("User " + cognitoID + " does not have permission to delete list " + listID); + } } PreparedStatement cleanAccess = connection.prepareStatement(DELETE_LIST_ACCESS); cleanAccess.setInt(1, listID); diff --git a/Lambdas/Lists/List/src/ListGetter.java b/Lambdas/Lists/List/src/ListGetter.java index 22bea8d..de3fe5f 100644 --- a/Lambdas/Lists/List/src/ListGetter.java +++ b/Lambdas/Lists/List/src/ListGetter.java @@ -1,3 +1,4 @@ +import java.security.AccessControlException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -40,7 +41,14 @@ public class ListGetter implements CallHandler{ System.out.println(checkAccess); ResultSet accessResults = checkAccess.executeQuery(); int sharees = 0; - while (sharees < 2 && accessResults.next()) { + boolean verifiedAccess = false; + while ((sharees < 2 && accessResults.next()) || !verifiedAccess) { + if (accessResults.getString("userID").equals(cognitoID)) { + verifiedAccess = true; + if (!ListPermissions.hasPermission(accessResults.getInt("permissionLevel"), "Read")) { + throw new AccessControlException("User " + cognitoID + " does not have permission to read list " + id); + } + } sharees++; } boolean shared = false; diff --git a/Lambdas/Lists/List/src/ListPermissions.java b/Lambdas/Lists/List/src/ListPermissions.java new file mode 100644 index 0000000..7405191 --- /dev/null +++ b/Lambdas/Lists/List/src/ListPermissions.java @@ -0,0 +1,41 @@ +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class ListPermissions { + private static final Map keysToPerms; + static { + //All keys should be a prime number > 1 + //All keys need to be maintained here and in ListShare object in data on the client side + HashMap keysToPermsTemp = new HashMap<>(); + keysToPermsTemp.put(2, "read"); + keysToPermsTemp.put(3, "write"); + keysToPermsTemp.put(5, "delete"); + keysToPermsTemp.put(7, "share"); + keysToPerms = Collections.unmodifiableMap(keysToPermsTemp); + } + + public static Integer getAll() { + Integer toReturn = 1; + for (Integer key : keysToPerms.keySet()) { + toReturn *= key; + } + return toReturn; + } + + public static boolean hasPermission(Integer level, String permission) { + return level % getKeyForPermission(permission) == 0; + } + + public static Integer getKeyForPermission(String permissionRaw) { + String permission = permissionRaw.toLowerCase(); + for (Map.Entry entry : keysToPerms.entrySet()) { + if (entry.getValue().equals(permission)) { + return entry.getKey(); + } + } + System.out.println("Tried to get key for invalid permission: " + permission); + return -1; + } + +} diff --git a/Lambdas/Lists/ListEntry/src/ListEntryAdder.java b/Lambdas/Lists/ListEntry/src/ListEntryAdder.java index 6f5dd33..0ed50a7 100644 --- a/Lambdas/Lists/ListEntry/src/ListEntryAdder.java +++ b/Lambdas/Lists/ListEntry/src/ListEntryAdder.java @@ -1,3 +1,4 @@ +import java.security.AccessControlException; import java.sql.*; import java.time.Instant; import java.util.HashMap; @@ -8,7 +9,7 @@ public class ListEntryAdder implements CallHandler { private Connection connection; private String cognitoID; - + private final String ACCESS_CHECK = "SELECT * from ListSharee WHERE userID = ? and listID = ?;"; private final String CHECK_ITEM_IN_LIST = "SELECT quantity from ListProduct WHERE productID = ? AND listID = ?;"; private final String CLEAR_PAIRING = "DELETE from ListProduct WHERE productID = ? AND listID = ?;"; private final String ITEM_TO_LIST = "INSERT INTO ListProduct (productID, listID, quantity, addedDate, purchased) VALUES (?, ?, ?, ?, ?)"; @@ -19,12 +20,24 @@ public class ListEntryAdder implements CallHandler { } public Object conductAction(Map bodyMap, HashMap queryString, String cognitoID) throws SQLException { - PreparedStatement quantitiyStatement = connection.prepareStatement(CHECK_ITEM_IN_LIST); Integer productID = (Integer) bodyMap.get("productID"); Integer listID = (Integer) bodyMap.get("listID"); - quantitiyStatement.setInt(1, productID); - quantitiyStatement.setInt(2, listID); - ResultSet quanitityRS = quantitiyStatement.executeQuery(); + PreparedStatement accessCheck = connection.prepareStatement(ACCESS_CHECK); + accessCheck.setString(1, cognitoID); + accessCheck.setInt(2, listID); + ResultSet access = accessCheck.executeQuery(); + if (access.next()) { + if (!ListPermissions.hasPermission(access.getInt("permissionLevel"), "Write")) { + throw new AccessControlException("User " + cognitoID + " does not have write permissions for list " + listID); + } + } else { + throw new AccessControlException("User " + cognitoID + " does not have any permissions to access list " + listID); + } + + PreparedStatement quantityStatement = connection.prepareStatement(CHECK_ITEM_IN_LIST); + quantityStatement.setInt(1, productID); + quantityStatement.setInt(2, listID); + ResultSet quanitityRS = quantityStatement.executeQuery(); int priorQuanity = 0; if (quanitityRS.next()) { priorQuanity = quanitityRS.getInt(1); diff --git a/Lambdas/Lists/ListEntry/src/ListEntryDeleter.java b/Lambdas/Lists/ListEntry/src/ListEntryDeleter.java index 2cb63cd..fbb063b 100644 --- a/Lambdas/Lists/ListEntry/src/ListEntryDeleter.java +++ b/Lambdas/Lists/ListEntry/src/ListEntryDeleter.java @@ -1,5 +1,7 @@ +import java.security.AccessControlException; import java.sql.Connection; import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.sql.SQLException; import java.util.HashMap; import java.util.Map; @@ -10,6 +12,7 @@ public class ListEntryDeleter implements CallHandler { private String cognitoID; private final String REMOVE_FROM_LIST = "DELETE FROM ListProduct WHERE (ProductID = ? AND ListID = ?);"; + private final String ACCESS_CHECK = "SELECT * from ListSharee WHERE userID = ? and listID = ?;"; public ListEntryDeleter(Connection connection, String cognitoID) { this.connection = connection; @@ -17,9 +20,26 @@ public class ListEntryDeleter implements CallHandler { } public Object conductAction(Map bodyMap, HashMap queryString, String cognitoID) throws SQLException { + Integer productID = (Integer) bodyMap.get("productID"); + Integer listID = (Integer) bodyMap.get("listID"); + + PreparedStatement accessCheck = connection.prepareStatement(ACCESS_CHECK); + accessCheck.setString(1, cognitoID); + accessCheck.setInt(2, listID); + ResultSet access = accessCheck.executeQuery(); + if (access.next()) { + if (!ListPermissions.hasPermission(access.getInt("permissionLevel"), "Write")) { + throw new AccessControlException("User " + cognitoID + " does not have write permissions for list " + listID); + } + } else { + throw new AccessControlException("User " + cognitoID + " does not have any permissions to access list " + listID); + } + + PreparedStatement statement = connection.prepareStatement(REMOVE_FROM_LIST); - statement.setInt(1, (Integer) bodyMap.get("productID")); - statement.setInt(2, (Integer) bodyMap.get("listID")); + statement.setInt(1, productID); + statement.setInt(2, listID); + System.out.println(statement); statement.executeUpdate(); connection.commit(); diff --git a/Lambdas/Lists/ListShare/src/ListSharer.java b/Lambdas/Lists/ListShare/src/ListSharer.java index f5488a7..c3a3e10 100644 --- a/Lambdas/Lists/ListShare/src/ListSharer.java +++ b/Lambdas/Lists/ListShare/src/ListSharer.java @@ -22,7 +22,7 @@ public class ListSharer implements CallHandler { } final private String CHECK_ACCESS = "SELECT * from ListSharee WHERE listID = ? AND userID = ?;"; - final private String SHARE_LIST = "INSERT INTO ListSharee(listID, userID, permissionLevel) VALUES(?, ?, ?);"; + final private String SHARE_LIST = "REPLACE INTO ListSharee(listID, userID, permissionLevel) VALUES(?, ?, ?);"; public Object conductAction(Map bodyMap, HashMap queryString, String cognitoID) throws SQLException { PreparedStatement checkAccess = connection.prepareStatement(CHECK_ACCESS); @@ -30,8 +30,12 @@ public class ListSharer implements CallHandler { checkAccess.setInt(1, listID); checkAccess.setString(2, cognitoID); ResultSet checkAccessRS = checkAccess.executeQuery(); - if (!checkAccessRS.next()) { - throw new AccessControlException("The requesting user does not have access to the requested list"); + if (checkAccessRS.next()) { + if (!ListPermissions.hasPermission(checkAccessRS.getInt("permissionLevel"), "Share")) { + throw new AccessControlException("User " + cognitoID + " does not have share permissions for list " + listID); + } + } else { + throw new AccessControlException("User " + cognitoID + " does not have any permissions to access list " + listID); } InvokeRequest invokeRequest = new InvokeRequest(); invokeRequest.setFunctionName("UserGET"); diff --git a/Lambdas/Lists/User/src/UserGetter.java b/Lambdas/Lists/User/src/UserGetter.java index 043a0c2..42d7422 100644 --- a/Lambdas/Lists/User/src/UserGetter.java +++ b/Lambdas/Lists/User/src/UserGetter.java @@ -28,11 +28,22 @@ public class UserGetter implements CallHandler { System.out.println(userPoolId); ListUsersRequest checkRequest = new ListUsersRequest().withUserPoolId(userPoolId); Object emailObject = bodyMap.get("emailToCheck"); + String attributeToGet = "sub"; if (emailObject != null) { checkRequest.setFilter("email=\"" + emailObject.toString() +"\""); } else { - // checkRequest.setFilter("sub=\"" + cognitoID + "\""); - return cognitoID; + try { + String id = queryMap.get("id"); + if ((id != null) && (!id.equals(""))) { + attributeToGet = "email"; + checkRequest.setFilter("sub=\"" + cognitoID + "\""); + } else { + return cognitoID; + } + } catch (Exception e) { + System.out.println(e); + return cognitoID; + } } System.out.println(checkRequest); AWSCognitoIdentityProvider awsCognitoIdentityProvider = AWSCognitoIdentityProviderClientBuilder.defaultClient(); @@ -47,14 +58,14 @@ public class UserGetter implements CallHandler { } UserType foundUser = foundUsers.get(0); System.out.println(foundUser.getAttributes()); - String sub = ""; + String attributeToReturn = ""; for (AttributeType attribute : foundUser.getAttributes()) { - if (attribute.getName().equals("sub")) { - sub = attribute.getValue(); + if (attribute.getName().equals(attributeToGet)) { + attributeToReturn = attribute.getValue(); break; } System.out.println(attribute.getName() + ": " + attribute.getValue()); } - return sub; + return attributeToReturn; } } diff --git a/Listify/app/src/main/java/com/example/listify/ListPage.java b/Listify/app/src/main/java/com/example/listify/ListPage.java index 454d32a..589d947 100644 --- a/Listify/app/src/main/java/com/example/listify/ListPage.java +++ b/Listify/app/src/main/java/com/example/listify/ListPage.java @@ -114,7 +114,7 @@ public class ListPage extends AppCompatActivity implements Requestor.Receiver { public void onClick(DialogInterface dialog, int which) { EditText sharedEmailText = (EditText) codeView.findViewById(R.id.editTextTextSharedEmail); String sharedEmail = sharedEmailText.getText().toString(); - ListShare listShare = new ListShare(listID, sharedEmail, "Read, Edit, Delete"); + ListShare listShare = new ListShare(listID, sharedEmail, "Read, Edit, Delete, Share"); try { requestor.postObject(listShare); } diff --git a/Listify/app/src/main/java/com/example/listify/adapter/ShoppingListsSwipeableAdapter.java b/Listify/app/src/main/java/com/example/listify/adapter/ShoppingListsSwipeableAdapter.java index 9ad540a..24163de 100644 --- a/Listify/app/src/main/java/com/example/listify/adapter/ShoppingListsSwipeableAdapter.java +++ b/Listify/app/src/main/java/com/example/listify/adapter/ShoppingListsSwipeableAdapter.java @@ -129,7 +129,7 @@ public class ShoppingListsSwipeableAdapter extends BaseAdapter { public void onClick(DialogInterface dialog, int which) { EditText sharedEmailText = (EditText) codeView.findViewById(R.id.editTextTextSharedEmail); String sharedEmail = sharedEmailText.getText().toString(); - ListShare listShare = new ListShare(curList.getItemID(), sharedEmail, "Read, Edit, Delete"); + ListShare listShare = new ListShare(curList.getItemID(), sharedEmail, "Read, Edit, Delete, Share"); try { requestor.postObject(listShare); } diff --git a/Listify/app/src/main/java/com/example/listify/data/ListShare.java b/Listify/app/src/main/java/com/example/listify/data/ListShare.java index bcc5226..36abd8a 100644 --- a/Listify/app/src/main/java/com/example/listify/data/ListShare.java +++ b/Listify/app/src/main/java/com/example/listify/data/ListShare.java @@ -3,7 +3,6 @@ package com.example.listify.data; import com.example.listify.BuildConfig; import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; import java.util.Map; @@ -15,10 +14,12 @@ public class ListShare { private static final Map keysToPerms; static { //All keys should be a prime number > 1 + //All keys need to be maintained here and in List module->ListPermissions class on the Lambda side HashMap keysToPermsTemp = new HashMap<>(); - keysToPermsTemp.put(2, "Read"); - keysToPermsTemp.put(3, "Edit"); - keysToPermsTemp.put(5, "Delete"); + keysToPermsTemp.put(2, "read"); + keysToPermsTemp.put(3, "write"); + keysToPermsTemp.put(5, "delete"); + keysToPermsTemp.put(7, "share"); keysToPerms = Collections.unmodifiableMap(keysToPermsTemp); } @@ -28,7 +29,8 @@ public class ListShare { this.permissionLevel = permissionLevel; } - public ListShare(Integer listID, String shareWithEmail, String permissions) { + public ListShare(Integer listID, String shareWithEmail, String permissionsRaw) { + String permissions = permissionsRaw.toLowerCase(); this.listID = listID; this.shareWithEmail = shareWithEmail; permissionLevel = 1; @@ -48,8 +50,8 @@ public class ListShare { " [Permissions: "); int permissionLevelCopy = permissionLevel; - for (Object permissionObject : keysToPerms.keySet().stream().sorted(Comparator.reverseOrder()).toArray()) { - Integer permissionInteger = (Integer) permissionObject; + for (Integer permissionObject : keysToPerms.keySet()) { + Integer permissionInteger = permissionObject; if (permissionLevelCopy % permissionInteger == 0) { permissionLevelCopy /= permissionInteger; toReturn.append(keysToPerms.get(permissionInteger)).append(","); From 3b938bdd2cd9f2b2a454f02e03c517eef29e0ba9 Mon Sep 17 00:00:00 2001 From: NMerz Date: Sat, 14 Nov 2020 14:35:08 -0500 Subject: [PATCH 05/11] Recracterize ListSharePOST as ListSharePUT Semantically, this is now an update and so should be PUT --- .../ListShare/src/{ListSharePOST.java => ListSharePUT.java} | 2 +- Listify/app/src/main/java/com/example/listify/ListPage.java | 2 +- .../example/listify/adapter/ShoppingListsSwipeableAdapter.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename Lambdas/Lists/ListShare/src/{ListSharePOST.java => ListSharePUT.java} (78%) diff --git a/Lambdas/Lists/ListShare/src/ListSharePOST.java b/Lambdas/Lists/ListShare/src/ListSharePUT.java similarity index 78% rename from Lambdas/Lists/ListShare/src/ListSharePOST.java rename to Lambdas/Lists/ListShare/src/ListSharePUT.java index c986edd..40d0aab 100644 --- a/Lambdas/Lists/ListShare/src/ListSharePOST.java +++ b/Lambdas/Lists/ListShare/src/ListSharePUT.java @@ -3,7 +3,7 @@ import com.amazonaws.services.lambda.runtime.RequestHandler; import java.util.Map; -public class ListSharePOST implements RequestHandler, Object> { +public class ListSharePUT implements RequestHandler, Object> { public Object handleRequest(Map inputMap, Context unfilled) { return BasicHandler.handleRequest(inputMap, unfilled, ListSharer.class); diff --git a/Listify/app/src/main/java/com/example/listify/ListPage.java b/Listify/app/src/main/java/com/example/listify/ListPage.java index 589d947..58e37eb 100644 --- a/Listify/app/src/main/java/com/example/listify/ListPage.java +++ b/Listify/app/src/main/java/com/example/listify/ListPage.java @@ -116,7 +116,7 @@ public class ListPage extends AppCompatActivity implements Requestor.Receiver { String sharedEmail = sharedEmailText.getText().toString(); ListShare listShare = new ListShare(listID, sharedEmail, "Read, Edit, Delete, Share"); try { - requestor.postObject(listShare); + requestor.putObject(listShare); } catch(Exception e) { e.printStackTrace(); diff --git a/Listify/app/src/main/java/com/example/listify/adapter/ShoppingListsSwipeableAdapter.java b/Listify/app/src/main/java/com/example/listify/adapter/ShoppingListsSwipeableAdapter.java index 24163de..d2d3b49 100644 --- a/Listify/app/src/main/java/com/example/listify/adapter/ShoppingListsSwipeableAdapter.java +++ b/Listify/app/src/main/java/com/example/listify/adapter/ShoppingListsSwipeableAdapter.java @@ -131,7 +131,7 @@ public class ShoppingListsSwipeableAdapter extends BaseAdapter { String sharedEmail = sharedEmailText.getText().toString(); ListShare listShare = new ListShare(curList.getItemID(), sharedEmail, "Read, Edit, Delete, Share"); try { - requestor.postObject(listShare); + requestor.putObject(listShare); } catch(Exception e) { e.printStackTrace(); From d4606df3502a951dc0a25e5337ac237b39aca987 Mon Sep 17 00:00:00 2001 From: NMerz Date: Sat, 14 Nov 2020 15:01:36 -0500 Subject: [PATCH 06/11] Fix unique assertion on share rows --- Lambdas/Lists/ListShare/src/ListSharer.java | 2 +- Listify/app/src/main/java/com/example/listify/ListPage.java | 2 +- .../example/listify/adapter/ShoppingListsSwipeableAdapter.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lambdas/Lists/ListShare/src/ListSharer.java b/Lambdas/Lists/ListShare/src/ListSharer.java index c3a3e10..32c755f 100644 --- a/Lambdas/Lists/ListShare/src/ListSharer.java +++ b/Lambdas/Lists/ListShare/src/ListSharer.java @@ -22,7 +22,7 @@ public class ListSharer implements CallHandler { } final private String CHECK_ACCESS = "SELECT * from ListSharee WHERE listID = ? AND userID = ?;"; - final private String SHARE_LIST = "REPLACE INTO ListSharee(listID, userID, permissionLevel) VALUES(?, ?, ?);"; + final private String SHARE_LIST = "INSERT INTO ListSharee(listID, userID, permissionLevel) VALUES(?, ?, ?) ON DUPLICATE;"; public Object conductAction(Map bodyMap, HashMap queryString, String cognitoID) throws SQLException { PreparedStatement checkAccess = connection.prepareStatement(CHECK_ACCESS); diff --git a/Listify/app/src/main/java/com/example/listify/ListPage.java b/Listify/app/src/main/java/com/example/listify/ListPage.java index 58e37eb..8714af7 100644 --- a/Listify/app/src/main/java/com/example/listify/ListPage.java +++ b/Listify/app/src/main/java/com/example/listify/ListPage.java @@ -114,7 +114,7 @@ public class ListPage extends AppCompatActivity implements Requestor.Receiver { public void onClick(DialogInterface dialog, int which) { EditText sharedEmailText = (EditText) codeView.findViewById(R.id.editTextTextSharedEmail); String sharedEmail = sharedEmailText.getText().toString(); - ListShare listShare = new ListShare(listID, sharedEmail, "Read, Edit, Delete, Share"); + ListShare listShare = new ListShare(listID, sharedEmail, "Read, Write, Delete, Share"); try { requestor.putObject(listShare); } diff --git a/Listify/app/src/main/java/com/example/listify/adapter/ShoppingListsSwipeableAdapter.java b/Listify/app/src/main/java/com/example/listify/adapter/ShoppingListsSwipeableAdapter.java index d2d3b49..8fa0d6a 100644 --- a/Listify/app/src/main/java/com/example/listify/adapter/ShoppingListsSwipeableAdapter.java +++ b/Listify/app/src/main/java/com/example/listify/adapter/ShoppingListsSwipeableAdapter.java @@ -129,7 +129,7 @@ public class ShoppingListsSwipeableAdapter extends BaseAdapter { public void onClick(DialogInterface dialog, int which) { EditText sharedEmailText = (EditText) codeView.findViewById(R.id.editTextTextSharedEmail); String sharedEmail = sharedEmailText.getText().toString(); - ListShare listShare = new ListShare(curList.getItemID(), sharedEmail, "Read, Edit, Delete, Share"); + ListShare listShare = new ListShare(curList.getItemID(), sharedEmail, "Read, Write, Delete, Share"); try { requestor.putObject(listShare); } From b478ace5529645b2673fdd45dd4da2060ae2dd9f Mon Sep 17 00:00:00 2001 From: NMerz Date: Sat, 14 Nov 2020 15:02:04 -0500 Subject: [PATCH 07/11] Update delete to use delete permission Previously used list creator as filter --- Lambdas/Lists/List/src/ListDeleter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lambdas/Lists/List/src/ListDeleter.java b/Lambdas/Lists/List/src/ListDeleter.java index f3761e9..d948007 100644 --- a/Lambdas/Lists/List/src/ListDeleter.java +++ b/Lambdas/Lists/List/src/ListDeleter.java @@ -10,7 +10,7 @@ public class ListDeleter implements CallHandler { private final Connection connection; private final String cognitoID; - private final String GET_LISTS = "SELECT * FROM List WHERE (owner = ? AND listID = ?);"; + private final String ACCESS_CHECK = "SELECT * from ListSharee WHERE userID = ? and listID = ?;"; private final String DELETE_LIST = "DELETE FROM List WHERE listID = ?;"; private final String DELETE_REQUESTOR_ACCESS = "DELETE FROM ListSharee where listID = ? AND userID = ?;"; private final String DELETE_LIST_ACCESS = "DELETE FROM ListSharee where listID = ?;"; @@ -30,7 +30,7 @@ public class ListDeleter implements CallHandler { System.out.println(cleanRequestorAccess); cleanRequestorAccess.executeUpdate(); - PreparedStatement accessCheck = connection.prepareStatement(GET_LISTS); + PreparedStatement accessCheck = connection.prepareStatement(ACCESS_CHECK); accessCheck.setString(1, cognitoID); accessCheck.setInt(2, listID); System.out.println(accessCheck); From 2c233313548ac12e1f58bdeb785a280309d1bf0f Mon Sep 17 00:00:00 2001 From: NMerz Date: Sat, 14 Nov 2020 15:16:52 -0500 Subject: [PATCH 08/11] Finish ON DUPLICATE in list sharing --- Lambdas/Lists/ListShare/src/ListSharer.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lambdas/Lists/ListShare/src/ListSharer.java b/Lambdas/Lists/ListShare/src/ListSharer.java index 32c755f..2d55631 100644 --- a/Lambdas/Lists/ListShare/src/ListSharer.java +++ b/Lambdas/Lists/ListShare/src/ListSharer.java @@ -22,7 +22,7 @@ public class ListSharer implements CallHandler { } final private String CHECK_ACCESS = "SELECT * from ListSharee WHERE listID = ? AND userID = ?;"; - final private String SHARE_LIST = "INSERT INTO ListSharee(listID, userID, permissionLevel) VALUES(?, ?, ?) ON DUPLICATE;"; + final private String SHARE_LIST = "INSERT INTO ListSharee(listID, userID, permissionLevel) VALUES(?, ?, ?) ON DUPLICATE KEY UPDATE permissionLevel = ?;"; public Object conductAction(Map bodyMap, HashMap queryString, String cognitoID) throws SQLException { PreparedStatement checkAccess = connection.prepareStatement(CHECK_ACCESS); @@ -67,6 +67,7 @@ public class ListSharer implements CallHandler { shareList.setString(2, shareWithSub); Integer permissionLevel = Integer.parseInt(bodyMap.get("permissionLevel").toString()); shareList.setInt(3, permissionLevel); + shareList.setInt(4, permissionLevel); shareList.executeUpdate(); connection.commit(); return null; From 7cb9639f9ae40e63e5cf0b9c593e91388ee450b8 Mon Sep 17 00:00:00 2001 From: NMerz Date: Sat, 14 Nov 2020 15:17:56 -0500 Subject: [PATCH 09/11] Refine delete access The requestor's access cannot be removed until after permissions are checked. Note, if the user does have permissions, they are remove along with all other users below these changes. --- Lambdas/Lists/List/src/ListDeleter.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Lambdas/Lists/List/src/ListDeleter.java b/Lambdas/Lists/List/src/ListDeleter.java index d948007..b999c4f 100644 --- a/Lambdas/Lists/List/src/ListDeleter.java +++ b/Lambdas/Lists/List/src/ListDeleter.java @@ -24,11 +24,6 @@ public class ListDeleter implements CallHandler { @Override public Object conductAction(Map bodyMap, HashMap queryMap, String cognitoID) throws SQLException { Integer listID = Integer.parseInt(queryMap.get("id")); - PreparedStatement cleanRequestorAccess = connection.prepareStatement(DELETE_REQUESTOR_ACCESS); - cleanRequestorAccess.setInt(1, listID); - cleanRequestorAccess.setString(2, cognitoID); - System.out.println(cleanRequestorAccess); - cleanRequestorAccess.executeUpdate(); PreparedStatement accessCheck = connection.prepareStatement(ACCESS_CHECK); accessCheck.setString(1, cognitoID); @@ -40,7 +35,12 @@ public class ListDeleter implements CallHandler { } else { Integer permissionLevel = userLists.getInt("permissionLevel"); if (!ListPermissions.hasPermission(permissionLevel, "Delete")) { - throw new AccessControlException("User " + cognitoID + " does not have permission to delete list " + listID); + PreparedStatement cleanRequestorAccess = connection.prepareStatement(DELETE_REQUESTOR_ACCESS); + cleanRequestorAccess.setInt(1, listID); + cleanRequestorAccess.setString(2, cognitoID); + System.out.println(cleanRequestorAccess); + cleanRequestorAccess.executeUpdate(); + return null; } } PreparedStatement cleanAccess = connection.prepareStatement(DELETE_LIST_ACCESS); From 7d827a4a7e9bc672a07353faf4a10c5a2a316a7e Mon Sep 17 00:00:00 2001 From: NMerz Date: Sun, 15 Nov 2020 10:38:43 -0500 Subject: [PATCH 10/11] Handle unshares with PUT --- Lambdas/Lists/List/src/ListGetter.java | 7 +++++-- Lambdas/Lists/ListShare/src/ListSharer.java | 3 ++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Lambdas/Lists/List/src/ListGetter.java b/Lambdas/Lists/List/src/ListGetter.java index de3fe5f..982a948 100644 --- a/Lambdas/Lists/List/src/ListGetter.java +++ b/Lambdas/Lists/List/src/ListGetter.java @@ -43,13 +43,16 @@ public class ListGetter implements CallHandler{ int sharees = 0; boolean verifiedAccess = false; while ((sharees < 2 && accessResults.next()) || !verifiedAccess) { + int permissionLevel = accessResults.getInt("permissionLevel"); if (accessResults.getString("userID").equals(cognitoID)) { verifiedAccess = true; - if (!ListPermissions.hasPermission(accessResults.getInt("permissionLevel"), "Read")) { + if (!ListPermissions.hasPermission(permissionLevel, "Read")) { throw new AccessControlException("User " + cognitoID + " does not have permission to read list " + id); } } - sharees++; + if (permissionLevel > 0) { + sharees++; + } } boolean shared = false; if (sharees > 1) { diff --git a/Lambdas/Lists/ListShare/src/ListSharer.java b/Lambdas/Lists/ListShare/src/ListSharer.java index 2d55631..f55d337 100644 --- a/Lambdas/Lists/ListShare/src/ListSharer.java +++ b/Lambdas/Lists/ListShare/src/ListSharer.java @@ -22,7 +22,8 @@ public class ListSharer implements CallHandler { } final private String CHECK_ACCESS = "SELECT * from ListSharee WHERE listID = ? AND userID = ?;"; - final private String SHARE_LIST = "INSERT INTO ListSharee(listID, userID, permissionLevel) VALUES(?, ?, ?) ON DUPLICATE KEY UPDATE permissionLevel = ?;"; + final private String SHARE_LIST = "INSERT INTO ListSharee(listID, userID, permissionLevel, uiPosition) VALUES(?, ?, ?, ?) ON DUPLICATE KEY UPDATE permissionLevel = ?;"; + public Object conductAction(Map bodyMap, HashMap queryString, String cognitoID) throws SQLException { PreparedStatement checkAccess = connection.prepareStatement(CHECK_ACCESS); From f8db33bde490e5b3f65e09666a2d493c7b0812ee Mon Sep 17 00:00:00 2001 From: NMerz Date: Sun, 15 Nov 2020 17:29:37 -0500 Subject: [PATCH 11/11] Add chain id list retrieval Update ChainGetter to work with getListOfIds --- Lambdas/Lists/Chain/src/ChainGetter.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Lambdas/Lists/Chain/src/ChainGetter.java b/Lambdas/Lists/Chain/src/ChainGetter.java index f1775a0..e6cee3b 100644 --- a/Lambdas/Lists/Chain/src/ChainGetter.java +++ b/Lambdas/Lists/Chain/src/ChainGetter.java @@ -2,6 +2,7 @@ import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.ArrayList; import java.util.HashMap; import java.util.Map; @@ -9,6 +10,7 @@ public class ChainGetter implements CallHandler { private final Connection connection; private final String GET_CHAIN = "SELECT * FROM Chain WHERE chainID = ?;"; + private final String GET_CHAINS = "SELECT chainID FROM Chain;"; public ChainGetter(Connection connection, String cognitoID) { this.connection = connection; @@ -16,8 +18,21 @@ public class ChainGetter implements CallHandler { @Override public Object conductAction(Map bodyMap, HashMap queryMap, String cognitoID) throws SQLException { + Integer id = Integer.parseInt(queryMap.get("id")); + if (id == -1) { + PreparedStatement getChains = connection.prepareStatement(GET_CHAINS); + System.out.println(getChains); + ResultSet getChainsResults = getChains.executeQuery(); + System.out.println(getChainsResults); + ArrayList chainIDs = new ArrayList<>(); + while (getChainsResults.next()) { + chainIDs.add(getChainsResults.getInt("chainID")); + } + return chainIDs; + } + PreparedStatement statement = connection.prepareStatement(GET_CHAIN); - statement.setInt(1, Integer.parseInt(queryMap.get("id"))); + statement.setInt(1, id); System.out.println(statement); ResultSet queryResults = statement.executeQuery(); queryResults.first();