users = new ArrayList<>();
+ users.add(new UserRoles(new User(), r2));
+ User u3 = new User("barnbarn", "ILuvM4th!", users);
+ u3.getQuotes().add(new Quote("Live long and prosper", u3));
+ u3.getQuotes().add(new Quote("The enemy of my enemy is the enemy I kill last", u3));
+ u3.getQuotes().add(new Quote("Beam me up", u3));
+ userService.save(u3);
+
+ users = new ArrayList<>();
+ users.add(new UserRoles(new User(), r2));
+ User u4 = new User("Bob", "password", users);
+ userService.save(u4);
+
+ users = new ArrayList<>();
+ users.add(new UserRoles(new User(), r2));
+ User u5 = new User("Jane", "password", users);
+ userService.save(u5);
+
+ Author a1 = new Author("Mitchell", "John");
+ Author a2 = new Author("Brown", "Dan");
+ Author a3 = new Author("Poe", "Jerry");
+ Author a4 = new Author("Teague", "Wells");
+ Author a5 = new Author("Gallinger", "George");
+ Author a6 = new Author("Stewart", "Ian");
+
+ authorService.save(a1);
+ authorService.save(a2);
+ authorService.save(a3);
+ authorService.save(a4);
+ authorService.save(a5);
+ authorService.save(a6);
+
+ Book b1 = new Book("Flatterland", "9780738206752", "2001", new ArrayList<>(Arrays.asList(a6)));
+ Book b2 = new Book("Digital Fortess", "9788489367012", "2007", new ArrayList<>(Arrays.asList(a2)));
+ Book b3 = new Book("The Da Vinci Code", "9780307474278", "2009", new ArrayList<>(Arrays.asList(a2)));
+ Book b4 = new Book("Essentials of Finance", "1314241651234", null, new ArrayList<>(Arrays.asList(a5, a3)));
+ Book b5 = new Book("Calling Texas Home", "1885171382134", "2000", new ArrayList<>(Arrays.asList(a4)));
+
+ bookService.save(b1);
+ bookService.save(b2);
+ bookService.save(b3);
+ bookService.save(b4);
+ bookService.save(b5);
+ }
+}
\ No newline at end of file
diff --git a/StartHere/src/main/java/com/lambdaschool/starthere/StartHereApplication.java b/StartHere/src/main/java/com/lambdaschool/starthere/StartHereApplication.java
new file mode 100644
index 00000000..49516924
--- /dev/null
+++ b/StartHere/src/main/java/com/lambdaschool/starthere/StartHereApplication.java
@@ -0,0 +1,27 @@
+package com.lambdaschool.starthere;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.ApplicationContext;
+import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
+import org.springframework.web.servlet.DispatcherServlet;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+@EnableWebMvc
+@EnableJpaAuditing
+@SpringBootApplication
+@EnableSwagger2
+public class StartHereApplication
+{
+
+ public static void main(String[] args)
+ {
+ ApplicationContext ctx = SpringApplication.run(StartHereApplication.class, args);
+
+ DispatcherServlet dispatcherServlet = (DispatcherServlet) ctx.getBean("dispatcherServlet");
+ dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
+
+ }
+
+}
diff --git a/StartHere/src/main/java/com/lambdaschool/starthere/config/AuthorizationServerConfig.java b/StartHere/src/main/java/com/lambdaschool/starthere/config/AuthorizationServerConfig.java
new file mode 100755
index 00000000..f639db89
--- /dev/null
+++ b/StartHere/src/main/java/com/lambdaschool/starthere/config/AuthorizationServerConfig.java
@@ -0,0 +1,54 @@
+package com.lambdaschool.starthere.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
+import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
+import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
+import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
+import org.springframework.security.oauth2.provider.token.TokenStore;
+
+@Configuration
+@EnableAuthorizationServer
+public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter
+{
+ // static final String CLIENT_ID = System.getenv("OAUTHCLIENTID"); // read from environment variable
+ // static final String CLIENT_SECRET = System.getenv("OAUTHCLIENTSECRET"); // read from environment variable
+ static final String CLIENT_ID = "lambda-client";
+ static final String CLIENT_SECRET = "lambda-secret";
+
+ static final String GRANT_TYPE_PASSWORD = "password";
+ static final String AUTHORIZATION_CODE = "authorization_code";
+ static final String REFRESH_TOKEN = "refresh_token";
+ static final String IMPLICIT = "implicit";
+ static final String SCOPE_READ = "read";
+ static final String SCOPE_WRITE = "write";
+ static final String TRUST = "trust";
+ static final int ACCESS_TOKEN_VALIDITY_SECONDS = 1 * 60 * 60;
+ static final int FREFRESH_TOKEN_VALIDITY_SECONDS = 6 * 60 * 60;
+
+ @Autowired
+ private TokenStore tokenStore;
+
+ @Autowired
+ private AuthenticationManager authenticationManager;
+
+ @Autowired
+ private PasswordEncoder encoder;
+
+ @Override
+ public void configure(ClientDetailsServiceConfigurer configurer) throws Exception
+ {
+ // .authorizedGrantTypes(GRANT_TYPE_PASSWORD, AUTHORIZATION_CODE, REFRESH_TOKEN, IMPLICIT)
+
+ configurer.inMemory().withClient(CLIENT_ID).secret(encoder.encode(CLIENT_SECRET)).authorizedGrantTypes(GRANT_TYPE_PASSWORD, AUTHORIZATION_CODE, IMPLICIT).scopes(SCOPE_READ, SCOPE_WRITE, TRUST).accessTokenValiditySeconds(ACCESS_TOKEN_VALIDITY_SECONDS).refreshTokenValiditySeconds(FREFRESH_TOKEN_VALIDITY_SECONDS);
+ }
+
+ @Override
+ public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception
+ {
+ endpoints.tokenStore(tokenStore).authenticationManager(authenticationManager);
+ }
+}
\ No newline at end of file
diff --git a/StartHere/src/main/java/com/lambdaschool/starthere/config/H2ServerConfiguration.java b/StartHere/src/main/java/com/lambdaschool/starthere/config/H2ServerConfiguration.java
new file mode 100644
index 00000000..73984a41
--- /dev/null
+++ b/StartHere/src/main/java/com/lambdaschool/starthere/config/H2ServerConfiguration.java
@@ -0,0 +1,48 @@
+package com.lambdaschool.starthere.config;
+
+import org.h2.tools.Server;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.sql.SQLException;
+
+@Configuration
+// taken from https://techdev.io/en/developer-blog/querying-the-embedded-h2-database-of-a-spring-boot-application
+// necessary for using the database tool built into intellij
+public class H2ServerConfiguration
+{
+
+ // TCP port for remote connections, default 9092
+ @Value("${h2.tcp.port:9092}")
+ private String h2TcpPort;
+
+ // Web port, default 8082
+ @Value("${h2.web.port:8082}")
+ private String h2WebPort;
+
+ /**
+ * TCP connection to connect with SQL clients to the embedded h2 database.
+ *
+ * Connect to "jdbc:h2:tcp://localhost:9092/mem:testdb", username "sa", password empty.
+ */
+ @Bean
+ @ConditionalOnExpression("${h2.tcp.enabled:true}")
+ public Server h2TcpServer() throws SQLException
+ {
+ return Server.createTcpServer("-tcp", "-tcpAllowOthers", "-tcpPort", h2TcpPort).start();
+ }
+
+ /**
+ * Web console for the embedded h2 database.
+ *
+ * Go to http://localhost:8082 and connect to the database "jdbc:h2:mem:testdb", username "sa", password empty.
+ */
+ @Bean
+ @ConditionalOnExpression("${h2.web.enabled:true}")
+ public Server h2WebServer() throws SQLException
+ {
+ return Server.createWebServer("-web", "-webAllowOthers", "-webPort", h2WebPort).start();
+ }
+}
\ No newline at end of file
diff --git a/StartHere/src/main/java/com/lambdaschool/starthere/config/ResourceServerConfig.java b/StartHere/src/main/java/com/lambdaschool/starthere/config/ResourceServerConfig.java
new file mode 100755
index 00000000..3bacb929
--- /dev/null
+++ b/StartHere/src/main/java/com/lambdaschool/starthere/config/ResourceServerConfig.java
@@ -0,0 +1,45 @@
+package com.lambdaschool.starthere.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
+import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
+import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
+import org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler;
+
+@Configuration
+@EnableResourceServer
+public class ResourceServerConfig extends ResourceServerConfigurerAdapter
+{
+
+ private static final String RESOURCE_ID = "resource_id";
+
+ @Override
+ public void configure(ResourceServerSecurityConfigurer resources)
+ {
+ resources.resourceId(RESOURCE_ID).stateless(false);
+ }
+
+ @Override
+ public void configure(HttpSecurity http) throws Exception
+ {
+ // http.anonymous().disable();
+ http.authorizeRequests().antMatchers("/",
+ "/h2-console/**",
+ "/swagger-resources/**",
+ "/swagger-resources/configuration/ui",
+ "/swagger-resources/configuration/security",
+ "/swagger-resource/**",
+ "/swagger-ui.html",
+ "/v2/api-docs",
+ "/webjars/**",
+ "/authors",
+ "/books",
+ "/createnewuser",
+ "/otherapis/**").permitAll().antMatchers("/users/**", "/oauth/revoke-token").authenticated().antMatchers("/roles/**").hasAnyRole("ADMIN", "USER", "DATA").antMatchers("/actuator/**").hasAnyRole("ADMIN").and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
+
+ // http.requiresChannel().anyRequest().requiresSecure();
+ http.csrf().disable();
+ http.headers().frameOptions().disable();
+ }
+}
diff --git a/StartHere/src/main/java/com/lambdaschool/starthere/config/SecurityConfig.java b/StartHere/src/main/java/com/lambdaschool/starthere/config/SecurityConfig.java
new file mode 100755
index 00000000..b9c05eb5
--- /dev/null
+++ b/StartHere/src/main/java/com/lambdaschool/starthere/config/SecurityConfig.java
@@ -0,0 +1,52 @@
+package com.lambdaschool.starthere.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.oauth2.provider.token.TokenStore;
+import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
+
+import javax.annotation.Resource;
+
+@Configuration
+@EnableWebSecurity
+@EnableGlobalMethodSecurity(prePostEnabled = true)
+public class SecurityConfig extends WebSecurityConfigurerAdapter
+{
+
+ @Resource(name = "userService")
+ private UserDetailsService userDetailsService;
+
+ @Override
+ @Bean
+ public AuthenticationManager authenticationManagerBean() throws Exception
+ {
+ return super.authenticationManagerBean();
+ }
+
+ @Autowired
+ public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception
+ {
+ auth.userDetailsService(userDetailsService).passwordEncoder(encoder());
+ }
+
+ @Bean
+ public TokenStore tokenStore()
+ {
+ return new InMemoryTokenStore();
+ }
+
+ @Bean
+ public PasswordEncoder encoder()
+ {
+ return new BCryptPasswordEncoder();
+ }
+}
\ No newline at end of file
diff --git a/StartHere/src/main/java/com/lambdaschool/starthere/config/SimpleCorsFilter.java b/StartHere/src/main/java/com/lambdaschool/starthere/config/SimpleCorsFilter.java
new file mode 100644
index 00000000..e6ece179
--- /dev/null
+++ b/StartHere/src/main/java/com/lambdaschool/starthere/config/SimpleCorsFilter.java
@@ -0,0 +1,52 @@
+package com.lambdaschool.starthere.config;
+
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
+import org.springframework.http.HttpMethod;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+@Component
+@Order(Ordered.HIGHEST_PRECEDENCE)
+public class SimpleCorsFilter implements Filter
+{
+
+ public SimpleCorsFilter()
+ {
+ }
+
+ @Override
+ public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException
+ {
+ HttpServletResponse response = (HttpServletResponse) res;
+ HttpServletRequest request = (HttpServletRequest) req;
+ response.setHeader("Access-Control-Allow-Origin", "*");
+ // response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
+ response.setHeader("Access-Control-Allow-Methods", "*");
+ // response.setHeader("Access-Control-Allow-Headers", "x-requested-with, authorization, content-type, access_token");
+ response.setHeader("Access-Control-Allow-Headers", "*");
+ response.setHeader("Access-Control-Max-Age", "3600");
+
+ if (HttpMethod.OPTIONS.name().equalsIgnoreCase(((HttpServletRequest) req).getMethod()))
+ {
+ response.setStatus(HttpServletResponse.SC_OK);
+ } else
+ {
+ chain.doFilter(req, res);
+ }
+ }
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException
+ {
+ }
+
+ @Override
+ public void destroy()
+ {
+ }
+}
\ No newline at end of file
diff --git a/StartHere/src/main/java/com/lambdaschool/starthere/config/Swagger2Config.java b/StartHere/src/main/java/com/lambdaschool/starthere/config/Swagger2Config.java
new file mode 100644
index 00000000..a49e6391
--- /dev/null
+++ b/StartHere/src/main/java/com/lambdaschool/starthere/config/Swagger2Config.java
@@ -0,0 +1,33 @@
+package com.lambdaschool.starthere.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.domain.Pageable;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.Contact;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+
+// http://localhost:2019/swagger-ui.html
+@Configuration
+public class Swagger2Config
+{
+ @Bean
+ public Docket api()
+ {
+ return new Docket(DocumentationType.SWAGGER_2)
+ .select().apis(RequestHandlerSelectors.any())
+ .paths(PathSelectors.any()).build()
+ .useDefaultResponseMessages(false) // Allows only my exception responses
+ .ignoredParameterTypes(Pageable.class) // allows only my paging parameter list
+ .apiInfo(apiEndPointsInfo());
+ }
+
+ private ApiInfo apiEndPointsInfo()
+ {
+ return new ApiInfoBuilder().title("Java String Back End Starting Project").description("A starting application for developing Java Spring Back End Projects").contact(new Contact("John Mitchell", "http://www.lambdaschool.com", "john@lambdaschool.com")).license("MIT").licenseUrl("https://github.com/LambdaSchool/java-starthere/blob/master/LICENSE").version("1.0.0").build();
+ }
+}
diff --git a/StartHere/src/main/java/com/lambdaschool/starthere/config/WebConfig.java b/StartHere/src/main/java/com/lambdaschool/starthere/config/WebConfig.java
new file mode 100644
index 00000000..a6370930
--- /dev/null
+++ b/StartHere/src/main/java/com/lambdaschool/starthere/config/WebConfig.java
@@ -0,0 +1,17 @@
+package com.lambdaschool.starthere.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class WebConfig implements WebMvcConfigurer
+{
+ @Override
+ public void addResourceHandlers(ResourceHandlerRegistry registry)
+ {
+ registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
+
+ registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
+ }
+}
diff --git a/StartHere/src/main/java/com/lambdaschool/starthere/controllers/APIsController.java b/StartHere/src/main/java/com/lambdaschool/starthere/controllers/APIsController.java
new file mode 100644
index 00000000..9b2c47e8
--- /dev/null
+++ b/StartHere/src/main/java/com/lambdaschool/starthere/controllers/APIsController.java
@@ -0,0 +1,56 @@
+package com.lambdaschool.starthere.controllers;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.lambdaschool.starthere.models.APIOpenLibrary;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.core.ParameterizedTypeReference;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.client.RestTemplate;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+@RestController
+@RequestMapping("/otherapis")
+public class APIsController
+{
+ private static final Logger logger = LoggerFactory.getLogger(RolesController.class);
+ private RestTemplate restTemplate = new RestTemplate();
+
+ // taken from https://openlibrary.org/dev/docs/api/books
+ // returns a list of books - you can include multiple ISBNs in a single request
+ // This API returns a map instead of the standard list
+ //
+ // localhost:2019/otherapis/openlibrary/0982477562
+
+ @GetMapping(value = "/openlibrary/{isbn}",
+ produces = {"application/json"})
+ public ResponseEntity> listABookGivenISBN(HttpServletRequest request, @PathVariable String isbn)
+ {
+ logger.trace(request.getRequestURI() + " accessed");
+
+ String requestURL = "https://openlibrary.org/api/books?bibkeys=" + "ISBN:" + isbn + "&format=json";
+
+ ParameterizedTypeReference