feat, fix : [FE] user Registration API add, refactoring connected ALL LOGIC
This commit is contained in:
60
src/frontend/package-lock.json
generated
60
src/frontend/package-lock.json
generated
@@ -9,6 +9,7 @@
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"assert": "^2.0.0",
|
||||
"axios": "^1.1.3",
|
||||
"core-js": "^3.8.3",
|
||||
"https-browserify": "^1.0.0",
|
||||
"path": "^0.12.7",
|
||||
@@ -3490,6 +3491,29 @@
|
||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz",
|
||||
"integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA=="
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.1.3.tgz",
|
||||
"integrity": "sha512-00tXVRwKx/FZr/IDVFt4C+f9FYairX517WoGCL6dpOntqLkZofjhu43F/Xl44UOpqa+9sLFDrG/XAnFsUYgkDA==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.0",
|
||||
"form-data": "^4.0.0",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/axios/node_modules/form-data": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"mime-types": "^2.1.12"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/babel-loader": {
|
||||
"version": "8.3.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.3.0.tgz",
|
||||
@@ -6144,7 +6168,6 @@
|
||||
"version": "1.15.2",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
|
||||
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -9305,6 +9328,11 @@
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
|
||||
},
|
||||
"node_modules/pseudomap": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
|
||||
@@ -14564,6 +14592,28 @@
|
||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz",
|
||||
"integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA=="
|
||||
},
|
||||
"axios": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.1.3.tgz",
|
||||
"integrity": "sha512-00tXVRwKx/FZr/IDVFt4C+f9FYairX517WoGCL6dpOntqLkZofjhu43F/Xl44UOpqa+9sLFDrG/XAnFsUYgkDA==",
|
||||
"requires": {
|
||||
"follow-redirects": "^1.15.0",
|
||||
"form-data": "^4.0.0",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"form-data": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"mime-types": "^2.1.12"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"babel-loader": {
|
||||
"version": "8.3.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.3.0.tgz",
|
||||
@@ -16547,8 +16597,7 @@
|
||||
"follow-redirects": {
|
||||
"version": "1.15.2",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
|
||||
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA=="
|
||||
},
|
||||
"for-each": {
|
||||
"version": "0.3.3",
|
||||
@@ -18830,6 +18879,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
|
||||
},
|
||||
"pseudomap": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"assert": "^2.0.0",
|
||||
"axios": "^1.1.3",
|
||||
"core-js": "^3.8.3",
|
||||
"https-browserify": "^1.0.0",
|
||||
"path": "^0.12.7",
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<router-link to="/login" class="nav-link" active-class="active">Sign in</router-link>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<router-link to="/signup" class="nav-link" active-class="active">Sign up</router-link>
|
||||
<router-link to="/register" class="nav-link" active-class="active">Sign up</router-link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import router from "./router";
|
||||
import axios from 'axios';
|
||||
|
||||
const app = createApp(App);
|
||||
app.use(router);
|
||||
app.use(router,axios);
|
||||
app.mount('#app');
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createWebHistory, createRouter } from "vue-router";
|
||||
import { createWebHashHistory, createRouter } from "vue-router";
|
||||
|
||||
const routes = [
|
||||
{
|
||||
@@ -7,8 +7,8 @@ const routes = [
|
||||
component: () => import(/* webpackChunkName "home" */ '@/views/TheHome.vue')
|
||||
},
|
||||
{
|
||||
path: "/setting",
|
||||
name: "Setting",
|
||||
path: "/settings",
|
||||
name: "Settings",
|
||||
component: () => import(/* webpackChunkName "inputTag" */ '@/views/TheSetting.vue')
|
||||
},
|
||||
{
|
||||
@@ -17,9 +17,9 @@ const routes = [
|
||||
component: () => import(/* webpackChunkName "inputTag" */ '@/views/TheLogin.vue')
|
||||
},
|
||||
{
|
||||
path: "/signup",
|
||||
name: "SignUp",
|
||||
component: () => import(/* webpackChunkName "inputTag" */ '@/views/TheSignUp.vue')
|
||||
path: "/register",
|
||||
name: "Register",
|
||||
component: () => import(/* webpackChunkName "inputTag" */ '@/views/TheRegister.vue')
|
||||
},
|
||||
{
|
||||
path: "/article",
|
||||
@@ -29,7 +29,7 @@ const routes = [
|
||||
];
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
history: createWebHashHistory(),
|
||||
routes,
|
||||
});
|
||||
|
||||
|
||||
99
src/frontend/src/views/TheRegister.vue
Normal file
99
src/frontend/src/views/TheRegister.vue
Normal file
@@ -0,0 +1,99 @@
|
||||
<template>
|
||||
|
||||
<div class="auth-page">
|
||||
<div class="container page">
|
||||
<div class="row">
|
||||
|
||||
<div class="col-md-6 offset-md-3 col-xs-12">
|
||||
<h1 class="text-xs-center">Sign up</h1>
|
||||
<p class="text-xs-center">
|
||||
<a href="">Have an account?</a>
|
||||
</p>
|
||||
|
||||
<ul class="error-messages" v-if="emailDuplicate">
|
||||
<li align="left">email has already been taken</li>
|
||||
</ul>
|
||||
<ul class="error-messages" v-if="usernameDuplicate">
|
||||
<li align="left">username has already been taken</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<form>
|
||||
<fieldset class="form-group">
|
||||
<input class="form-control form-control-lg" type="text" placeholder="Your Name" v-model="username">
|
||||
</fieldset>
|
||||
<fieldset class="form-group">
|
||||
<input class="form-control form-control-lg" type="text" placeholder="Email" v-model="email">
|
||||
</fieldset>
|
||||
<fieldset class="form-group">
|
||||
<input class="form-control form-control-lg" type="password" placeholder="Password" v-model="password">
|
||||
</fieldset>
|
||||
<button @click = "signup" class="btn btn-lg btn-primary pull-xs-right">
|
||||
Sign up
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import axios from "axios";
|
||||
import router from "@/router";
|
||||
|
||||
export default {
|
||||
name: "TheRegister.vue",
|
||||
data() {
|
||||
return {
|
||||
emailDuplicate: false,
|
||||
usernameDuplicate: false,
|
||||
}
|
||||
},
|
||||
methods:{
|
||||
showEmailUsernameError(){
|
||||
this.emailDuplicate = true;
|
||||
this.usernameDuplicate = true
|
||||
},
|
||||
showEmailError(){
|
||||
this.emailDuplicate = true;
|
||||
this.usernameDuplicate = false;
|
||||
},
|
||||
showUsernameError(){
|
||||
this.usernameDuplicate = true;
|
||||
this.emailDuplicate = false;
|
||||
},
|
||||
signup: function(){
|
||||
axios.post('http://localhost:8080/api/users',{
|
||||
user : {
|
||||
username: this.username,
|
||||
email: this.email,
|
||||
password: this.password,
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
window.localStorage.setItem("token",response.data.user.token);
|
||||
this.emailDuplicate = false;
|
||||
this.usernameDuplicate = false;
|
||||
router.push("/");
|
||||
})
|
||||
.catch(error =>{
|
||||
const code = error.response.data.errors.code;
|
||||
if(code == "DUPLICATE_EMAIL_USERNAME"){
|
||||
this.showEmailUsernameError();
|
||||
}else if(code == "DUPLICATE_EMAIL"){
|
||||
this.showEmailError();
|
||||
}else if(code == "DUPLICATE_USERNAME"){
|
||||
this.showUsernameError();
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -1,46 +0,0 @@
|
||||
<template>
|
||||
|
||||
<div class="auth-page">
|
||||
<div class="container page">
|
||||
<div class="row">
|
||||
|
||||
<div class="col-md-6 offset-md-3 col-xs-12">
|
||||
<h1 class="text-xs-center">Sign up</h1>
|
||||
<p class="text-xs-center">
|
||||
<a href="">Have an account?</a>
|
||||
</p>
|
||||
|
||||
<ul class="error-messages">
|
||||
<li>That email is already taken</li>
|
||||
</ul>
|
||||
|
||||
<form>
|
||||
<fieldset class="form-group">
|
||||
<input class="form-control form-control-lg" type="text" placeholder="Your Name">
|
||||
</fieldset>
|
||||
<fieldset class="form-group">
|
||||
<input class="form-control form-control-lg" type="text" placeholder="Email">
|
||||
</fieldset>
|
||||
<fieldset class="form-group">
|
||||
<input class="form-control form-control-lg" type="password" placeholder="Password">
|
||||
</fieldset>
|
||||
<button class="btn btn-lg btn-primary pull-xs-right">
|
||||
Sign up
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "TheSignUp.vue"
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -13,6 +13,8 @@ import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Log4j2
|
||||
@@ -25,9 +27,17 @@ public class UserServiceImpl implements UserService {
|
||||
private final JwtService jwtService;
|
||||
|
||||
public UserResponse signup(UserSignupRequest userSignupRequest) {
|
||||
if (userRepository.findByEmail(userSignupRequest.getEmail()) != null) {
|
||||
throw new CustomException(Error.DUPLICATE_USER);
|
||||
} else {
|
||||
User findEmail = userRepository.findByEmail(userSignupRequest.getEmail());
|
||||
Optional<User> findUsername = userRepository.findByUsername(userSignupRequest.getUsername());
|
||||
|
||||
if ( findEmail != null && !findUsername.isEmpty()) {
|
||||
throw new CustomException(Error.DUPLICATE_EMAIL_USERNAME);
|
||||
}else if(findEmail != null){
|
||||
throw new CustomException(Error.DUPLICATE_EMAIL);
|
||||
}else if(!findUsername.isEmpty()){
|
||||
throw new CustomException(Error.DUPLICATE_USERNAME);
|
||||
}
|
||||
else {
|
||||
return convertUser(userRepository.save(User.builder().
|
||||
username(userSignupRequest.getUsername()).
|
||||
email(userSignupRequest.getEmail()).
|
||||
@@ -67,7 +77,7 @@ public class UserServiceImpl implements UserService {
|
||||
if(userUpdate.getEmail() != null){
|
||||
userRepository.findAllByEmail(userUpdate.getEmail())
|
||||
.stream().filter(found -> !found.getId().equals(userRepository.findById(user.getId())))
|
||||
.findAny().ifPresent(found -> new CustomException(Error.DUPLICATE_USER));
|
||||
.findAny().ifPresent(found -> new CustomException(Error.DUPLICATE_EMAIL));
|
||||
user.changeEmail(userUpdate.getEmail());
|
||||
}
|
||||
userUpdate.setId(user.getId());
|
||||
|
||||
@@ -5,7 +5,10 @@ import org.springframework.http.HttpStatus;
|
||||
|
||||
@Getter
|
||||
public enum Error {
|
||||
DUPLICATE_USER("duplicate user", HttpStatus.CONFLICT),
|
||||
DUPLICATE_EMAIL_USERNAME("duplicate user email, username",HttpStatus.CONFLICT),
|
||||
DUPLICATE_EMAIL("duplicate user email", HttpStatus.CONFLICT),
|
||||
|
||||
DUPLICATE_USERNAME("duplicate user username", HttpStatus.CONFLICT),
|
||||
SIGNUP_NULL_DATA("request body include null",HttpStatus.BAD_REQUEST),
|
||||
EMAIL_NULL_OR_INVALID("email is blank or invalid check plz",HttpStatus.BAD_REQUEST),
|
||||
USER_NOT_FOUND("user not found check your info",HttpStatus.NOT_FOUND),
|
||||
|
||||
@@ -75,7 +75,7 @@ class UsersControllerTest {
|
||||
@MethodSource("validUsers")
|
||||
@ParameterizedTest(name = "conroller:회원가입 중복 테스트")
|
||||
void signupDuplicate(UserSignupRequest user) throws Exception {
|
||||
when(userService.signup(any(UserSignupRequest.class))).thenThrow(new CustomException(Error.DUPLICATE_USER));
|
||||
when(userService.signup(any(UserSignupRequest.class))).thenThrow(new CustomException(Error.DUPLICATE_EMAIL));
|
||||
|
||||
mockMvc.perform(post("/api/users")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
@@ -83,7 +83,7 @@ class UsersControllerTest {
|
||||
.with(csrf())
|
||||
)
|
||||
.andExpect(MockMvcResultMatchers.status().isConflict())
|
||||
.andExpect(MockMvcResultMatchers.jsonPath("$.errors.message", Matchers.equalTo(Error.DUPLICATE_USER.getMessage())));
|
||||
.andExpect(MockMvcResultMatchers.jsonPath("$.errors.message", Matchers.equalTo(Error.DUPLICATE_EMAIL.getMessage())));
|
||||
}
|
||||
|
||||
@WithMockUser
|
||||
|
||||
@@ -87,7 +87,7 @@ class UserServiceImplTest {
|
||||
.password(requestUser.getPassword())
|
||||
.build();
|
||||
|
||||
when(userRepository.findByEmail(any(String.class))).thenReturn(null).thenThrow(new CustomException(Error.DUPLICATE_USER));
|
||||
when(userRepository.findByEmail(any(String.class))).thenReturn(null).thenThrow(new CustomException(Error.DUPLICATE_EMAIL));
|
||||
when(userRepository.save(any(User.class))).thenReturn(user);
|
||||
userService.signup(requestUser);
|
||||
}
|
||||
@@ -178,12 +178,12 @@ class UserServiceImplTest {
|
||||
when(userRepository.findById(AdditionalMatchers.not(eq(repoUser.getId())))).thenThrow(new CustomException(Error.USER_NOT_FOUND));
|
||||
// case 2
|
||||
if(userUpdate.getEmail() != null){
|
||||
lenient().when(userRepository.findByEmail(eq(repoUser.getEmail()))).thenThrow(new CustomException(Error.DUPLICATE_USER));
|
||||
lenient().when(userRepository.findByEmail(eq(repoUser.getEmail()))).thenThrow(new CustomException(Error.DUPLICATE_EMAIL));
|
||||
try{
|
||||
userService.updateUser(userUpdate,userAuth);
|
||||
}catch(CustomException e){
|
||||
assertThat(e.getError().equals(Error.DUPLICATE_USER));
|
||||
assertThat(e.getError().getMessage().equals(Error.DUPLICATE_USER.getMessage()));
|
||||
assertThat(e.getError().equals(Error.DUPLICATE_EMAIL));
|
||||
assertThat(e.getError().getMessage().equals(Error.DUPLICATE_EMAIL.getMessage()));
|
||||
}
|
||||
}
|
||||
// case 1
|
||||
|
||||
Reference in New Issue
Block a user