From cd20dfd7cf897a0fa1a9677107797c38b7a97e4a Mon Sep 17 00:00:00 2001 From: vran Date: Wed, 2 Mar 2022 20:13:25 +0800 Subject: [PATCH] Feature/oauth2 github (#27) * feat: jooq generate * feat: support github oauth * feat: support oauth2 login * feat: update content-type * feat: add custom authentication exception * feat: add oauth2 app api * fix: checkstyle --- api/build.gradle | 1 + .../com/databasir/api/LoginController.java | 19 +- .../databasir/api/OpenAuth2AppController.java | 87 +++ .../databasir/api/OperationLogController.java | 2 + .../main/java/com/databasir/api/Routes.java | 17 + .../databasir/api/config/SecurityConfig.java | 2 + .../oauth2/DatabasirOAuth2Authentication.java | 28 + .../oauth2/DatabasirOauth2LoginFilter.java | 62 ++ .../OAuth2AuthenticationSuccessHandler.java | 42 ++ ...DatabasirAuthenticationFailureHandler.java | 7 + ...DatabasirAuthenticationSuccessHandler.java | 28 +- .../security/DatabasirUserDetailService.java | 3 - .../resources/application-local.properties | 2 +- .../java/com/databasir/common/JsonData.java | 10 +- core/build.gradle | 3 + .../databasir/core/domain/DomainErrors.java | 4 +- .../core/domain/app/OpenAuthAppService.java | 111 ++++ .../app/converter/OAuthAppPojoConverter.java | 26 + .../converter/OAuthAppResponseConverter.java | 11 + .../app/data/OAuthAppCreateRequest.java | 35 ++ .../app/data/OAuthAppDetailResponse.java | 31 + .../app/data/OAuthAppPageCondition.java | 30 + .../domain/app/data/OAuthAppPageResponse.java | 30 + .../domain/app/data/OAuthAppResponse.java | 28 + .../app/data/OAuthAppUpdateRequest.java | 39 ++ .../DatabasirAuthenticationException.java | 19 + .../app/handler/GithubOpenAuthHandler.java | 83 +++ .../app/handler/OAuthProcessContext.java | 22 + .../app/handler/OAuthProcessResult.java | 16 + .../domain/app/handler/OpenAuthHandler.java | 10 + .../data/UserLoginResponse.java | 4 +- .../domain/login/service/LoginService.java | 40 ++ .../domain/user/data/UserLoginRequest.java | 16 - .../core/domain/user/service/UserService.java | 19 +- .../infrastructure/remote/ClientConfig.java | 34 ++ .../remote/github/GithubApiClient.java | 23 + .../remote/github/GithubOauthClient.java | 20 + .../remote/github/GithubRemoteService.java | 74 +++ .../remote/github/TokenRequest.java | 32 ++ .../java/com/databasir/dao/Databasir.java | 7 + .../main/java/com/databasir/dao/Indexes.java | 2 - .../main/java/com/databasir/dao/Keys.java | 5 + .../main/java/com/databasir/dao/Tables.java | 6 + .../com/databasir/dao/tables/OauthApp.java | 199 +++++++ .../dao/tables/UserFavoriteProject.java | 12 +- .../dao/tables/pojos/OauthAppPojo.java | 265 +++++++++ .../dao/tables/records/OauthAppRecord.java | 539 ++++++++++++++++++ .../com/databasir/dao/enums/OAuthAppType.java | 10 + .../java/com/databasir/dao/impl/BaseDao.java | 6 + .../java/com/databasir/dao/impl/LoginDao.java | 7 + .../com/databasir/dao/impl/OauthAppDao.java | 37 ++ .../resources/db/migration/V1.4__oauth.sql | 18 + 52 files changed, 2120 insertions(+), 63 deletions(-) create mode 100644 api/src/main/java/com/databasir/api/OpenAuth2AppController.java create mode 100644 api/src/main/java/com/databasir/api/config/oauth2/DatabasirOAuth2Authentication.java create mode 100644 api/src/main/java/com/databasir/api/config/oauth2/DatabasirOauth2LoginFilter.java create mode 100644 api/src/main/java/com/databasir/api/config/oauth2/OAuth2AuthenticationSuccessHandler.java create mode 100644 core/src/main/java/com/databasir/core/domain/app/OpenAuthAppService.java create mode 100644 core/src/main/java/com/databasir/core/domain/app/converter/OAuthAppPojoConverter.java create mode 100644 core/src/main/java/com/databasir/core/domain/app/converter/OAuthAppResponseConverter.java create mode 100644 core/src/main/java/com/databasir/core/domain/app/data/OAuthAppCreateRequest.java create mode 100644 core/src/main/java/com/databasir/core/domain/app/data/OAuthAppDetailResponse.java create mode 100644 core/src/main/java/com/databasir/core/domain/app/data/OAuthAppPageCondition.java create mode 100644 core/src/main/java/com/databasir/core/domain/app/data/OAuthAppPageResponse.java create mode 100644 core/src/main/java/com/databasir/core/domain/app/data/OAuthAppResponse.java create mode 100644 core/src/main/java/com/databasir/core/domain/app/data/OAuthAppUpdateRequest.java create mode 100644 core/src/main/java/com/databasir/core/domain/app/exception/DatabasirAuthenticationException.java create mode 100644 core/src/main/java/com/databasir/core/domain/app/handler/GithubOpenAuthHandler.java create mode 100644 core/src/main/java/com/databasir/core/domain/app/handler/OAuthProcessContext.java create mode 100644 core/src/main/java/com/databasir/core/domain/app/handler/OAuthProcessResult.java create mode 100644 core/src/main/java/com/databasir/core/domain/app/handler/OpenAuthHandler.java rename core/src/main/java/com/databasir/core/domain/{user => login}/data/UserLoginResponse.java (86%) delete mode 100644 core/src/main/java/com/databasir/core/domain/user/data/UserLoginRequest.java create mode 100644 core/src/main/java/com/databasir/core/infrastructure/remote/ClientConfig.java create mode 100644 core/src/main/java/com/databasir/core/infrastructure/remote/github/GithubApiClient.java create mode 100644 core/src/main/java/com/databasir/core/infrastructure/remote/github/GithubOauthClient.java create mode 100644 core/src/main/java/com/databasir/core/infrastructure/remote/github/GithubRemoteService.java create mode 100644 core/src/main/java/com/databasir/core/infrastructure/remote/github/TokenRequest.java create mode 100644 dao/generated-src/jooq/main/java/com/databasir/dao/tables/OauthApp.java create mode 100644 dao/generated-src/jooq/main/java/com/databasir/dao/tables/pojos/OauthAppPojo.java create mode 100644 dao/generated-src/jooq/main/java/com/databasir/dao/tables/records/OauthAppRecord.java create mode 100644 dao/src/main/java/com/databasir/dao/enums/OAuthAppType.java create mode 100644 dao/src/main/java/com/databasir/dao/impl/OauthAppDao.java create mode 100644 dao/src/main/resources/db/migration/V1.4__oauth.sql diff --git a/api/build.gradle b/api/build.gradle index 664a822..9fab618 100644 --- a/api/build.gradle +++ b/api/build.gradle @@ -26,6 +26,7 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jdbc' implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-quartz' + implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' implementation 'org.flywaydb:flyway-core' diff --git a/api/src/main/java/com/databasir/api/LoginController.java b/api/src/main/java/com/databasir/api/LoginController.java index bb319d5..ad5408a 100644 --- a/api/src/main/java/com/databasir/api/LoginController.java +++ b/api/src/main/java/com/databasir/api/LoginController.java @@ -1,5 +1,6 @@ package com.databasir.api; +import com.databasir.api.config.security.DatabasirUserDetails; import com.databasir.common.DatabasirException; import com.databasir.common.JsonData; import com.databasir.common.exception.InvalidTokenException; @@ -7,10 +8,10 @@ import com.databasir.core.domain.DomainErrors; import com.databasir.core.domain.log.annotation.Operation; import com.databasir.core.domain.login.data.AccessTokenRefreshRequest; import com.databasir.core.domain.login.data.AccessTokenRefreshResponse; +import com.databasir.core.domain.login.data.UserLoginResponse; import com.databasir.core.domain.login.service.LoginService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; @@ -27,8 +28,6 @@ import java.util.Objects; @Slf4j public class LoginController { - private final AuthenticationManager authenticationManager; - private final LoginService loginService; @GetMapping(Routes.Login.LOGOUT) @@ -39,8 +38,8 @@ public class LoginController { } @PostMapping(Routes.Login.REFRESH_ACCESS_TOKEN) - public JsonData refreshAccessTokens(@RequestBody @Valid - AccessTokenRefreshRequest request) { + public JsonData refreshAccessTokens(@RequestBody + @Valid AccessTokenRefreshRequest request) { try { return JsonData.ok(loginService.refreshAccessTokens(request)); } catch (DatabasirException e) { @@ -53,4 +52,14 @@ public class LoginController { throw e; } } + + @GetMapping(Routes.Login.LOGIN_INFO) + public JsonData getUserLoginData() { + DatabasirUserDetails user = (DatabasirUserDetails) SecurityContextHolder.getContext() + .getAuthentication() + .getPrincipal(); + Integer userId = user.getUserPojo().getId(); + return JsonData.ok(loginService.getUserLoginData(userId)); + } + } diff --git a/api/src/main/java/com/databasir/api/OpenAuth2AppController.java b/api/src/main/java/com/databasir/api/OpenAuth2AppController.java new file mode 100644 index 0000000..d3bbf2c --- /dev/null +++ b/api/src/main/java/com/databasir/api/OpenAuth2AppController.java @@ -0,0 +1,87 @@ +package com.databasir.api; + +import com.databasir.common.JsonData; +import com.databasir.core.domain.app.OpenAuthAppService; +import com.databasir.core.domain.app.data.*; +import com.databasir.core.domain.app.handler.OpenAuthHandler; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.web.PageableDefault; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; + +import static org.springframework.data.domain.Sort.Direction.DESC; + +@Controller +@RequiredArgsConstructor +public class OpenAuth2AppController { + + private final OpenAuthHandler openAuthHandler; + + private final OpenAuthAppService openAuthAppService; + + /** + * 无需授权 + */ + @GetMapping("/oauth2/authorization/{registrationId}") + @ResponseBody + public JsonData authorization(@PathVariable String registrationId) { + String authorization = openAuthHandler.authorization(registrationId); + return JsonData.ok(authorization); + } + + /** + * 无需授权 + */ + @GetMapping("/oauth2/apps") + @ResponseBody + public JsonData> listApps() { + return JsonData.ok(openAuthAppService.listAll()); + } + + @GetMapping(Routes.OAuth2App.LIST_PAGE) + @PreAuthorize("hasAnyAuthority('SYS_OWNER')") + @ResponseBody + public JsonData> listPage(@PageableDefault(sort = "id", direction = DESC) + Pageable page, + OAuthAppPageCondition condition) { + return JsonData.ok(openAuthAppService.listPage(page, condition)); + } + + @GetMapping(Routes.OAuth2App.GET_ONE) + @PreAuthorize("hasAnyAuthority('SYS_OWNER')") + @ResponseBody + public JsonData getOne(@PathVariable Integer id) { + return JsonData.ok(openAuthAppService.getOne(id)); + + } + + @PostMapping(Routes.OAuth2App.CREATE) + @PreAuthorize("hasAnyAuthority('SYS_OWNER')") + @ResponseBody + public JsonData create(@RequestBody @Valid OAuthAppCreateRequest request) { + Integer id = openAuthAppService.create(request); + return JsonData.ok(id); + } + + @PatchMapping(Routes.OAuth2App.UPDATE) + @PreAuthorize("hasAnyAuthority('SYS_OWNER')") + @ResponseBody + public JsonData updateById(@RequestBody @Valid OAuthAppUpdateRequest request) { + openAuthAppService.updateById(request); + return JsonData.ok(); + } + + @DeleteMapping(Routes.OAuth2App.DELETE) + @PreAuthorize("hasAnyAuthority('SYS_OWNER')") + @ResponseBody + public JsonData deleteById(@PathVariable Integer id) { + openAuthAppService.deleteById(id); + return JsonData.ok(); + } +} diff --git a/api/src/main/java/com/databasir/api/OperationLogController.java b/api/src/main/java/com/databasir/api/OperationLogController.java index 7345735..7c0e94f 100644 --- a/api/src/main/java/com/databasir/api/OperationLogController.java +++ b/api/src/main/java/com/databasir/api/OperationLogController.java @@ -9,6 +9,7 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.web.PageableDefault; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @@ -21,6 +22,7 @@ public class OperationLogController { private final OperationLogService operationLogService; @GetMapping(Routes.OperationLog.LIST) + @PreAuthorize("hasAnyAuthority('SYS_OWNER')") public JsonData> list(@PageableDefault(sort = "id", direction = Sort.Direction.DESC) Pageable page, OperationLogPageCondition condition) { diff --git a/api/src/main/java/com/databasir/api/Routes.java b/api/src/main/java/com/databasir/api/Routes.java index e6b213f..a4aefbc 100644 --- a/api/src/main/java/com/databasir/api/Routes.java +++ b/api/src/main/java/com/databasir/api/Routes.java @@ -102,9 +102,26 @@ public interface Routes { String LOGOUT = "/logout"; String REFRESH_ACCESS_TOKEN = "/access_tokens"; + + String LOGIN_INFO = "/login_info"; + } interface OperationLog { String LIST = BASE + "/operation_logs"; } + + interface OAuth2App { + + String LIST_PAGE = BASE + "/oauth2_apps"; + + String CREATE = BASE + "/oauth2_apps"; + + String UPDATE = BASE + "/oauth2_apps"; + + String DELETE = BASE + "/oauth2_apps/{id}"; + + String GET_ONE = BASE + "/oauth2_apps/{id}"; + + } } diff --git a/api/src/main/java/com/databasir/api/config/SecurityConfig.java b/api/src/main/java/com/databasir/api/config/SecurityConfig.java index 79d634d..7eb3d2d 100644 --- a/api/src/main/java/com/databasir/api/config/SecurityConfig.java +++ b/api/src/main/java/com/databasir/api/config/SecurityConfig.java @@ -45,6 +45,8 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { .and() .authorizeRequests() .antMatchers("/login", Routes.Login.REFRESH_ACCESS_TOKEN).permitAll() + .antMatchers("/oauth2/apps", "/oauth2/failure", "/oauth2/authorization/*", "/oauth2/login/*") + .permitAll() .antMatchers("/", "/*.html", "/js/**", "/css/**", "/img/**", "/*.ico").permitAll() .anyRequest().authenticated() .and() diff --git a/api/src/main/java/com/databasir/api/config/oauth2/DatabasirOAuth2Authentication.java b/api/src/main/java/com/databasir/api/config/oauth2/DatabasirOAuth2Authentication.java new file mode 100644 index 0000000..e8f432b --- /dev/null +++ b/api/src/main/java/com/databasir/api/config/oauth2/DatabasirOAuth2Authentication.java @@ -0,0 +1,28 @@ +package com.databasir.api.config.oauth2; + +import org.springframework.security.authentication.AbstractAuthenticationToken; +import org.springframework.security.core.userdetails.UserDetails; + +public class DatabasirOAuth2Authentication extends AbstractAuthenticationToken { + + private Object credentials; + + private Object principal; + + public DatabasirOAuth2Authentication(UserDetails principal) { + super(principal.getAuthorities()); + this.credentials = null; + this.principal = principal; + setAuthenticated(false); + } + + @Override + public Object getCredentials() { + return this.credentials; + } + + @Override + public Object getPrincipal() { + return this.principal; + } +} diff --git a/api/src/main/java/com/databasir/api/config/oauth2/DatabasirOauth2LoginFilter.java b/api/src/main/java/com/databasir/api/config/oauth2/DatabasirOauth2LoginFilter.java new file mode 100644 index 0000000..5152fa9 --- /dev/null +++ b/api/src/main/java/com/databasir/api/config/oauth2/DatabasirOauth2LoginFilter.java @@ -0,0 +1,62 @@ +package com.databasir.api.config.oauth2; + +import com.databasir.api.config.security.DatabasirUserDetailService; +import com.databasir.core.domain.user.data.UserDetailResponse; +import com.databasir.core.domain.app.OpenAuthAppService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.DisabledException; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; +import org.springframework.security.web.authentication.AuthenticationFailureHandler; +import org.springframework.stereotype.Component; +import org.springframework.util.AntPathMatcher; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Map; + +@Component +@Slf4j +public class DatabasirOauth2LoginFilter extends AbstractAuthenticationProcessingFilter { + + public static final String OAUTH_LOGIN_URI = "/oauth2/login/*"; + + @Autowired + private OpenAuthAppService openAuthAppService; + + @Autowired + private DatabasirUserDetailService databasirUserDetailService; + + public DatabasirOauth2LoginFilter(AuthenticationManager authenticationManager, + OAuth2AuthenticationSuccessHandler auth2AuthenticationSuccessHandler, + AuthenticationFailureHandler authenticationFailureHandler) { + super(OAUTH_LOGIN_URI, authenticationManager); + this.setAuthenticationSuccessHandler(auth2AuthenticationSuccessHandler); + this.setAuthenticationFailureHandler(authenticationFailureHandler); + } + + @Override + public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) + throws AuthenticationException, IOException, ServletException { + Map params = request.getParameterMap(); + String registrationId = new AntPathMatcher().extractPathWithinPattern(OAUTH_LOGIN_URI, request.getRequestURI()); + UserDetailResponse userDetailResponse = openAuthAppService.oauthCallback(registrationId, params); + UserDetails details = databasirUserDetailService.loadUserByUsername(userDetailResponse.getUsername()); + DatabasirOAuth2Authentication authentication = new DatabasirOAuth2Authentication(details); + if (!userDetailResponse.getEnabled()) { + throw new DisabledException("账号已禁用"); + } + authentication.setAuthenticated(true); + if (log.isDebugEnabled()) { + log.debug("login {} success", registrationId); + } + return authentication; + } + +} diff --git a/api/src/main/java/com/databasir/api/config/oauth2/OAuth2AuthenticationSuccessHandler.java b/api/src/main/java/com/databasir/api/config/oauth2/OAuth2AuthenticationSuccessHandler.java new file mode 100644 index 0000000..0173db3 --- /dev/null +++ b/api/src/main/java/com/databasir/api/config/oauth2/OAuth2AuthenticationSuccessHandler.java @@ -0,0 +1,42 @@ +package com.databasir.api.config.oauth2; + +import com.databasir.api.config.security.DatabasirUserDetails; +import com.databasir.common.JsonData; +import com.databasir.core.domain.login.data.LoginKeyResponse; +import com.databasir.core.domain.login.data.UserLoginResponse; +import com.databasir.core.domain.login.service.LoginService; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.RequiredArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.security.authentication.CredentialsExpiredException; +import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.AuthenticationSuccessHandler; +import org.springframework.stereotype.Component; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +@Component +@RequiredArgsConstructor +public class OAuth2AuthenticationSuccessHandler implements AuthenticationSuccessHandler { + + private final LoginService loginService; + + private final ObjectMapper objectMapper; + + @Override + public void onAuthenticationSuccess(HttpServletRequest request, + HttpServletResponse response, + Authentication authentication) throws IOException, ServletException { + DatabasirUserDetails details = (DatabasirUserDetails) authentication.getPrincipal(); + LoginKeyResponse loginKey = loginService.generate(details.getUserPojo().getId()); + UserLoginResponse data = loginService.getUserLoginData(details.getUserPojo().getId()) + .orElseThrow(() -> new CredentialsExpiredException("请重新登陆")); + response.setCharacterEncoding(StandardCharsets.UTF_8.name()); + response.setContentType(MediaType.APPLICATION_JSON_VALUE); + objectMapper.writeValue(response.getWriter(), JsonData.ok(data)); + } +} diff --git a/api/src/main/java/com/databasir/api/config/security/DatabasirAuthenticationFailureHandler.java b/api/src/main/java/com/databasir/api/config/security/DatabasirAuthenticationFailureHandler.java index a4fdefb..5c291eb 100644 --- a/api/src/main/java/com/databasir/api/config/security/DatabasirAuthenticationFailureHandler.java +++ b/api/src/main/java/com/databasir/api/config/security/DatabasirAuthenticationFailureHandler.java @@ -1,5 +1,6 @@ package com.databasir.api.config.security; +import com.databasir.core.domain.app.exception.DatabasirAuthenticationException; import com.databasir.common.JsonData; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; @@ -39,6 +40,12 @@ public class DatabasirAuthenticationFailureHandler implements AuthenticationFail String jsonString = objectMapper.writeValueAsString(data); response.setStatus(HttpStatus.OK.value()); response.getOutputStream().write(jsonString.getBytes(StandardCharsets.UTF_8)); + } else if (exception instanceof DatabasirAuthenticationException) { + DatabasirAuthenticationException bizException = (DatabasirAuthenticationException) exception; + JsonData data = JsonData.error("-1", bizException.getMessage()); + String jsonString = objectMapper.writeValueAsString(data); + response.setStatus(HttpStatus.OK.value()); + response.getOutputStream().write(jsonString.getBytes(StandardCharsets.UTF_8)); } else { JsonData data = JsonData.error("-1", "未登录或未授权用户"); String jsonString = objectMapper.writeValueAsString(data); diff --git a/api/src/main/java/com/databasir/api/config/security/DatabasirAuthenticationSuccessHandler.java b/api/src/main/java/com/databasir/api/config/security/DatabasirAuthenticationSuccessHandler.java index 884601f..b9c3ec0 100644 --- a/api/src/main/java/com/databasir/api/config/security/DatabasirAuthenticationSuccessHandler.java +++ b/api/src/main/java/com/databasir/api/config/security/DatabasirAuthenticationSuccessHandler.java @@ -2,11 +2,12 @@ package com.databasir.api.config.security; import com.databasir.common.JsonData; import com.databasir.core.domain.login.data.LoginKeyResponse; +import com.databasir.core.domain.login.data.UserLoginResponse; import com.databasir.core.domain.login.service.LoginService; -import com.databasir.core.domain.user.data.UserLoginResponse; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; import org.springframework.http.MediaType; +import org.springframework.security.authentication.CredentialsExpiredException; import org.springframework.security.core.Authentication; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.stereotype.Component; @@ -16,9 +17,6 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.time.ZoneId; -import java.util.List; -import java.util.stream.Collectors; @Component @RequiredArgsConstructor @@ -35,28 +33,10 @@ public class DatabasirAuthenticationSuccessHandler implements AuthenticationSucc DatabasirUserDetails user = (DatabasirUserDetails) authentication.getPrincipal(); response.setCharacterEncoding(StandardCharsets.UTF_8.name()); response.setContentType(MediaType.APPLICATION_JSON_VALUE); - UserLoginResponse data = new UserLoginResponse(); - data.setId(user.getUserPojo().getId()); - data.setNickname(user.getUserPojo().getNickname()); - data.setEmail(user.getUserPojo().getEmail()); - data.setUsername(user.getUserPojo().getUsername()); LoginKeyResponse loginKey = loginService.generate(user.getUserPojo().getId()); - data.setAccessToken(loginKey.getAccessToken()); - long expireAt = loginKey.getAccessTokenExpireAt().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(); - data.setAccessTokenExpireAt(expireAt); - data.setRefreshToken(loginKey.getRefreshToken()); - - List roles = user.getRoles() - .stream() - .map(ur -> { - UserLoginResponse.RoleResponse roleResponse = new UserLoginResponse.RoleResponse(); - roleResponse.setRole(ur.getRole()); - roleResponse.setGroupId(ur.getGroupId()); - return roleResponse; - }) - .collect(Collectors.toList()); - data.setRoles(roles); + UserLoginResponse data = loginService.getUserLoginData(user.getUserPojo().getId()) + .orElseThrow(() -> new CredentialsExpiredException("请重新登陆")); objectMapper.writeValue(response.getWriter(), JsonData.ok(data)); } } diff --git a/api/src/main/java/com/databasir/api/config/security/DatabasirUserDetailService.java b/api/src/main/java/com/databasir/api/config/security/DatabasirUserDetailService.java index 1780391..6873433 100644 --- a/api/src/main/java/com/databasir/api/config/security/DatabasirUserDetailService.java +++ b/api/src/main/java/com/databasir/api/config/security/DatabasirUserDetailService.java @@ -1,6 +1,5 @@ package com.databasir.api.config.security; -import com.databasir.dao.impl.LoginDao; import com.databasir.dao.impl.UserDao; import com.databasir.dao.impl.UserRoleDao; import com.databasir.dao.tables.pojos.UserPojo; @@ -22,8 +21,6 @@ public class DatabasirUserDetailService implements UserDetailsService { private final UserRoleDao userRoleDao; - private final LoginDao loginDao; - @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { UserPojo user = userDao.selectByEmailOrUsername(username) diff --git a/api/src/main/resources/application-local.properties b/api/src/main/resources/application-local.properties index b3da7a4..60c4656 100644 --- a/api/src/main/resources/application-local.properties +++ b/api/src/main/resources/application-local.properties @@ -8,4 +8,4 @@ spring.jooq.sql-dialect=mysql spring.flyway.enabled=true spring.flyway.baseline-on-migrate=true -spring.flyway.locations=classpath:db/migration \ No newline at end of file +spring.flyway.locations=classpath:db/migration diff --git a/common/src/main/java/com/databasir/common/JsonData.java b/common/src/main/java/com/databasir/common/JsonData.java index 84d11ed..754e132 100644 --- a/common/src/main/java/com/databasir/common/JsonData.java +++ b/common/src/main/java/com/databasir/common/JsonData.java @@ -2,6 +2,8 @@ package com.databasir.common; import lombok.Data; +import java.util.Optional; + @Data public class JsonData { @@ -21,7 +23,7 @@ public class JsonData { private String errMessage; public static JsonData ok() { - return ok(null); + return ok(Optional.empty()); } public static JsonData ok(T data) { @@ -30,6 +32,12 @@ public class JsonData { return jsonData; } + public static JsonData ok(Optional data) { + JsonData jsonData = new JsonData<>(); + jsonData.setData(data.orElse(null)); + return jsonData; + } + public static JsonData error(String errorCode, String errMessage) { JsonData jsonData = new JsonData<>(); jsonData.setErrCode(errorCode); diff --git a/core/build.gradle b/core/build.gradle index b274cc2..58cd16d 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -31,6 +31,9 @@ dependencies { implementation 'org.commonmark:commonmark:0.18.1' implementation 'org.freemarker:freemarker:2.3.31' + implementation 'com.squareup.retrofit2:retrofit:2.9.0' + implementation 'com.squareup.retrofit2:converter-jackson:2.9.0' + // test testImplementation "mysql:mysql-connector-java:${mysqlConnectorVersion}" } diff --git a/core/src/main/java/com/databasir/core/domain/DomainErrors.java b/core/src/main/java/com/databasir/core/domain/DomainErrors.java index 40e6b61..606361f 100644 --- a/core/src/main/java/com/databasir/core/domain/DomainErrors.java +++ b/core/src/main/java/com/databasir/core/domain/DomainErrors.java @@ -10,6 +10,7 @@ import lombok.RequiredArgsConstructor; public enum DomainErrors implements DatabasirErrors { REFRESH_TOKEN_EXPIRED("X_0001", "refresh token expired"), INVALID_REFRESH_TOKEN_OPERATION("X_0002", "invalid refresh token operation"), + NETWORK_ERROR("X_0003", "网络似乎不稳定,请稍后再试"), NOT_SUPPORT_DATABASE_TYPE("A_10000", "不支持的数据库类型, 请检查项目配置"), PROJECT_NOT_FOUND("A_10001", "项目不存在"), @@ -23,7 +24,8 @@ public enum DomainErrors implements DatabasirErrors { CANNOT_UPDATE_SELF_ROLE("A_10009", "无法对自己执行角色变更的操作"), UPDATE_PASSWORD_CONFIRM_FAILED("A_10010", "两次密码输入不一致"), ORIGIN_PASSWORD_NOT_CORRECT("A_10011", "原密码不正确"), - INVALID_CRON_EXPRESSION("A_10012", "不合法的 cron 表达式"); + INVALID_CRON_EXPRESSION("A_10012", "不合法的 cron 表达式"), + REGISTRATION_ID_DUPLICATE("A_10013", "应用注册 ID 不能重复"); private final String errCode; diff --git a/core/src/main/java/com/databasir/core/domain/app/OpenAuthAppService.java b/core/src/main/java/com/databasir/core/domain/app/OpenAuthAppService.java new file mode 100644 index 0000000..d25ffcb --- /dev/null +++ b/core/src/main/java/com/databasir/core/domain/app/OpenAuthAppService.java @@ -0,0 +1,111 @@ +package com.databasir.core.domain.app; + +import com.databasir.core.domain.DomainErrors; +import com.databasir.core.domain.app.converter.OAuthAppPojoConverter; +import com.databasir.core.domain.app.converter.OAuthAppResponseConverter; +import com.databasir.core.domain.app.data.*; +import com.databasir.core.domain.app.handler.OpenAuthHandler; +import com.databasir.core.domain.app.handler.OAuthProcessContext; +import com.databasir.core.domain.app.handler.OAuthProcessResult; +import com.databasir.core.domain.user.data.UserCreateRequest; +import com.databasir.core.domain.user.data.UserDetailResponse; +import com.databasir.core.domain.user.service.UserService; +import com.databasir.dao.impl.OauthAppDao; +import com.databasir.dao.tables.pojos.OauthAppPojo; +import lombok.RequiredArgsConstructor; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class OpenAuthAppService { + + private final List openAuthHandlers; + + private final OauthAppDao oauthAppDao; + + private final UserService userService; + + private final OAuthAppResponseConverter oauthAppResponseConverter; + + private final OAuthAppPojoConverter oauthAppPojoConverter; + + public UserDetailResponse oauthCallback(String registrationId, Map params) { + + // match handler + OauthAppPojo app = oauthAppDao.selectByRegistrationId(registrationId); + OpenAuthHandler openAuthHandler = openAuthHandlers.stream() + .filter(handler -> handler.support(app.getAppType())) + .findFirst() + .orElseThrow(() -> new UsernameNotFoundException("暂不支持该类型登陆")); + + // process by handler + OAuthProcessContext context = OAuthProcessContext.builder() + .callbackParameters(params) + .registrationId(registrationId) + .build(); + OAuthProcessResult result = openAuthHandler.process(context); + + // get or create new user + return userService.get(result.getEmail()) + .orElseGet(() -> { + UserCreateRequest user = new UserCreateRequest(); + user.setUsername(result.getUsername()); + user.setNickname(result.getNickname()); + user.setEmail(result.getEmail()); + user.setAvatar(result.getAvatar()); + user.setEnabled(true); + user.setPassword(UUID.randomUUID().toString().substring(0, 6)); + Integer id = userService.create(user); + return userService.get(id); + }); + } + + public List listAll() { + List apps = oauthAppDao.selectAll(); + return apps.stream() + .map(oauthAppResponseConverter::to) + .collect(Collectors.toList()); + } + + public void deleteById(Integer id) { + if (oauthAppDao.existsById(id)) { + oauthAppDao.deleteById(id); + } + } + + public void updateById(OAuthAppUpdateRequest request) { + OauthAppPojo pojo = oauthAppPojoConverter.of(request); + try { + oauthAppDao.updateById(pojo); + } catch (DuplicateKeyException e) { + throw DomainErrors.REGISTRATION_ID_DUPLICATE.exception(); + } + } + + public Integer create(OAuthAppCreateRequest request) { + OauthAppPojo pojo = oauthAppPojoConverter.of(request); + try { + return oauthAppDao.insertAndReturnId(pojo); + } catch (DuplicateKeyException e) { + throw DomainErrors.REGISTRATION_ID_DUPLICATE.exception(); + } + } + + public Page listPage(Pageable page, OAuthAppPageCondition condition) { + return oauthAppDao.selectByPage(page, condition.toCondition()).map(oauthAppPojoConverter::toPageResponse); + } + + public Optional getOne(Integer id) { + return oauthAppDao.selectOptionalById(id).map(oauthAppPojoConverter::toDetailResponse); + } +} diff --git a/core/src/main/java/com/databasir/core/domain/app/converter/OAuthAppPojoConverter.java b/core/src/main/java/com/databasir/core/domain/app/converter/OAuthAppPojoConverter.java new file mode 100644 index 0000000..1d6aed2 --- /dev/null +++ b/core/src/main/java/com/databasir/core/domain/app/converter/OAuthAppPojoConverter.java @@ -0,0 +1,26 @@ +package com.databasir.core.domain.app.converter; + +import com.databasir.core.domain.app.data.OAuthAppCreateRequest; +import com.databasir.core.domain.app.data.OAuthAppDetailResponse; +import com.databasir.core.domain.app.data.OAuthAppPageResponse; +import com.databasir.core.domain.app.data.OAuthAppUpdateRequest; +import com.databasir.dao.tables.pojos.OauthAppPojo; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +@Mapper(componentModel = "spring") +public interface OAuthAppPojoConverter { + + @Mapping(target = "id", ignore = true) + @Mapping(target = "createAt", ignore = true) + @Mapping(target = "updateAt", ignore = true) + OauthAppPojo of(OAuthAppCreateRequest request); + + @Mapping(target = "createAt", ignore = true) + @Mapping(target = "updateAt", ignore = true) + OauthAppPojo of(OAuthAppUpdateRequest request); + + OAuthAppPageResponse toPageResponse(OauthAppPojo pojo); + + OAuthAppDetailResponse toDetailResponse(OauthAppPojo pojo); +} diff --git a/core/src/main/java/com/databasir/core/domain/app/converter/OAuthAppResponseConverter.java b/core/src/main/java/com/databasir/core/domain/app/converter/OAuthAppResponseConverter.java new file mode 100644 index 0000000..18e5f9b --- /dev/null +++ b/core/src/main/java/com/databasir/core/domain/app/converter/OAuthAppResponseConverter.java @@ -0,0 +1,11 @@ +package com.databasir.core.domain.app.converter; + +import com.databasir.core.domain.app.data.OAuthAppResponse; +import com.databasir.dao.tables.pojos.OauthAppPojo; +import org.mapstruct.Mapper; + +@Mapper(componentModel = "spring") +public interface OAuthAppResponseConverter { + + OAuthAppResponse to(OauthAppPojo pojo); +} diff --git a/core/src/main/java/com/databasir/core/domain/app/data/OAuthAppCreateRequest.java b/core/src/main/java/com/databasir/core/domain/app/data/OAuthAppCreateRequest.java new file mode 100644 index 0000000..d898d23 --- /dev/null +++ b/core/src/main/java/com/databasir/core/domain/app/data/OAuthAppCreateRequest.java @@ -0,0 +1,35 @@ +package com.databasir.core.domain.app.data; + +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +@Data +public class OAuthAppCreateRequest { + + @NotNull + private String registrationId; + + @NotBlank + private String appName; + + @NotBlank + private String appType; + + private String appIcon; + + @NotBlank + private String authUrl; + + @NotBlank + private String resourceUrl; + + @NotBlank + private String clientId; + + @NotBlank + private String clientSecret; + + private String scope; +} diff --git a/core/src/main/java/com/databasir/core/domain/app/data/OAuthAppDetailResponse.java b/core/src/main/java/com/databasir/core/domain/app/data/OAuthAppDetailResponse.java new file mode 100644 index 0000000..fc2428a --- /dev/null +++ b/core/src/main/java/com/databasir/core/domain/app/data/OAuthAppDetailResponse.java @@ -0,0 +1,31 @@ +package com.databasir.core.domain.app.data; + +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class OAuthAppDetailResponse { + + private Integer id; + + private String appName; + + private String appIcon; + + private String appType; + + private String registrationId; + + private String clientId; + + private String clientSecret; + + private String authUrl; + + private String resourceUrl; + + private LocalDateTime updateAt; + + private LocalDateTime createAt; +} diff --git a/core/src/main/java/com/databasir/core/domain/app/data/OAuthAppPageCondition.java b/core/src/main/java/com/databasir/core/domain/app/data/OAuthAppPageCondition.java new file mode 100644 index 0000000..94666f0 --- /dev/null +++ b/core/src/main/java/com/databasir/core/domain/app/data/OAuthAppPageCondition.java @@ -0,0 +1,30 @@ +package com.databasir.core.domain.app.data; + +import com.databasir.dao.Tables; +import lombok.Data; +import org.jooq.Condition; +import org.jooq.impl.DSL; + +import java.util.ArrayList; +import java.util.List; + +@Data +public class OAuthAppPageCondition { + + private String appNameContains; + + private String appType; + + public Condition toCondition() { + List conditions = new ArrayList<>(); + if (appNameContains != null && !appNameContains.trim().equals("")) { + conditions.add(Tables.OAUTH_APP.APP_NAME.contains(appNameContains)); + } + if (appType != null) { + conditions.add(Tables.OAUTH_APP.APP_TYPE.eq(appType)); + } + return conditions.stream() + .reduce(Condition::and) + .orElse(DSL.trueCondition()); + } +} diff --git a/core/src/main/java/com/databasir/core/domain/app/data/OAuthAppPageResponse.java b/core/src/main/java/com/databasir/core/domain/app/data/OAuthAppPageResponse.java new file mode 100644 index 0000000..46e27c8 --- /dev/null +++ b/core/src/main/java/com/databasir/core/domain/app/data/OAuthAppPageResponse.java @@ -0,0 +1,30 @@ +package com.databasir.core.domain.app.data; + +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class OAuthAppPageResponse { + + private Integer id; + + private String appName; + + private String appIcon; + + private String appType; + + private String registrationId; + + private String clientId; + + private String authUrl; + + private String resourceUrl; + + private LocalDateTime updateAt; + + private LocalDateTime createAt; + +} diff --git a/core/src/main/java/com/databasir/core/domain/app/data/OAuthAppResponse.java b/core/src/main/java/com/databasir/core/domain/app/data/OAuthAppResponse.java new file mode 100644 index 0000000..c460aae --- /dev/null +++ b/core/src/main/java/com/databasir/core/domain/app/data/OAuthAppResponse.java @@ -0,0 +1,28 @@ +package com.databasir.core.domain.app.data; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class OAuthAppResponse { + + private Integer id; + + private String appName; + + private String appIcon; + + private String appType; + + private String registrationId; + + private LocalDateTime createAt; + +} diff --git a/core/src/main/java/com/databasir/core/domain/app/data/OAuthAppUpdateRequest.java b/core/src/main/java/com/databasir/core/domain/app/data/OAuthAppUpdateRequest.java new file mode 100644 index 0000000..0d633cd --- /dev/null +++ b/core/src/main/java/com/databasir/core/domain/app/data/OAuthAppUpdateRequest.java @@ -0,0 +1,39 @@ +package com.databasir.core.domain.app.data; + +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +@Data +public class OAuthAppUpdateRequest { + + @NotNull + private Integer id; + + @NotBlank + private String registrationId; + + @NotBlank + private String appName; + + @NotBlank + private String appType; + + private String appIcon; + + @NotBlank + private String authUrl; + + @NotBlank + private String resourceUrl; + + @NotBlank + private String clientId; + + @NotBlank + private String clientSecret; + + private String scope; + +} diff --git a/core/src/main/java/com/databasir/core/domain/app/exception/DatabasirAuthenticationException.java b/core/src/main/java/com/databasir/core/domain/app/exception/DatabasirAuthenticationException.java new file mode 100644 index 0000000..1d9986f --- /dev/null +++ b/core/src/main/java/com/databasir/core/domain/app/exception/DatabasirAuthenticationException.java @@ -0,0 +1,19 @@ +package com.databasir.core.domain.app.exception; + +import com.databasir.common.DatabasirException; +import org.springframework.security.core.AuthenticationException; + +public class DatabasirAuthenticationException extends AuthenticationException { + + public DatabasirAuthenticationException(DatabasirException databasirException) { + super(databasirException.getErrMessage(), databasirException); + } + + public DatabasirAuthenticationException(String msg) { + super(msg); + } + + public DatabasirAuthenticationException(String msg, Throwable cause) { + super(msg, cause); + } +} diff --git a/core/src/main/java/com/databasir/core/domain/app/handler/GithubOpenAuthHandler.java b/core/src/main/java/com/databasir/core/domain/app/handler/GithubOpenAuthHandler.java new file mode 100644 index 0000000..79d58ec --- /dev/null +++ b/core/src/main/java/com/databasir/core/domain/app/handler/GithubOpenAuthHandler.java @@ -0,0 +1,83 @@ +package com.databasir.core.domain.app.handler; + +import com.databasir.core.domain.DomainErrors; +import com.databasir.core.domain.app.exception.DatabasirAuthenticationException; +import com.databasir.core.infrastructure.remote.github.GithubRemoteService; +import com.databasir.dao.enums.OAuthAppType; +import com.databasir.dao.impl.OauthAppDao; +import com.databasir.dao.tables.pojos.OauthAppPojo; +import com.fasterxml.jackson.databind.JsonNode; +import lombok.RequiredArgsConstructor; +import org.jooq.tools.StringUtils; +import org.springframework.security.authentication.CredentialsExpiredException; +import org.springframework.stereotype.Component; +import org.springframework.web.util.UriComponentsBuilder; + +import java.util.Map; + +@Component +@RequiredArgsConstructor +public class GithubOpenAuthHandler implements OpenAuthHandler { + + private final GithubRemoteService githubRemoteService; + + private final OauthAppDao oauthAppDao; + + @Override + public boolean support(String oauthAppType) { + return OAuthAppType.GITHUB.isSame(oauthAppType); + } + + @Override + public String authorization(String registrationId) { + OauthAppPojo app = oauthAppDao.selectByRegistrationId(registrationId); + String authUrl = app.getAuthUrl(); + String clientId = app.getClientId(); + String authorizeUrl = authUrl + "/login/oauth/authorize"; + String url = UriComponentsBuilder.fromUriString(authorizeUrl) + .queryParam("client_id", clientId) + .queryParam("scope", "read:user user:email") + .encode() + .build() + .toUriString(); + return url; + } + + @Override + public OAuthProcessResult process(OAuthProcessContext context) { + OauthAppPojo authApp = oauthAppDao.selectByRegistrationId(context.getRegistrationId()); + String clientId = authApp.getClientId(); + String clientSecret = authApp.getClientSecret(); + String baseUrl = authApp.getResourceUrl(); + + Map params = context.getCallbackParameters(); + String code = params.get("code")[0]; + JsonNode tokenNode = githubRemoteService.getToken(baseUrl, clientId, clientSecret, code) + .get("access_token"); + if (tokenNode == null) { + throw new DatabasirAuthenticationException(DomainErrors.NETWORK_ERROR.exception()); + } + String accessToken = tokenNode.asText(); + if (StringUtils.isBlank(accessToken)) { + throw new CredentialsExpiredException("授权失效,请重新登陆"); + } + String email = null; + for (JsonNode node : githubRemoteService.getEmail(baseUrl, accessToken)) { + if (node.get("primary").asBoolean()) { + email = node.get("email").asText(); + } + } + if (StringUtils.isBlank(email)) { + throw new CredentialsExpiredException("授权失效,请重新登陆"); + } + JsonNode profile = githubRemoteService.getProfile(baseUrl, accessToken); + String nickname = profile.get("name").asText(); + String avatar = profile.get("avatar_url").asText(); + OAuthProcessResult result = new OAuthProcessResult(); + result.setEmail(email); + result.setNickname(nickname); + result.setUsername(email); + result.setAvatar(avatar); + return result; + } +} diff --git a/core/src/main/java/com/databasir/core/domain/app/handler/OAuthProcessContext.java b/core/src/main/java/com/databasir/core/domain/app/handler/OAuthProcessContext.java new file mode 100644 index 0000000..9f57768 --- /dev/null +++ b/core/src/main/java/com/databasir/core/domain/app/handler/OAuthProcessContext.java @@ -0,0 +1,22 @@ +package com.databasir.core.domain.app.handler; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.HashMap; +import java.util.Map; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class OAuthProcessContext { + + private String registrationId; + + @Builder.Default + private Map callbackParameters = new HashMap<>(); + +} diff --git a/core/src/main/java/com/databasir/core/domain/app/handler/OAuthProcessResult.java b/core/src/main/java/com/databasir/core/domain/app/handler/OAuthProcessResult.java new file mode 100644 index 0000000..a0a2eb6 --- /dev/null +++ b/core/src/main/java/com/databasir/core/domain/app/handler/OAuthProcessResult.java @@ -0,0 +1,16 @@ +package com.databasir.core.domain.app.handler; + +import lombok.Data; + +@Data +public class OAuthProcessResult { + + private String email; + + private String username; + + private String nickname; + + private String avatar; + +} diff --git a/core/src/main/java/com/databasir/core/domain/app/handler/OpenAuthHandler.java b/core/src/main/java/com/databasir/core/domain/app/handler/OpenAuthHandler.java new file mode 100644 index 0000000..a99f401 --- /dev/null +++ b/core/src/main/java/com/databasir/core/domain/app/handler/OpenAuthHandler.java @@ -0,0 +1,10 @@ +package com.databasir.core.domain.app.handler; + +public interface OpenAuthHandler { + + boolean support(String oauthAppType); + + String authorization(String registrationId); + + OAuthProcessResult process(OAuthProcessContext context); +} diff --git a/core/src/main/java/com/databasir/core/domain/user/data/UserLoginResponse.java b/core/src/main/java/com/databasir/core/domain/login/data/UserLoginResponse.java similarity index 86% rename from core/src/main/java/com/databasir/core/domain/user/data/UserLoginResponse.java rename to core/src/main/java/com/databasir/core/domain/login/data/UserLoginResponse.java index a5176a8..33c9556 100644 --- a/core/src/main/java/com/databasir/core/domain/user/data/UserLoginResponse.java +++ b/core/src/main/java/com/databasir/core/domain/login/data/UserLoginResponse.java @@ -1,4 +1,4 @@ -package com.databasir.core.domain.user.data; +package com.databasir.core.domain.login.data; import lombok.Data; @@ -15,6 +15,8 @@ public class UserLoginResponse { private String username; + private String avatar; + private String accessToken; private long accessTokenExpireAt; diff --git a/core/src/main/java/com/databasir/core/domain/login/service/LoginService.java b/core/src/main/java/com/databasir/core/domain/login/service/LoginService.java index f275094..dc7a7ab 100644 --- a/core/src/main/java/com/databasir/core/domain/login/service/LoginService.java +++ b/core/src/main/java/com/databasir/core/domain/login/service/LoginService.java @@ -4,11 +4,14 @@ import com.databasir.core.domain.DomainErrors; import com.databasir.core.domain.login.data.AccessTokenRefreshRequest; import com.databasir.core.domain.login.data.AccessTokenRefreshResponse; import com.databasir.core.domain.login.data.LoginKeyResponse; +import com.databasir.core.domain.login.data.UserLoginResponse; import com.databasir.core.infrastructure.jwt.JwtTokens; import com.databasir.dao.impl.LoginDao; import com.databasir.dao.impl.UserDao; +import com.databasir.dao.impl.UserRoleDao; import com.databasir.dao.tables.pojos.LoginPojo; import com.databasir.dao.tables.pojos.UserPojo; +import com.databasir.dao.tables.pojos.UserRolePojo; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -16,8 +19,11 @@ import org.springframework.stereotype.Service; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; +import java.util.Collections; +import java.util.List; import java.util.Optional; import java.util.UUID; +import java.util.stream.Collectors; @Service @RequiredArgsConstructor @@ -28,6 +34,8 @@ public class LoginService { private final UserDao userDao; + private final UserRoleDao userRoleDao; + private final JwtTokens jwtTokens; public AccessTokenRefreshResponse refreshAccessTokens(AccessTokenRefreshRequest request) { @@ -91,4 +99,36 @@ public class LoginService { .refreshTokenExpireAt(refreshTokenExpireAt) .build(); } + + public Optional getUserLoginData(Integer userId) { + return loginDao.selectByUserId(userId) + .map(login -> { + UserPojo user = userDao.selectById(login.getUserId()); + UserLoginResponse data = new UserLoginResponse(); + data.setId(user.getId()); + data.setNickname(user.getNickname()); + data.setEmail(user.getEmail()); + data.setUsername(user.getUsername()); + data.setAccessToken(login.getAccessToken()); + data.setAvatar(user.getAvatar()); + long expireAt = login.getAccessTokenExpireAt() + .atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(); + data.setAccessTokenExpireAt(expireAt); + data.setRefreshToken(login.getRefreshToken()); + List rolePojoList = + userRoleDao.selectByUserIds(Collections.singletonList(user.getId())); + List roles = rolePojoList + .stream() + .map(ur -> { + UserLoginResponse.RoleResponse roleResponse = new UserLoginResponse.RoleResponse(); + roleResponse.setRole(ur.getRole()); + roleResponse.setGroupId(ur.getGroupId()); + return roleResponse; + }) + .collect(Collectors.toList()); + data.setRoles(roles); + return data; + }); + } + } diff --git a/core/src/main/java/com/databasir/core/domain/user/data/UserLoginRequest.java b/core/src/main/java/com/databasir/core/domain/user/data/UserLoginRequest.java deleted file mode 100644 index 5b5d8a0..0000000 --- a/core/src/main/java/com/databasir/core/domain/user/data/UserLoginRequest.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.databasir.core.domain.user.data; - -import lombok.Data; - -import javax.validation.constraints.NotBlank; - -@Data -public class UserLoginRequest { - - @NotBlank - private String username; - - @NotBlank - private String password; - -} diff --git a/core/src/main/java/com/databasir/core/domain/user/service/UserService.java b/core/src/main/java/com/databasir/core/domain/user/service/UserService.java index 5cbff1e..dcf680b 100644 --- a/core/src/main/java/com/databasir/core/domain/user/service/UserService.java +++ b/core/src/main/java/com/databasir/core/domain/user/service/UserService.java @@ -65,14 +65,14 @@ public class UserService { } @Transactional - public void create(UserCreateRequest userCreateRequest) { + public Integer create(UserCreateRequest userCreateRequest) { userDao.selectByEmailOrUsername(userCreateRequest.getUsername()).ifPresent(data -> { throw DomainErrors.USERNAME_OR_EMAIL_DUPLICATE.exception(); }); String hashedPassword = bCryptPasswordEncoder.encode(userCreateRequest.getPassword()); UserPojo pojo = userPojoConverter.of(userCreateRequest, hashedPassword); try { - userDao.insertAndReturnId(pojo); + return userDao.insertAndReturnId(pojo); } catch (DuplicateKeyException e) { throw DomainErrors.USERNAME_OR_EMAIL_DUPLICATE.exception(); } @@ -91,6 +91,21 @@ public class UserService { return userResponseConverter.detailResponse(pojo, roles, groupNameMapById); } + public Optional get(String email) { + return userDao.selectByEmail(email) + .map(user -> { + List roles = userRoleDao.selectByUserIds(Collections.singletonList(user.getId())); + List groupIds = roles.stream() + .map(UserRolePojo::getGroupId) + .filter(Objects::nonNull) + .collect(toList()); + Map groupNameMapById = groupDao.selectInIds(groupIds) + .stream() + .collect(toMap(GroupPojo::getId, GroupPojo::getName)); + return userResponseConverter.detailResponse(user, roles, groupNameMapById); + }); + } + @Transactional public String renewPassword(Integer userId) { UserPojo userPojo = userDao.selectById(userId); diff --git a/core/src/main/java/com/databasir/core/infrastructure/remote/ClientConfig.java b/core/src/main/java/com/databasir/core/infrastructure/remote/ClientConfig.java new file mode 100644 index 0000000..356cec3 --- /dev/null +++ b/core/src/main/java/com/databasir/core/infrastructure/remote/ClientConfig.java @@ -0,0 +1,34 @@ +package com.databasir.core.infrastructure.remote; + +import com.databasir.core.infrastructure.remote.github.GithubApiClient; +import com.databasir.core.infrastructure.remote.github.GithubOauthClient; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import retrofit2.Retrofit; +import retrofit2.converter.jackson.JacksonConverterFactory; + +@Configuration +@RequiredArgsConstructor +@Slf4j +public class ClientConfig { + + @Bean + public GithubApiClient githubApiClient() { + Retrofit retrofit = new Retrofit.Builder() + .baseUrl("https://api.github.com") + .addConverterFactory(JacksonConverterFactory.create()) + .build(); + return retrofit.create(GithubApiClient.class); + } + + @Bean + public GithubOauthClient githubOauthClient() { + Retrofit retrofit = new Retrofit.Builder() + .baseUrl("https://github.com") + .addConverterFactory(JacksonConverterFactory.create()) + .build(); + return retrofit.create(GithubOauthClient.class); + } +} diff --git a/core/src/main/java/com/databasir/core/infrastructure/remote/github/GithubApiClient.java b/core/src/main/java/com/databasir/core/infrastructure/remote/github/GithubApiClient.java new file mode 100644 index 0000000..b2a5f8c --- /dev/null +++ b/core/src/main/java/com/databasir/core/infrastructure/remote/github/GithubApiClient.java @@ -0,0 +1,23 @@ +package com.databasir.core.infrastructure.remote.github; + +import com.fasterxml.jackson.databind.JsonNode; +import retrofit2.Call; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.Headers; +import retrofit2.http.Url; + +public interface GithubApiClient { + + @GET + @Headers(value = { + "Accept: application/json" + }) + Call getEmail(@Url String url, @Header("Authorization") String token); + + @GET + @Headers(value = { + "Accept: application/json" + }) + Call getProfile(@Url String url, @Header("Authorization") String token); +} diff --git a/core/src/main/java/com/databasir/core/infrastructure/remote/github/GithubOauthClient.java b/core/src/main/java/com/databasir/core/infrastructure/remote/github/GithubOauthClient.java new file mode 100644 index 0000000..b22dee9 --- /dev/null +++ b/core/src/main/java/com/databasir/core/infrastructure/remote/github/GithubOauthClient.java @@ -0,0 +1,20 @@ +package com.databasir.core.infrastructure.remote.github; + +import com.fasterxml.jackson.databind.JsonNode; +import retrofit2.Call; +import retrofit2.http.Headers; +import retrofit2.http.POST; +import retrofit2.http.QueryMap; +import retrofit2.http.Url; + +import java.util.Map; + +public interface GithubOauthClient { + + @Headers(value = { + "Accept: application/json" + }) + @POST + Call getAccessToken(@Url String url, @QueryMap Map request); + +} diff --git a/core/src/main/java/com/databasir/core/infrastructure/remote/github/GithubRemoteService.java b/core/src/main/java/com/databasir/core/infrastructure/remote/github/GithubRemoteService.java new file mode 100644 index 0000000..df77b59 --- /dev/null +++ b/core/src/main/java/com/databasir/core/infrastructure/remote/github/GithubRemoteService.java @@ -0,0 +1,74 @@ +package com.databasir.core.infrastructure.remote.github; + +import com.databasir.common.SystemException; +import com.fasterxml.jackson.databind.JsonNode; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import retrofit2.Call; +import retrofit2.Response; + +import java.io.IOException; + +@Service +@RequiredArgsConstructor +@Slf4j +public class GithubRemoteService { + + private static final String TOKEN_PREFIX = "token "; + + private final GithubApiClient githubApiClient; + + private final GithubOauthClient githubOauthClient; + + public JsonNode getToken(String baseUrl, + String clientId, + String clientSecret, + String code) { + TokenRequest request = TokenRequest.builder() + .client_id(clientId) + .client_secret(clientSecret) + .code(code) + .build(); + String path = "/login/oauth/access_token"; + String url = baseUrl + path; + return execute(githubOauthClient.getAccessToken(url, request.toMap())); + } + + public JsonNode getEmail(String baseUrl, String token) { + String path; + if (baseUrl.contains("api.github.com")) { + path = "/user/emails"; + } else { + path = "/api/v3/user/emails"; + } + String url = baseUrl + path; + return execute(githubApiClient.getEmail(url, TOKEN_PREFIX + token)); + } + + public JsonNode getProfile(String baseUrl, String token) { + String path; + if (baseUrl.contains("api.github.com")) { + path = "/user"; + } else { + path = "/api/v3/user"; + } + String url = baseUrl + path; + return execute(githubApiClient.getProfile(url, TOKEN_PREFIX + token)); + } + + private T execute(Call call) { + try { + Response response = call.execute(); + if (!response.isSuccessful()) { + log.error("request error: " + call.request() + ", response = " + response); + throw new SystemException("Call Remote Error"); + } else { + T body = response.body(); + return body; + } + } catch (IOException e) { + throw new SystemException("System Error", e); + } + } +} diff --git a/core/src/main/java/com/databasir/core/infrastructure/remote/github/TokenRequest.java b/core/src/main/java/com/databasir/core/infrastructure/remote/github/TokenRequest.java new file mode 100644 index 0000000..4392473 --- /dev/null +++ b/core/src/main/java/com/databasir/core/infrastructure/remote/github/TokenRequest.java @@ -0,0 +1,32 @@ +package com.databasir.core.infrastructure.remote.github; + +import lombok.Builder; +import lombok.Data; + +import java.util.HashMap; +import java.util.Map; + +@Data +@SuppressWarnings("checkstyle:all") +@Builder +public class TokenRequest { + + private String client_id; + + private String client_secret; + + private String code; + + private String redirect_uri; + + public Map toMap() { + HashMap map = new HashMap<>(); + map.put("client_id", client_id); + map.put("client_secret", client_secret); + map.put("code", code); + if (redirect_uri != null) { + map.put("redirect_uri", redirect_uri); + } + return map; + } +} diff --git a/dao/generated-src/jooq/main/java/com/databasir/dao/Databasir.java b/dao/generated-src/jooq/main/java/com/databasir/dao/Databasir.java index 6e86c78..9326c63 100644 --- a/dao/generated-src/jooq/main/java/com/databasir/dao/Databasir.java +++ b/dao/generated-src/jooq/main/java/com/databasir/dao/Databasir.java @@ -11,6 +11,7 @@ import com.databasir.dao.tables.DatabaseDocumentHistory; import com.databasir.dao.tables.DocumentRemark; import com.databasir.dao.tables.Group; import com.databasir.dao.tables.Login; +import com.databasir.dao.tables.OauthApp; import com.databasir.dao.tables.OperationLog; import com.databasir.dao.tables.Project; import com.databasir.dao.tables.ProjectSyncRule; @@ -80,6 +81,11 @@ public class Databasir extends SchemaImpl { */ public final Login LOGIN = Login.LOGIN; + /** + * oauth app info + */ + public final OauthApp OAUTH_APP = OauthApp.OAUTH_APP; + /** * The table databasir.operation_log. */ @@ -163,6 +169,7 @@ public class Databasir extends SchemaImpl { DocumentRemark.DOCUMENT_REMARK, Group.GROUP, Login.LOGIN, + OauthApp.OAUTH_APP, OperationLog.OPERATION_LOG, Project.PROJECT, ProjectSyncRule.PROJECT_SYNC_RULE, diff --git a/dao/generated-src/jooq/main/java/com/databasir/dao/Indexes.java b/dao/generated-src/jooq/main/java/com/databasir/dao/Indexes.java index 42f58ef..9c24e68 100644 --- a/dao/generated-src/jooq/main/java/com/databasir/dao/Indexes.java +++ b/dao/generated-src/jooq/main/java/com/databasir/dao/Indexes.java @@ -11,7 +11,6 @@ import com.databasir.dao.tables.TableColumnDocument; import com.databasir.dao.tables.TableDocument; import com.databasir.dao.tables.TableIndexDocument; import com.databasir.dao.tables.TableTriggerDocument; -import com.databasir.dao.tables.UserFavoriteProject; import org.jooq.Index; import org.jooq.OrderField; @@ -39,5 +38,4 @@ public class Indexes { public static final Index TABLE_COLUMN_DOCUMENT_IDX_TABLE_DOCUMENT_ID = Internal.createIndex(DSL.name("idx_table_document_id"), TableColumnDocument.TABLE_COLUMN_DOCUMENT, new OrderField[] { TableColumnDocument.TABLE_COLUMN_DOCUMENT.TABLE_DOCUMENT_ID }, false); public static final Index TABLE_INDEX_DOCUMENT_IDX_TABLE_DOCUMENT_ID = Internal.createIndex(DSL.name("idx_table_document_id"), TableIndexDocument.TABLE_INDEX_DOCUMENT, new OrderField[] { TableIndexDocument.TABLE_INDEX_DOCUMENT.TABLE_DOCUMENT_ID }, false); public static final Index TABLE_TRIGGER_DOCUMENT_IDX_TABLE_DOCUMENT_ID = Internal.createIndex(DSL.name("idx_table_document_id"), TableTriggerDocument.TABLE_TRIGGER_DOCUMENT, new OrderField[] { TableTriggerDocument.TABLE_TRIGGER_DOCUMENT.TABLE_DOCUMENT_ID }, false); - public static final Index USER_FAVORITE_PROJECT_IDX_USER_ID = Internal.createIndex(DSL.name("idx_user_id"), UserFavoriteProject.USER_FAVORITE_PROJECT, new OrderField[] { UserFavoriteProject.USER_FAVORITE_PROJECT.USER_ID }, false); } diff --git a/dao/generated-src/jooq/main/java/com/databasir/dao/Keys.java b/dao/generated-src/jooq/main/java/com/databasir/dao/Keys.java index 4fdfa66..90a1b17 100644 --- a/dao/generated-src/jooq/main/java/com/databasir/dao/Keys.java +++ b/dao/generated-src/jooq/main/java/com/databasir/dao/Keys.java @@ -11,6 +11,7 @@ import com.databasir.dao.tables.DatabaseDocumentHistory; import com.databasir.dao.tables.DocumentRemark; import com.databasir.dao.tables.Group; import com.databasir.dao.tables.Login; +import com.databasir.dao.tables.OauthApp; import com.databasir.dao.tables.OperationLog; import com.databasir.dao.tables.Project; import com.databasir.dao.tables.ProjectSyncRule; @@ -30,6 +31,7 @@ import com.databasir.dao.tables.records.DatabaseDocumentRecord; import com.databasir.dao.tables.records.DocumentRemarkRecord; import com.databasir.dao.tables.records.GroupRecord; import com.databasir.dao.tables.records.LoginRecord; +import com.databasir.dao.tables.records.OauthAppRecord; import com.databasir.dao.tables.records.OperationLogRecord; import com.databasir.dao.tables.records.ProjectRecord; import com.databasir.dao.tables.records.ProjectSyncRuleRecord; @@ -71,6 +73,8 @@ public class Keys { public static final UniqueKey KEY_GROUP_PRIMARY = Internal.createUniqueKey(Group.GROUP, DSL.name("KEY_group_PRIMARY"), new TableField[] { Group.GROUP.ID }, true); public static final UniqueKey KEY_LOGIN_PRIMARY = Internal.createUniqueKey(Login.LOGIN, DSL.name("KEY_login_PRIMARY"), new TableField[] { Login.LOGIN.ID }, true); public static final UniqueKey KEY_LOGIN_UK_USER_ID = Internal.createUniqueKey(Login.LOGIN, DSL.name("KEY_login_uk_user_id"), new TableField[] { Login.LOGIN.USER_ID }, true); + public static final UniqueKey KEY_OAUTH_APP_PRIMARY = Internal.createUniqueKey(OauthApp.OAUTH_APP, DSL.name("KEY_oauth_app_PRIMARY"), new TableField[] { OauthApp.OAUTH_APP.ID }, true); + public static final UniqueKey KEY_OAUTH_APP_UK_REGISTRATION_ID = Internal.createUniqueKey(OauthApp.OAUTH_APP, DSL.name("KEY_oauth_app_uk_registration_id"), new TableField[] { OauthApp.OAUTH_APP.REGISTRATION_ID }, true); public static final UniqueKey KEY_OPERATION_LOG_PRIMARY = Internal.createUniqueKey(OperationLog.OPERATION_LOG, DSL.name("KEY_operation_log_PRIMARY"), new TableField[] { OperationLog.OPERATION_LOG.ID }, true); public static final UniqueKey KEY_PROJECT_PRIMARY = Internal.createUniqueKey(Project.PROJECT, DSL.name("KEY_project_PRIMARY"), new TableField[] { Project.PROJECT.ID }, true); public static final UniqueKey KEY_PROJECT_UK_GROUP_ID_NAME = Internal.createUniqueKey(Project.PROJECT, DSL.name("KEY_project_uk_group_id_name"), new TableField[] { Project.PROJECT.GROUP_ID, Project.PROJECT.NAME }, true); @@ -86,6 +90,7 @@ public class Keys { public static final UniqueKey KEY_USER_UK_EMAIL = Internal.createUniqueKey(User.USER, DSL.name("KEY_user_uk_email"), new TableField[] { User.USER.EMAIL }, true); public static final UniqueKey KEY_USER_UK_USERNAME = Internal.createUniqueKey(User.USER, DSL.name("KEY_user_uk_username"), new TableField[] { User.USER.USERNAME }, true); public static final UniqueKey KEY_USER_FAVORITE_PROJECT_PRIMARY = Internal.createUniqueKey(UserFavoriteProject.USER_FAVORITE_PROJECT, DSL.name("KEY_user_favorite_project_PRIMARY"), new TableField[] { UserFavoriteProject.USER_FAVORITE_PROJECT.ID }, true); + public static final UniqueKey KEY_USER_FAVORITE_PROJECT_UK_USER_ID_PROJECT_ID = Internal.createUniqueKey(UserFavoriteProject.USER_FAVORITE_PROJECT, DSL.name("KEY_user_favorite_project_uk_user_id_project_id"), new TableField[] { UserFavoriteProject.USER_FAVORITE_PROJECT.USER_ID, UserFavoriteProject.USER_FAVORITE_PROJECT.PROJECT_ID }, true); public static final UniqueKey KEY_USER_ROLE_PRIMARY = Internal.createUniqueKey(UserRole.USER_ROLE, DSL.name("KEY_user_role_PRIMARY"), new TableField[] { UserRole.USER_ROLE.ID }, true); public static final UniqueKey KEY_USER_ROLE_UK_USER_ID_GROUP_ID_ROLE = Internal.createUniqueKey(UserRole.USER_ROLE, DSL.name("KEY_user_role_uk_user_id_group_id_role"), new TableField[] { UserRole.USER_ROLE.USER_ID, UserRole.USER_ROLE.GROUP_ID, UserRole.USER_ROLE.ROLE }, true); } diff --git a/dao/generated-src/jooq/main/java/com/databasir/dao/Tables.java b/dao/generated-src/jooq/main/java/com/databasir/dao/Tables.java index 9feeba6..0873fe8 100644 --- a/dao/generated-src/jooq/main/java/com/databasir/dao/Tables.java +++ b/dao/generated-src/jooq/main/java/com/databasir/dao/Tables.java @@ -11,6 +11,7 @@ import com.databasir.dao.tables.DatabaseDocumentHistory; import com.databasir.dao.tables.DocumentRemark; import com.databasir.dao.tables.Group; import com.databasir.dao.tables.Login; +import com.databasir.dao.tables.OauthApp; import com.databasir.dao.tables.OperationLog; import com.databasir.dao.tables.Project; import com.databasir.dao.tables.ProjectSyncRule; @@ -66,6 +67,11 @@ public class Tables { */ public static final Login LOGIN = Login.LOGIN; + /** + * oauth app info + */ + public static final OauthApp OAUTH_APP = OauthApp.OAUTH_APP; + /** * The table databasir.operation_log. */ diff --git a/dao/generated-src/jooq/main/java/com/databasir/dao/tables/OauthApp.java b/dao/generated-src/jooq/main/java/com/databasir/dao/tables/OauthApp.java new file mode 100644 index 0000000..ea3cee8 --- /dev/null +++ b/dao/generated-src/jooq/main/java/com/databasir/dao/tables/OauthApp.java @@ -0,0 +1,199 @@ +/* + * This file is generated by jOOQ. + */ +package com.databasir.dao.tables; + + +import com.databasir.dao.Databasir; +import com.databasir.dao.Keys; +import com.databasir.dao.tables.records.OauthAppRecord; + +import java.time.LocalDateTime; +import java.util.Arrays; +import java.util.List; + +import org.jooq.Field; +import org.jooq.ForeignKey; +import org.jooq.Identity; +import org.jooq.Name; +import org.jooq.Record; +import org.jooq.Row12; +import org.jooq.Schema; +import org.jooq.Table; +import org.jooq.TableField; +import org.jooq.TableOptions; +import org.jooq.UniqueKey; +import org.jooq.impl.DSL; +import org.jooq.impl.SQLDataType; +import org.jooq.impl.TableImpl; + + +/** + * oauth app info + */ +@SuppressWarnings({ "all", "unchecked", "rawtypes" }) +public class OauthApp extends TableImpl { + + private static final long serialVersionUID = 1L; + + /** + * The reference instance of databasir.oauth_app + */ + public static final OauthApp OAUTH_APP = new OauthApp(); + + /** + * The class holding records for this type + */ + @Override + public Class getRecordType() { + return OauthAppRecord.class; + } + + /** + * The column databasir.oauth_app.id. + */ + public final TableField ID = createField(DSL.name("id"), SQLDataType.INTEGER.nullable(false).identity(true), this, ""); + + /** + * The column databasir.oauth_app.registration_id. + */ + public final TableField REGISTRATION_ID = createField(DSL.name("registration_id"), SQLDataType.VARCHAR(100).nullable(false), this, ""); + + /** + * The column databasir.oauth_app.app_name. + */ + public final TableField APP_NAME = createField(DSL.name("app_name"), SQLDataType.VARCHAR(128).nullable(false), this, ""); + + /** + * The column databasir.oauth_app.app_icon. + */ + public final TableField APP_ICON = createField(DSL.name("app_icon"), SQLDataType.VARCHAR(256).nullable(false).defaultValue(DSL.inline("", SQLDataType.VARCHAR)), this, ""); + + /** + * The column databasir.oauth_app.app_type. github, gitlab + */ + public final TableField APP_TYPE = createField(DSL.name("app_type"), SQLDataType.VARCHAR(64).nullable(false), this, "github, gitlab"); + + /** + * The column databasir.oauth_app.client_id. + */ + public final TableField CLIENT_ID = createField(DSL.name("client_id"), SQLDataType.VARCHAR(256), this, ""); + + /** + * The column databasir.oauth_app.client_secret. + */ + public final TableField CLIENT_SECRET = createField(DSL.name("client_secret"), SQLDataType.VARCHAR(256), this, ""); + + /** + * The column databasir.oauth_app.auth_url. + */ + public final TableField AUTH_URL = createField(DSL.name("auth_url"), SQLDataType.VARCHAR(256), this, ""); + + /** + * The column databasir.oauth_app.resource_url. + */ + public final TableField RESOURCE_URL = createField(DSL.name("resource_url"), SQLDataType.VARCHAR(256), this, ""); + + /** + * The column databasir.oauth_app.scope. + */ + public final TableField SCOPE = createField(DSL.name("scope"), SQLDataType.VARCHAR(256), this, ""); + + /** + * The column databasir.oauth_app.update_at. + */ + public final TableField UPDATE_AT = createField(DSL.name("update_at"), SQLDataType.LOCALDATETIME(0).nullable(false).defaultValue(DSL.field("CURRENT_TIMESTAMP", SQLDataType.LOCALDATETIME)), this, ""); + + /** + * The column databasir.oauth_app.create_at. + */ + public final TableField CREATE_AT = createField(DSL.name("create_at"), SQLDataType.LOCALDATETIME(0).nullable(false).defaultValue(DSL.field("CURRENT_TIMESTAMP", SQLDataType.LOCALDATETIME)), this, ""); + + private OauthApp(Name alias, Table aliased) { + this(alias, aliased, null); + } + + private OauthApp(Name alias, Table aliased, Field[] parameters) { + super(alias, null, aliased, parameters, DSL.comment("oauth app info"), TableOptions.table()); + } + + /** + * Create an aliased databasir.oauth_app table reference + */ + public OauthApp(String alias) { + this(DSL.name(alias), OAUTH_APP); + } + + /** + * Create an aliased databasir.oauth_app table reference + */ + public OauthApp(Name alias) { + this(alias, OAUTH_APP); + } + + /** + * Create a databasir.oauth_app table reference + */ + public OauthApp() { + this(DSL.name("oauth_app"), null); + } + + public OauthApp(Table child, ForeignKey key) { + super(child, key, OAUTH_APP); + } + + @Override + public Schema getSchema() { + return aliased() ? null : Databasir.DATABASIR; + } + + @Override + public Identity getIdentity() { + return (Identity) super.getIdentity(); + } + + @Override + public UniqueKey getPrimaryKey() { + return Keys.KEY_OAUTH_APP_PRIMARY; + } + + @Override + public List> getUniqueKeys() { + return Arrays.asList(Keys.KEY_OAUTH_APP_UK_REGISTRATION_ID); + } + + @Override + public OauthApp as(String alias) { + return new OauthApp(DSL.name(alias), this); + } + + @Override + public OauthApp as(Name alias) { + return new OauthApp(alias, this); + } + + /** + * Rename this table + */ + @Override + public OauthApp rename(String name) { + return new OauthApp(DSL.name(name), null); + } + + /** + * Rename this table + */ + @Override + public OauthApp rename(Name name) { + return new OauthApp(name, null); + } + + // ------------------------------------------------------------------------- + // Row12 type methods + // ------------------------------------------------------------------------- + + @Override + public Row12 fieldsRow() { + return (Row12) super.fieldsRow(); + } +} diff --git a/dao/generated-src/jooq/main/java/com/databasir/dao/tables/UserFavoriteProject.java b/dao/generated-src/jooq/main/java/com/databasir/dao/tables/UserFavoriteProject.java index 89758d9..0a0e3c9 100644 --- a/dao/generated-src/jooq/main/java/com/databasir/dao/tables/UserFavoriteProject.java +++ b/dao/generated-src/jooq/main/java/com/databasir/dao/tables/UserFavoriteProject.java @@ -5,7 +5,6 @@ package com.databasir.dao.tables; import com.databasir.dao.Databasir; -import com.databasir.dao.Indexes; import com.databasir.dao.Keys; import com.databasir.dao.tables.records.UserFavoriteProjectRecord; @@ -16,7 +15,6 @@ import java.util.List; import org.jooq.Field; import org.jooq.ForeignKey; import org.jooq.Identity; -import org.jooq.Index; import org.jooq.Name; import org.jooq.Record; import org.jooq.Row4; @@ -111,11 +109,6 @@ public class UserFavoriteProject extends TableImpl { return aliased() ? null : Databasir.DATABASIR; } - @Override - public List getIndexes() { - return Arrays.asList(Indexes.USER_FAVORITE_PROJECT_IDX_USER_ID); - } - @Override public Identity getIdentity() { return (Identity) super.getIdentity(); @@ -126,6 +119,11 @@ public class UserFavoriteProject extends TableImpl { return Keys.KEY_USER_FAVORITE_PROJECT_PRIMARY; } + @Override + public List> getUniqueKeys() { + return Arrays.asList(Keys.KEY_USER_FAVORITE_PROJECT_UK_USER_ID_PROJECT_ID); + } + @Override public UserFavoriteProject as(String alias) { return new UserFavoriteProject(DSL.name(alias), this); diff --git a/dao/generated-src/jooq/main/java/com/databasir/dao/tables/pojos/OauthAppPojo.java b/dao/generated-src/jooq/main/java/com/databasir/dao/tables/pojos/OauthAppPojo.java new file mode 100644 index 0000000..1670761 --- /dev/null +++ b/dao/generated-src/jooq/main/java/com/databasir/dao/tables/pojos/OauthAppPojo.java @@ -0,0 +1,265 @@ +/* + * This file is generated by jOOQ. + */ +package com.databasir.dao.tables.pojos; + + +import java.io.Serializable; +import java.time.LocalDateTime; + + +/** + * oauth app info + */ +@SuppressWarnings({ "all", "unchecked", "rawtypes" }) +public class OauthAppPojo implements Serializable { + + private static final long serialVersionUID = 1L; + + private Integer id; + private String registrationId; + private String appName; + private String appIcon; + private String appType; + private String clientId; + private String clientSecret; + private String authUrl; + private String resourceUrl; + private String scope; + private LocalDateTime updateAt; + private LocalDateTime createAt; + + public OauthAppPojo() {} + + public OauthAppPojo(OauthAppPojo value) { + this.id = value.id; + this.registrationId = value.registrationId; + this.appName = value.appName; + this.appIcon = value.appIcon; + this.appType = value.appType; + this.clientId = value.clientId; + this.clientSecret = value.clientSecret; + this.authUrl = value.authUrl; + this.resourceUrl = value.resourceUrl; + this.scope = value.scope; + this.updateAt = value.updateAt; + this.createAt = value.createAt; + } + + public OauthAppPojo( + Integer id, + String registrationId, + String appName, + String appIcon, + String appType, + String clientId, + String clientSecret, + String authUrl, + String resourceUrl, + String scope, + LocalDateTime updateAt, + LocalDateTime createAt + ) { + this.id = id; + this.registrationId = registrationId; + this.appName = appName; + this.appIcon = appIcon; + this.appType = appType; + this.clientId = clientId; + this.clientSecret = clientSecret; + this.authUrl = authUrl; + this.resourceUrl = resourceUrl; + this.scope = scope; + this.updateAt = updateAt; + this.createAt = createAt; + } + + /** + * Getter for databasir.oauth_app.id. + */ + public Integer getId() { + return this.id; + } + + /** + * Setter for databasir.oauth_app.id. + */ + public void setId(Integer id) { + this.id = id; + } + + /** + * Getter for databasir.oauth_app.registration_id. + */ + public String getRegistrationId() { + return this.registrationId; + } + + /** + * Setter for databasir.oauth_app.registration_id. + */ + public void setRegistrationId(String registrationId) { + this.registrationId = registrationId; + } + + /** + * Getter for databasir.oauth_app.app_name. + */ + public String getAppName() { + return this.appName; + } + + /** + * Setter for databasir.oauth_app.app_name. + */ + public void setAppName(String appName) { + this.appName = appName; + } + + /** + * Getter for databasir.oauth_app.app_icon. + */ + public String getAppIcon() { + return this.appIcon; + } + + /** + * Setter for databasir.oauth_app.app_icon. + */ + public void setAppIcon(String appIcon) { + this.appIcon = appIcon; + } + + /** + * Getter for databasir.oauth_app.app_type. github, gitlab + */ + public String getAppType() { + return this.appType; + } + + /** + * Setter for databasir.oauth_app.app_type. github, gitlab + */ + public void setAppType(String appType) { + this.appType = appType; + } + + /** + * Getter for databasir.oauth_app.client_id. + */ + public String getClientId() { + return this.clientId; + } + + /** + * Setter for databasir.oauth_app.client_id. + */ + public void setClientId(String clientId) { + this.clientId = clientId; + } + + /** + * Getter for databasir.oauth_app.client_secret. + */ + public String getClientSecret() { + return this.clientSecret; + } + + /** + * Setter for databasir.oauth_app.client_secret. + */ + public void setClientSecret(String clientSecret) { + this.clientSecret = clientSecret; + } + + /** + * Getter for databasir.oauth_app.auth_url. + */ + public String getAuthUrl() { + return this.authUrl; + } + + /** + * Setter for databasir.oauth_app.auth_url. + */ + public void setAuthUrl(String authUrl) { + this.authUrl = authUrl; + } + + /** + * Getter for databasir.oauth_app.resource_url. + */ + public String getResourceUrl() { + return this.resourceUrl; + } + + /** + * Setter for databasir.oauth_app.resource_url. + */ + public void setResourceUrl(String resourceUrl) { + this.resourceUrl = resourceUrl; + } + + /** + * Getter for databasir.oauth_app.scope. + */ + public String getScope() { + return this.scope; + } + + /** + * Setter for databasir.oauth_app.scope. + */ + public void setScope(String scope) { + this.scope = scope; + } + + /** + * Getter for databasir.oauth_app.update_at. + */ + public LocalDateTime getUpdateAt() { + return this.updateAt; + } + + /** + * Setter for databasir.oauth_app.update_at. + */ + public void setUpdateAt(LocalDateTime updateAt) { + this.updateAt = updateAt; + } + + /** + * Getter for databasir.oauth_app.create_at. + */ + public LocalDateTime getCreateAt() { + return this.createAt; + } + + /** + * Setter for databasir.oauth_app.create_at. + */ + public void setCreateAt(LocalDateTime createAt) { + this.createAt = createAt; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("OauthAppPojo ("); + + sb.append(id); + sb.append(", ").append(registrationId); + sb.append(", ").append(appName); + sb.append(", ").append(appIcon); + sb.append(", ").append(appType); + sb.append(", ").append(clientId); + sb.append(", ").append(clientSecret); + sb.append(", ").append(authUrl); + sb.append(", ").append(resourceUrl); + sb.append(", ").append(scope); + sb.append(", ").append(updateAt); + sb.append(", ").append(createAt); + + sb.append(")"); + return sb.toString(); + } +} diff --git a/dao/generated-src/jooq/main/java/com/databasir/dao/tables/records/OauthAppRecord.java b/dao/generated-src/jooq/main/java/com/databasir/dao/tables/records/OauthAppRecord.java new file mode 100644 index 0000000..20d9d5e --- /dev/null +++ b/dao/generated-src/jooq/main/java/com/databasir/dao/tables/records/OauthAppRecord.java @@ -0,0 +1,539 @@ +/* + * This file is generated by jOOQ. + */ +package com.databasir.dao.tables.records; + + +import com.databasir.dao.tables.OauthApp; +import com.databasir.dao.tables.pojos.OauthAppPojo; + +import java.time.LocalDateTime; + +import org.jooq.Field; +import org.jooq.Record1; +import org.jooq.Record12; +import org.jooq.Row12; +import org.jooq.impl.UpdatableRecordImpl; + + +/** + * oauth app info + */ +@SuppressWarnings({ "all", "unchecked", "rawtypes" }) +public class OauthAppRecord extends UpdatableRecordImpl implements Record12 { + + private static final long serialVersionUID = 1L; + + /** + * Setter for databasir.oauth_app.id. + */ + public void setId(Integer value) { + set(0, value); + } + + /** + * Getter for databasir.oauth_app.id. + */ + public Integer getId() { + return (Integer) get(0); + } + + /** + * Setter for databasir.oauth_app.registration_id. + */ + public void setRegistrationId(String value) { + set(1, value); + } + + /** + * Getter for databasir.oauth_app.registration_id. + */ + public String getRegistrationId() { + return (String) get(1); + } + + /** + * Setter for databasir.oauth_app.app_name. + */ + public void setAppName(String value) { + set(2, value); + } + + /** + * Getter for databasir.oauth_app.app_name. + */ + public String getAppName() { + return (String) get(2); + } + + /** + * Setter for databasir.oauth_app.app_icon. + */ + public void setAppIcon(String value) { + set(3, value); + } + + /** + * Getter for databasir.oauth_app.app_icon. + */ + public String getAppIcon() { + return (String) get(3); + } + + /** + * Setter for databasir.oauth_app.app_type. github, gitlab + */ + public void setAppType(String value) { + set(4, value); + } + + /** + * Getter for databasir.oauth_app.app_type. github, gitlab + */ + public String getAppType() { + return (String) get(4); + } + + /** + * Setter for databasir.oauth_app.client_id. + */ + public void setClientId(String value) { + set(5, value); + } + + /** + * Getter for databasir.oauth_app.client_id. + */ + public String getClientId() { + return (String) get(5); + } + + /** + * Setter for databasir.oauth_app.client_secret. + */ + public void setClientSecret(String value) { + set(6, value); + } + + /** + * Getter for databasir.oauth_app.client_secret. + */ + public String getClientSecret() { + return (String) get(6); + } + + /** + * Setter for databasir.oauth_app.auth_url. + */ + public void setAuthUrl(String value) { + set(7, value); + } + + /** + * Getter for databasir.oauth_app.auth_url. + */ + public String getAuthUrl() { + return (String) get(7); + } + + /** + * Setter for databasir.oauth_app.resource_url. + */ + public void setResourceUrl(String value) { + set(8, value); + } + + /** + * Getter for databasir.oauth_app.resource_url. + */ + public String getResourceUrl() { + return (String) get(8); + } + + /** + * Setter for databasir.oauth_app.scope. + */ + public void setScope(String value) { + set(9, value); + } + + /** + * Getter for databasir.oauth_app.scope. + */ + public String getScope() { + return (String) get(9); + } + + /** + * Setter for databasir.oauth_app.update_at. + */ + public void setUpdateAt(LocalDateTime value) { + set(10, value); + } + + /** + * Getter for databasir.oauth_app.update_at. + */ + public LocalDateTime getUpdateAt() { + return (LocalDateTime) get(10); + } + + /** + * Setter for databasir.oauth_app.create_at. + */ + public void setCreateAt(LocalDateTime value) { + set(11, value); + } + + /** + * Getter for databasir.oauth_app.create_at. + */ + public LocalDateTime getCreateAt() { + return (LocalDateTime) get(11); + } + + // ------------------------------------------------------------------------- + // Primary key information + // ------------------------------------------------------------------------- + + @Override + public Record1 key() { + return (Record1) super.key(); + } + + // ------------------------------------------------------------------------- + // Record12 type implementation + // ------------------------------------------------------------------------- + + @Override + public Row12 fieldsRow() { + return (Row12) super.fieldsRow(); + } + + @Override + public Row12 valuesRow() { + return (Row12) super.valuesRow(); + } + + @Override + public Field field1() { + return OauthApp.OAUTH_APP.ID; + } + + @Override + public Field field2() { + return OauthApp.OAUTH_APP.REGISTRATION_ID; + } + + @Override + public Field field3() { + return OauthApp.OAUTH_APP.APP_NAME; + } + + @Override + public Field field4() { + return OauthApp.OAUTH_APP.APP_ICON; + } + + @Override + public Field field5() { + return OauthApp.OAUTH_APP.APP_TYPE; + } + + @Override + public Field field6() { + return OauthApp.OAUTH_APP.CLIENT_ID; + } + + @Override + public Field field7() { + return OauthApp.OAUTH_APP.CLIENT_SECRET; + } + + @Override + public Field field8() { + return OauthApp.OAUTH_APP.AUTH_URL; + } + + @Override + public Field field9() { + return OauthApp.OAUTH_APP.RESOURCE_URL; + } + + @Override + public Field field10() { + return OauthApp.OAUTH_APP.SCOPE; + } + + @Override + public Field field11() { + return OauthApp.OAUTH_APP.UPDATE_AT; + } + + @Override + public Field field12() { + return OauthApp.OAUTH_APP.CREATE_AT; + } + + @Override + public Integer component1() { + return getId(); + } + + @Override + public String component2() { + return getRegistrationId(); + } + + @Override + public String component3() { + return getAppName(); + } + + @Override + public String component4() { + return getAppIcon(); + } + + @Override + public String component5() { + return getAppType(); + } + + @Override + public String component6() { + return getClientId(); + } + + @Override + public String component7() { + return getClientSecret(); + } + + @Override + public String component8() { + return getAuthUrl(); + } + + @Override + public String component9() { + return getResourceUrl(); + } + + @Override + public String component10() { + return getScope(); + } + + @Override + public LocalDateTime component11() { + return getUpdateAt(); + } + + @Override + public LocalDateTime component12() { + return getCreateAt(); + } + + @Override + public Integer value1() { + return getId(); + } + + @Override + public String value2() { + return getRegistrationId(); + } + + @Override + public String value3() { + return getAppName(); + } + + @Override + public String value4() { + return getAppIcon(); + } + + @Override + public String value5() { + return getAppType(); + } + + @Override + public String value6() { + return getClientId(); + } + + @Override + public String value7() { + return getClientSecret(); + } + + @Override + public String value8() { + return getAuthUrl(); + } + + @Override + public String value9() { + return getResourceUrl(); + } + + @Override + public String value10() { + return getScope(); + } + + @Override + public LocalDateTime value11() { + return getUpdateAt(); + } + + @Override + public LocalDateTime value12() { + return getCreateAt(); + } + + @Override + public OauthAppRecord value1(Integer value) { + setId(value); + return this; + } + + @Override + public OauthAppRecord value2(String value) { + setRegistrationId(value); + return this; + } + + @Override + public OauthAppRecord value3(String value) { + setAppName(value); + return this; + } + + @Override + public OauthAppRecord value4(String value) { + setAppIcon(value); + return this; + } + + @Override + public OauthAppRecord value5(String value) { + setAppType(value); + return this; + } + + @Override + public OauthAppRecord value6(String value) { + setClientId(value); + return this; + } + + @Override + public OauthAppRecord value7(String value) { + setClientSecret(value); + return this; + } + + @Override + public OauthAppRecord value8(String value) { + setAuthUrl(value); + return this; + } + + @Override + public OauthAppRecord value9(String value) { + setResourceUrl(value); + return this; + } + + @Override + public OauthAppRecord value10(String value) { + setScope(value); + return this; + } + + @Override + public OauthAppRecord value11(LocalDateTime value) { + setUpdateAt(value); + return this; + } + + @Override + public OauthAppRecord value12(LocalDateTime value) { + setCreateAt(value); + return this; + } + + @Override + public OauthAppRecord values(Integer value1, String value2, String value3, String value4, String value5, String value6, String value7, String value8, String value9, String value10, LocalDateTime value11, LocalDateTime value12) { + value1(value1); + value2(value2); + value3(value3); + value4(value4); + value5(value5); + value6(value6); + value7(value7); + value8(value8); + value9(value9); + value10(value10); + value11(value11); + value12(value12); + return this; + } + + // ------------------------------------------------------------------------- + // Constructors + // ------------------------------------------------------------------------- + + /** + * Create a detached OauthAppRecord + */ + public OauthAppRecord() { + super(OauthApp.OAUTH_APP); + } + + /** + * Create a detached, initialised OauthAppRecord + */ + public OauthAppRecord(Integer id, String registrationId, String appName, String appIcon, String appType, String clientId, String clientSecret, String authUrl, String resourceUrl, String scope, LocalDateTime updateAt, LocalDateTime createAt) { + super(OauthApp.OAUTH_APP); + + setId(id); + setRegistrationId(registrationId); + setAppName(appName); + setAppIcon(appIcon); + setAppType(appType); + setClientId(clientId); + setClientSecret(clientSecret); + setAuthUrl(authUrl); + setResourceUrl(resourceUrl); + setScope(scope); + setUpdateAt(updateAt); + setCreateAt(createAt); + } + + /** + * Create a detached, initialised OauthAppRecord + */ + public OauthAppRecord(OauthAppPojo value) { + super(OauthApp.OAUTH_APP); + + if (value != null) { + setId(value.getId()); + setRegistrationId(value.getRegistrationId()); + setAppName(value.getAppName()); + setAppIcon(value.getAppIcon()); + setAppType(value.getAppType()); + setClientId(value.getClientId()); + setClientSecret(value.getClientSecret()); + setAuthUrl(value.getAuthUrl()); + setResourceUrl(value.getResourceUrl()); + setScope(value.getScope()); + setUpdateAt(value.getUpdateAt()); + setCreateAt(value.getCreateAt()); + } + } +} diff --git a/dao/src/main/java/com/databasir/dao/enums/OAuthAppType.java b/dao/src/main/java/com/databasir/dao/enums/OAuthAppType.java new file mode 100644 index 0000000..fb2f082 --- /dev/null +++ b/dao/src/main/java/com/databasir/dao/enums/OAuthAppType.java @@ -0,0 +1,10 @@ +package com.databasir.dao.enums; + +public enum OAuthAppType { + + GITHUB, GITLAB; + + public boolean isSame(String type) { + return this.name().equalsIgnoreCase(type); + } +} diff --git a/dao/src/main/java/com/databasir/dao/impl/BaseDao.java b/dao/src/main/java/com/databasir/dao/impl/BaseDao.java index 872ab8c..0ab42b7 100644 --- a/dao/src/main/java/com/databasir/dao/impl/BaseDao.java +++ b/dao/src/main/java/com/databasir/dao/impl/BaseDao.java @@ -90,6 +90,12 @@ public abstract class BaseDao { .fetchInto(pojoType); } + public List selectAll() { + return this.getDslContext() + .selectFrom(table()) + .fetchInto(pojoType); + } + public Page selectByPage(Pageable request, Condition condition) { Integer count = getDslContext() .selectCount().from(table).where(condition) diff --git a/dao/src/main/java/com/databasir/dao/impl/LoginDao.java b/dao/src/main/java/com/databasir/dao/impl/LoginDao.java index fc5f6ed..cd5adbb 100644 --- a/dao/src/main/java/com/databasir/dao/impl/LoginDao.java +++ b/dao/src/main/java/com/databasir/dao/impl/LoginDao.java @@ -40,6 +40,13 @@ public class LoginDao extends BaseDao { .fetchOptionalInto(LoginPojo.class); } + public Optional selectByAccessToken(String accessToken) { + return getDslContext() + .selectFrom(LOGIN).where(LOGIN.ACCESS_TOKEN.eq(accessToken) + .and(LOGIN.ACCESS_TOKEN_EXPIRE_AT.ge(LocalDateTime.now()))) + .fetchOptionalInto(LoginPojo.class); + } + public void updateAccessToken(String accessToken, LocalDateTime accessTokenExpireAt, Integer userId) { getDslContext() .update(LOGIN) diff --git a/dao/src/main/java/com/databasir/dao/impl/OauthAppDao.java b/dao/src/main/java/com/databasir/dao/impl/OauthAppDao.java new file mode 100644 index 0000000..bd7450b --- /dev/null +++ b/dao/src/main/java/com/databasir/dao/impl/OauthAppDao.java @@ -0,0 +1,37 @@ +package com.databasir.dao.impl; + +import com.databasir.dao.exception.DataNotExistsException; +import com.databasir.dao.tables.pojos.OauthAppPojo; +import lombok.Getter; +import org.jooq.DSLContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +import static com.databasir.dao.Tables.OAUTH_APP; + +@Repository +public class OauthAppDao extends BaseDao { + + @Autowired + @Getter + private DSLContext dslContext; + + public OauthAppDao() { + super(OAUTH_APP, OauthAppPojo.class); + } + + public Optional selectOptionByRegistrationId(String registrationId) { + return this.getDslContext() + .select(OAUTH_APP.fields()).from(OAUTH_APP).where(OAUTH_APP.REGISTRATION_ID.eq(registrationId)) + .fetchOptionalInto(OauthAppPojo.class); + } + + public OauthAppPojo selectByRegistrationId(String registrationId) { + return this.getDslContext() + .select(OAUTH_APP.fields()).from(OAUTH_APP).where(OAUTH_APP.REGISTRATION_ID.eq(registrationId)) + .fetchOptionalInto(OauthAppPojo.class) + .orElseThrow(() -> new DataNotExistsException("can not found oauth app by " + registrationId)); + } +} \ No newline at end of file diff --git a/dao/src/main/resources/db/migration/V1.4__oauth.sql b/dao/src/main/resources/db/migration/V1.4__oauth.sql new file mode 100644 index 0000000..46e705e --- /dev/null +++ b/dao/src/main/resources/db/migration/V1.4__oauth.sql @@ -0,0 +1,18 @@ +CREATE TABLE IF NOT EXISTS oauth_app +( + id INT PRIMARY KEY NOT NULL AUTO_INCREMENT, + registration_id VARCHAR(100) NOT NULL, + app_name VARCHAR(128) NOT NULL, + app_icon VARCHAR(256) NOT NULL DEFAULT '', + app_type VARCHAR(64) NOT NULL COMMENT 'github, gitlab', + client_id VARCHAR(256), + client_secret VARCHAR(256), + auth_url VARCHAR(256), + resource_url VARCHAR(256), + scope VARCHAR(256), + update_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + create_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + UNIQUE uk_registration_id (registration_id) +) CHARSET utf8mb4 + COLLATE utf8mb4_unicode_ci COMMENT 'oauth app info'; +