From 50f500c60229a66efd0b33ecb2d82889cc9622dd Mon Sep 17 00:00:00 2001 From: jayednchee97 Date: Sat, 26 Oct 2024 20:28:32 +0800 Subject: [PATCH] debug and implement update and post accommodation through api --- amplify/backend/backend-config.json | 21 ++ .../generateEncryptionKeyAPI/amplify.state | 6 + .../custom-policies.json | 6 + .../function-parameters.json | 3 + ...ryptionKeyAPI-cloudformation-template.json | 202 ++++++++++++++++++ .../generateEncryptionKeyAPI/src/event.json | 5 + .../generateEncryptionKeyAPI/src/index.js | 24 +++ .../generateEncryptionKeyAPI/src/package.json | 10 + .../generateEncryptionKeyAPI/src/yarn.lock | 8 + .../function/recommendationHandler/src/app.js | 16 +- .../amplify-dependent-resources-ref.d.ts | 7 + amplify/team-provider-info.json | 6 +- src/api/GoogleMapsAPI.tsx | 3 +- src/components/EditImageInputList.tsx | 50 +++++ src/model/EPropertyType.ts | 1 + src/screens/EditAccommodationScreen.tsx | 112 +++++++--- src/screens/HostingStep1.tsx | 70 ++++-- src/screens/ListingDetailScreen.tsx | 18 +- 18 files changed, 511 insertions(+), 57 deletions(-) create mode 100644 amplify/backend/function/generateEncryptionKeyAPI/amplify.state create mode 100644 amplify/backend/function/generateEncryptionKeyAPI/custom-policies.json create mode 100644 amplify/backend/function/generateEncryptionKeyAPI/function-parameters.json create mode 100644 amplify/backend/function/generateEncryptionKeyAPI/generateEncryptionKeyAPI-cloudformation-template.json create mode 100644 amplify/backend/function/generateEncryptionKeyAPI/src/event.json create mode 100644 amplify/backend/function/generateEncryptionKeyAPI/src/index.js create mode 100644 amplify/backend/function/generateEncryptionKeyAPI/src/package.json create mode 100644 amplify/backend/function/generateEncryptionKeyAPI/src/yarn.lock create mode 100644 src/components/EditImageInputList.tsx diff --git a/amplify/backend/backend-config.json b/amplify/backend/backend-config.json index 7e7756f..1f54348 100644 --- a/amplify/backend/backend-config.json +++ b/amplify/backend/backend-config.json @@ -111,6 +111,11 @@ "providerPlugin": "awscloudformation", "service": "Lambda" }, + "generateEncryptionKeyAPI": { + "build": true, + "providerPlugin": "awscloudformation", + "service": "Lambda" + }, "geocodingHandler": { "build": true, "providerPlugin": "awscloudformation", @@ -144,6 +149,22 @@ } ] }, + "AMPLIFY_function_generateEncryptionKeyAPI_deploymentBucketName": { + "usedBy": [ + { + "category": "function", + "resourceName": "generateEncryptionKeyAPI" + } + ] + }, + "AMPLIFY_function_generateEncryptionKeyAPI_s3Key": { + "usedBy": [ + { + "category": "function", + "resourceName": "generateEncryptionKeyAPI" + } + ] + }, "AMPLIFY_function_geocodingHandler_deploymentBucketName": { "usedBy": [ { diff --git a/amplify/backend/function/generateEncryptionKeyAPI/amplify.state b/amplify/backend/function/generateEncryptionKeyAPI/amplify.state new file mode 100644 index 0000000..3062a78 --- /dev/null +++ b/amplify/backend/function/generateEncryptionKeyAPI/amplify.state @@ -0,0 +1,6 @@ +{ + "pluginId": "amplify-nodejs-function-runtime-provider", + "functionRuntime": "nodejs", + "useLegacyBuild": true, + "defaultEditorFile": "src\\index.js" +} \ No newline at end of file diff --git a/amplify/backend/function/generateEncryptionKeyAPI/custom-policies.json b/amplify/backend/function/generateEncryptionKeyAPI/custom-policies.json new file mode 100644 index 0000000..528c94f --- /dev/null +++ b/amplify/backend/function/generateEncryptionKeyAPI/custom-policies.json @@ -0,0 +1,6 @@ +[ + { + "Action": [], + "Resource": [] + } +] \ No newline at end of file diff --git a/amplify/backend/function/generateEncryptionKeyAPI/function-parameters.json b/amplify/backend/function/generateEncryptionKeyAPI/function-parameters.json new file mode 100644 index 0000000..d507877 --- /dev/null +++ b/amplify/backend/function/generateEncryptionKeyAPI/function-parameters.json @@ -0,0 +1,3 @@ +{ + "lambdaLayers": [] +} \ No newline at end of file diff --git a/amplify/backend/function/generateEncryptionKeyAPI/generateEncryptionKeyAPI-cloudformation-template.json b/amplify/backend/function/generateEncryptionKeyAPI/generateEncryptionKeyAPI-cloudformation-template.json new file mode 100644 index 0000000..e7fc82e --- /dev/null +++ b/amplify/backend/function/generateEncryptionKeyAPI/generateEncryptionKeyAPI-cloudformation-template.json @@ -0,0 +1,202 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "{\"createdOn\":\"Windows\",\"createdBy\":\"Amplify\",\"createdWith\":\"12.13.0\",\"stackType\":\"function-Lambda\",\"metadata\":{\"whyContinueWithGen1\":\"\"}}", + "Parameters": { + "CloudWatchRule": { + "Type": "String", + "Default": "NONE", + "Description": " Schedule Expression" + }, + "deploymentBucketName": { + "Type": "String" + }, + "env": { + "Type": "String" + }, + "s3Key": { + "Type": "String" + } + }, + "Conditions": { + "ShouldNotCreateEnvResources": { + "Fn::Equals": [ + { + "Ref": "env" + }, + "NONE" + ] + } + }, + "Resources": { + "LambdaFunction": { + "Type": "AWS::Lambda::Function", + "Metadata": { + "aws:asset:path": "./src", + "aws:asset:property": "Code" + }, + "Properties": { + "Code": { + "S3Bucket": { + "Ref": "deploymentBucketName" + }, + "S3Key": { + "Ref": "s3Key" + } + }, + "Handler": "index.handler", + "FunctionName": { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "generateEncryptionKeyAPI", + { + "Fn::Join": [ + "", + [ + "generateEncryptionKeyAPI", + "-", + { + "Ref": "env" + } + ] + ] + } + ] + }, + "Environment": { + "Variables": { + "ENV": { + "Ref": "env" + }, + "REGION": { + "Ref": "AWS::Region" + } + } + }, + "Role": { + "Fn::GetAtt": [ + "LambdaExecutionRole", + "Arn" + ] + }, + "Runtime": "nodejs18.x", + "Layers": [], + "Timeout": 25 + } + }, + "LambdaExecutionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "RoleName": { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "unirentLambdaRolef4eecc0c", + { + "Fn::Join": [ + "", + [ + "unirentLambdaRolef4eecc0c", + "-", + { + "Ref": "env" + } + ] + ] + } + ] + }, + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + }, + "Action": [ + "sts:AssumeRole" + ] + } + ] + } + } + }, + "lambdaexecutionpolicy": { + "DependsOn": [ + "LambdaExecutionRole" + ], + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyName": "lambda-execution-policy", + "Roles": [ + { + "Ref": "LambdaExecutionRole" + } + ], + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Resource": { + "Fn::Sub": [ + "arn:aws:logs:${region}:${account}:log-group:/aws/lambda/${lambda}:log-stream:*", + { + "region": { + "Ref": "AWS::Region" + }, + "account": { + "Ref": "AWS::AccountId" + }, + "lambda": { + "Ref": "LambdaFunction" + } + } + ] + } + } + ] + } + } + } + }, + "Outputs": { + "Name": { + "Value": { + "Ref": "LambdaFunction" + } + }, + "Arn": { + "Value": { + "Fn::GetAtt": [ + "LambdaFunction", + "Arn" + ] + } + }, + "Region": { + "Value": { + "Ref": "AWS::Region" + } + }, + "LambdaExecutionRole": { + "Value": { + "Ref": "LambdaExecutionRole" + } + }, + "LambdaExecutionRoleArn": { + "Value": { + "Fn::GetAtt": [ + "LambdaExecutionRole", + "Arn" + ] + } + } + } +} \ No newline at end of file diff --git a/amplify/backend/function/generateEncryptionKeyAPI/src/event.json b/amplify/backend/function/generateEncryptionKeyAPI/src/event.json new file mode 100644 index 0000000..fd2722e --- /dev/null +++ b/amplify/backend/function/generateEncryptionKeyAPI/src/event.json @@ -0,0 +1,5 @@ +{ + "key1": "value1", + "key2": "value2", + "key3": "value3" +} diff --git a/amplify/backend/function/generateEncryptionKeyAPI/src/index.js b/amplify/backend/function/generateEncryptionKeyAPI/src/index.js new file mode 100644 index 0000000..15a6dbe --- /dev/null +++ b/amplify/backend/function/generateEncryptionKeyAPI/src/index.js @@ -0,0 +1,24 @@ +const AWS = require("aws-sdk"); +const kms = new AWS.KMS(); + +AWS.config.update({ region: "ap-southeast-1" }); + +exports.handler = async (event) => { + console.log(`EVENT: ${JSON.stringify(event)}`); + try { + const dekParams = { KeyId: keyId, KeySpec: "AES_256" }; + const dekResponse = await kms.generateDataKey(dekParams).promise(); + const plaintextDek = dekResponse.Plaintext.toString("base64"); + console.log("plaintextDek: " + plaintextDek); + return { + statusCode: 200, + body: JSON.stringify({ dek: plaintextDek }) + }; + } catch (error) { + console.error("Error generating DEK:", error); + return { + statusCode: 500, + body: JSON.stringify({ error: error.message }), + }; + } +}; diff --git a/amplify/backend/function/generateEncryptionKeyAPI/src/package.json b/amplify/backend/function/generateEncryptionKeyAPI/src/package.json new file mode 100644 index 0000000..eefc21e --- /dev/null +++ b/amplify/backend/function/generateEncryptionKeyAPI/src/package.json @@ -0,0 +1,10 @@ +{ + "name": "generateencryptionkeyapi", + "version": "2.0.0", + "description": "Lambda function generated by Amplify", + "main": "index.js", + "license": "Apache-2.0", + "devDependencies": { + "@types/aws-lambda": "^8.10.92" + } +} diff --git a/amplify/backend/function/generateEncryptionKeyAPI/src/yarn.lock b/amplify/backend/function/generateEncryptionKeyAPI/src/yarn.lock new file mode 100644 index 0000000..c47ec9b --- /dev/null +++ b/amplify/backend/function/generateEncryptionKeyAPI/src/yarn.lock @@ -0,0 +1,8 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@types/aws-lambda@^8.10.92": + version "8.10.145" + resolved "https://registry.yarnpkg.com/@types/aws-lambda/-/aws-lambda-8.10.145.tgz#b2d31a987f4888e5553ff1819f57cafa475594d9" + integrity sha512-dtByW6WiFk5W5Jfgz1VM+YPA21xMXTuSFoLYIDY0L44jDLLflVPtZkYuu3/YxpGcvjzKFBZLU+GyKjR0HOYtyw== diff --git a/amplify/backend/function/recommendationHandler/src/app.js b/amplify/backend/function/recommendationHandler/src/app.js index 12e299f..95b5ffd 100644 --- a/amplify/backend/function/recommendationHandler/src/app.js +++ b/amplify/backend/function/recommendationHandler/src/app.js @@ -103,22 +103,24 @@ app.post("/recommendation", async function (req, res) { longitude: req.body.coords.longitude }; - // TODO: Check the structure of address and find out how to decrpyt data for (let i = 0; i < data.length; i++) { const address = JSON.parse(data[i].address); console.log(`address[${i}]: ` + JSON.stringify(address, null, 2)); - const addressCoords = { - latitude: address.geo.geometry.location.lat, - longitude: address.geo.geometry.location.lng - }; + // const addressCoords = { + // latitude: address.geo.geometry.location.lat, + // longitude: address.geo.geometry.location.lng + // }; + + const jsonAddress = JSON.parse(address); console.log(`userCoords[${i}]: ` + JSON.stringify(userCoords, null, 2)); - console.log(`addressCoords[${i}]: ` + JSON.stringify(userCoords, null, 2)); + console.log(`jsonAddress.geo[${i}]: ` + JSON.stringify(jsonAddress.geo, null, 2)); // const dist = geolib.getDistance(req.body.coords, address.geo); - const dist = geolib.getDistance(userCoords, addressCoords); + // const dist = geolib.getDistance(userCoords, addressCoords); + const dist = geolib.getDistance(userCoords, jsonAddress.geo); console.log(`dist[${i}]: ` + dist); map.set(data[i], dist); diff --git a/amplify/backend/types/amplify-dependent-resources-ref.d.ts b/amplify/backend/types/amplify-dependent-resources-ref.d.ts index e2c7406..a0693fe 100644 --- a/amplify/backend/types/amplify-dependent-resources-ref.d.ts +++ b/amplify/backend/types/amplify-dependent-resources-ref.d.ts @@ -39,6 +39,13 @@ export type AmplifyDependentResourcesAttributes = { "Name": "string", "Region": "string" }, + "generateEncryptionKeyAPI": { + "Arn": "string", + "LambdaExecutionRole": "string", + "LambdaExecutionRoleArn": "string", + "Name": "string", + "Region": "string" + }, "geocodingHandler": { "Arn": "string", "LambdaExecutionRole": "string", diff --git a/amplify/team-provider-info.json b/amplify/team-provider-info.json index 7f96dad..95c273e 100644 --- a/amplify/team-provider-info.json +++ b/amplify/team-provider-info.json @@ -30,7 +30,11 @@ }, "recommendationHandler": { "deploymentBucketName": "amplify-unirent-staging-195410-deployment", - "s3Key": "amplify-builds/recommendationHandler-726e587555504a4e3555-build.zip" + "s3Key": "amplify-builds/recommendationHandler-2f4134666c38362f412f-build.zip" + }, + "generateEncryptionKeyAPI": { + "deploymentBucketName": "amplify-unirent-staging-195410-deployment", + "s3Key": "amplify-builds/generateEncryptionKeyAPI-4c544d3658454135734e-build.zip" } }, "storage": { diff --git a/src/api/GoogleMapsAPI.tsx b/src/api/GoogleMapsAPI.tsx index 434321a..a3fe09a 100644 --- a/src/api/GoogleMapsAPI.tsx +++ b/src/api/GoogleMapsAPI.tsx @@ -13,7 +13,8 @@ export async function getGeocode(request) { try { const response = await API.post(apiName, path, myInit); - return response; + console.log(response.geometry.location) + return response.geometry.location; } catch (error) { console.error("Error in google maps API: " + error); } diff --git a/src/components/EditImageInputList.tsx b/src/components/EditImageInputList.tsx new file mode 100644 index 0000000..dc7f61e --- /dev/null +++ b/src/components/EditImageInputList.tsx @@ -0,0 +1,50 @@ +import { View, ScrollView } from "react-native"; +import { Storage } from "aws-amplify"; +import { useEffect, useState } from "react"; +import ImageInput from "../components/ImageInput"; + +export default function ImageInputList({ + imageUris = [], + onRemoveImage, + onAddImage, +}) { + const [imageUrls, setImageUrls] = useState([]); + + useEffect(() => { + const fetchImageUrls = async () => { + const urls = await Promise.all( + imageUris.map(async (uri) => { + if (!uri.startsWith("data:image")) { + const convertedUri = await Storage.get(uri); + console.log("Fetched S3 image URI:", convertedUri); + return convertedUri; + } else { + console.log("Base64 image URI detected, skipping fetch:", uri); + return uri; + } + }) + ); + setImageUrls(urls); + }; + fetchImageUrls(); + }, [imageUris]); + + return ( + + + {imageUrls.map((url, index) => ( + + onRemoveImage(imageUris[index])} + /> + + ))} + onAddImage(uri)} + imageUri={undefined} + /> + + + ); +} diff --git a/src/model/EPropertyType.ts b/src/model/EPropertyType.ts index a381582..0d77f34 100644 --- a/src/model/EPropertyType.ts +++ b/src/model/EPropertyType.ts @@ -2,6 +2,7 @@ enum EPropertyType { Condo = "Condo", Landed = "Landed", HDB = "HDB", + UNIVERSITY = "UNIVERSITY" } export default EPropertyType; diff --git a/src/screens/EditAccommodationScreen.tsx b/src/screens/EditAccommodationScreen.tsx index c65f3ef..f0bfe34 100644 --- a/src/screens/EditAccommodationScreen.tsx +++ b/src/screens/EditAccommodationScreen.tsx @@ -14,7 +14,6 @@ import { import { getGeocode } from "../api/GoogleMapsAPI"; import alert from "../components/Alert"; import ImageInputList from "../components/ImageInputList"; -import { updateAccommodation } from "../graphql/mutations"; import EPropertyType from "../model/EPropertyType"; import IAddress from "../model/IAddress"; import IGeo from "../model/IGeo"; @@ -26,6 +25,9 @@ import { getFeatureLabel, } from "../utils/UnitFeatureUtil"; +import { updateAccommodation, updateUniAccommodation } from "../api/AccommodationAPI"; +import EditImageInputList from "../components/EditImageInputList"; + const EditAccommodationScreen = (props: any, uriArray: string[]) => { const navigation = useNavigation(); @@ -36,6 +38,8 @@ const EditAccommodationScreen = (props: any, uriArray: string[]) => { const [unitFeature, setUnitFeature] = useState({}); const [address, setAddress] = useState(); const [propertyType, setPropertyType] = useState(""); + const [userType, setUserType] = useState(null); // State to store userType + const invokeGoogleMaps = async (address: object) => { const resp = await getGeocode(address); @@ -57,16 +61,18 @@ const EditAccommodationScreen = (props: any, uriArray: string[]) => { }; const presetAllValue = () => { + const details = props.route.params.details; + console.log("details"); console.log(details); setTitle(details.title); setDescription(details.description); setPropertyType(details.propertyType); setPrice(details.price.toString()); - setAddress(JSON.parse(details.address)); + setAddress(details.address); setUnitFeature(convertArrayToUnitFeature(details.unitFeature)); - setImageUris(props.route.params.uriArray); + // setImageUris(props.route.params.uriArray); }; const CheckboxGroup = ({ unitFeature, setUnitFeature }) => { @@ -92,6 +98,52 @@ const EditAccommodationScreen = (props: any, uriArray: string[]) => { ); }; + const propertyTypeButton = () => { + + if (userType == "universityPartner") { + return ( + + ); + } else { + return( + + ); + } + + } + const onNavigate = async () => { console.log("Publish"); const authUser = await Auth.currentAuthenticatedUser(); @@ -99,6 +151,7 @@ const EditAccommodationScreen = (props: any, uriArray: string[]) => { const geocode = await invokeGoogleMaps(address); address.geo = geocode; console.log("geo"); + console.log(geocode); console.log(address.geo); const s3ObjectKeys = await uploadToStorage( imageUris, @@ -116,13 +169,20 @@ const EditAccommodationScreen = (props: any, uriArray: string[]) => { availableDate: new Date().toISOString().substring(0, 10), unitFeature: convertUnitFeatureToArray(unitFeature), userId: authUser.attributes.sub, + latitude: geocode.lat, + longitude: geocode.lng, }; console.log("newAccomm"); console.log(newAccomm); - const newAccommData = await API.graphql( - graphqlOperation(updateAccommodation, { input: newAccomm }), - ); - if (newAccommData.data.updateAccommodation) { + // const newAccommData = await API.graphql( + // graphqlOperation(updateAccommodation, { input: newAccomm }), + // ); + + console.log(authUser); + console.log(authUser.attributes['custom:userType']); + const newAccommData = await updateAccommodation(newAccomm); + + if (newAccommData.success) { alert("Update Listing", "Update successful!", [ { text: "OK", @@ -143,10 +203,14 @@ const EditAccommodationScreen = (props: any, uriArray: string[]) => { async function uploadToStorage(imageUris: any[], uuid: string) { const stored = []; + console.log("uploadToStorage"); + console.log(uuid); + console.log(imageUris); for (let index = 0; index < imageUris.length; index++) { const imageUri = imageUris[index]; try { const response = await fetch(imageUri); + console.log(response); const blob = await response.blob(); const resp = await Storage.put(uuid + "/image_" + index, blob, { contentType: "image/jpeg", @@ -176,9 +240,20 @@ const EditAccommodationScreen = (props: any, uriArray: string[]) => { // } useEffect(() => { + const fetchUserType = async () => { + try { + const authUser = await Auth.currentAuthenticatedUser(); + setUserType(authUser.attributes['custom:userType']); // Set userType + } catch (error) { + console.log("Error fetching user type:", error); + } + }; + + fetchUserType(); console.log("edit accommodation"); console.log(props); setImageUris(props.route.params.uriArray); + // setImageUris(props.route.params.details.images); presetAllValue(); // console.log(price); }, []); @@ -197,28 +272,7 @@ const EditAccommodationScreen = (props: any, uriArray: string[]) => { Accommodation Details - + {propertyTypeButton()} (); + const [userType, setUserType] = useState(null); // State to store userType + // const [guest, setGuest] = useState(0); // const [bed, setBed] = useState(0); // const [bath, setBath] = useState(0); @@ -55,23 +58,29 @@ export default function HostingStep1({ navigation, route }) { navigation.navigate("HostingStep2"); }; - return ( - - - - Which of these best describes your place? - + const propertyTypeButton = () => { + if (userType == "universityPartner") { + return ( + + ); + } else { + return( + ); + } + + } + + useEffect(() => { + const fetchUserType = async () => { + try { + const authUser = await Auth.currentAuthenticatedUser(); + setUserType(authUser.attributes['custom:userType']); // Set userType + } catch (error) { + console.log("Error fetching user type:", error); + } + }; + + fetchUserType(); + }, []); + + return ( + + + + Which of these best describes your place? + + + {propertyTypeButton()} { .catch((err) => console.log("Error downloading file:" + err)); } setDetails(data); + + data.address = JSON.parse(JSON.parse(data.address)); + console.log("data.address"); + console.log(data.address); + console.log(data.address.geo); + console.log(array); + setUriArray(array); - setAddress(JSON.parse(data.address)); + setAddress(data.address); setLoading(false); - console.log("Listing details"); - console.log(data); - console.log(array); - console.log(JSON.parse(data.address)); + // console.log("Listing details"); + // console.log(data); + // console.log(array); + // console.log(JSON.parse(data.address)); + } // useEffect(() => {