Merge branch 'master' into 버그픽스_상범

This commit is contained in:
백창훈
2022-03-18 18:09:47 +09:00
committed by GitHub
23 changed files with 377 additions and 58 deletions

View File

@@ -1,5 +1,6 @@
import axios from "axios"; import axios from "axios";
import jwt from "@/common/jwt"; import jwt from "@/common/jwt";
import router from "@/router/router";
export default { export default {
async requestReissue() { async requestReissue() {
@@ -22,5 +23,12 @@ export default {
axios.defaults.headers.common['Authorization'] = "Bearer " + jwt.getToken(); axios.defaults.headers.common['Authorization'] = "Bearer " + jwt.getToken();
return axios.get(process.env.VUE_APP_CUSTOMER_SERVICE_BASEURL+"/user-service/auth/check/access-token"); return axios.get(process.env.VUE_APP_CUSTOMER_SERVICE_BASEURL+"/user-service/auth/check/access-token");
},
logout(){
axios.post(process.env.VUE_APP_CUSTOMER_SERVICE_BASEURL+"/user-service/auth/logout",'',{headers: {"X-AUTH-TOKEN": jwt.getToken(),}})
.finally(()=>{
router.push('/login')
jwt.destroyAll()
})
} }
} }

View File

@@ -41,5 +41,12 @@ export default {
}, },
requestStore(storeId) { requestStore(storeId) {
return axios.get(process.env.VUE_APP_CUSTOMER_SERVICE_BASEURL + "/store-service/store/" + storeId); return axios.get(process.env.VUE_APP_CUSTOMER_SERVICE_BASEURL + "/store-service/store/" + storeId);
},
getFavoriteStoreByStoreId(storeId) {
return axios.get(process.env.VUE_APP_CUSTOMER_SERVICE_BASEURL + "/store-service/api/customer/favoriteStore/" + storeId);
},
markStar(storeId) {
return axios.patch(process.env.VUE_APP_CUSTOMER_SERVICE_BASEURL + "/store-service/api/customer/favoriteStore/" + storeId);
} }
} }

View File

