fix: User Repository, Service Refactoring.

This commit is contained in:
minseokkang
2022-12-07 16:12:30 +09:00
10 changed files with 105 additions and 33 deletions

View File

@@ -35,4 +35,31 @@ you can See Vue.js + SpringBoot FullStack Web Site Demo
#### **Total 82% Code Coverage**
------
-----
# How it works
- Spring Boot(Java)
- JPA
- Security
- H2
- Vue3
- Vite
- vuerouter
- vuex
- localStorage
# Getting started
## Run Local
```shell
./gradlew bootRun
```
# FrontEnd
**I don't know much about the front end. I wanted to create a visible application, so I adopted and implemented that framework.**
But my codes are simple codes that even beginners can easily see.

View File

@@ -61,9 +61,10 @@ public class CommentServiceImpl implements CommentService {
if (article.isEmpty()) {
throw new CustomException(Error.ARTICLE_NOT_FOUND);
}
System.out.println(user.get().getUsername()+"!!");
Comment comment = commentRepository.save(Comment.builder().body(commentdto.getBody()).article(article.get()).author(user.get()).build());
return convertComment(userAuth, article.get(), comment);
return convertComment(userAuth, comment);
}
@Override
@@ -80,9 +81,9 @@ public class CommentServiceImpl implements CommentService {
commentRepository.delete(comment.get());
}
private CommentResponse convertComment(UserAuth userAuth, Article article, Comment comment) {
private CommentResponse convertComment(UserAuth userAuth, Comment comment) {
ProfileResponse profile = profileService.getProfile(userAuth, article.getAuthor().getUsername());
ProfileResponse profile = profileService.getProfile(userAuth, userAuth.getUsername());
return CommentResponse.builder()
.id(comment.getId())

View File

@@ -2,9 +2,6 @@ package com.io.realworld.domain.aggregate.user.repository;
import com.io.realworld.domain.aggregate.user.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import java.util.Collection;
import java.util.List;
import java.util.Optional;

View File

@@ -1,7 +1,6 @@
package com.io.realworld.domain.aggregate.user.service;
import com.io.realworld.domain.aggregate.user.dto.*;
import com.io.realworld.domain.aggregate.user.entity.User;
public interface UserService {
UserResponse signup(UserSignupRequest userSignupRequest);

View File

@@ -8,7 +8,6 @@ import com.io.realworld.domain.aggregate.user.entity.User;
import com.io.realworld.domain.aggregate.user.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -17,7 +16,6 @@ import java.util.Optional;
@Service
@RequiredArgsConstructor
@Log4j2
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;

View File

@@ -74,7 +74,7 @@ const createArticle = async (article: object | undefined): Promise<AxiosResponse
})
}
const updateArticle = async (article: object | undefined, slug: string): Promise<AxiosResponse> => {
const updateArticle = async (article: object | undefined, slug: string | undefined): Promise<AxiosResponse> => {
let currentToken = localStorage.getItem("token");
return await axiosService.put('/api/articles/' + slug, { article },{
headers :{
@@ -84,6 +84,16 @@ const updateArticle = async (article: object | undefined, slug: string): Promise
})
}
const deleteArticle = async (slug: string | undefined): Promise<AxiosResponse> => {
let currentToken = localStorage.getItem("token");
return await axiosService.delete('/api/articles/' + slug,{
headers :{
Authorization : "TOKEN " + currentToken,
"Content-Type": `application/json`,
}
})
}
const listArticles = async (): Promise<AxiosResponse> => {
let currentToken = localStorage.getItem("token");
if(currentToken == null){
@@ -171,6 +181,17 @@ const getCommentsFromArticle = async (slug: string | undefined): Promise<AxiosRe
}
}
const deleteCommentsFromArticle = async (slug: string | undefined, id: number): Promise<AxiosResponse> => {
let currentToken = localStorage.getItem("token");
return await axiosService.delete('/api/articles/' + slug + '/comments/' + id,{
headers:{
Authorization : "TOKEN " + currentToken,
"Content-Type": `application/json`,
}
});
}
const favoriteArticle = async (slug: string | undefined): Promise<AxiosResponse> => {
let currentToken = localStorage.getItem("token");
return await axiosService.post('/api/articles/' + slug + '/favorite',{},
@@ -206,5 +227,6 @@ export { signUp, signIn,
addCommentToArticle, getCommentsFromArticle,
favoriteArticle, unFavoriteArticle,
listArticlesByFavorite, updateArticle,
deleteArticle, deleteCommentsFromArticle,
getTags
}

View File

@@ -7,17 +7,21 @@
<a href="javascript:(0)" class="comment-author" @click="viewProfile">
<img :src="comment.author.image" class="comment-author-img"/>
</a>
&nbsp;
<a href="javascript:(0)" class="comment-author" @click="viewProfile">{{comment.author.username}}</a>
<span class="date-posted">{{convertDate(comment.updatedAt)}}</span>
<span v-if="isMe" class="mod-options" @click="deleteComment">
<i class="ion-trash-a"></i>
</span>
</div>
</div>
</template>
<script lang="ts">
import {defineComponent,} from "vue";
import {defineComponent, defineEmits, onMounted, ref,} from "vue";
import convertDate from "@/ts/common";
import router from "@/router";
import {useStore} from "vuex";
export default defineComponent({
name: "commentList",
props:{
@@ -36,7 +40,10 @@ export default defineComponent({
}
}
},
setup(props){
setup(props, {emit}){
const store = useStore();
const isMe = ref(false);
const viewProfile = () => {
router.push({
@@ -44,7 +51,19 @@ export default defineComponent({
params: {username: props.comment.author.username}})
}
return { convertDate, viewProfile}
const deleteComment = () => {
emit('delete:comment', props.comment.id);
}
onMounted(async () => {
if(store.state.username == props.comment.author.username){
isMe.value = true;
}else{
isMe.value = false;
}
})
return { isMe, convertDate, viewProfile, deleteComment}
}
})

View File

@@ -34,7 +34,7 @@ const routes = [
component: () => import(/* webpackChunkName "inputTag" */ '@/views/TheArticle.vue')
},
{
path: "/editor/@:slug",
path: "/editor/:slug",
name: "ArticleUpdateEditor",
component: () => import(/* webpackChunkName "inputTag" */ '@/views/ArticleUpdate.vue'),
props: true

View File

@@ -31,33 +31,29 @@
</template>
<script lang="ts">
import { reactive } from "vue";
import { reactive, defineComponent } from "vue";
import { updateArticle } from "@/api/index.js";
import router from "@/router";
export default {
export default defineComponent({
name: "ArticleUpdate",
props:{
slug: String,
},
setup(){
setup(props){
const article = reactive({
title: "",
description: "",
body: "",
})
const getSlug = (title:string) => {
return title.replace(' ','-');
}
const updateContent = async () => {
const slug = getSlug(article.title);
try{
await updateArticle(article, slug);
const { data } = await updateArticle(article, props.slug);
await router.push({
name:"ArticleDetail",
params: {slug}
params: {slug: data.article.slug}
})
}catch (error: any){
alert(error);
@@ -66,7 +62,7 @@ export default {
return { article, updateContent }
}
}
})
</script>
<style scoped>

View File

@@ -16,7 +16,7 @@
<i class="ion-edit"></i>
Edit Article
</button>
<button v-if= "isMe" class="btn btn-outline-danger btn-sm" @click="followUpdate(articleDetail.article.author.following)">
<button v-if= "isMe" class="btn btn-outline-danger btn-sm" @click="articleDelete()">
<i class="ion-trash-a"></i>
Delete Article
</button>
@@ -62,11 +62,11 @@
<a href="javascript:void(0)" class="author" @click="viewProfile">{{ articleDetail.article.author.username }}</a>
<span class="date">{{convertDate(articleDetail.article.createdAt)}}</span>
</div>
<button v-if= "isMe" class="btn btn-sm btn-outline-secondary" @click="followUpdate(articleDetail.article.author.following)">
<button v-if= "isMe" class="btn btn-sm btn-outline-secondary" @click="articleUpdate()">
<i class="ion-edit"></i>
Edit Article
</button>
<button v-if= "isMe" class="btn btn-outline-danger btn-sm" @click="followUpdate(articleDetail.article.author.following)">
<button v-if= "isMe" class="btn btn-outline-danger btn-sm" @click="articleDelete()">
<i class="ion-trash-a"></i>
Delete Article
</button>
@@ -112,6 +112,7 @@
<comment-list v-for="(comment,index) in getCommentList.comment"
:key="comment.id"
:comment="comment"
@delete:comment="deleteComment"
:imgs="comment.author.image">
</comment-list>
</div>
@@ -130,7 +131,7 @@ import router from "@/router";
import { useStore } from "vuex";
import convertDate from "@/ts/common";
import {
addCommentToArticle,
addCommentToArticle, deleteArticle, deleteCommentsFromArticle,
favoriteArticle,
followUser,
getArticle,
@@ -157,7 +158,7 @@ export default defineComponent({
})
const getCommentList = reactive({
comment: reactive([{id:0,author:{image:""}}])
comment: reactive([{id:0,author:{username:"",image:""}}])
})
const articleDetail = reactive({
@@ -188,11 +189,18 @@ export default defineComponent({
const articleUpdate = async () => {
await router.push({
name: 'ArticleEditor',
name: 'ArticleUpdateEditor',
params: {slug: articleDetail.article.slug}
})
}
const articleDelete = async () => {
await deleteArticle(articleDetail.article.slug);
await router.push({
name: 'Home'
})
}
const followUpdate = async (followState: boolean) => {
if(token == ''){
await router.push({name:"Login"});
@@ -241,6 +249,11 @@ export default defineComponent({
}
}
const deleteComment = async (commentId: number) => {
await deleteCommentsFromArticle(articleDetail.article.slug,commentId);
getCommentList.comment.splice(commentId,1);
}
onMounted(async ()=>{
try{
const { data } = await getArticle(props.slug);
@@ -260,7 +273,7 @@ export default defineComponent({
}
})
return { isMe, articleDetail, comment, getCommentList, convertDate, viewProfile, articleUpdate, followUpdate, favoriteUpdate, sendComment }
return { isMe, articleDetail, comment, getCommentList, convertDate, deleteComment, viewProfile, articleUpdate, followUpdate, favoriteUpdate, sendComment, articleDelete }
}
})
</script>