├── .github └── workflows │ └── manual.yml ├── .gitignore ├── CODEOWNERS ├── LICENSE.md ├── README.md └── starter_code ├── auth-course.iml ├── mvnw ├── mvnw.cmd ├── pom.xml ├── src ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── demo │ │ │ ├── SareetaApplication.java │ │ │ ├── controllers │ │ │ ├── CartController.java │ │ │ ├── ItemController.java │ │ │ ├── OrderController.java │ │ │ └── UserController.java │ │ │ └── model │ │ │ ├── persistence │ │ │ ├── Cart.java │ │ │ ├── Item.java │ │ │ ├── User.java │ │ │ ├── UserOrder.java │ │ │ └── repositories │ │ │ │ ├── CartRepository.java │ │ │ │ ├── ItemRepository.java │ │ │ │ ├── OrderRepository.java │ │ │ │ └── UserRepository.java │ │ │ └── requests │ │ │ ├── CreateUserRequest.java │ │ │ └── ModifyCartRequest.java │ └── resources │ │ ├── application.properties │ │ └── data.sql └── test │ └── java │ └── com │ └── example │ └── demo │ └── SareetaApplicationTests.java └── target ├── classes ├── application.properties ├── com │ └── example │ │ └── demo │ │ ├── SareetaApplication.class │ │ ├── controllers │ │ ├── CartController.class │ │ ├── ItemController.class │ │ ├── OrderController.class │ │ └── UserController.class │ │ └── model │ │ ├── persistence │ │ ├── Cart.class │ │ ├── Item.class │ │ ├── User.class │ │ ├── UserOrder.class │ │ └── repositories │ │ │ ├── CartRepository.class │ │ │ ├── ItemRepository.class │ │ │ ├── OrderRepository.class │ │ │ └── UserRepository.class │ │ └── requests │ │ ├── CreateUserRequest.class │ │ └── ModifyCartRequest.class └── data.sql └── test-classes └── com └── example └── demo └── SareetaApplicationTests.class /.github/workflows/manual.yml: -------------------------------------------------------------------------------- 1 | # Workflow to ensure whenever a Github PR is submitted, 2 | # a JIRA ticket gets created automatically. 3 | name: Manual Workflow 4 | 5 | # Controls when the action will run. 6 | on: 7 | # Triggers the workflow on pull request events but only for the master branch 8 | pull_request_target: 9 | types: [opened, reopened] 10 | 11 | # Allows you to run this workflow manually from the Actions tab 12 | workflow_dispatch: 13 | 14 | jobs: 15 | test-transition-issue: 16 | name: Convert Github Issue to Jira Issue 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@master 21 | 22 | - name: Login 23 | uses: atlassian/gajira-login@master 24 | env: 25 | JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} 26 | JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} 27 | JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} 28 | 29 | - name: Create NEW JIRA ticket 30 | id: create 31 | uses: atlassian/gajira-create@master 32 | with: 33 | project: CONUPDATE 34 | issuetype: Task 35 | summary: | 36 | Github PR nd035 - Java Developer ND C4 | Repo: ${{ github.repository }} | PR# ${{github.event.number}} 37 | description: | 38 | Repo link: https://github.com/${{ github.repository }} 39 | PR no. ${{ github.event.pull_request.number }} 40 | PR title: ${{ github.event.pull_request.title }} 41 | PR description: ${{ github.event.pull_request.description }} 42 | In addition, please resolve other issues, if any. 43 | fields: '{"components": [{"name":"nd035 - Java Developer ND"}], "customfield_16449":"https://classroom.udacity.com/", "customfield_16450":"Resolve the PR", "labels": ["github"], "priority":{"id": "4"}}' 44 | 45 | - name: Log created issue 46 | run: echo "Issue ${{ steps.create.outputs.issue }} was created" 47 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | /starter_code/target/ 3 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @udacity/active-public-content -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | 2 | Copyright © 2012 - 2020, Udacity, Inc. 3 | 4 | Udacity hereby grants you a license in and to the Educational Content, including but not limited to homework assignments, programming assignments, code samples, and other educational materials and tools (as further described in the Udacity Terms of Use), subject to, as modified herein, the terms and conditions of the Creative Commons Attribution-NonCommercial- NoDerivs 3.0 License located at http://creativecommons.org/licenses/by-nc-nd/4.0 and successor locations for such license (the "CC License") provided that, in each case, the Educational Content is specifically marked as being subject to the CC License. 5 | Udacity expressly defines the following as falling outside the definition of "non-commercial": 6 | (a) the sale or rental of (i) any part of the Educational Content, (ii) any derivative works based at least in part on the Educational Content, or (iii) any collective work that includes any part of the Educational Content; 7 | (b) the sale of access or a link to any part of the Educational Content without first obtaining informed consent from the buyer (that the buyer is aware that the Educational Content, or such part thereof, is available at the Website free of charge); 8 | (c) providing training, support, or editorial services that use or reference the Educational Content in exchange for a fee; 9 | (d) the sale of advertisements, sponsorships, or promotions placed on the Educational Content, or any part thereof, or the sale of advertisements, sponsorships, or promotions on any website or blog containing any part of the Educational Material, including without limitation any "pop-up advertisements"; 10 | (e) the use of Educational Content by a college, university, school, or other educational institution for instruction where tuition is charged; and 11 | (f) the use of Educational Content by a for-profit corporation or non-profit entity for internal professional development or training. 12 | 13 | 14 | 15 | THE SERVICES AND ONLINE COURSES (INCLUDING ANY CONTENT) ARE PROVIDED "AS IS" AND "AS AVAILABLE" WITH NO REPRESENTATIONS OR WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. YOU ASSUME TOTAL RESPONSIBILITY AND THE ENTIRE RISK FOR YOUR USE OF THE SERVICES, ONLINE COURSES, AND CONTENT. WITHOUT LIMITING THE FOREGOING, WE DO NOT WARRANT THAT (A) THE SERVICES, WEBSITES, CONTENT, OR THE ONLINE COURSES WILL MEET YOUR REQUIREMENTS OR EXPECTATIONS OR ACHIEVE THE INTENDED PURPOSES, (B) THE WEBSITES OR THE ONLINE COURSES WILL NOT EXPERIENCE OUTAGES OR OTHERWISE BE UNINTERRUPTED, TIMELY, SECURE OR ERROR-FREE, (C) THE INFORMATION OR CONTENT OBTAINED THROUGH THE SERVICES, SUCH AS CHAT ROOM SERVICES, WILL BE ACCURATE, COMPLETE, CURRENT, ERROR- FREE, COMPLETELY SECURE OR RELIABLE, OR (D) THAT DEFECTS IN OR ON THE SERVICES OR CONTENT WILL BE CORRECTED. YOU ASSUME ALL RISK OF PERSONAL INJURY, INCLUDING DEATH AND DAMAGE TO PERSONAL PROPERTY, SUSTAINED FROM USE OF SERVICES. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # eCommerce Application 2 | 3 | In this project, you'll have an opportunity to demonstrate the security and DevOps skills that you learned in this lesson by completing an eCommerce application. You'll start with a template for the complete application, and your goal will be to take this template and add proper authentication and authorization controls so users can only access their data, and that data can only be accessed in a secure way. 4 | 5 | ## Project Template 6 | First, you'll want to get set up with the template. The template is written in Java using Spring Boot, Hibernate ORM, and the H2 database. H2 is an in memory database, so if you need to retry something, every application startup is a fresh copy. 7 | 8 | To use the template, import it in the IDE of your choice as a Spring Boot application. Where required, this readme assumes the eclipse IDE. 9 | 10 | Once the project is set up, you will see 5 packages: 11 | 12 | * demo - this package contains the main method which runs the application 13 | 14 | * model.persistence - this package contains the data models that Hibernate persists to H2. There are 4 models: Cart, for holding a User's items; Item , for defining new items; User, to hold user account information; and UserOrder, to hold information about submitted orders. Looking back at the application “demo” class, you'll see the `@EntityScan` annotation, telling Spring that this package contains our data models 15 | 16 | * model.persistence.repositories - these contain a `JpaRepository` interface for each of our models. This allows Hibernate to connect them with our database so we can access data in the code, as well as define certain convenience methods. Look through them and see the methods that have been declared. Looking at the application “demo” class, you’ll see the `@EnableJpaRepositories` annotation, telling Spring that this package contains our data repositories. 17 | 18 | * model.requests - this package contains the request models. The request models will be transformed by Jackson from JSON to these models as requests are made. Note the `Json` annotations, telling Jackson to include and ignore certain fields of the requests. You can also see these annotations on the models themselves. 19 | 20 | * controllers - these contain the api endpoints for our app, 1 per model. Note they all have the `@RestController` annotation to allow Spring to understand that they are a part of a REST API 21 | 22 | In resources, you'll see the application configuration that sets up our database and Hibernate, It also contains a data.sql file with a couple of items to populate the database with. Spring will run this file every time the application starts 23 | 24 | In eclipse, you can right click the project and click “run as” and select Spring Boot application. The application should tell you it’s starting in the console view. Once started, using a REST client, such as Postman, explore the APIs. 25 | 26 | Some examples are as below: 27 | To create a new user for example, you would send a POST request to: 28 | http://localhost:8080/api/user/create with an example body like 29 | 30 | ``` 31 | { 32 | "username": "test" 33 | } 34 | ``` 35 | 36 | 37 | and this would return 38 | ``` 39 | { 40 | "id" 1, 41 | "username": "test" 42 | } 43 | ``` 44 | 45 | 46 | Exercise: 47 | Once you've created a user, try to add items to cart (see the `ModifyCartRequest` class) and submit an order. 48 | 49 | ## Adding Authentication and Authorization 50 | We need to add proper authentication and authorization controls so users can only access their data, and that data can only be accessed in a secure way. We will do this using a combination of usernames and passwords for authentication, as well as JSON Web Tokens (JWT) to handle the authorization. 51 | 52 | As stated prior, we will implement a password based authentication scheme. To do this, we need to store the users' passwords in a secure way. This needs to be done with hashing, and it's this hash which should be stored. Additionally when viewing their user information, the user's hash should not be returned to them in the response, You should also add some requirements and validation, as well as a confirm field in the request, to make sure they didn't make a typo. 53 | 54 | 1. Add spring security dependencies: 55 | * Spring-boot-starter-security 56 | 1. JWT does not ship as a part of spring security, so you will have to add the 57 | * java-jwt dependency to your project. 58 | 1. Spring Boot ships with an automatically configured security module that must be disabled, as we will be implementing our own. This must be done in the Application class. 59 | 2. Create password for the user 60 | 3. Once that is disabled, you will need to implement 4 classes (at minimum, you can break it down however you like): 61 | * a subclass of `UsernamePasswordAuthenticationFilter` for taking the username and password from a login request and logging in. This, upon successful authentication, should hand back a valid JWT in the `Authorization` header 62 | * a subclass of `BasicAuthenticationFilter`. 63 | * an implementation of the `UserDetailsService` interface. This should take a username and return a userdetails User instance with the user's username and hashed password. 64 | * a subclass of `WebSecurityConfigurerAdapter`. This should attach your user details service implementation to Spring's `AuthenticationManager`. It also handles session management and what endpoints are secured. For us, we manage the session so session management should be disabled. Your filters should be added to the authentication chain and every endpoint but 1 should have security required. The one that should not is the one responsible for creating new users. 65 | 66 | 67 | Once all this is setup, you can use Spring's default /login endpoint to login like so 68 | 69 | ``` 70 | POST /login 71 | { 72 | "username": "test", 73 | "password": "somepassword" 74 | } 75 | ``` 76 | 77 | and that should, if those are valid credentials, return a 200 OK with an Authorization header which looks like "Bearer " this "Bearer " is a JWT and must be sent as a Authorization header for all other rqeuests. If it's not present, endpoints should return 401 Unauthorized. If it's present and valid, the endpoints should function as normal. 78 | 79 | ## Testing 80 | You must implement unit tests demonstrating at least 80% code coverage. 81 | -------------------------------------------------------------------------------- /starter_code/auth-course.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | -------------------------------------------------------------------------------- /starter_code/mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # https://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven2 Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 59 | if [ -z "$JAVA_HOME" ]; then 60 | if [ -x "/usr/libexec/java_home" ]; then 61 | export JAVA_HOME="`/usr/libexec/java_home`" 62 | else 63 | export JAVA_HOME="/Library/Java/Home" 64 | fi 65 | fi 66 | ;; 67 | esac 68 | 69 | if [ -z "$JAVA_HOME" ] ; then 70 | if [ -r /etc/gentoo-release ] ; then 71 | JAVA_HOME=`java-config --jre-home` 72 | fi 73 | fi 74 | 75 | if [ -z "$M2_HOME" ] ; then 76 | ## resolve links - $0 may be a link to maven's home 77 | PRG="$0" 78 | 79 | # need this for relative symlinks 80 | while [ -h "$PRG" ] ; do 81 | ls=`ls -ld "$PRG"` 82 | link=`expr "$ls" : '.*-> \(.*\)$'` 83 | if expr "$link" : '/.*' > /dev/null; then 84 | PRG="$link" 85 | else 86 | PRG="`dirname "$PRG"`/$link" 87 | fi 88 | done 89 | 90 | saveddir=`pwd` 91 | 92 | M2_HOME=`dirname "$PRG"`/.. 93 | 94 | # make it fully qualified 95 | M2_HOME=`cd "$M2_HOME" && pwd` 96 | 97 | cd "$saveddir" 98 | # echo Using m2 at $M2_HOME 99 | fi 100 | 101 | # For Cygwin, ensure paths are in UNIX format before anything is touched 102 | if $cygwin ; then 103 | [ -n "$M2_HOME" ] && 104 | M2_HOME=`cygpath --unix "$M2_HOME"` 105 | [ -n "$JAVA_HOME" ] && 106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 107 | [ -n "$CLASSPATH" ] && 108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 109 | fi 110 | 111 | # For Mingw, ensure paths are in UNIX format before anything is touched 112 | if $mingw ; then 113 | [ -n "$M2_HOME" ] && 114 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 115 | [ -n "$JAVA_HOME" ] && 116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 117 | # TODO classpath? 118 | fi 119 | 120 | if [ -z "$JAVA_HOME" ]; then 121 | javaExecutable="`which javac`" 122 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 123 | # readlink(1) is not available as standard on Solaris 10. 124 | readLink=`which readlink` 125 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 126 | if $darwin ; then 127 | javaHome="`dirname \"$javaExecutable\"`" 128 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 129 | else 130 | javaExecutable="`readlink -f \"$javaExecutable\"`" 131 | fi 132 | javaHome="`dirname \"$javaExecutable\"`" 133 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 134 | JAVA_HOME="$javaHome" 135 | export JAVA_HOME 136 | fi 137 | fi 138 | fi 139 | 140 | if [ -z "$JAVACMD" ] ; then 141 | if [ -n "$JAVA_HOME" ] ; then 142 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 143 | # IBM's JDK on AIX uses strange locations for the executables 144 | JAVACMD="$JAVA_HOME/jre/sh/java" 145 | else 146 | JAVACMD="$JAVA_HOME/bin/java" 147 | fi 148 | else 149 | JAVACMD="`which java`" 150 | fi 151 | fi 152 | 153 | if [ ! -x "$JAVACMD" ] ; then 154 | echo "Error: JAVA_HOME is not defined correctly." >&2 155 | echo " We cannot execute $JAVACMD" >&2 156 | exit 1 157 | fi 158 | 159 | if [ -z "$JAVA_HOME" ] ; then 160 | echo "Warning: JAVA_HOME environment variable is not set." 161 | fi 162 | 163 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 164 | 165 | # traverses directory structure from process work directory to filesystem root 166 | # first directory with .mvn subdirectory is considered project base directory 167 | find_maven_basedir() { 168 | 169 | if [ -z "$1" ] 170 | then 171 | echo "Path not specified to find_maven_basedir" 172 | return 1 173 | fi 174 | 175 | basedir="$1" 176 | wdir="$1" 177 | while [ "$wdir" != '/' ] ; do 178 | if [ -d "$wdir"/.mvn ] ; then 179 | basedir=$wdir 180 | break 181 | fi 182 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 183 | if [ -d "${wdir}" ]; then 184 | wdir=`cd "$wdir/.."; pwd` 185 | fi 186 | # end of workaround 187 | done 188 | echo "${basedir}" 189 | } 190 | 191 | # concatenates all lines of a file 192 | concat_lines() { 193 | if [ -f "$1" ]; then 194 | echo "$(tr -s '\n' ' ' < "$1")" 195 | fi 196 | } 197 | 198 | BASE_DIR=`find_maven_basedir "$(pwd)"` 199 | if [ -z "$BASE_DIR" ]; then 200 | exit 1; 201 | fi 202 | 203 | ########################################################################################## 204 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 205 | # This allows using the maven wrapper in projects that prohibit checking in binary data. 206 | ########################################################################################## 207 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then 208 | if [ "$MVNW_VERBOSE" = true ]; then 209 | echo "Found .mvn/wrapper/maven-wrapper.jar" 210 | fi 211 | else 212 | if [ "$MVNW_VERBOSE" = true ]; then 213 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." 214 | fi 215 | jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" 216 | while IFS="=" read key value; do 217 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;; 218 | esac 219 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" 220 | if [ "$MVNW_VERBOSE" = true ]; then 221 | echo "Downloading from: $jarUrl" 222 | fi 223 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" 224 | 225 | if command -v wget > /dev/null; then 226 | if [ "$MVNW_VERBOSE" = true ]; then 227 | echo "Found wget ... using wget" 228 | fi 229 | wget "$jarUrl" -O "$wrapperJarPath" 230 | elif command -v curl > /dev/null; then 231 | if [ "$MVNW_VERBOSE" = true ]; then 232 | echo "Found curl ... using curl" 233 | fi 234 | curl -o "$wrapperJarPath" "$jarUrl" 235 | else 236 | if [ "$MVNW_VERBOSE" = true ]; then 237 | echo "Falling back to using Java to download" 238 | fi 239 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" 240 | if [ -e "$javaClass" ]; then 241 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 242 | if [ "$MVNW_VERBOSE" = true ]; then 243 | echo " - Compiling MavenWrapperDownloader.java ..." 244 | fi 245 | # Compiling the Java class 246 | ("$JAVA_HOME/bin/javac" "$javaClass") 247 | fi 248 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 249 | # Running the downloader 250 | if [ "$MVNW_VERBOSE" = true ]; then 251 | echo " - Running MavenWrapperDownloader.java ..." 252 | fi 253 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") 254 | fi 255 | fi 256 | fi 257 | fi 258 | ########################################################################################## 259 | # End of extension 260 | ########################################################################################## 261 | 262 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 263 | if [ "$MVNW_VERBOSE" = true ]; then 264 | echo $MAVEN_PROJECTBASEDIR 265 | fi 266 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 267 | 268 | # For Cygwin, switch paths to Windows format before running java 269 | if $cygwin; then 270 | [ -n "$M2_HOME" ] && 271 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 272 | [ -n "$JAVA_HOME" ] && 273 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 274 | [ -n "$CLASSPATH" ] && 275 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 276 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 277 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 278 | fi 279 | 280 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 281 | 282 | exec "$JAVACMD" \ 283 | $MAVEN_OPTS \ 284 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 285 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 286 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 287 | -------------------------------------------------------------------------------- /starter_code/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM https://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 50 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" 124 | FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO ( 125 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 126 | ) 127 | 128 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 129 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 130 | if exist %WRAPPER_JAR% ( 131 | echo Found %WRAPPER_JAR% 132 | ) else ( 133 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 134 | echo Downloading from: %DOWNLOAD_URL% 135 | powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')" 136 | echo Finished downloading %WRAPPER_JAR% 137 | ) 138 | @REM End of extension 139 | 140 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 141 | if ERRORLEVEL 1 goto error 142 | goto end 143 | 144 | :error 145 | set ERROR_CODE=1 146 | 147 | :end 148 | @endlocal & set ERROR_CODE=%ERROR_CODE% 149 | 150 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 151 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 152 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 153 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 154 | :skipRcPost 155 | 156 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 157 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 158 | 159 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 160 | 161 | exit /B %ERROR_CODE% 162 | -------------------------------------------------------------------------------- /starter_code/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.3.5 9 | 10 | 11 | com.example 12 | auth-course 13 | war 14 | 0.0.1-SNAPSHOT 15 | auth-course 16 | Demo project for Spring Boot 17 | 18 | 19 | 21 20 | 3.1.1 21 | 22 | 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-data-jpa 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-web 31 | 32 | 33 | 34 | com.h2database 35 | h2 36 | runtime 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-starter-test 41 | test 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | org.springframework.boot 52 | spring-boot-maven-plugin 53 | 54 | 55 | org.apache.maven.plugins 56 | maven-compiler-plugin 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /starter_code/src/main/java/com/example/demo/SareetaApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.boot.autoconfigure.domain.EntityScan; 6 | import org.springframework.data.jpa.repository.config.EnableJpaRepositories; 7 | 8 | @EnableJpaRepositories("com.example.demo.model.persistence.repositories") 9 | @EntityScan("com.example.demo.model.persistence") 10 | @SpringBootApplication 11 | public class SareetaApplication { 12 | 13 | public static void main(String[] args) { 14 | SpringApplication.run(SareetaApplication.class, args); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /starter_code/src/main/java/com/example/demo/controllers/CartController.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.controllers; 2 | 3 | import java.util.Optional; 4 | import java.util.stream.IntStream; 5 | 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.http.HttpStatus; 8 | import org.springframework.http.ResponseEntity; 9 | import org.springframework.web.bind.annotation.PostMapping; 10 | import org.springframework.web.bind.annotation.RequestBody; 11 | import org.springframework.web.bind.annotation.RequestMapping; 12 | import org.springframework.web.bind.annotation.RestController; 13 | 14 | import com.example.demo.model.persistence.Cart; 15 | import com.example.demo.model.persistence.Item; 16 | import com.example.demo.model.persistence.User; 17 | import com.example.demo.model.persistence.repositories.CartRepository; 18 | import com.example.demo.model.persistence.repositories.ItemRepository; 19 | import com.example.demo.model.persistence.repositories.UserRepository; 20 | import com.example.demo.model.requests.ModifyCartRequest; 21 | 22 | @RestController 23 | @RequestMapping("/api/cart") 24 | public class CartController { 25 | 26 | @Autowired 27 | private UserRepository userRepository; 28 | 29 | @Autowired 30 | private CartRepository cartRepository; 31 | 32 | @Autowired 33 | private ItemRepository itemRepository; 34 | 35 | @PostMapping("/addToCart") 36 | public ResponseEntity addTocart(@RequestBody ModifyCartRequest request) { 37 | User user = userRepository.findByUsername(request.getUsername()); 38 | if(user == null) { 39 | return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); 40 | } 41 | Optional item = itemRepository.findById(request.getItemId()); 42 | if(!item.isPresent()) { 43 | return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); 44 | } 45 | Cart cart = user.getCart(); 46 | IntStream.range(0, request.getQuantity()) 47 | .forEach(i -> cart.addItem(item.get())); 48 | cartRepository.save(cart); 49 | return ResponseEntity.ok(cart); 50 | } 51 | 52 | @PostMapping("/removeFromCart") 53 | public ResponseEntity removeFromcart(@RequestBody ModifyCartRequest request) { 54 | User user = userRepository.findByUsername(request.getUsername()); 55 | if(user == null) { 56 | return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); 57 | } 58 | Optional item = itemRepository.findById(request.getItemId()); 59 | if(!item.isPresent()) { 60 | return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); 61 | } 62 | Cart cart = user.getCart(); 63 | IntStream.range(0, request.getQuantity()) 64 | .forEach(i -> cart.removeItem(item.get())); 65 | cartRepository.save(cart); 66 | return ResponseEntity.ok(cart); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /starter_code/src/main/java/com/example/demo/controllers/ItemController.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.controllers; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.http.ResponseEntity; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.PathVariable; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | import com.example.demo.model.persistence.Item; 13 | import com.example.demo.model.persistence.repositories.ItemRepository; 14 | 15 | @RestController 16 | @RequestMapping("/api/item") 17 | public class ItemController { 18 | 19 | @Autowired 20 | private ItemRepository itemRepository; 21 | 22 | @GetMapping 23 | public ResponseEntity> getItems() { 24 | return ResponseEntity.ok(itemRepository.findAll()); 25 | } 26 | 27 | @GetMapping("/{id}") 28 | public ResponseEntity getItemById(@PathVariable Long id) { 29 | return ResponseEntity.of(itemRepository.findById(id)); 30 | } 31 | 32 | @GetMapping("/name/{name}") 33 | public ResponseEntity> getItemsByName(@PathVariable String name) { 34 | List items = itemRepository.findByName(name); 35 | return items == null || items.isEmpty() ? ResponseEntity.notFound().build() 36 | : ResponseEntity.ok(items); 37 | 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /starter_code/src/main/java/com/example/demo/controllers/OrderController.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.controllers; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.http.ResponseEntity; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.PathVariable; 9 | import org.springframework.web.bind.annotation.PostMapping; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.RestController; 12 | 13 | import com.example.demo.model.persistence.Cart; 14 | import com.example.demo.model.persistence.User; 15 | import com.example.demo.model.persistence.UserOrder; 16 | import com.example.demo.model.persistence.repositories.CartRepository; 17 | import com.example.demo.model.persistence.repositories.OrderRepository; 18 | import com.example.demo.model.persistence.repositories.UserRepository; 19 | 20 | @RestController 21 | @RequestMapping("/api/order") 22 | public class OrderController { 23 | 24 | 25 | @Autowired 26 | private UserRepository userRepository; 27 | 28 | @Autowired 29 | private OrderRepository orderRepository; 30 | 31 | 32 | @PostMapping("/submit/{username}") 33 | public ResponseEntity submit(@PathVariable String username) { 34 | User user = userRepository.findByUsername(username); 35 | if(user == null) { 36 | return ResponseEntity.notFound().build(); 37 | } 38 | UserOrder order = UserOrder.createFromCart(user.getCart()); 39 | orderRepository.save(order); 40 | return ResponseEntity.ok(order); 41 | } 42 | 43 | @GetMapping("/history/{username}") 44 | public ResponseEntity> getOrdersForUser(@PathVariable String username) { 45 | User user = userRepository.findByUsername(username); 46 | if(user == null) { 47 | return ResponseEntity.notFound().build(); 48 | } 49 | return ResponseEntity.ok(orderRepository.findByUser(user)); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /starter_code/src/main/java/com/example/demo/controllers/UserController.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.controllers; 2 | 3 | import java.util.Optional; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.http.HttpStatus; 7 | import org.springframework.http.ResponseEntity; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.PathVariable; 10 | import org.springframework.web.bind.annotation.PostMapping; 11 | import org.springframework.web.bind.annotation.RequestBody; 12 | import org.springframework.web.bind.annotation.RequestMapping; 13 | import org.springframework.web.bind.annotation.RestController; 14 | 15 | import com.example.demo.model.persistence.Cart; 16 | import com.example.demo.model.persistence.User; 17 | import com.example.demo.model.persistence.repositories.CartRepository; 18 | import com.example.demo.model.persistence.repositories.UserRepository; 19 | import com.example.demo.model.requests.CreateUserRequest; 20 | 21 | @RestController 22 | @RequestMapping("/api/user") 23 | public class UserController { 24 | 25 | @Autowired 26 | private UserRepository userRepository; 27 | 28 | @Autowired 29 | private CartRepository cartRepository; 30 | 31 | @GetMapping("/id/{id}") 32 | public ResponseEntity findById(@PathVariable Long id) { 33 | return ResponseEntity.of(userRepository.findById(id)); 34 | } 35 | 36 | @GetMapping("/{username}") 37 | public ResponseEntity findByUserName(@PathVariable String username) { 38 | User user = userRepository.findByUsername(username); 39 | return user == null ? ResponseEntity.notFound().build() : ResponseEntity.ok(user); 40 | } 41 | 42 | @PostMapping("/create") 43 | public ResponseEntity createUser(@RequestBody CreateUserRequest createUserRequest) { 44 | User user = new User(); 45 | user.setUsername(createUserRequest.getUsername()); 46 | Cart cart = new Cart(); 47 | cartRepository.save(cart); 48 | user.setCart(cart); 49 | userRepository.save(user); 50 | return ResponseEntity.ok(user); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /starter_code/src/main/java/com/example/demo/model/persistence/Cart.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.model.persistence; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | import com.fasterxml.jackson.annotation.JsonProperty; 8 | 9 | import jakarta.persistence.Column; 10 | import jakarta.persistence.Entity; 11 | import jakarta.persistence.GeneratedValue; 12 | import jakarta.persistence.GenerationType; 13 | import jakarta.persistence.Id; 14 | import jakarta.persistence.ManyToMany; 15 | import jakarta.persistence.OneToOne; 16 | import jakarta.persistence.Table; 17 | 18 | @Entity 19 | @Table(name = "cart") 20 | public class Cart { 21 | 22 | @Id 23 | @GeneratedValue(strategy = GenerationType.IDENTITY) 24 | @JsonProperty 25 | @Column 26 | private Long id; 27 | 28 | @ManyToMany 29 | @JsonProperty 30 | @Column 31 | private List items; 32 | 33 | @OneToOne(mappedBy = "cart") 34 | @JsonProperty 35 | private User user; 36 | 37 | @Column 38 | @JsonProperty 39 | private BigDecimal total; 40 | 41 | public BigDecimal getTotal() { 42 | return total; 43 | } 44 | 45 | public void setTotal(BigDecimal total) { 46 | this.total = total; 47 | } 48 | 49 | public User getUser() { 50 | return user; 51 | } 52 | 53 | public void setUser(User user) { 54 | this.user = user; 55 | } 56 | 57 | public Long getId() { 58 | return id; 59 | } 60 | 61 | public void setId(Long id) { 62 | this.id = id; 63 | } 64 | 65 | public List getItems() { 66 | return items; 67 | } 68 | 69 | public void setItems(List items) { 70 | this.items = items; 71 | } 72 | 73 | public void addItem(Item item) { 74 | if(items == null) { 75 | items = new ArrayList<>(); 76 | } 77 | items.add(item); 78 | if(total == null) { 79 | total = new BigDecimal(0); 80 | } 81 | total = total.add(item.getPrice()); 82 | } 83 | 84 | public void removeItem(Item item) { 85 | if(items == null) { 86 | items = new ArrayList<>(); 87 | } 88 | items.remove(item); 89 | if(total == null) { 90 | total = new BigDecimal(0); 91 | } 92 | total = total.subtract(item.getPrice()); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /starter_code/src/main/java/com/example/demo/model/persistence/Item.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.model.persistence; 2 | 3 | import java.math.BigDecimal; 4 | 5 | import jakarta.persistence.Column; 6 | import jakarta.persistence.Entity; 7 | import jakarta.persistence.GeneratedValue; 8 | import jakarta.persistence.GenerationType; 9 | import jakarta.persistence.Id; 10 | import jakarta.persistence.JoinColumn; 11 | import jakarta.persistence.ManyToOne; 12 | import jakarta.persistence.Table; 13 | 14 | import com.fasterxml.jackson.annotation.JsonIgnore; 15 | import com.fasterxml.jackson.annotation.JsonProperty; 16 | 17 | @Entity 18 | @Table(name = "item") 19 | public class Item { 20 | 21 | @Id 22 | @GeneratedValue(strategy = GenerationType.IDENTITY) 23 | @JsonProperty 24 | private Long id; 25 | 26 | @Column(nullable = false) 27 | @JsonProperty 28 | private String name; 29 | 30 | @Column(nullable = false) 31 | @JsonProperty 32 | private BigDecimal price; 33 | 34 | @Column(nullable = false) 35 | @JsonProperty 36 | private String description; 37 | 38 | @Override 39 | public int hashCode() { 40 | final int prime = 31; 41 | int result = 1; 42 | result = prime * result + ((id == null) ? 0 : id.hashCode()); 43 | return result; 44 | } 45 | 46 | @Override 47 | public boolean equals(Object obj) { 48 | if (this == obj) 49 | return true; 50 | if (obj == null) 51 | return false; 52 | if (getClass() != obj.getClass()) 53 | return false; 54 | Item other = (Item) obj; 55 | if (id == null) { 56 | if (other.id != null) 57 | return false; 58 | } else if (!id.equals(other.id)) 59 | return false; 60 | return true; 61 | } 62 | 63 | public Long getId() { 64 | return id; 65 | } 66 | 67 | public void setId(Long id) { 68 | this.id = id; 69 | } 70 | 71 | public String getName() { 72 | return name; 73 | } 74 | 75 | public void setName(String name) { 76 | this.name = name; 77 | } 78 | 79 | public BigDecimal getPrice() { 80 | return price; 81 | } 82 | 83 | public void setPrice(BigDecimal price) { 84 | this.price = price; 85 | } 86 | 87 | public String getDescription() { 88 | return description; 89 | } 90 | 91 | public void setDescription(String description) { 92 | this.description = description; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /starter_code/src/main/java/com/example/demo/model/persistence/User.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.model.persistence; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | 6 | import jakarta.persistence.CascadeType; 7 | import jakarta.persistence.Column; 8 | import jakarta.persistence.Entity; 9 | import jakarta.persistence.GeneratedValue; 10 | import jakarta.persistence.GenerationType; 11 | import jakarta.persistence.Id; 12 | import jakarta.persistence.JoinColumn; 13 | import jakarta.persistence.OneToOne; 14 | import jakarta.persistence.Table; 15 | 16 | 17 | @Entity 18 | @Table(name = "user") 19 | public class User { 20 | 21 | @Id 22 | @GeneratedValue(strategy = GenerationType.IDENTITY) 23 | @JsonProperty 24 | private long id; 25 | 26 | @Column(nullable = false, unique = true) 27 | @JsonProperty 28 | private String username; 29 | 30 | @OneToOne(cascade = CascadeType.ALL) 31 | @JoinColumn(name = "cart_id", referencedColumnName = "id") 32 | @JsonIgnore 33 | private Cart cart; 34 | 35 | public Cart getCart() { 36 | return cart; 37 | } 38 | 39 | public void setCart(Cart cart) { 40 | this.cart = cart; 41 | } 42 | 43 | public long getId() { 44 | return id; 45 | } 46 | 47 | public void setId(long id) { 48 | this.id = id; 49 | } 50 | 51 | public String getUsername() { 52 | return username; 53 | } 54 | 55 | public void setUsername(String username) { 56 | this.username = username; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /starter_code/src/main/java/com/example/demo/model/persistence/UserOrder.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.model.persistence; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.List; 5 | import java.util.stream.Collectors; 6 | 7 | import jakarta.persistence.CascadeType; 8 | import jakarta.persistence.Column; 9 | import jakarta.persistence.Entity; 10 | import jakarta.persistence.GeneratedValue; 11 | import jakarta.persistence.GenerationType; 12 | import jakarta.persistence.Id; 13 | import jakarta.persistence.JoinColumn; 14 | import jakarta.persistence.JoinTable; 15 | import jakarta.persistence.ManyToMany; 16 | import jakarta.persistence.ManyToOne; 17 | import jakarta.persistence.Table; 18 | 19 | import com.fasterxml.jackson.annotation.JsonProperty; 20 | 21 | @Entity 22 | @Table(name = "user_order") 23 | public class UserOrder { 24 | 25 | @Id 26 | @GeneratedValue(strategy = GenerationType.IDENTITY) 27 | @JsonProperty 28 | @Column 29 | private Long id; 30 | 31 | @ManyToMany(cascade = CascadeType.ALL) 32 | @JsonProperty 33 | @Column 34 | private List items; 35 | 36 | @ManyToOne 37 | @JoinColumn(name="user_id", nullable = false, referencedColumnName = "id") 38 | @JsonProperty 39 | private User user; 40 | 41 | @JsonProperty 42 | @Column 43 | private BigDecimal total; 44 | 45 | public Long getId() { 46 | return id; 47 | } 48 | 49 | public void setId(Long id) { 50 | this.id = id; 51 | } 52 | 53 | public List getItems() { 54 | return items; 55 | } 56 | 57 | public void setItems(List items) { 58 | this.items = items; 59 | } 60 | 61 | public User getUser() { 62 | return user; 63 | } 64 | 65 | public void setUser(User user) { 66 | this.user = user; 67 | } 68 | 69 | public BigDecimal getTotal() { 70 | return total; 71 | } 72 | 73 | public void setTotal(BigDecimal total) { 74 | this.total = total; 75 | } 76 | 77 | public static UserOrder createFromCart(Cart cart) { 78 | UserOrder order = new UserOrder(); 79 | order.setItems(cart.getItems().stream().collect(Collectors.toList())); 80 | order.setTotal(cart.getTotal()); 81 | order.setUser(cart.getUser()); 82 | return order; 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /starter_code/src/main/java/com/example/demo/model/persistence/repositories/CartRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.model.persistence.repositories; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | import com.example.demo.model.persistence.Cart; 6 | import com.example.demo.model.persistence.User; 7 | 8 | import org.springframework.stereotype.Repository; 9 | 10 | @Repository 11 | public interface CartRepository extends JpaRepository { 12 | Cart findByUser(User user); 13 | } 14 | -------------------------------------------------------------------------------- /starter_code/src/main/java/com/example/demo/model/persistence/repositories/ItemRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.model.persistence.repositories; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | 7 | import com.example.demo.model.persistence.Item; 8 | import org.springframework.stereotype.Repository; 9 | 10 | @Repository 11 | public interface ItemRepository extends JpaRepository { 12 | List findByName(String name); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /starter_code/src/main/java/com/example/demo/model/persistence/repositories/OrderRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.model.persistence.repositories; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | 7 | import com.example.demo.model.persistence.User; 8 | import com.example.demo.model.persistence.UserOrder; 9 | import org.springframework.stereotype.Repository; 10 | 11 | @Repository 12 | public interface OrderRepository extends JpaRepository { 13 | List findByUser(User user); 14 | } 15 | -------------------------------------------------------------------------------- /starter_code/src/main/java/com/example/demo/model/persistence/repositories/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.model.persistence.repositories; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | import com.example.demo.model.persistence.User; 6 | import org.springframework.stereotype.Repository; 7 | 8 | @Repository 9 | public interface UserRepository extends JpaRepository { 10 | User findByUsername(String username); 11 | } 12 | -------------------------------------------------------------------------------- /starter_code/src/main/java/com/example/demo/model/requests/CreateUserRequest.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.model.requests; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | public class CreateUserRequest { 6 | 7 | @JsonProperty 8 | private String username; 9 | 10 | public String getUsername() { 11 | return username; 12 | } 13 | 14 | public void setUsername(String username) { 15 | this.username = username; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /starter_code/src/main/java/com/example/demo/model/requests/ModifyCartRequest.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.model.requests; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | public class ModifyCartRequest { 6 | 7 | @JsonProperty 8 | private String username; 9 | 10 | @JsonProperty 11 | private long itemId; 12 | 13 | @JsonProperty 14 | private int quantity; 15 | 16 | public String getUsername() { 17 | return username; 18 | } 19 | 20 | public void setUsername(String username) { 21 | this.username = username; 22 | } 23 | 24 | public long getItemId() { 25 | return itemId; 26 | } 27 | 28 | public void setItemId(long itemId) { 29 | this.itemId = itemId; 30 | } 31 | 32 | public int getQuantity() { 33 | return quantity; 34 | } 35 | 36 | public void setQuantity(int quantity) { 37 | this.quantity = quantity; 38 | } 39 | 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /starter_code/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.driver-class-name=org.h2.Driver 2 | spring.datasource.url=jdbc:h2:mem:bootapp;NON_KEYWORDS=user 3 | spring.datasource.username=sa 4 | spring.datasource.password= 5 | spring.jpa.hibernate.ddl-auto=create 6 | spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect 7 | spring.jpa.defer-datasource-initialization=true 8 | spring.jpa.properties.hibernate.format_sql=true 9 | 10 | server.port=8080 11 | spring.h2.console.enabled=true 12 | spring.h2.console.path=/h2 13 | -------------------------------------------------------------------------------- /starter_code/src/main/resources/data.sql: -------------------------------------------------------------------------------- 1 | insert into item (name, price, description) values ('Round Widget', 2.99, 'A widget that is round'); 2 | insert into item (name, price, description) values ('Square Widget', 1.99, 'A widget that is square'); -------------------------------------------------------------------------------- /starter_code/src/test/java/com/example/demo/SareetaApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import org.springframework.boot.test.context.SpringBootTest; 4 | import org.junit.jupiter.api.Test; 5 | 6 | @SpringBootTest 7 | public class SareetaApplicationTests { 8 | 9 | @Test 10 | public void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /starter_code/target/classes/application.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.driver-class-name=org.h2.Driver 2 | spring.datasource.url=jdbc:h2:mem:bootapp;DB_CLOSE_DELAY=-1 3 | spring.datasource.username=sa 4 | spring.datasource.password= 5 | spring.jpa.hibernate.ddl-auto=update 6 | spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect -------------------------------------------------------------------------------- /starter_code/target/classes/com/example/demo/SareetaApplication.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/nd035-c4-Security-and-DevOps/6302143ac1cac6a953f75f46349b348c3bbcf60c/starter_code/target/classes/com/example/demo/SareetaApplication.class -------------------------------------------------------------------------------- /starter_code/target/classes/com/example/demo/controllers/CartController.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/nd035-c4-Security-and-DevOps/6302143ac1cac6a953f75f46349b348c3bbcf60c/starter_code/target/classes/com/example/demo/controllers/CartController.class -------------------------------------------------------------------------------- /starter_code/target/classes/com/example/demo/controllers/ItemController.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/nd035-c4-Security-and-DevOps/6302143ac1cac6a953f75f46349b348c3bbcf60c/starter_code/target/classes/com/example/demo/controllers/ItemController.class -------------------------------------------------------------------------------- /starter_code/target/classes/com/example/demo/controllers/OrderController.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/nd035-c4-Security-and-DevOps/6302143ac1cac6a953f75f46349b348c3bbcf60c/starter_code/target/classes/com/example/demo/controllers/OrderController.class -------------------------------------------------------------------------------- /starter_code/target/classes/com/example/demo/controllers/UserController.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/nd035-c4-Security-and-DevOps/6302143ac1cac6a953f75f46349b348c3bbcf60c/starter_code/target/classes/com/example/demo/controllers/UserController.class -------------------------------------------------------------------------------- /starter_code/target/classes/com/example/demo/model/persistence/Cart.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/nd035-c4-Security-and-DevOps/6302143ac1cac6a953f75f46349b348c3bbcf60c/starter_code/target/classes/com/example/demo/model/persistence/Cart.class -------------------------------------------------------------------------------- /starter_code/target/classes/com/example/demo/model/persistence/Item.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/nd035-c4-Security-and-DevOps/6302143ac1cac6a953f75f46349b348c3bbcf60c/starter_code/target/classes/com/example/demo/model/persistence/Item.class -------------------------------------------------------------------------------- /starter_code/target/classes/com/example/demo/model/persistence/User.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/nd035-c4-Security-and-DevOps/6302143ac1cac6a953f75f46349b348c3bbcf60c/starter_code/target/classes/com/example/demo/model/persistence/User.class -------------------------------------------------------------------------------- /starter_code/target/classes/com/example/demo/model/persistence/UserOrder.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/nd035-c4-Security-and-DevOps/6302143ac1cac6a953f75f46349b348c3bbcf60c/starter_code/target/classes/com/example/demo/model/persistence/UserOrder.class -------------------------------------------------------------------------------- /starter_code/target/classes/com/example/demo/model/persistence/repositories/CartRepository.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/nd035-c4-Security-and-DevOps/6302143ac1cac6a953f75f46349b348c3bbcf60c/starter_code/target/classes/com/example/demo/model/persistence/repositories/CartRepository.class -------------------------------------------------------------------------------- /starter_code/target/classes/com/example/demo/model/persistence/repositories/ItemRepository.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/nd035-c4-Security-and-DevOps/6302143ac1cac6a953f75f46349b348c3bbcf60c/starter_code/target/classes/com/example/demo/model/persistence/repositories/ItemRepository.class -------------------------------------------------------------------------------- /starter_code/target/classes/com/example/demo/model/persistence/repositories/OrderRepository.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/nd035-c4-Security-and-DevOps/6302143ac1cac6a953f75f46349b348c3bbcf60c/starter_code/target/classes/com/example/demo/model/persistence/repositories/OrderRepository.class -------------------------------------------------------------------------------- /starter_code/target/classes/com/example/demo/model/persistence/repositories/UserRepository.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/nd035-c4-Security-and-DevOps/6302143ac1cac6a953f75f46349b348c3bbcf60c/starter_code/target/classes/com/example/demo/model/persistence/repositories/UserRepository.class -------------------------------------------------------------------------------- /starter_code/target/classes/com/example/demo/model/requests/CreateUserRequest.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/nd035-c4-Security-and-DevOps/6302143ac1cac6a953f75f46349b348c3bbcf60c/starter_code/target/classes/com/example/demo/model/requests/CreateUserRequest.class -------------------------------------------------------------------------------- /starter_code/target/classes/com/example/demo/model/requests/ModifyCartRequest.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/nd035-c4-Security-and-DevOps/6302143ac1cac6a953f75f46349b348c3bbcf60c/starter_code/target/classes/com/example/demo/model/requests/ModifyCartRequest.class -------------------------------------------------------------------------------- /starter_code/target/classes/data.sql: -------------------------------------------------------------------------------- 1 | insert into item (name, price, description) values ('Round Widget', 2.99, 'A widget that is round'); 2 | insert into item (name, price, description) values ('Square Widget', 1.99, 'A widget that is square'); -------------------------------------------------------------------------------- /starter_code/target/test-classes/com/example/demo/SareetaApplicationTests.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/nd035-c4-Security-and-DevOps/6302143ac1cac6a953f75f46349b348c3bbcf60c/starter_code/target/test-classes/com/example/demo/SareetaApplicationTests.class --------------------------------------------------------------------------------