@@ -23,6 +23,9 @@ export default {
localStorage.removeItem(EXPIRED_TIME_NAME); localStorage.removeItem(EXPIRED_TIME_NAME);
}, },
isExpired() { isExpired() {
if(this.getExpiredTime() == null || this.getToken() == null)
return true;
const expiredTime = this.getExpiredTime(); const expiredTime = this.getExpiredTime();
const expiredMoment = moment(expiredTime); const expiredMoment = moment(expiredTime);

View File

@@ -6,7 +6,7 @@
elevation="1" elevation="1"
> >
<v-app-bar-nav-icon> <v-app-bar-nav-icon @click="$router.back()">
<v-icon>mdi-arrow-left</v-icon> <v-icon>mdi-arrow-left</v-icon>
</v-app-bar-nav-icon> </v-app-bar-nav-icon>
<v-spacer></v-spacer> <v-spacer></v-spacer>
@@ -29,16 +29,31 @@
<v-icon>mdi-bell-outline</v-icon> <v-icon>mdi-bell-outline</v-icon>
</v-badge> </v-badge>
</v-btn> </v-btn>
<v-btn
color="white"
elevation="0"
@click="logout"
>
<v-icon>mdi-logout</v-icon>
</v-btn>
</v-app-bar> </v-app-bar>
</template> </template>
<script> <script>
import authApi from "@/api/auth";
export default { export default {
name: "AppNavigation", name: "AppNavigation",
props: ["notificationCounts"], props: ["notificationCounts"],
methods: { methods: {
goNotification: function() { goNotification: function() {
this.$router.push('/notification'); this.$router.push('/notification');
},
logout: function () {
if(confirm("로그아웃하시겠습니까?")){
authApi.logout();
}
} }
} }
} }

View File

@@ -15,16 +15,69 @@
<b>{{store.name}}</b> <b>{{store.name}}</b>
</v-toolbar-title> </v-toolbar-title>
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn icon> <v-btn
<v-icon>mdi-magnify</v-icon> icon
@click="markStar()"
>
<v-icon
:color="favoriteStore.color"
>{{ favoriteStore.icon }}</v-icon>
</v-btn> </v-btn>
</v-app-bar> </v-app-bar>
</template> </template>
<script> <script>
import storeApi from "@/api/store";
export default { export default {
name: "StoreNavigation", name: "StoreNavigation",
props: ["store"], props: ["store"],
data: function() {
return {
storeId:-1,
favoriteStore:{
status:true,
color:null,
icon: 'mdi-heart-outline'
}
}
},
methods:{
markStar:function () {
this.changeStarStatus()
var vm = this
storeApi.markStar(this.storeId)
.then(()=>{
vm.favoriteStore.status?
alert('즐겨찾는 매장에서 제외되었습니다.') : alert('즐겨찾는 매장에 등록되었습니다.')
})
},
getFavoriteStoreByStoreId: function (storeId){
var vm = this
storeApi.getFavoriteStoreByStoreId(storeId)
.then((response)=>{
if(response.data.data.exist) vm.changeStarStatus()
})
},
changeStarStatus(){
if(this.favoriteStore.status){
this.favoriteStore.color = "rgb(255, 152, 0)"
this.favoriteStore.icon = "mdi-heart"
}else{
this.favoriteStore.color = null
this.favoriteStore.icon = "mdi-heart-outline"
}
this.favoriteStore.status= !this.favoriteStore.status
}
},
mounted() {
console.log(this.$route.params)
this.storeId =this.$route.params.storeId
this.getFavoriteStoreByStoreId(this.storeId)
}
} }
</script> </script>

View File

@@ -32,51 +32,63 @@ const routes = [
{ {
path: '/', path: '/',
redirect: 'home', redirect: 'home',
beforeEnter: authCheck,
component: HomeLayout, component: HomeLayout,
children: [ children: [
{ {
path: "/home", path: "/home",
beforeEnter: authCheck,
name: 'home', name: 'home',
beforeEnter: authCheck, beforeEnter: authCheck,
component: () => import('../views/HomeView') component: () => import('../views/HomeView')
}, },
{ {
path: "/search", path: "/search",
beforeEnter: authCheck,
name: 'search-store', name: 'search-store',
beforeEnter: authCheck, beforeEnter: authCheck,
component: () => import('../views/SearchStore') component: () => import('../views/SearchStore')
}, },
{ {
path: "/history", path: "/history",
beforeEnter: authCheck,
name: 'order-history', name: 'order-history',
beforeEnter: authCheck, beforeEnter: authCheck,
component: () => import('../views/OrderHistory') component: () => import('../views/OrderHistory')
}, },
{ {
path: "/favorite", path: "/favorite",
beforeEnter: authCheck,
name: 'favorite-store', name: 'favorite-store',
beforeEnter: authCheck, beforeEnter: authCheck,
component: () => import('../views/FavoriteStore') component: () => import('../views/FavoriteStore')
}, },
{ {
path: "/notification", path: "/notification",
beforeEnter: authCheck,
name: 'notification', name: 'notification',
beforeEnter: authCheck, beforeEnter: authCheck,
component: () => import('../views/NotificationView') component: () => import('../views/NotificationView')
}, },
{ {
path: "/item/:itemId", path: "/item/:itemId",
beforeEnter: authCheck,
name: 'itemDetail', name: 'itemDetail',
beforeEnter: authCheck, beforeEnter: authCheck,
component: () => import('../views/ItemDetail') component: () => import('../views/ItemDetail')
}, },
{ {
path: "/order", path: "/order",
beforeEnter: authCheck,
name: 'orderPage', name: 'orderPage',
beforeEnter: authCheck, beforeEnter: authCheck,
component: () => import('../views/OrderPage') component: () => import('../views/OrderPage')
}, },
{
path: "/mypage",
beforeEnter: authCheck,
name: 'mypage',
component: () => import('../views/MyPage')
},
] ]
}, },
{ {
@@ -87,12 +99,12 @@ const routes = [
{ {
path: '/store', path: '/store',
redirect: 'store', redirect: 'store',
beforeEnter: authCheck,
component: StoreLayout, component: StoreLayout,
children: [ children: [
{ {
path: "/store/:storeId", path: "/store/:storeId",
name: "store", name: "store",
beforeEnter: authCheck,
component: () => import('../views/StoreView'), component: () => import('../views/StoreView'),
props: true props: true
}, },

View File

@@ -36,6 +36,7 @@
<v-col > <v-col >
<v-container> <v-container>
<v-text-field <v-text-field
readonly
v-model="setItem.count" v-model="setItem.count"
append-outer-icon="mdi-plus" append-outer-icon="mdi-plus"
prepend-icon="mdi-minus" prepend-icon="mdi-minus"
@@ -111,7 +112,7 @@ export default {
itemOptions:[], itemOptions:[],
}, },
setItem:{ setItem:{
count:0, count:1,
storeId:-1, storeId:-1,
itemId:-1, itemId:-1,
price:0, price:0,
@@ -145,9 +146,12 @@ export default {
}, },
addItemCount: function (v){ addItemCount: function (v){
this.setItem.count = this.setItem.count =
this.setItem.count+v >=0? this.setItem.count+v: 0; this.setItem.count+v >=1? this.setItem.count+v: 1;
}, },
addItem: function(){ addItem: function(){
if(!this.validItem())
return;
orderApi.addItemToBasket(this.setItem) orderApi.addItemToBasket(this.setItem)
.then(response=>{ .then(response=>{
console.log(response) console.log(response)
@@ -156,7 +160,16 @@ export default {
.catch(error=>{ .catch(error=>{
console.log(error.response) console.log(error.response)
}) })
},
validItem(){
if(this.setItem.count <= 0 || isNaN(this.setItem.count)){
alert("수량이 잘못되었습니다.")
this.setItem.count =1
return false
}
} }
}, },
} }
</script> </script>

View File

@@ -120,7 +120,6 @@ export default {
}, },
}, },
async mounted() { async mounted() {
if (!jwt.isExpired()) if (!jwt.isExpired())
await router.push("/"); await router.push("/");

View File

@@ -56,11 +56,6 @@
@click="saveOrder" @click="saveOrder"
color="primary" color="primary"
>주문하기</v-btn> >주문하기</v-btn>
<!-- <v-btn-->
<!-- style="position: absolute; bottom: 0;transform: translateY(-100%); width: 100%"-->
<!-- @click="orderItems"-->
<!-- >주문하기</v-btn>-->
</div> </div>
</template> </template>
@@ -90,10 +85,12 @@ export default {
orderApi.saveOrder() orderApi.saveOrder()
.then(()=>{ .then(()=>{
this.$emit('plusCount')
alert('주문되었습니다.') alert('주문되었습니다.')
this.$router.push("/history") this.$router.push("/history")
}) })
.catch(error=>{ .catch(error=>{
alert("문제가 발생하였습니다. 다시 시도해보세요.")
console.log(error) console.log(error)
//this.$router.replace("/") //this.$router.replace("/")
}) })
@@ -105,8 +102,9 @@ export default {
this.orderData=response.data.data this.orderData=response.data.data
}) })
.catch(error=>{ .catch(error=>{
alert("장바구니에 상품이 없습니다.")
this.$router.back();
console.log(error.response) console.log(error.response)
history.back();
}) })
}, },
} }

View File

@@ -28,6 +28,7 @@
class="mx-auto mb-5" class="mx-auto mb-5"
outlined outlined
v-for="item in category.items" v-for="item in category.items"
@click="itemDetail(item.id)"
:key="item.id" :key="item.id"
> >
<v-list-item three-line> <v-list-item three-line>
@@ -91,6 +92,9 @@ export default {
this.tags.push(category.name); this.tags.push(category.name);
}) })
}, },
itemDetail: function (itemId) {
this.$router.push("/item/"+itemId)
}
} }
} }
</script> </script>

