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(); diff --git a/Lambdas/Lists/List/src/List.java b/Lambdas/Lists/List/src/List.java index eeef2e4..daaa7b0 100644 --- a/Lambdas/Lists/List/src/List.java +++ b/Lambdas/Lists/List/src/List.java @@ -21,10 +21,6 @@ public class List { this.uiPosition = uiPosition; } - public void addItemEntry(ItemEntry entry) { - entries.add(entry); - } - @Override public String toString() { return "List{" + @@ -38,10 +34,6 @@ public class List { '}'; } - public ItemEntry[] getEntries() { - return entries.toArray(new ItemEntry[entries.size()]); - } - public Integer getItemID() { return itemID; } @@ -88,5 +80,12 @@ public class List { public void setUiPosition(Integer uiPosition) { this.uiPosition = uiPosition; + + public ItemEntry[] getEntries() { + return entries.toArray(new ItemEntry[entries.size()]); + } + + public void addItemEntry(ItemEntry entry) { + entries.add(entry); } } diff --git a/Lambdas/Lists/ListShare/src/ListShare.java b/Lambdas/Lists/ListShare/src/ListShare.java new file mode 100644 index 0000000..151d842 --- /dev/null +++ b/Lambdas/Lists/ListShare/src/ListShare.java @@ -0,0 +1,37 @@ +package com.example.listify.data; + +public class ListShare { + Integer listID; + String shareWithEmail; + ArrayList other; + + public ListShare(ResultSet listRow) throws SQLException { + this.listID = listRow.getInt("listID"); + this.shareWithEmail = listRow.getString("userID"); + other = new ArrayList<>(); + } + + public Integer getListID() { + return listID; + } + + public void setListID(Integer listID) { + this.listID = listID; + } + + public String getShareWithEmail() { + return shareWithEmail; + } + + public void setShareWithEmail(String shareWithEmail) { + this.shareWithEmail = shareWithEmail; + } + + public ListShare[] getEntries() { + return other.toArray(new ListShare[other.size()]); + } + + public void addtoList(ListShare entry) { + other.add(entry); + } +} diff --git a/Lambdas/Lists/ListShare/src/ListShareDELETE.java b/Lambdas/Lists/ListShare/src/ListShareDELETE.java new file mode 100644 index 0000000..784a725 --- /dev/null +++ b/Lambdas/Lists/ListShare/src/ListShareDELETE.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 ListShareDELETE implements RequestHandler, Object> { + + public Object handleRequest(Map inputMap, Context unfilled) { + return BasicHandler.handleRequest(inputMap, unfilled, ListShareDeleter.class); + } + +} diff --git a/Lambdas/Lists/ListShare/src/ListShareDeleter.java b/Lambdas/Lists/ListShare/src/ListShareDeleter.java new file mode 100644 index 0000000..7ec0076 --- /dev/null +++ b/Lambdas/Lists/ListShare/src/ListShareDeleter.java @@ -0,0 +1,65 @@ +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; + +public class ListShareDeleter implements CallHandler { + private final Connection connection; + private final String cognitoID; + + private final String GET_LIST_ACCESS = "SELECT * FROM List WHERE (owner = ? AND listID = ?);"; + private final String REMOVE_SHAREE = "DELETE FROM ListSharee WHERE listID = ? AND user = ?;"; + + public ListShareDeleter(Connection connection, String cognitoID) { + this.connection = connection; + this.cognitoID = cognitoID; + } + + @Override + public Object conductAction(Map bodyMap, HashMap queryMap, String cognitoID) throws SQLException { + Integer listID = Integer.parseInt(queryMap.get("id")); + + InvokeRequest invokeRequest = new InvokeRequest(); + invokeRequest.setFunctionName("UserGET"); + invokeRequest.setPayload("{" + + " \"body\": {" + + " \"emailToCheck\": \"" + bodyMap.get("shareWithEmail").toString() + "\"" + + " }," + + " \"params\": {" + + " \"querystring\": {" + + " }" + + " }," + + " \"context\": {" + + " \"sub\": \"not used\"" + + " }" + + "}"); + InvokeResult invokeResult = AWSLambdaClientBuilder.defaultClient().invoke(invokeRequest); + + String shareeID = new String(invokeResult.getPayload().array()).replace("\"", ""); + + //Ensure that the user who is unsharing a list is the owner of that list + PreparedStatement accessCheck = connection.prepareStatement(GET_LIST_ACCESS); + accessCheck.setString(1, cognitoID); + accessCheck.setInt(2, listID); + + ResultSet userLists = accessCheck.executeQuery(); + + //User does not own the list; unshare attempt fails + if (!userLists.next()) { + throw new AccessControlException("User does not have access to list"); + } + + //Unshare the list with the specified sharee + PreparedStatement unshareList = connection.prepareStatement(REMOVE_SHAREE); + unshareList.setInt(1, listID); + unshareList.setInt(2, shareeID); + + cleanAccess.executeUpdate(); + connection.commit(); + + return null; + } +} diff --git a/Lambdas/Lists/ListShare/src/ListShareGET.java b/Lambdas/Lists/ListShare/src/ListShareGET.java new file mode 100644 index 0000000..d59ffcf --- /dev/null +++ b/Lambdas/Lists/ListShare/src/ListShareGET.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 ListShareGET implements RequestHandler, Object> { + + public Object handleRequest(Map inputMap, Context unfilled) { + return BasicHandler.handleRequest(inputMap, unfilled, ListShareGetter.class); + } +} diff --git a/Lambdas/Lists/ListShare/src/ListShareGetter.java b/Lambdas/Lists/ListShare/src/ListShareGetter.java new file mode 100644 index 0000000..009f0d6 --- /dev/null +++ b/Lambdas/Lists/ListShare/src/ListShareGetter.java @@ -0,0 +1,40 @@ +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; + +public class ListShareGetter implements CallHandler{ + private final Connection connection; + private final String cognitoID; + + private final String GET_LISTS = "SELECT * FROM ListSharee WHERE listID = ?;"; + + public ListShareGetter(Connection connection, String cognitoID) { + this.connection = connection; + this.cognitoID = cognitoID; + } + + @Override + public Object conductAction(Map bodyMap, HashMap queryMap, String cognitoID) throws SQLException { + Integer listID = Integer.parseInt(queryMap.get("id")); + + PreparedStatement getList = connection.prepareStatement(GET_LIST); + getList.setInt(1, listID); + + ResultSet getListResults = getList.executeQuery(); + getListResults.first(); + + //ListShare object to hold the data values of the first row retrived + ListShare first = new ListShare(getListResults); + + //Insert the ListShare objects to hold the data of the remaining rows into first's ListShare list + while (getListResults.next()) { + first.addtoList(new ListShare(getListResults)); + } + + return first; + } +} 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 8714af7..309eb2d 100644 --- a/Listify/app/src/main/java/com/example/listify/ListPage.java +++ b/Listify/app/src/main/java/com/example/listify/ListPage.java @@ -283,7 +283,7 @@ public class ListPage extends AppCompatActivity implements Requestor.Receiver { MyAdapter (Context c, ArrayList names, ArrayList stores, ArrayList prices, ArrayList quantity, ArrayList images) { - super(c, R.layout.activity_listproductentry, R.id.productView, names); + super(c, R.layout.shopping_list_product_entry, R.id.productView, names); context = c; pNames = names; pStores = stores; @@ -296,7 +296,7 @@ public class ListPage extends AppCompatActivity implements Requestor.Receiver { @Override public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { LayoutInflater layoutInflater = (LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); - View listproduct = layoutInflater.inflate(R.layout.activity_listproductentry, parent,false); + View listproduct = layoutInflater.inflate(R.layout.shopping_list_product_entry, parent,false); decrQuan = (Button) listproduct.findViewById(R.id.buttonDecr); incrQuan = (Button) listproduct.findViewById(R.id.buttonIncr); diff --git a/Listify/app/src/main/java/com/example/listify/ListSharees.java b/Listify/app/src/main/java/com/example/listify/ListSharees.java new file mode 100644 index 0000000..c7527a8 --- /dev/null +++ b/Listify/app/src/main/java/com/example/listify/ListSharees.java @@ -0,0 +1,102 @@ +package com.example.listify; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.ProgressBar; +import android.widget.TextView; + +import com.bumptech.glide.Glide; +import com.example.listify.adapter.ShareeSwipeableAdapter; +import com.example.listify.adapter.ShoppingListsSwipeableAdapter; +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 org.json.JSONException; + +import java.io.IOException; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import static com.example.listify.MainActivity.am; + +public class ListSharees extends AppCompatActivity implements Requestor.Receiver { + ShareeSwipeableAdapter myAdapter; + Requestor requestor; + ProgressBar loadingListItems; + + + DecimalFormat df = new DecimalFormat("0.00"); + + // TODO: Display a message if their list is empty + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_listofsharees); + + final int listID = (int) getIntent().getSerializableExtra("listID"); + + Properties configs = new Properties(); + try { + configs = AuthManager.loadProperties(this, "android.resource://" + getPackageName() + "/raw/auths.json"); + } catch (IOException | JSONException e) { + e.printStackTrace(); + } + requestor = new Requestor(am, configs.getProperty("apiKey")); + requestor.getObject(Integer.toString(listID), ListShare.class, this); + + loadingListItems = findViewById(R.id.progress_loading_list_items); + loadingListItems.setVisibility(View.VISIBLE); + } + + @Override + public void acceptDelivery(Object delivered) { + ListShare sharee = (ListShare) delivered; + + if(sharee != null) { + SynchronousReceiver listShareReceiver = new SynchronousReceiver<>(); + requestor.getObject(Integer.toString(sharee.getListID()), ListShare.class, listShareReceiver, listShareReceiver); + + ArrayList resultList = new ArrayList<>(); + ListShare result; + + try { + result = listShareReceiver.await(); + } + catch (Exception e) { + e.printStackTrace(); + result = null; + } + + if(result != null) { + resultList.add(result); + + for(ListShare r : result.getEntries()) { + resultList.add(r); + } + + myAdapter = new ShareeSwipeableAdapter(this, resultList); + } + } + } +} diff --git a/Listify/app/src/main/java/com/example/listify/adapter/ShareeSwipeableAdapter.java b/Listify/app/src/main/java/com/example/listify/adapter/ShareeSwipeableAdapter.java new file mode 100644 index 0000000..ac8ee0e --- /dev/null +++ b/Listify/app/src/main/java/com/example/listify/adapter/ShareeSwipeableAdapter.java @@ -0,0 +1,128 @@ +package com.example.listify.adapter; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.Toast; + +import com.chauthai.swipereveallayout.SwipeRevealLayout; +import com.chauthai.swipereveallayout.ViewBinderHelper; +import com.example.listify.AuthManager; +import com.example.listify.ListPage; +import com.example.listify.R; +import com.example.listify.Requestor; +import com.example.listify.data.List; +import com.example.listify.data.ListShare; + +import org.json.JSONException; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Properties; + +import static com.example.listify.MainActivity.am; + +public class ShareeSwipeableAdapter extends BaseAdapter { + private Activity activity; + private ArrayList sharees; + private LayoutInflater inflater; + private final ViewBinderHelper binderHelper; + + public ShareeSwipeableAdapter(Activity activity, ArrayList sharees){ + binderHelper = new ViewBinderHelper(); + this.activity = activity; + this.sharees = sharees; + } + + @Override + public int getCount() { + return sharees.size(); + } + + @Override + public Object getItem(int position) { + return sharees.get(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + ViewHolder holder; + + Properties configs = new Properties(); + try { + configs = AuthManager.loadProperties(activity, "android.resource://" + activity.getPackageName() + "/raw/auths.json"); + } catch (IOException | JSONException e) { + e.printStackTrace(); + } + Requestor requestor = new Requestor(am, configs.getProperty("apiKey")); + + if (inflater == null) { + inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + } + if (convertView == null) { + convertView = inflater.inflate(R.layout.shopping_lists_swipeable_name_item, null); + + holder = new ViewHolder(); + holder.swipeLayout = (SwipeRevealLayout)convertView.findViewById(R.id.swipe_layout); + holder.frontView = convertView.findViewById(R.id.front_layout); + holder.deleteList = convertView.findViewById(R.id.delete_list); + holder.shareList = convertView.findViewById(R.id.share_list); + holder.textView = (TextView) convertView.findViewById(R.id.shopping_list_name); + + convertView.setTag(holder); + } else { + holder = (ViewHolder) convertView.getTag(); + } + + final ListShare currSharee = sharees.get(position); + + // Bind the view to the unique list ID + binderHelper.bind(holder.swipeLayout, currSharee.getShareWithEmail()); + + holder.textView.setText(currSharee.getShareWithEmail()); + + holder.deleteList.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + } + }); + + holder.shareList.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + } + }); + + holder.frontView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + } + }); + + return convertView; + } + + private class ViewHolder { + SwipeRevealLayout swipeLayout; + View frontView; + View deleteList; + View shareList; + TextView textView; + } +} diff --git a/Listify/app/src/main/java/com/example/listify/data/List.java b/Listify/app/src/main/java/com/example/listify/data/List.java index 580eef6..0c4388b 100644 --- a/Listify/app/src/main/java/com/example/listify/data/List.java +++ b/Listify/app/src/main/java/com/example/listify/data/List.java @@ -70,10 +70,6 @@ public class List { this.lastUpdated = lastUpdated; } - public ListEntry[] getEntries() { - return entries; - } - public boolean isShared() { return shared; } @@ -88,5 +84,8 @@ public class List { public void setUiPosition(Integer uiPosition) { this.uiPosition = uiPosition; + + public ListEntry[] getEntries() { + return entries; } } 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 36abd8a..0b3f800 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 @@ -9,9 +9,10 @@ import java.util.Map; public class ListShare { Integer listID; String shareWithEmail; + final ListShare[] other; Integer permissionLevel; - 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 @@ -22,18 +23,20 @@ public class ListShare { keysToPermsTemp.put(7, "share"); keysToPerms = Collections.unmodifiableMap(keysToPermsTemp); } - - public ListShare(Integer listID, String shareWithEmail, Integer permissionLevel) { + + public ListShare(Integer listID, String shareWithEmail, Integer permissionLevel, ListShare[] other) { this.listID = listID; this.shareWithEmail = shareWithEmail; this.permissionLevel = permissionLevel; + this.other = other } - public ListShare(Integer listID, String shareWithEmail, String permissionsRaw) { + public ListShare(Integer listID, String shareWithEmail, String permissionsRaw, ListShare[] other) { String permissions = permissionsRaw.toLowerCase(); this.listID = listID; this.shareWithEmail = shareWithEmail; permissionLevel = 1; + this.other = other; for (Map.Entry keytoPermEntry: keysToPerms.entrySet()) { if (permissions.contains(keytoPermEntry.getValue())) { permissionLevel *= keytoPermEntry.getKey(); @@ -62,6 +65,7 @@ public class ListShare { } toReturn.append("]}"); return toReturn.toString(); + } public Integer getListID() { @@ -79,7 +83,11 @@ public class ListShare { public void setShareWithEmail(String shareWithEmail) { this.shareWithEmail = shareWithEmail; } - + + public ListShare[] getEntries() { + return other; + } + public Integer getPermissionLevel() { return permissionLevel; } @@ -87,5 +95,4 @@ public class ListShare { public void setPermissionLevel(Integer permissionLevel) { this.permissionLevel = permissionLevel; } - } diff --git a/Listify/app/src/main/res/layout/activity_listofsharees.xml b/Listify/app/src/main/res/layout/activity_listofsharees.xml new file mode 100644 index 0000000..58747d3 --- /dev/null +++ b/Listify/app/src/main/res/layout/activity_listofsharees.xml @@ -0,0 +1,22 @@ + + + + + + + \ No newline at end of file diff --git a/Listify/app/src/main/res/layout/activity_listproductentry.xml b/Listify/app/src/main/res/layout/shopping_list_product_entry.xml similarity index 100% rename from Listify/app/src/main/res/layout/activity_listproductentry.xml rename to Listify/app/src/main/res/layout/shopping_list_product_entry.xml