diff --git a/.github/.keep b/.github/.keep new file mode 100644 index 000000000..e69de29bb diff --git a/.github/workflows/ci-cd.yaml b/.github/workflows/ci-cd.yaml new file mode 100644 index 000000000..6b47f2fc7 --- /dev/null +++ b/.github/workflows/ci-cd.yaml @@ -0,0 +1,79 @@ +name: AWS Lambda CI/CD +on: + push: + branches: [main] +jobs: + build-and-deploy: + permissions: + id-token: write # This is required for requesting the JWT + contents: read # This is required for actions/checkout + + runs-on: ubuntu-latest + steps: + - name: Code Checkout + uses: actions/checkout@v3 + + - name: Setup Java + uses: actions/setup-java@v3 + with: + distribution: 'corretto' + java-version: '17' + +# - name: Build GetMyPostList Lambda function +# run: | +# cd GetMyPostList +# mvn clean package -B +# cd .. +# +# - name: Build GetPostList Lambda function +# run: | +# cd GetPostList +# mvn clean package -B +# cd .. +# +# +# - name: Build UpdateMyPostInfo Lambda function +# run: | +# cd UpdateMyPostInfo +# mvn clean package -B +# cd .. + + - name: Build GetSpecificPostDetail Lambda function + run: | + cd code/backend/RentalNinja/GetSpecificPostDetail + mvn clean package -B + cd .. + + - name: Build GetPresignedUrl Lambda function + run: | + cd code/backend/RentalNinja/GetPresignedUrl + mvn clean package -B + cd .. + + - name: Build UploadPost Lambda function + run: | + cd code/backend/RentalNinja/UploadPost + mvn clean package -B + cd .. + + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: arn:aws:iam::730335295917:role/github-action-lambda + aws-region: us-east-2 + + - name: Create AWS Lambda Function + run: | + aws lambda create-function --function-name GetPresignedUrl --runtime java17 --handler com.rundong.GetPresignedUrl::handleRequest --role arn:aws:iam::730335295917:role/lambda-role --zip-file fileb://code/backend/RentalNinja/GetPresignedUrl/target/GetPresignedUrl-1.0-SNAPSHOT.jar + aws lambda create-function --function-name UploadPost --runtime java17 --handler com.rundong.UploadPost::handleRequest --role arn:aws:iam::730335295917:role/lambda-role --zip-file fileb://code/backend/RentalNinja/UploadPost/target/UploadPost-1.0-SNAPSHOT.jar + aws lambda create-function --function-name GetSpecificPostDetail --runtime java17 --handler com.rundong.GetSpecificPostDetail::handleRequest --role arn:aws:iam::730335295917:role/lambda-role --zip-file fileb://code/backend/RentalNinja/GetSpecificPostDetail/target/GetSpecificPostDetail-1.0-SNAPSHOT.jar + continue-on-error: true + + - name: Update Lambda Function + run: | + aws lambda update-function-code --function-name GetPresignedUrl --zip-file fileb://code/backend/RentalNinja/GetPresignedUrl/target/GetPresignedUrl-1.0-SNAPSHOT.jar + aws lambda update-function-code --function-name UploadPost --zip-file fileb://code/backend/RentalNinja/UploadPost/target/UploadPost-1.0-SNAPSHOT.jar + aws lambda update-function-code --function-name GetSpecificPostDetail --zip-file fileb://code/backend/RentalNinja/GetSpecificPostDetail/target/GetSpecificPostDetail-1.0-SNAPSHOT.jar + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..65d299249 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.DS_Store +.DS_Store diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 000000000..13566b81b --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/aws.xml b/.idea/aws.xml new file mode 100644 index 000000000..1850186a1 --- /dev/null +++ b/.idea/aws.xml @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 000000000..8c171c7d5 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 000000000..df7189e0d --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 000000000..712ab9d98 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 000000000..288598561 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,16 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 000000000..a0733a5cd --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/project.iml b/.idea/project.iml new file mode 100644 index 000000000..d6ebd4805 --- /dev/null +++ b/.idea/project.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 000000000..35eb1ddfb --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 802192f46..b12af06cc 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,63 @@ -# GroupProjectTemplate -Please make sure to modify this readme file as well as the "about" property of the project! +# Project: Rent & Housing Platform + +## Project Introduction: +The Rent & Housing Platform is a web application designed to streamline the housing search process for students. Whether they are looking for shared apartments, individual rental properties, or housing information, our platform offers a seamless and efficient user experience +Key features include user registration and management, posting and searching rental listings, and collecting rental details. + +## Objectives + +The primary objectives of this web application are to: +- User Registration and Profile Management: Students can create accounts, manage their profiles, and save listings. +- Rental Listings: Users can post, browse, and filter rental properties based on various criteria such as location, price, and property type. +- Advanced Search and Filtering: Our platform allows students to search properties using filters like price range, proximity to universities, and property amenities. +- Real-time Performance Enhancements: our platform ensures fast and efficient data access, providing users with quick responses and real-time updates. +- Scalable and Reliable Backend: Built using Java and powered by DynamoDB, the system is designed to handle large volumes of data while maintaining performance, ensuring the platform can grow as more users join. + +## Tech Stack + +- **Frontend**: Vue.js for responsive and dynamic user interfaces. +- **Backend**: Java (AWS Lambda) for handling business logic and server-side processes. +- **Database**: AWS DynamoDB Service for data storage and management. + +## Installation and Setup + +### Prerequisites +- **Java**: Version 17 or higher +- **Vue.js**: Version 3.53 or higher +- **Dynamodb**: AWS DynamoDB Service + +### Steps +1. **Clone the Repository** + ```bash + git clone https://github.com/BUMETCS673/seprojects-cs673f24a2team2.git + ``` +2. **Frontend(Vue.js)** + ```bash + cd code/frontend + npm install + ``` +3. **Backend(Java Spring Boot)** + ```bash + cd code/backend + 1. install sam cli(You will need an AWS account and properly configured AWS credentials.) + 2. sam local invoke --debug-port --event + ``` +4. **Database Configuration:** +- Make sure your AWS credentials are set up to access DynamoDB. + +5. **Access the Application** +- Frontend: Open your browser and navigate to http://localhost:8081 to access the platform. +- Backend API: The backend is running at http://localhost:8080. + +## Team Introduction: +- Yongjing Wu (Team Leader) +- Xueqi Zhou (Requirement Leader) +- Yueyang He (Design and Implementation Leader) +- Rundong Zhong (Configuration Leader) +- Xiang Zhang (QA Leader) +- Jiacheng Ding (Security Leader) + +## Related Resources: +- Jira: https://rentandhousing.atlassian.net/jira/software/projects/SCRUM/boards/1 +- Google Drive: https://drive.google.com/drive/u/3/folders/1tMHmvLavN5HOh6yXjT-2AVVOctPHYFme +- Github: https://github.com/BUMETCS673/seprojects-cs673olf24team2 diff --git a/code/backend/Readme.md b/code/backend/Readme.md new file mode 100644 index 000000000..762e28e42 --- /dev/null +++ b/code/backend/Readme.md @@ -0,0 +1 @@ +This folder contains all backend source code and test code. diff --git a/code/backend/RentalNinja/.gitignore b/code/backend/RentalNinja/.gitignore new file mode 100644 index 000000000..fd697eefc --- /dev/null +++ b/code/backend/RentalNinja/.gitignore @@ -0,0 +1,45 @@ +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +replay_pid* + +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### aws lambda +debugEvents/ +template.yaml +.aws-sam/ +.github/ \ No newline at end of file diff --git a/code/backend/RentalNinja/GetMyPostList/pom.xml b/code/backend/RentalNinja/GetMyPostList/pom.xml new file mode 100644 index 000000000..0bb54e268 --- /dev/null +++ b/code/backend/RentalNinja/GetMyPostList/pom.xml @@ -0,0 +1,25 @@ + + 4.0.0 + + com.rundong + GetMyPostList + 1.0-SNAPSHOT + jar + + GetMyPostList + http://maven.apache.org + + + UTF-8 + + + + + junit + junit + 3.8.1 + test + + + diff --git a/code/backend/RentalNinja/GetMyPostList/src/main/java/com/rundong/App.java b/code/backend/RentalNinja/GetMyPostList/src/main/java/com/rundong/App.java new file mode 100644 index 000000000..55a9b28d7 --- /dev/null +++ b/code/backend/RentalNinja/GetMyPostList/src/main/java/com/rundong/App.java @@ -0,0 +1,13 @@ +package com.rundong; + +/** + * Hello world! + * + */ +public class App +{ + public static void main( String[] args ) + { + System.out.println( "Hello World!" ); + } +} diff --git a/code/backend/RentalNinja/GetMyPostList/src/test/java/com/rundong/AppTest.java b/code/backend/RentalNinja/GetMyPostList/src/test/java/com/rundong/AppTest.java new file mode 100644 index 000000000..94ab576bc --- /dev/null +++ b/code/backend/RentalNinja/GetMyPostList/src/test/java/com/rundong/AppTest.java @@ -0,0 +1,38 @@ +package com.rundong; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +/** + * Unit test for simple App. + */ +public class AppTest + extends TestCase +{ + /** + * Create the test case + * + * @param testName name of the test case + */ + public AppTest( String testName ) + { + super( testName ); + } + + /** + * @return the suite of tests being tested + */ + public static Test suite() + { + return new TestSuite( AppTest.class ); + } + + /** + * Rigourous Test :-) + */ + public void testApp() + { + assertTrue( true ); + } +} diff --git a/code/backend/RentalNinja/GetPostList/pom.xml b/code/backend/RentalNinja/GetPostList/pom.xml new file mode 100644 index 000000000..1e4188647 --- /dev/null +++ b/code/backend/RentalNinja/GetPostList/pom.xml @@ -0,0 +1,27 @@ + + 4.0.0 + + com.rundong + GetPostList + 1.0-SNAPSHOT + jar + + GetPostList + http://maven.apache.org + + + UTF-8 + 17 + 17 + + + + + org.junit.jupiter + junit-jupiter + 5.10.3 + test + + + diff --git a/code/backend/RentalNinja/GetPostList/src/main/java/com/rundong/App.java b/code/backend/RentalNinja/GetPostList/src/main/java/com/rundong/App.java new file mode 100644 index 000000000..55a9b28d7 --- /dev/null +++ b/code/backend/RentalNinja/GetPostList/src/main/java/com/rundong/App.java @@ -0,0 +1,13 @@ +package com.rundong; + +/** + * Hello world! + * + */ +public class App +{ + public static void main( String[] args ) + { + System.out.println( "Hello World!" ); + } +} diff --git a/code/backend/RentalNinja/GetPostList/src/test/java/com/rundong/AppTest.java b/code/backend/RentalNinja/GetPostList/src/test/java/com/rundong/AppTest.java new file mode 100644 index 000000000..94ab576bc --- /dev/null +++ b/code/backend/RentalNinja/GetPostList/src/test/java/com/rundong/AppTest.java @@ -0,0 +1,38 @@ +package com.rundong; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +/** + * Unit test for simple App. + */ +public class AppTest + extends TestCase +{ + /** + * Create the test case + * + * @param testName name of the test case + */ + public AppTest( String testName ) + { + super( testName ); + } + + /** + * @return the suite of tests being tested + */ + public static Test suite() + { + return new TestSuite( AppTest.class ); + } + + /** + * Rigourous Test :-) + */ + public void testApp() + { + assertTrue( true ); + } +} diff --git a/code/backend/RentalNinja/GetPresignedUrl/pom.xml b/code/backend/RentalNinja/GetPresignedUrl/pom.xml new file mode 100644 index 000000000..42e493c14 --- /dev/null +++ b/code/backend/RentalNinja/GetPresignedUrl/pom.xml @@ -0,0 +1,62 @@ + + 4.0.0 + + com.rundong + GetPresignedUrl + 1.0-SNAPSHOT + jar + + GetPresignedUrl + http://maven.apache.org + + + UTF-8 + 17 + 17 + + + + + com.google.code.gson + gson + 2.10.1 + + + com.amazonaws + aws-lambda-java-events + 3.12.0 + + + com.amazonaws + aws-java-sdk-s3 + 1.12.771 + + + com.amazonaws + aws-lambda-java-core + 1.2.3 + + + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.6.0 + + false + + + + package + + shade + + + + + + + diff --git a/code/backend/RentalNinja/GetPresignedUrl/src/main/java/com/rundong/Error.java b/code/backend/RentalNinja/GetPresignedUrl/src/main/java/com/rundong/Error.java new file mode 100644 index 000000000..0c5ac48d3 --- /dev/null +++ b/code/backend/RentalNinja/GetPresignedUrl/src/main/java/com/rundong/Error.java @@ -0,0 +1,31 @@ +package com.rundong; + +public class Error { + private String errorCode; + private String errorMessage; + + + public String getErrorCode() { + return errorCode; + } + + public void setErrorCode(String errorCode) { + this.errorCode = errorCode; + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + @Override + public String toString() { + return "Error{" + + "errorCode='" + errorCode + '\'' + + ", errorMessage='" + errorMessage + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/code/backend/RentalNinja/GetPresignedUrl/src/main/java/com/rundong/GetPresignedUrl.java b/code/backend/RentalNinja/GetPresignedUrl/src/main/java/com/rundong/GetPresignedUrl.java new file mode 100644 index 000000000..cfd0aa70e --- /dev/null +++ b/code/backend/RentalNinja/GetPresignedUrl/src/main/java/com/rundong/GetPresignedUrl.java @@ -0,0 +1,104 @@ +package com.rundong; + +import com.amazonaws.HttpMethod; +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.LambdaLogger; +import com.amazonaws.services.lambda.runtime.RequestHandler; +import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent; +import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent; +import com.amazonaws.services.lambda.runtime.logging.LogLevel; +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.AmazonS3ClientBuilder; +import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest; +import com.amazonaws.util.StringUtils; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * Rundong Zhong + * + */ +public class GetPresignedUrl implements RequestHandler { + + private final AmazonS3 s3Client = AmazonS3ClientBuilder.defaultClient(); + private static final Gson gson = new GsonBuilder().setPrettyPrinting().create(); + @Override + public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent event, final Context context) { + LambdaLogger logger = context.getLogger(); + logger.log("Function" + context.getFunctionName() + "is called", LogLevel.INFO); + + // Get user ID from request context + Object claims = event.getRequestContext().getAuthorizer().get("claims"); + try { + if (!(claims instanceof Map)) { + throw new RuntimeException("request authorization header claims not type of map"); + } + }catch (RuntimeException e){ + logger.log("convert claims in auth header to map failed", LogLevel.ERROR); + return returnApiResponse(400, "auth header not valid.", "auth header not valid.", "400", logger); + } + Map claimsMap = (Map) claims; + String username = (String)claimsMap.get("cognito:username"); + + // Log or use the user ID as needed + logger.log("Authenticated User ID: " + username, LogLevel.INFO); + + // generate pre-signed url + logger.log("Generating pre-signed URL..."); + String bucketName = "rentalninja"; + String objectKey = System.currentTimeMillis() + ".png"; + + // Set expiration for the pre-signed URL (e.g., 15 minutes) + Date expiration = new Date(); + long expTimeMillis = expiration.getTime(); + expTimeMillis += 1000 * 60 * 15; // 15 minutes + expiration.setTime(expTimeMillis); + + // Generate the pre-signed URL + GeneratePresignedUrlRequest generatePresignedUrlRequest = + new GeneratePresignedUrlRequest(bucketName, objectKey) + .withMethod(HttpMethod.PUT) + .withExpiration(expiration); + + String preSignedUrl = s3Client.generatePresignedUrl(generatePresignedUrlRequest).toString(); + logger.log("Pre-signed URL generated: " + preSignedUrl); + + + //prepare response body + Map responseBody = new HashMap<>(); + responseBody.put("presignedUrl", preSignedUrl); + responseBody.put("objectKey", objectKey); + + // Convert the response to JSON + String json = gson.toJson(responseBody); + + // String responseBody = "{\"presignedUrl\": \"" + preSignedUrl + "\", \"objectKey\": \"" + objectKey + "\"}"; + return returnApiResponse(200, json, null, null, logger); + } + + public APIGatewayProxyResponseEvent returnApiResponse(int statusCode, String responseBody, + String errorMessage, String errorCode, LambdaLogger logger){ + final Error error = new Error(); + if(!StringUtils.isNullOrEmpty(errorCode)){ + error.setErrorCode(errorCode); + error.setErrorMessage(errorMessage); + } + + // Prepare response header + Map responseHeaders = new HashMap<>(); + responseHeaders.put("Content-Type", "application/json"); + + APIGatewayProxyResponseEvent responseEvent = new APIGatewayProxyResponseEvent() + .withHeaders(responseHeaders) + .withStatusCode(statusCode) + .withBody(gson.toJson(new Response(statusCode, responseBody, error))); + logger.log("\n" + responseEvent.toString(), LogLevel.INFO); + + return responseEvent; + + } +} diff --git a/code/backend/RentalNinja/GetPresignedUrl/src/main/java/com/rundong/RequestBody.java b/code/backend/RentalNinja/GetPresignedUrl/src/main/java/com/rundong/RequestBody.java new file mode 100644 index 000000000..fa1af2e58 --- /dev/null +++ b/code/backend/RentalNinja/GetPresignedUrl/src/main/java/com/rundong/RequestBody.java @@ -0,0 +1,4 @@ +package com.rundong; + +public record RequestBody(String field1) { +} diff --git a/code/backend/RentalNinja/GetPresignedUrl/src/main/java/com/rundong/Response.java b/code/backend/RentalNinja/GetPresignedUrl/src/main/java/com/rundong/Response.java new file mode 100644 index 000000000..f64657fdb --- /dev/null +++ b/code/backend/RentalNinja/GetPresignedUrl/src/main/java/com/rundong/Response.java @@ -0,0 +1,47 @@ +package com.rundong; + +public class Response { + + private int httpStatusCode; + private T responseBody; + private Error error; + + public Response(int httpStatusCode, T responseBody, Error error) { + this.httpStatusCode = httpStatusCode; + this.responseBody = responseBody; + this.error = error; + } + + @Override + public String toString() { + return "Response{" + + "httpStatusCode=" + httpStatusCode + + ", responseBody=" + responseBody + + ", error=" + error + + '}'; + } + + public int getHttpStatusCode() { + return httpStatusCode; + } + + public void setHttpStatusCode(int httpStatusCode) { + this.httpStatusCode = httpStatusCode; + } + + public T getResponseBody() { + return responseBody; + } + + public void setResponseBody(T responseBody) { + this.responseBody = responseBody; + } + + public Error getError() { + return error; + } + + public void setError(Error error) { + this.error = error; + } +} \ No newline at end of file diff --git a/code/backend/RentalNinja/GetPresignedUrl/src/test/java/com/rundong/AppTest.java b/code/backend/RentalNinja/GetPresignedUrl/src/test/java/com/rundong/AppTest.java new file mode 100644 index 000000000..b84458da4 --- /dev/null +++ b/code/backend/RentalNinja/GetPresignedUrl/src/test/java/com/rundong/AppTest.java @@ -0,0 +1,9 @@ +package com.rundong; + + +/** + * Unit test for simple App. + */ +public class AppTest +{ +} diff --git a/code/backend/RentalNinja/GetSpecificPostDetail/pom.xml b/code/backend/RentalNinja/GetSpecificPostDetail/pom.xml new file mode 100644 index 000000000..992ca59be --- /dev/null +++ b/code/backend/RentalNinja/GetSpecificPostDetail/pom.xml @@ -0,0 +1,61 @@ + + 4.0.0 + + com.rundong + GetSpecificPostDetail + 1.0-SNAPSHOT + jar + + GetSpecificPostDetail + http://maven.apache.org + + + UTF-8 + 17 + 17 + + + + + com.google.code.gson + gson + 2.10.1 + + + com.amazonaws + aws-lambda-java-events + 3.12.0 + + + com.amazonaws + aws-lambda-java-core + 1.2.3 + + + com.amazonaws + aws-java-sdk-dynamodb + 1.12.771 + + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.6.0 + + false + + + + package + + shade + + + + + + + diff --git a/code/backend/RentalNinja/GetSpecificPostDetail/src/main/java/com/rundong/DeleteStates.java b/code/backend/RentalNinja/GetSpecificPostDetail/src/main/java/com/rundong/DeleteStates.java new file mode 100644 index 000000000..9a7c3cf0a --- /dev/null +++ b/code/backend/RentalNinja/GetSpecificPostDetail/src/main/java/com/rundong/DeleteStates.java @@ -0,0 +1,6 @@ +package com.rundong; + +public class DeleteStates { + public static final Integer ACTIVE = 0; + public static final Integer DELETED = 1; +} diff --git a/code/backend/RentalNinja/GetSpecificPostDetail/src/main/java/com/rundong/GetSpecificPostDetail.java b/code/backend/RentalNinja/GetSpecificPostDetail/src/main/java/com/rundong/GetSpecificPostDetail.java new file mode 100644 index 000000000..e382420cd --- /dev/null +++ b/code/backend/RentalNinja/GetSpecificPostDetail/src/main/java/com/rundong/GetSpecificPostDetail.java @@ -0,0 +1,62 @@ +package com.rundong; + +import com.amazonaws.services.dynamodbv2.AmazonDynamoDB; +import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder; +import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper; +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.LambdaLogger; +import com.amazonaws.services.lambda.runtime.RequestHandler; +import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent; +import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent; +import com.amazonaws.services.lambda.runtime.logging.LogLevel; +import com.google.gson.Gson; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * Hello world! + * + */ +public class GetSpecificPostDetail implements RequestHandler +{ + private static final AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build(); + private static final DynamoDBMapper dynamoDBMapper = new DynamoDBMapper(client); + @Override + public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent event, final Context context) { + // set up response header + Map responseHeaders = new HashMap<>(); + responseHeaders.put("Content-Type", "application/json"); + responseHeaders.put("X-Custom-Header", "application/json"); + APIGatewayProxyResponseEvent response = new APIGatewayProxyResponseEvent().withHeaders(responseHeaders); + // initialize logger + LambdaLogger logger = context.getLogger(); + logger.log("Function" + context.getFunctionName() + " is called", LogLevel.INFO); + + Gson gson = new Gson(); + Request request = gson.fromJson(event.getBody(), Request.class); + String postId = request.postId(); + logger.log("this is post ID: " + postId, LogLevel.INFO); + + // get specific post from dynamodb + Post post; + try { + post = dynamoDBMapper.load(Post.class, postId); + }catch (Exception e){ + //todo: throw new exception + logger.log("load post with postId error "+e, LogLevel.ERROR); + return new APIGatewayProxyResponseEvent() + .withHeaders(responseHeaders) + .withBody("internal server error!!") + .withStatusCode(500); + } + // convert to json object then return to client + String json = gson.toJson(post); + + return new APIGatewayProxyResponseEvent() + .withHeaders(responseHeaders) + .withBody(json) + .withStatusCode(200); + } +} diff --git a/code/backend/RentalNinja/GetSpecificPostDetail/src/main/java/com/rundong/Post.java b/code/backend/RentalNinja/GetSpecificPostDetail/src/main/java/com/rundong/Post.java new file mode 100644 index 000000000..d2fa5f810 --- /dev/null +++ b/code/backend/RentalNinja/GetSpecificPostDetail/src/main/java/com/rundong/Post.java @@ -0,0 +1,162 @@ +package com.rundong; + +import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute; +import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAutoGeneratedKey; +import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey; +import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable; + +import java.util.Date; + +@DynamoDBTable(tableName = "posts") +public class Post { + + @DynamoDBHashKey(attributeName = "post_id") + @DynamoDBAutoGeneratedKey + private String postId; + + @DynamoDBAttribute(attributeName = "user_id") + private String userId; + + @DynamoDBAttribute(attributeName = "title") + private String title; + + @DynamoDBAttribute(attributeName = "content") + private String content; + + @DynamoDBAttribute(attributeName = "contact_info") + private String contactInfo; + + @DynamoDBAttribute(attributeName = "pic_urls") + private String picUrls; + + @DynamoDBAttribute(attributeName = "country_code") + private String country; + + @DynamoDBAttribute(attributeName = "state_code") + private String state; + + @DynamoDBAttribute(attributeName = "city_code") + private String city; + + /** + * optional, can be something like Allston, downtown + */ + @DynamoDBAttribute(attributeName = "area") + private String area; + + @DynamoDBAttribute(attributeName = "create_time") + private Date createTime; + + @DynamoDBAttribute(attributeName = "update_time") + private Date updateTime; + + /** + * 0: active, 1: deleted + */ + @DynamoDBAttribute(attributeName = "delete_flag") + private Integer deleteFlag; + + public String getPostId() { + return postId; + } + + public void setPostId(String postId) { + this.postId = postId; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getContactInfo() { + return contactInfo; + } + + public void setContactInfo(String contactInfo) { + this.contactInfo = contactInfo; + } + + public String getPicUrls() { + return picUrls; + } + + public void setPicUrls(String picUrls) { + this.picUrls = picUrls; + } + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getArea() { + return area; + } + + public void setArea(String area) { + this.area = area; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + public Date getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(Date updateTime) { + this.updateTime = updateTime; + } + + public Integer getDeleteFlag() { + return deleteFlag; + } + + public void setDeleteFlag(Integer deleteFlag) { + this.deleteFlag = deleteFlag; + } +} diff --git a/code/backend/RentalNinja/GetSpecificPostDetail/src/main/java/com/rundong/Request.java b/code/backend/RentalNinja/GetSpecificPostDetail/src/main/java/com/rundong/Request.java new file mode 100644 index 000000000..60e621c62 --- /dev/null +++ b/code/backend/RentalNinja/GetSpecificPostDetail/src/main/java/com/rundong/Request.java @@ -0,0 +1,4 @@ +package com.rundong; + +public record Request(String postId) { +} diff --git a/code/backend/RentalNinja/GetSpecificPostDetail/src/test/java/com/rundong/AppTest.java b/code/backend/RentalNinja/GetSpecificPostDetail/src/test/java/com/rundong/AppTest.java new file mode 100644 index 000000000..b84458da4 --- /dev/null +++ b/code/backend/RentalNinja/GetSpecificPostDetail/src/test/java/com/rundong/AppTest.java @@ -0,0 +1,9 @@ +package com.rundong; + + +/** + * Unit test for simple App. + */ +public class AppTest +{ +} diff --git a/code/backend/RentalNinja/UpdateMyPostInfo/pom.xml b/code/backend/RentalNinja/UpdateMyPostInfo/pom.xml new file mode 100644 index 000000000..951a5f337 --- /dev/null +++ b/code/backend/RentalNinja/UpdateMyPostInfo/pom.xml @@ -0,0 +1,25 @@ + + 4.0.0 + + com.rundong + UpdateMyPostInfo + 1.0-SNAPSHOT + jar + + UpdateMyPostInfo + http://maven.apache.org + + + UTF-8 + + + + + junit + junit + 3.8.1 + test + + + diff --git a/code/backend/RentalNinja/UpdateMyPostInfo/src/main/java/com/rundong/App.java b/code/backend/RentalNinja/UpdateMyPostInfo/src/main/java/com/rundong/App.java new file mode 100644 index 000000000..55a9b28d7 --- /dev/null +++ b/code/backend/RentalNinja/UpdateMyPostInfo/src/main/java/com/rundong/App.java @@ -0,0 +1,13 @@ +package com.rundong; + +/** + * Hello world! + * + */ +public class App +{ + public static void main( String[] args ) + { + System.out.println( "Hello World!" ); + } +} diff --git a/code/backend/RentalNinja/UpdateMyPostInfo/src/test/java/com/rundong/AppTest.java b/code/backend/RentalNinja/UpdateMyPostInfo/src/test/java/com/rundong/AppTest.java new file mode 100644 index 000000000..94ab576bc --- /dev/null +++ b/code/backend/RentalNinja/UpdateMyPostInfo/src/test/java/com/rundong/AppTest.java @@ -0,0 +1,38 @@ +package com.rundong; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +/** + * Unit test for simple App. + */ +public class AppTest + extends TestCase +{ + /** + * Create the test case + * + * @param testName name of the test case + */ + public AppTest( String testName ) + { + super( testName ); + } + + /** + * @return the suite of tests being tested + */ + public static Test suite() + { + return new TestSuite( AppTest.class ); + } + + /** + * Rigourous Test :-) + */ + public void testApp() + { + assertTrue( true ); + } +} diff --git a/code/backend/RentalNinja/UploadPost/.aws-sam/temp-template.yaml b/code/backend/RentalNinja/UploadPost/.aws-sam/temp-template.yaml new file mode 100644 index 000000000..2fe83e50c --- /dev/null +++ b/code/backend/RentalNinja/UploadPost/.aws-sam/temp-template.yaml @@ -0,0 +1,11 @@ +Resources: + Function: + Type: AWS::Serverless::Function + Properties: + Timeout: 300 + MemorySize: 128 + Handler: com.rundong.UploadPost::handleRequest + CodeUri: /Users/amdyes/Documents/Study/MyProjects/java-learn/test/RentalNinja/UploadPost + Runtime: java17 + Architectures: + - arm64 \ No newline at end of file diff --git a/code/backend/RentalNinja/UploadPost/pom.xml b/code/backend/RentalNinja/UploadPost/pom.xml new file mode 100644 index 000000000..317a037b4 --- /dev/null +++ b/code/backend/RentalNinja/UploadPost/pom.xml @@ -0,0 +1,66 @@ + + 4.0.0 + + com.rundong + UploadPost + 1.0-SNAPSHOT + jar + + UploadPost + http://maven.apache.org + + + UTF-8 + 17 + 17 + + + + + com.google.code.gson + gson + 2.10.1 + + + com.amazonaws + aws-lambda-java-events + 3.12.0 + + + com.amazonaws + aws-lambda-java-core + 1.2.3 + + + org.junit.jupiter + junit-jupiter + 5.10.3 + test + + + com.amazonaws + aws-java-sdk-dynamodb + 1.12.771 + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.6.0 + + false + + + + package + + shade + + + + + + + diff --git a/code/backend/RentalNinja/UploadPost/src/main/java/com/rundong/DeleteStates.java b/code/backend/RentalNinja/UploadPost/src/main/java/com/rundong/DeleteStates.java new file mode 100644 index 000000000..9a7c3cf0a --- /dev/null +++ b/code/backend/RentalNinja/UploadPost/src/main/java/com/rundong/DeleteStates.java @@ -0,0 +1,6 @@ +package com.rundong; + +public class DeleteStates { + public static final Integer ACTIVE = 0; + public static final Integer DELETED = 1; +} diff --git a/code/backend/RentalNinja/UploadPost/src/main/java/com/rundong/Post.java b/code/backend/RentalNinja/UploadPost/src/main/java/com/rundong/Post.java new file mode 100644 index 000000000..d2fa5f810 --- /dev/null +++ b/code/backend/RentalNinja/UploadPost/src/main/java/com/rundong/Post.java @@ -0,0 +1,162 @@ +package com.rundong; + +import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute; +import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAutoGeneratedKey; +import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey; +import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable; + +import java.util.Date; + +@DynamoDBTable(tableName = "posts") +public class Post { + + @DynamoDBHashKey(attributeName = "post_id") + @DynamoDBAutoGeneratedKey + private String postId; + + @DynamoDBAttribute(attributeName = "user_id") + private String userId; + + @DynamoDBAttribute(attributeName = "title") + private String title; + + @DynamoDBAttribute(attributeName = "content") + private String content; + + @DynamoDBAttribute(attributeName = "contact_info") + private String contactInfo; + + @DynamoDBAttribute(attributeName = "pic_urls") + private String picUrls; + + @DynamoDBAttribute(attributeName = "country_code") + private String country; + + @DynamoDBAttribute(attributeName = "state_code") + private String state; + + @DynamoDBAttribute(attributeName = "city_code") + private String city; + + /** + * optional, can be something like Allston, downtown + */ + @DynamoDBAttribute(attributeName = "area") + private String area; + + @DynamoDBAttribute(attributeName = "create_time") + private Date createTime; + + @DynamoDBAttribute(attributeName = "update_time") + private Date updateTime; + + /** + * 0: active, 1: deleted + */ + @DynamoDBAttribute(attributeName = "delete_flag") + private Integer deleteFlag; + + public String getPostId() { + return postId; + } + + public void setPostId(String postId) { + this.postId = postId; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getContactInfo() { + return contactInfo; + } + + public void setContactInfo(String contactInfo) { + this.contactInfo = contactInfo; + } + + public String getPicUrls() { + return picUrls; + } + + public void setPicUrls(String picUrls) { + this.picUrls = picUrls; + } + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getArea() { + return area; + } + + public void setArea(String area) { + this.area = area; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + public Date getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(Date updateTime) { + this.updateTime = updateTime; + } + + public Integer getDeleteFlag() { + return deleteFlag; + } + + public void setDeleteFlag(Integer deleteFlag) { + this.deleteFlag = deleteFlag; + } +} diff --git a/code/backend/RentalNinja/UploadPost/src/main/java/com/rundong/UploadPost.java b/code/backend/RentalNinja/UploadPost/src/main/java/com/rundong/UploadPost.java new file mode 100644 index 000000000..cfceb670c --- /dev/null +++ b/code/backend/RentalNinja/UploadPost/src/main/java/com/rundong/UploadPost.java @@ -0,0 +1,63 @@ +package com.rundong; + +import com.amazonaws.Response; +import com.amazonaws.services.dynamodbv2.AmazonDynamoDB; +import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder; +import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper; +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.LambdaLogger; +import com.amazonaws.services.lambda.runtime.RequestHandler; +import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent; +import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent; +import com.amazonaws.services.lambda.runtime.logging.LogLevel; +import com.amazonaws.util.StringUtils; +import com.google.gson.Gson; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * Hello world! + * + */ +public class UploadPost implements RequestHandler { + + + private static final AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build(); + private static final DynamoDBMapper dynamoDBMapper = new DynamoDBMapper(client); + + @Override + public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent event, final Context context) { + // set up response header + Map responseHeaders = new HashMap<>(); + responseHeaders.put("Content-Type", "application/json"); + responseHeaders.put("X-Custom-Header", "application/json"); + APIGatewayProxyResponseEvent response = new APIGatewayProxyResponseEvent().withHeaders(responseHeaders); + // initialize logger + LambdaLogger logger = context.getLogger(); + logger.log("Function" + context.getFunctionName() + " is called", LogLevel.INFO); + + Gson gson = new Gson(); + Post post = gson.fromJson(event.getBody(), Post.class); + post.setCreateTime(new Date()); + post.setUpdateTime(new Date()); + post.setDeleteFlag(DeleteStates.ACTIVE); + + try { + dynamoDBMapper.save(post); + }catch (Exception e){ + logger.log("save post to dynamodb error: " + e, LogLevel.ERROR); + // todo this need to be modified with error handler + return response + .withStatusCode(500) + .withBody("internal server error!"); + } + String json = gson.toJson("success!"); + + return response + .withStatusCode(200) + .withBody(json); + } + +} diff --git a/code/backend/RentalNinja/UploadPost/src/test/java/com/rundong/AppTest.java b/code/backend/RentalNinja/UploadPost/src/test/java/com/rundong/AppTest.java new file mode 100644 index 000000000..bcc881c1e --- /dev/null +++ b/code/backend/RentalNinja/UploadPost/src/test/java/com/rundong/AppTest.java @@ -0,0 +1,9 @@ +package com.rundong; + + +/** + * Unit test for simple App. + */ +public class AppTest +{ +} diff --git a/demo/Readme.md b/demo/Readme.md index 4b40ee6bb..f5351bdb5 100644 --- a/demo/Readme.md +++ b/demo/Readme.md @@ -1 +1,3 @@ This folder contains all demo vidoes + +### iteration 0 Video: https://drive.google.com/drive/u/3/folders/1tMHmvLavN5HOh6yXjT-2AVVOctPHYFme diff --git a/doc/CS673_ProgressReport_teamX.xlsx b/doc/CS673_ProgressReport_teamX.xlsx new file mode 100644 index 000000000..dcabacc63 Binary files /dev/null and b/doc/CS673_ProgressReport_teamX.xlsx differ diff --git a/doc/CS673_SDD.docx b/doc/CS673_SDD.docx new file mode 100644 index 000000000..8a1ef0334 Binary files /dev/null and b/doc/CS673_SDD.docx differ diff --git a/doc/CS673_SPPP.docx b/doc/CS673_SPPP.docx new file mode 100644 index 000000000..3c3a17817 Binary files /dev/null and b/doc/CS673_SPPP.docx differ diff --git a/doc/CS673_SPPP_RiskManagement.xlsx b/doc/CS673_SPPP_RiskManagement.xlsx new file mode 100644 index 000000000..03ed7549f Binary files /dev/null and b/doc/CS673_SPPP_RiskManagement.xlsx differ diff --git a/doc/CS673_STD.docx b/doc/CS673_STD.docx new file mode 100644 index 000000000..353b40eb1 Binary files /dev/null and b/doc/CS673_STD.docx differ diff --git a/doc/CS673_Team2_MeetingMinutes.docx b/doc/CS673_Team2_MeetingMinutes.docx new file mode 100644 index 000000000..4a371494e Binary files /dev/null and b/doc/CS673_Team2_MeetingMinutes.docx differ diff --git a/doc/CS673_presentation0_team2.pptx b/doc/CS673_presentation0_team2.pptx new file mode 100644 index 000000000..8b877a12f Binary files /dev/null and b/doc/CS673_presentation0_team2.pptx differ diff --git a/team.md b/team.md new file mode 100644 index 000000000..034a9a505 --- /dev/null +++ b/team.md @@ -0,0 +1,6 @@ +### My name is Jiacheng Ding and I enjoy coding!!!! +### My name is Xiang Zhang. I am continuously learning and expanding my knowledge in software engineering and data science. +### My name is Yongjing Wu. I'm in my second semester in the CS MET department. I have 6 years of experience working as a software engineer, primarily focused on backend development. +### My name is Yueyang He. I am currently a student in CS673 and am currently doing Lab 1 of Git/GitHub. +### My name is Rundong Zhong. I am Computer Science student master student and in my final semester. I have two years of experience working as a software engineer, primarily focused on backend development/deployment/solution architecture design. +### My name is Xueqi Zhou. My major is Computer Science. This is my second semester and this is my first git commit.