View File

@@ -20,7 +20,8 @@ export default {
return axios.get(process.env.VUE_APP_OWNER_SERVICE_BASEURL+'/store-service/api/owner/item/'+itemId) return axios.get(process.env.VUE_APP_OWNER_SERVICE_BASEURL+'/store-service/api/owner/item/'+itemId)
}, },
saveItem(method, itemData){ saveItem(method, itemData){
const _url = process.env.VUE_APP_OWNER_SERVICE_BASEURL+'/store-service/api/owner/item'+(method==='put'?+"/"+itemData.itemId:'') const _url = process.env.VUE_APP_OWNER_SERVICE_BASEURL+'/store-service/api/owner/item'+(method==='put'? "/"+itemData.itemId:'')
return axios({ return axios({
method:method, method:method,
url: _url, url: _url,

View File

@@ -163,6 +163,7 @@ export default {
}, },
methods:{ methods:{
save : function () { save : function () {
this.dialog =false
this.$emit('save') this.$emit('save')
}, },
addItemOption : function (itemOptionValue,optionType){ addItemOption : function (itemOptionValue,optionType){

View File

@@ -1,9 +1,8 @@
<template> <template>
<v-app id="inspire"> <v-app id="inspire">
<side-bar v-bind:drawer="drawer"></side-bar> <side-bar :drawer="drawer"></side-bar>
<top-bar v-on:drawEvent="drawer = !drawer" <top-bar @drawerEvent="drawer = !drawer"
:notificationCounts="notificationCounts" :notificationCounts="notificationCounts"/>
></top-bar>
<v-main style="background: #f5f5f540"> <v-main style="background: #f5f5f540">
<v-container class="py-8, px-6" fluid> <v-container class="py-8, px-6" fluid>
<router-view <router-view

View File

@@ -5,20 +5,9 @@
app> app>
<v-img <v-img
height="140" height="140"
class="pa-4" class="px-7 mx-7"
src="https://preview.pixlr.com/images/800wm/1439/2/1439104804.jpg" :src="require('@/assets/just-logo.png')"
contain/>
>
<div class="text-center">
<v-avatar class="mb-4" color="grey darken-1" size="64">
<v-img
aspect-ratio="30"
src="https://yt3.ggpht.com/esazPAO03T0f0vKdByJvkDy6MSwjyG5f-c_2S2CJapszQ3KPQyZarpoqvgv0Us0atUbILytj=s88-c-k-c0x00ffffff-no-rj"
/>
</v-avatar>
<h2 class="white--text">Web Burden</h2>
</div>
</v-img>
<v-divider></v-divider> <v-divider></v-divider>
<v-list> <v-list>
<v-list-item v-for="(link,index) in links" :key="link.icon" link @click="clickGo(index, link.url)"> <v-list-item v-for="(link,index) in links" :key="link.icon" link @click="clickGo(index, link.url)">
@@ -41,10 +30,10 @@ export default {
data() { data() {
return { return {
links: [ links: [
{name: "지난 주문", url: "/prev-order", icon: "mdi-home-outline"}, {name: "지난 주문", url: "/prev-order", icon: "mdi-clipboard-check-outline"},
{name: "카테고리", url: "/category", icon: "mdi-magnify"}, {name: "카테고리", url: "/category", icon: "mdi-shape-outline"},
{name: "주문", url: "/order", icon: "mdi-cards-heart"}, {name: "주문", url: "/order", icon: "mdi-order-numeric-ascending"},
{name: "메뉴 관리", url: "/menu", icon: "mdi-cards-heart-outline"}, {name: "메뉴 관리", url: "/menu", icon: "mdi-cog-outline"},
], ],
}; };
}, },

View File

@@ -75,7 +75,6 @@ operation::items-get[snippets='curl-request,http-request,http-response,path-para
== 상품 (판매자) == 상품 (판매자)
=== 상품 조회 === 상품 조회
=======
=== 상품 리스트 조회(구매자) === 상품 리스트 조회(구매자)
operation::customer-itemList-get[snippets='curl-request,http-request,http-response,path-parameters,response-fields'] operation::customer-itemList-get[snippets='curl-request,http-request,http-response,path-parameters,response-fields']
@@ -109,3 +108,9 @@ operation::store-get[snippets='curl-request,http-request,http-response,path-para
operation::api-get-store-byUserId[snippets='curl-request,http-request,http-response,request-headers,response-fields'] operation::api-get-store-byUserId[snippets='curl-request,http-request,http-response,request-headers,response-fields']
=== 매장 리스트 조회 === 매장 리스트 조회
operation::stores-get[snippets='curl-request,http-request,http-response,path-parameters,response-fields'] operation::stores-get[snippets='curl-request,http-request,http-response,path-parameters,response-fields']
== 즐겨찾는 매장
=== 즐겨찾는 매장 조회
operation::get-favoritestore-by-storeid[snippets='curl-request,http-request,http-response,request-headers,path-parameters,response-fields']
=== 즐겨찾는 매장 추가/삭제
operation::patch-FavoriteStore[snippets='curl-request,http-request,http-response,request-headers,path-parameters']

View File

@@ -0,0 +1,14 @@
package com.justpickup.storeservice.domain.favoritestore.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class GetFavoriteStoreByStoreIdDto {
private Long userId;
private Long storeId;
private boolean isExist;
}

View File

@@ -1,7 +1,12 @@
package com.justpickup.storeservice.domain.favoritestore.repository; package com.justpickup.storeservice.domain.favoritestore.repository;
import com.justpickup.storeservice.domain.favoritestore.entity.FavoriteStore; import com.justpickup.storeservice.domain.favoritestore.entity.FavoriteStore;
import com.justpickup.storeservice.domain.store.entity.Store;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface FavoriteStoreRepository extends JpaRepository<FavoriteStore,Long> { public interface FavoriteStoreRepository extends JpaRepository<FavoriteStore,Long> {
Optional<FavoriteStore> findByUserIdAndStore(Long userId, Store store);
} }

View File

@@ -0,0 +1,55 @@
package com.justpickup.storeservice.domain.favoritestore.service;
import com.justpickup.storeservice.domain.favoritestore.dto.GetFavoriteStoreByStoreIdDto;
import com.justpickup.storeservice.domain.favoritestore.entity.FavoriteStore;
import com.justpickup.storeservice.domain.favoritestore.repository.FavoriteStoreRepository;
import com.justpickup.storeservice.domain.store.entity.Store;
import com.justpickup.storeservice.domain.store.exception.NotExistStoreException;
import com.justpickup.storeservice.domain.store.repository.StoreRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
@Slf4j
@RequiredArgsConstructor
@Service
public class FavoriteStoreService {
private final FavoriteStoreRepository favoriteStoreRepository;
private final StoreRepository storeRepository;
@Transactional
public void patchFavoriteStore(Long userId, Long storeId){
Store store = storeRepository.findById(storeId)
.orElseThrow(()-> new NotExistStoreException("매장이 존재하지않습니다."));
favoriteStoreRepository
.findByUserIdAndStore(userId, store)
.ifPresentOrElse(
favoriteStoreRepository::delete,
()->favoriteStoreRepository.save(FavoriteStore.of(userId, store))
);
}
@Transactional
public GetFavoriteStoreByStoreIdDto getFavoriteStoreByStoreId(Long userId, Long storeId){
Store store = storeRepository.findById(storeId)
.orElseThrow(()-> new NotExistStoreException("매장이 존재하지않습니다."));
Optional<FavoriteStore> byUserIdAndStore = favoriteStoreRepository
.findByUserIdAndStore(userId, store);
if(byUserIdAndStore.isPresent()){
return new GetFavoriteStoreByStoreIdDto(userId,storeId, true);
}else {
return new GetFavoriteStoreByStoreIdDto(userId,storeId, false);
}
}
}

View File

@@ -0,0 +1,40 @@
package com.justpickup.storeservice.domain.favoritestore.web;
import com.justpickup.storeservice.domain.favoritestore.dto.GetFavoriteStoreByStoreIdDto;
import com.justpickup.storeservice.domain.favoritestore.service.FavoriteStoreService;
import com.justpickup.storeservice.global.dto.Result;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@Slf4j
@RequiredArgsConstructor
@RequestMapping("/api/customer/favoriteStore")
public class FavoriteStoreCustomerApiController {
private final FavoriteStoreService favoriteStoreService;
@GetMapping("/{storeId}")
public ResponseEntity getFavoriteStoreByStoreId(@RequestHeader(value = "user-id") String userId, @PathVariable Long storeId){
GetFavoriteStoreByStoreIdDto favoriteStoreByStoreId = favoriteStoreService.getFavoriteStoreByStoreId(Long.parseLong(userId), storeId);
return ResponseEntity
.status(HttpStatus.OK)
.body(Result.createSuccessResult(favoriteStoreByStoreId));
}
@PatchMapping("/{storeId}")
public ResponseEntity patchFavoriteStore(@RequestHeader(value = "user-id") String userId, @PathVariable Long storeId){
favoriteStoreService.patchFavoriteStore(Long.parseLong(userId),storeId);
return ResponseEntity
.status(HttpStatus.NO_CONTENT)
.body(Result.success());
}
}

View File

@@ -48,24 +48,22 @@ public class ItemRepositoryCustom {
Long count = queryFactory.select(QItem.item.count()) Long count = queryFactory.select(QItem.item.count())
.from(QItem.item) .from(QItem.item)
.join(QItem.item.category) .join(QItem.item.category)
.leftJoin(QItem.item.store) .join(QItem.item.store)
.on(QItem.item.store.userId.eq(userId))
.where( .where(
QItem.item.name.contains(word) QItem.item.name.contains(word)
.or(QItem.item.category.name.contains(word)) .or(QItem.item.category.name.contains(word)),
QItem.item.store.userId.eq(userId)
) )
.limit(pageable.getPageSize())
.offset(pageable.getOffset())
.fetchOne(); .fetchOne();
//List 가져오기 //List 가져오기
List<Item> itemList = queryFactory.selectFrom(QItem.item) List<Item> itemList = queryFactory.selectFrom(QItem.item)
.join(QItem.item.category).fetchJoin() .join(QItem.item.category).fetchJoin()
.leftJoin(QItem.item.store) .join(QItem.item.store)
.on(QItem.item.store.id.eq(userId))
.where( .where(
QItem.item.name.contains(word) QItem.item.name.contains(word)
.or(QItem.item.category.name.contains(word)) .or(QItem.item.category.name.contains(word)),
QItem.item.store.userId.eq(userId)
) )
.limit(pageable.getPageSize()) .limit(pageable.getPageSize())
.offset(pageable.getOffset()) .offset(pageable.getOffset())

View File

@@ -91,7 +91,7 @@ public class ItemServiceImpl implements ItemService {
itemOptionDtos itemOptionDtos
.forEach(itemOptionDto -> { .forEach(itemOptionDto -> {
if(itemOptionDto.getId()==null) return; if(itemOptionDto.getId()!=null) return;
if (itemOptionRepository.existsById(itemOptionDto.getId())) if (itemOptionRepository.existsById(itemOptionDto.getId()))
itemOptionRepository.save(ItemOptionDto.createItemOption(itemOptionDto, item)); itemOptionRepository.save(ItemOptionDto.createItemOption(itemOptionDto, item));
}); });

View File

@@ -0,0 +1,111 @@
package com.justpickup.storeservice.domain.favoritestore.web;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.justpickup.storeservice.config.TestConfig;
import com.justpickup.storeservice.domain.favoritestore.dto.GetFavoriteStoreByStoreIdDto;
import com.justpickup.storeservice.domain.favoritestore.service.FavoriteStoreService;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.BDDMockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName;
import static org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.patch;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
import static org.springframework.restdocs.request.RequestDocumentation.pathParameters;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@WebMvcTest(FavoriteStoreCustomerApiController.class)
@Import(TestConfig.class)
@AutoConfigureRestDocs(uriHost = "just-pickup.com", uriPort = 8000)
class FavoriteStoreCustomerApiControllerTest {
@Autowired
ObjectMapper objectMapper;
@Autowired
MockMvc mockMvc;
@MockBean
FavoriteStoreService favoriteStoreService;
@Test
@DisplayName("Get_즐겨찾는 매장")
void getFavoriteStoreByStoreId() throws Exception {
//given
Long userId=1L;
Long storeId=1L;
BDDMockito.given(favoriteStoreService
.getFavoriteStoreByStoreId(userId,storeId))
.willReturn(
new GetFavoriteStoreByStoreIdDto(userId,storeId,true));
//when
ResultActions resultActions = mockMvc.perform(
get("/api/customer/favoriteStore/{storeId}",storeId)
.header("user-id", userId));
//then
resultActions.andExpect(status().isOk())
.andDo(print())
.andDo(document("get-favoritestore-by-storeid",
requestHeaders(
headerWithName("user-id").description("로그인한 유저 id")
),
pathParameters(
parameterWithName("storeId").description("매장 고유 번호")
),
responseFields(
fieldWithPath("code").description("결과 코드 SUCCESS/ERROR"),
fieldWithPath("message").description("메시지"),
fieldWithPath("data.userId").description("유저 고유번호"),
fieldWithPath("data.storeId").description("매장 고유 번호"),
fieldWithPath("data.exist").description("즐겨찾기 매장 존재여부")
))
);
}
@Test
@DisplayName("즐겨찾는 매장 추가 or 제거")
void patchFavoriteStore() throws Exception {
//given
Long userId=1L;
Long storeId=1L;
//when
ResultActions resultActions = mockMvc.perform(
patch("/api/customer/favoriteStore/{storeId}",storeId)
.header("user-id", userId));
//then
resultActions.andExpect(status().isNoContent())
.andDo(print())
.andDo(document("patch-FavoriteStore",
requestHeaders(
headerWithName("user-id").description("로그인한 유저 id")
),
pathParameters(
parameterWithName("storeId").description("매장 고유 번호")
)
)
);
}
}

View File

@@ -1,11 +1,9 @@
package com.justpickup.userservice.domain.jwt.service; package com.justpickup.userservice.domain.jwt.service;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.justpickup.userservice.domain.user.dto.OAuthAttributeDto; import com.justpickup.userservice.domain.user.dto.OAuthAttributeDto;
import com.justpickup.userservice.domain.user.entity.Customer; import com.justpickup.userservice.domain.user.entity.Customer;
import com.justpickup.userservice.domain.user.repository.CustomerRepository; import com.justpickup.userservice.domain.user.repository.CustomerRepository;
import com.justpickup.userservice.domain.user.service.UserServiceImpl; import com.justpickup.userservice.domain.user.service.UserServiceImpl;
import com.justpickup.userservice.global.dto.Result;
import com.justpickup.userservice.global.utils.CookieProvider; import com.justpickup.userservice.global.utils.CookieProvider;
import com.justpickup.userservice.global.utils.JwtTokenProvider; import com.justpickup.userservice.global.utils.JwtTokenProvider;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@@ -30,8 +28,6 @@ import java.io.IOException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Collection; import java.util.Collection;
import java.util.Date; import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
@@ -42,8 +38,6 @@ import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
public class OAuthService implements OAuth2UserService<OAuth2UserRequest, OAuth2User> { public class OAuthService implements OAuth2UserService<OAuth2UserRequest, OAuth2User> {
private final CustomerRepository customerRepository; private final CustomerRepository customerRepository;
private final HttpServletResponse response;
private final HttpServletRequest request;
private final JwtTokenProvider jwtTokenProvider; private final JwtTokenProvider jwtTokenProvider;
private final RefreshTokenService refreshTokenService; private final RefreshTokenService refreshTokenService;
private final UserServiceImpl userServiceImpl; private final UserServiceImpl userServiceImpl;
@@ -71,11 +65,6 @@ public class OAuthService implements OAuth2UserService<OAuth2UserRequest, OAuth2
Collection<? extends GrantedAuthority> authorities = userServiceImpl.loadUserByUsername(userEmail).getAuthorities(); Collection<? extends GrantedAuthority> authorities = userServiceImpl.loadUserByUsername(userEmail).getAuthorities();
List<String> roles = authorities
.stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.toList());
return new DefaultOAuth2User( return new DefaultOAuth2User(
authorities authorities
, attributeDto.getAttributes() , attributeDto.getAttributes()