diff --git a/api/build.gradle b/api/build.gradle index 920566e..6e0a8cd 100644 --- a/api/build.gradle +++ b/api/build.gradle @@ -1,23 +1,18 @@ -apply plugin: 'java' -apply plugin: 'application' -apply plugin: "io.spring.dependency-management" -apply plugin: "org.springframework.boot" +plugins { + id 'java' + id 'application' + id "io.spring.dependency-management" + id "org.springframework.boot" +} dependencies { + implementation project(':core') implementation "org.springframework.boot:spring-boot-starter-data-jpa" - implementation "org.springframework.boot:spring-boot-starter-security" - implementation "org.springframework.session:spring-session-jdbc" implementation "org.springframework.boot:spring-boot-starter-web" - runtimeOnly "org.postgresql:postgresql:42.2.23" + implementation "org.springframework.boot:spring-boot-starter-security" testImplementation "org.springframework.boot:spring-boot-starter-test" - testImplementation "org.springframework.security:spring-security-test:5.1.5.RELEASE" + testImplementation "org.springframework.security:spring-security-test" } -jar { - description = "twigs" -} - -mainClassName = "com.wbrawner.twigs.TwigsServerApplication" - sourceCompatibility = 17 targetCompatibility = 17 diff --git a/api/src/main/java/com/wbrawner/twigs/user/UserController.java b/api/src/main/java/com/wbrawner/twigs/user/UserController.java index c7db6a7..7ff6070 100644 --- a/api/src/main/java/com/wbrawner/twigs/user/UserController.java +++ b/api/src/main/java/com/wbrawner/twigs/user/UserController.java @@ -9,6 +9,7 @@ import com.wbrawner.twigs.session.SessionResponse; import com.wbrawner.twigs.session.UserSessionRepository; import jakarta.transaction.Transactional; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; @@ -34,6 +35,7 @@ public class UserController { private final PasswordEncoder passwordEncoder; private final UserPermissionRepository userPermissionsRepository; private final UserSessionRepository userSessionRepository; + private final UserService userService; private final DaoAuthenticationProvider authenticationProvider; @Autowired @@ -43,13 +45,14 @@ public class UserController { UserSessionRepository userSessionRepository, PasswordEncoder passwordEncoder, UserPermissionRepository userPermissionsRepository, - DaoAuthenticationProvider authenticationProvider + UserService userService, DaoAuthenticationProvider authenticationProvider ) { this.budgetRepository = budgetRepository; this.userRepository = userRepository; this.userSessionRepository = userSessionRepository; this.passwordEncoder = passwordEncoder; this.userPermissionsRepository = userPermissionsRepository; + this.userService = userService; this.authenticationProvider = authenticationProvider; } @@ -75,17 +78,13 @@ public class UserController { @PostMapping(path = "/login", produces = {MediaType.APPLICATION_JSON_VALUE}) ResponseEntity login(@RequestBody LoginRequest request) { - var authReq = new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword()); - Authentication auth; try { - auth = authenticationProvider.authenticate(authReq); + return ResponseEntity.ok(new SessionResponse( + userService.login(request.getUsername(), request.getPassword()) + )); } catch (AuthenticationException e) { - return ResponseEntity.notFound().build(); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); } - SecurityContextHolder.getContext().setAuthentication(auth); - var user = Objects.requireNonNull(getCurrentUser()); - var session = userSessionRepository.save(new Session(user.getId())); - return ResponseEntity.ok(new SessionResponse(session)); } @GetMapping(path = "/me", produces = {MediaType.APPLICATION_JSON_VALUE}) diff --git a/api/src/main/resources/application.properties b/api/src/main/resources/application.properties index deebd4a..d86f879 100644 --- a/api/src/main/resources/application.properties +++ b/api/src/main/resources/application.properties @@ -1,11 +1,6 @@ spring.jpa.hibernate.ddl-auto=update -spring.datasource.url=jdbc:postgresql://localhost:5432/twigs -spring.datasource.username=twigs -spring.datasource.password=twigs +spring.datasource.url=jdbc:h2:./twigs.db spring.profiles.active=prod spring.session.jdbc.initialize-schema=always -spring.datasource.testWhileIdle=true -spring.datasource.timeBetweenEvictionRunsMillis=60000 -spring.datasource.validationQuery=SELECT 1 -twigs.cors.domains=* +twigs.cors.domains=http://localhost:4200 logging.level.org.springframework.security=DEBUG diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..8921cf9 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,25 @@ +plugins { + id 'java' + id 'application' + id "io.spring.dependency-management" + id "org.springframework.boot" + id 'org.graalvm.buildtools.native' version '0.9.18' +} + +dependencies { + implementation project(':core') + implementation project(':api') + implementation "org.springframework.boot:spring-boot-starter-data-jpa" + implementation "org.springframework.boot:spring-boot-starter-security" + implementation "org.springframework.boot:spring-boot-starter-web" + implementation "org.springframework.session:spring-session-jdbc" + runtimeOnly 'org.postgresql:postgresql:42.2.27' + runtimeOnly 'com.h2database:h2:2.2.220' + testImplementation "org.springframework.boot:spring-boot-starter-test" +} + +jar { + description = "twigs" +} + +mainClassName = "com.wbrawner.twigs.TwigsServerApplication" \ No newline at end of file diff --git a/api/src/main/java/com/wbrawner/twigs/TwigsServerApplication.java b/app/src/main/java/com/wbrawner/twigs/TwigsServerApplication.java similarity index 100% rename from api/src/main/java/com/wbrawner/twigs/TwigsServerApplication.java rename to app/src/main/java/com/wbrawner/twigs/TwigsServerApplication.java diff --git a/api/src/main/java/com/wbrawner/twigs/config/JdbcUserDetailsService.java b/app/src/main/java/com/wbrawner/twigs/config/JdbcUserDetailsService.java similarity index 100% rename from api/src/main/java/com/wbrawner/twigs/config/JdbcUserDetailsService.java rename to app/src/main/java/com/wbrawner/twigs/config/JdbcUserDetailsService.java diff --git a/api/src/main/java/com/wbrawner/twigs/config/SecurityConfig.java b/app/src/main/java/com/wbrawner/twigs/config/SecurityConfig.java similarity index 92% rename from api/src/main/java/com/wbrawner/twigs/config/SecurityConfig.java rename to app/src/main/java/com/wbrawner/twigs/config/SecurityConfig.java index b8703bd..ecdc165 100644 --- a/api/src/main/java/com/wbrawner/twigs/config/SecurityConfig.java +++ b/app/src/main/java/com/wbrawner/twigs/config/SecurityConfig.java @@ -1,6 +1,6 @@ package com.wbrawner.twigs.config; -import com.wbrawner.twigs.passwordresetrequest.PasswordResetRequestRepository; +import com.wbrawner.twigs.user.PasswordResetRequestRepository; import com.wbrawner.twigs.session.UserSessionRepository; import com.wbrawner.twigs.user.UserRepository; import org.springframework.context.annotation.Bean; @@ -11,7 +11,6 @@ import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.provisioning.JdbcUserDetailsManager; @@ -80,10 +79,12 @@ public class SecurityConfig { return httpSecurity.authorizeHttpRequests((authz) -> { try { authz - .requestMatchers("/api/users/register", "/api/users/login") - .permitAll() - .anyRequest() + .requestMatchers( + "/api/^(users/register|users/login)" + ) .authenticated() + .anyRequest() + .permitAll() .and() .httpBasic() .authenticationEntryPoint(new SilentAuthenticationEntryPoint()) @@ -111,9 +112,7 @@ public class SecurityConfig { .and() .csrf() .disable() - .addFilter(new TokenAuthenticationFilter(authenticationManager)) - .sessionManagement() - .sessionCreationPolicy(SessionCreationPolicy.STATELESS); + .addFilter(new TokenAuthenticationFilter(authenticationManager)); } catch (Exception e) { throw new RuntimeException(e); } diff --git a/api/src/main/java/com/wbrawner/twigs/config/SessionAuthenticationToken.java b/app/src/main/java/com/wbrawner/twigs/config/SessionAuthenticationToken.java similarity index 100% rename from api/src/main/java/com/wbrawner/twigs/config/SessionAuthenticationToken.java rename to app/src/main/java/com/wbrawner/twigs/config/SessionAuthenticationToken.java diff --git a/api/src/main/java/com/wbrawner/twigs/config/SilentAuthenticationEntryPoint.java b/app/src/main/java/com/wbrawner/twigs/config/SilentAuthenticationEntryPoint.java similarity index 100% rename from api/src/main/java/com/wbrawner/twigs/config/SilentAuthenticationEntryPoint.java rename to app/src/main/java/com/wbrawner/twigs/config/SilentAuthenticationEntryPoint.java diff --git a/api/src/main/java/com/wbrawner/twigs/config/TokenAuthenticationFilter.java b/app/src/main/java/com/wbrawner/twigs/config/TokenAuthenticationFilter.java similarity index 100% rename from api/src/main/java/com/wbrawner/twigs/config/TokenAuthenticationFilter.java rename to app/src/main/java/com/wbrawner/twigs/config/TokenAuthenticationFilter.java diff --git a/api/src/main/java/com/wbrawner/twigs/config/TokenAuthenticationProvider.java b/app/src/main/java/com/wbrawner/twigs/config/TokenAuthenticationProvider.java similarity index 96% rename from api/src/main/java/com/wbrawner/twigs/config/TokenAuthenticationProvider.java rename to app/src/main/java/com/wbrawner/twigs/config/TokenAuthenticationProvider.java index 9236f76..e78d4fd 100644 --- a/api/src/main/java/com/wbrawner/twigs/config/TokenAuthenticationProvider.java +++ b/app/src/main/java/com/wbrawner/twigs/config/TokenAuthenticationProvider.java @@ -1,5 +1,6 @@ package com.wbrawner.twigs.config; +import com.wbrawner.twigs.Utils; import com.wbrawner.twigs.session.UserSessionRepository; import com.wbrawner.twigs.user.UserRepository; import org.springframework.security.authentication.BadCredentialsException; @@ -47,7 +48,7 @@ public class TokenAuthenticationProvider extends DaoAuthenticationProvider { new Thread(() -> { // Update the session on a background thread to avoid holding up the request longer than necessary var updatedSession = session.get(); - updatedSession.setExpiration(twoWeeksFromNow()); + updatedSession.setExpiration(Utils.twoWeeksFromNow()); userSessionRepository.save(updatedSession); }).start(); return new SessionAuthenticationToken( diff --git a/app/src/main/java/com/wbrawner/twigs/config/WebConfig.java b/app/src/main/java/com/wbrawner/twigs/config/WebConfig.java new file mode 100644 index 0000000..b92aa48 --- /dev/null +++ b/app/src/main/java/com/wbrawner/twigs/config/WebConfig.java @@ -0,0 +1,22 @@ +//package com.wbrawner.twigs.config; +// +//import org.springframework.context.annotation.Configuration; +//import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +//import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; +//import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +// +//@Configuration +//public class WebConfig implements WebMvcConfigurer { +// +// @Override +// public void addViewControllers(ViewControllerRegistry registry) { +// registry.addViewController("/").setViewName("forward:/index.html"); +// registry.addViewController("/{path:\\w*}").setViewName("forward:/index.html"); +// registry.addViewController("/(^api)/**").setViewName("forward:/index.html"); +// } +// +// @Override +// public void addResourceHandlers(ResourceHandlerRegistry registry) { +// registry.addResourceHandler("/**").addResourceLocations("classpath:/webapp/"); +// } +//} diff --git a/core/build.gradle b/core/build.gradle new file mode 100644 index 0000000..181c028 --- /dev/null +++ b/core/build.gradle @@ -0,0 +1,12 @@ +plugins { + id 'java' + id 'application' + id "io.spring.dependency-management" + id "org.springframework.boot" +} + +dependencies { + implementation "org.springframework.boot:spring-boot-starter-security" + implementation "org.springframework.boot:spring-boot-starter-web" + implementation "org.springframework.boot:spring-boot-starter-data-jpa" +} diff --git a/api/src/main/java/com/wbrawner/twigs/Utils.java b/core/src/main/java/com/wbrawner/twigs/Utils.java similarity index 100% rename from api/src/main/java/com/wbrawner/twigs/Utils.java rename to core/src/main/java/com/wbrawner/twigs/Utils.java diff --git a/api/src/main/java/com/wbrawner/twigs/budget/Budget.java b/core/src/main/java/com/wbrawner/twigs/budget/Budget.java similarity index 96% rename from api/src/main/java/com/wbrawner/twigs/budget/Budget.java rename to core/src/main/java/com/wbrawner/twigs/budget/Budget.java index 15c29bf..86a73d4 100644 --- a/api/src/main/java/com/wbrawner/twigs/budget/Budget.java +++ b/core/src/main/java/com/wbrawner/twigs/budget/Budget.java @@ -1,5 +1,6 @@ package com.wbrawner.twigs.budget; +import com.wbrawner.twigs.Utils; import com.wbrawner.twigs.category.Category; import com.wbrawner.twigs.transaction.Transaction; import jakarta.persistence.Entity; @@ -15,7 +16,7 @@ import static com.wbrawner.twigs.Utils.randomId; @Entity public class Budget { @Id - private String id = randomId(); + private String id = Utils.randomId(); private String name; private String description; private String currencyCode; diff --git a/api/src/main/java/com/wbrawner/twigs/budget/BudgetRepository.java b/core/src/main/java/com/wbrawner/twigs/budget/BudgetRepository.java similarity index 100% rename from api/src/main/java/com/wbrawner/twigs/budget/BudgetRepository.java rename to core/src/main/java/com/wbrawner/twigs/budget/BudgetRepository.java diff --git a/api/src/main/java/com/wbrawner/twigs/category/Category.java b/core/src/main/java/com/wbrawner/twigs/category/Category.java similarity index 100% rename from api/src/main/java/com/wbrawner/twigs/category/Category.java rename to core/src/main/java/com/wbrawner/twigs/category/Category.java diff --git a/api/src/main/java/com/wbrawner/twigs/category/CategoryRepository.java b/core/src/main/java/com/wbrawner/twigs/category/CategoryRepository.java similarity index 100% rename from api/src/main/java/com/wbrawner/twigs/category/CategoryRepository.java rename to core/src/main/java/com/wbrawner/twigs/category/CategoryRepository.java diff --git a/api/src/main/java/com/wbrawner/twigs/permission/Permission.java b/core/src/main/java/com/wbrawner/twigs/permission/Permission.java similarity index 100% rename from api/src/main/java/com/wbrawner/twigs/permission/Permission.java rename to core/src/main/java/com/wbrawner/twigs/permission/Permission.java diff --git a/api/src/main/java/com/wbrawner/twigs/permission/UserPermission.java b/core/src/main/java/com/wbrawner/twigs/permission/UserPermission.java similarity index 100% rename from api/src/main/java/com/wbrawner/twigs/permission/UserPermission.java rename to core/src/main/java/com/wbrawner/twigs/permission/UserPermission.java diff --git a/api/src/main/java/com/wbrawner/twigs/permission/UserPermissionKey.java b/core/src/main/java/com/wbrawner/twigs/permission/UserPermissionKey.java similarity index 100% rename from api/src/main/java/com/wbrawner/twigs/permission/UserPermissionKey.java rename to core/src/main/java/com/wbrawner/twigs/permission/UserPermissionKey.java diff --git a/api/src/main/java/com/wbrawner/twigs/permission/UserPermissionRepository.java b/core/src/main/java/com/wbrawner/twigs/permission/UserPermissionRepository.java similarity index 100% rename from api/src/main/java/com/wbrawner/twigs/permission/UserPermissionRepository.java rename to core/src/main/java/com/wbrawner/twigs/permission/UserPermissionRepository.java diff --git a/core/src/main/java/com/wbrawner/twigs/recurringtransaction/RecurringTransaction.java b/core/src/main/java/com/wbrawner/twigs/recurringtransaction/RecurringTransaction.java new file mode 100644 index 0000000..a03272a --- /dev/null +++ b/core/src/main/java/com/wbrawner/twigs/recurringtransaction/RecurringTransaction.java @@ -0,0 +1,127 @@ +package com.wbrawner.twigs.recurringtransaction; + +import com.wbrawner.twigs.budget.Budget; +import com.wbrawner.twigs.category.Category; +import com.wbrawner.twigs.user.User; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; + +import java.time.Instant; + +import static com.wbrawner.twigs.Utils.randomId; + +@Entity +public class RecurringTransaction implements Comparable { + @Id + private final String id = randomId(); + @ManyToOne + @JoinColumn(nullable = false) + private final User createdBy; + private String title; + private String description; + private Instant date; + private Long amount; + @ManyToOne + private Category category; + private Boolean expense; + @ManyToOne + @JoinColumn(nullable = false) + private Budget budget; + + public RecurringTransaction() { + this(null, null, null, null, null, null, null, null); + } + + public RecurringTransaction( + String title, + String description, + Instant date, + Long amount, + Category category, + Boolean expense, + User createdBy, + Budget budget + ) { + this.title = title; + this.description = description; + this.date = date; + this.amount = amount; + this.category = category; + this.expense = expense; + this.createdBy = createdBy; + this.budget = budget; + } + + public String getId() { + // This should only be set from Hibernate so it shouldn't actually be null ever + //noinspection ConstantConditions + return id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Instant getDate() { + return date; + } + + public void setDate(Instant date) { + this.date = date; + } + + public Long getAmount() { + return amount; + } + + public void setAmount(Long amount) { + this.amount = amount; + } + + public Category getCategory() { + return category; + } + + public void setCategory(Category category) { + this.category = category; + } + + public Boolean getExpense() { + return expense; + } + + public void setExpense(Boolean expense) { + this.expense = expense; + } + + public User getCreatedBy() { + return createdBy; + } + + public Budget getBudget() { + return budget; + } + + public void setBudget(Budget budget) { + this.budget = budget; + } + + @Override + public int compareTo(RecurringTransaction other) { + return this.date.compareTo(other.date); + } +} \ No newline at end of file diff --git a/core/src/main/java/com/wbrawner/twigs/recurringtransaction/RecurringTransactionRepository.java b/core/src/main/java/com/wbrawner/twigs/recurringtransaction/RecurringTransactionRepository.java new file mode 100644 index 0000000..e88a76a --- /dev/null +++ b/core/src/main/java/com/wbrawner/twigs/recurringtransaction/RecurringTransactionRepository.java @@ -0,0 +1,36 @@ +package com.wbrawner.twigs.recurringtransaction; + +import com.wbrawner.twigs.budget.Budget; +import com.wbrawner.twigs.category.Category; +import com.wbrawner.twigs.transaction.Transaction; +import org.springframework.data.domain.Pageable; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.PagingAndSortingRepository; + +import java.time.Instant; +import java.util.List; +import java.util.Optional; + +public interface RecurringTransactionRepository extends CrudRepository, + PagingAndSortingRepository { + Optional findByIdAndBudgetIn(String id, List budgets); + + List findAllByBudgetInAndCategoryInAndDateGreaterThanAndDateLessThan( + List budgets, + List categories, + Instant start, + Instant end, + Pageable pageable + ); + + List findAllByBudgetInAndDateGreaterThanAndDateLessThan( + List budgets, + Instant start, + Instant end, + Pageable pageable + ); + + List findAllByBudgetAndCategory(Budget budget, Category category); + + void deleteAllByBudget(Budget budget); +} \ No newline at end of file diff --git a/api/src/main/java/com/wbrawner/twigs/session/Session.java b/core/src/main/java/com/wbrawner/twigs/session/Session.java similarity index 100% rename from api/src/main/java/com/wbrawner/twigs/session/Session.java rename to core/src/main/java/com/wbrawner/twigs/session/Session.java diff --git a/api/src/main/java/com/wbrawner/twigs/session/SessionCleanupTask.java b/core/src/main/java/com/wbrawner/twigs/session/SessionCleanupTask.java similarity index 100% rename from api/src/main/java/com/wbrawner/twigs/session/SessionCleanupTask.java rename to core/src/main/java/com/wbrawner/twigs/session/SessionCleanupTask.java diff --git a/api/src/main/java/com/wbrawner/twigs/session/UserSessionRepository.java b/core/src/main/java/com/wbrawner/twigs/session/UserSessionRepository.java similarity index 100% rename from api/src/main/java/com/wbrawner/twigs/session/UserSessionRepository.java rename to core/src/main/java/com/wbrawner/twigs/session/UserSessionRepository.java diff --git a/api/src/main/java/com/wbrawner/twigs/transaction/Transaction.java b/core/src/main/java/com/wbrawner/twigs/transaction/Transaction.java similarity index 100% rename from api/src/main/java/com/wbrawner/twigs/transaction/Transaction.java rename to core/src/main/java/com/wbrawner/twigs/transaction/Transaction.java diff --git a/api/src/main/java/com/wbrawner/twigs/transaction/TransactionRepository.java b/core/src/main/java/com/wbrawner/twigs/transaction/TransactionRepository.java similarity index 100% rename from api/src/main/java/com/wbrawner/twigs/transaction/TransactionRepository.java rename to core/src/main/java/com/wbrawner/twigs/transaction/TransactionRepository.java diff --git a/api/src/main/java/com/wbrawner/twigs/passwordresetrequest/PasswordResetRequest.java b/core/src/main/java/com/wbrawner/twigs/user/PasswordResetRequest.java similarity index 94% rename from api/src/main/java/com/wbrawner/twigs/passwordresetrequest/PasswordResetRequest.java rename to core/src/main/java/com/wbrawner/twigs/user/PasswordResetRequest.java index fa8c1c2..986575a 100644 --- a/api/src/main/java/com/wbrawner/twigs/passwordresetrequest/PasswordResetRequest.java +++ b/core/src/main/java/com/wbrawner/twigs/user/PasswordResetRequest.java @@ -1,4 +1,4 @@ -package com.wbrawner.twigs.passwordresetrequest; +package com.wbrawner.twigs.user; import com.wbrawner.twigs.user.User; import jakarta.persistence.Entity; diff --git a/api/src/main/java/com/wbrawner/twigs/passwordresetrequest/PasswordResetRequestRepository.java b/core/src/main/java/com/wbrawner/twigs/user/PasswordResetRequestRepository.java similarity index 79% rename from api/src/main/java/com/wbrawner/twigs/passwordresetrequest/PasswordResetRequestRepository.java rename to core/src/main/java/com/wbrawner/twigs/user/PasswordResetRequestRepository.java index eecebdd..dae7a0b 100644 --- a/api/src/main/java/com/wbrawner/twigs/passwordresetrequest/PasswordResetRequestRepository.java +++ b/core/src/main/java/com/wbrawner/twigs/user/PasswordResetRequestRepository.java @@ -1,4 +1,4 @@ -package com.wbrawner.twigs.passwordresetrequest; +package com.wbrawner.twigs.user; import org.springframework.data.repository.PagingAndSortingRepository; diff --git a/api/src/main/java/com/wbrawner/twigs/user/User.java b/core/src/main/java/com/wbrawner/twigs/user/User.java similarity index 100% rename from api/src/main/java/com/wbrawner/twigs/user/User.java rename to core/src/main/java/com/wbrawner/twigs/user/User.java diff --git a/api/src/main/java/com/wbrawner/twigs/user/UserRepository.java b/core/src/main/java/com/wbrawner/twigs/user/UserRepository.java similarity index 100% rename from api/src/main/java/com/wbrawner/twigs/user/UserRepository.java rename to core/src/main/java/com/wbrawner/twigs/user/UserRepository.java diff --git a/core/src/main/java/com/wbrawner/twigs/user/UserService.java b/core/src/main/java/com/wbrawner/twigs/user/UserService.java new file mode 100644 index 0000000..304aee8 --- /dev/null +++ b/core/src/main/java/com/wbrawner/twigs/user/UserService.java @@ -0,0 +1,37 @@ +package com.wbrawner.twigs.user; + +import com.wbrawner.twigs.session.Session; +import com.wbrawner.twigs.session.UserSessionRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.authentication.dao.DaoAuthenticationProvider; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Service; + +import java.util.Objects; + +import static com.wbrawner.twigs.Utils.getCurrentUser; + +@Service +public class UserService { + private final DaoAuthenticationProvider authenticationProvider; + private final UserRepository userRepository; + private final UserSessionRepository userSessionRepository; + + @Autowired + public UserService(DaoAuthenticationProvider authenticationProvider, UserRepository userRepository, UserSessionRepository userSessionRepository) { + this.authenticationProvider = authenticationProvider; + this.userRepository = userRepository; + this.userSessionRepository = userSessionRepository; + } + + public Session login(String username, String password) throws AuthenticationException { + var authReq = new UsernamePasswordAuthenticationToken(username, password); + Authentication auth = authenticationProvider.authenticate(authReq); + SecurityContextHolder.getContext().setAuthentication(auth); + var user = Objects.requireNonNull(getCurrentUser()); + return userSessionRepository.save(new Session(user.getId())); + } +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 7881ed3..4ae1d0b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -3,4 +3,7 @@ */ rootProject.name = 'twigs' -include ':api' \ No newline at end of file +include ':api' +include 'app' +include 'core' +