Skip to content

Commit 56023bd

Browse files
committed
implemented tempsave delete and edit post from write
1 parent d8284d7 commit 56023bd

File tree

7 files changed

+127
-40
lines changed

7 files changed

+127
-40
lines changed

velog-backend/src/router/posts/post/post.ctrl.js

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,25 @@ import type { Context } from 'koa';
33
import { serializePost } from 'database/models/Post';
44
import db from 'database/db';
55
import Joi from 'joi';
6-
import { validateSchema, generateSlugId, escapeForUrl, extractKeys } from 'lib/common';
6+
import {
7+
validateSchema,
8+
generateSlugId,
9+
escapeForUrl,
10+
extractKeys,
11+
} from 'lib/common';
712
import { diff } from 'json-diff';
8-
import { Post, PostLike, PostsTags, PostsCategories, Category } from 'database/models';
9-
10-
11-
export const checkPostExistancy = async (ctx: Context, next: () => Promise<*>): Promise<*> => {
13+
import {
14+
Post,
15+
PostLike,
16+
PostsTags,
17+
PostsCategories,
18+
Category,
19+
} from 'database/models';
20+
21+
export const checkPostExistancy = async (
22+
ctx: Context,
23+
next: () => Promise<*>,
24+
): Promise<*> => {
1225
const { id } = ctx.params;
1326
try {
1427
const post = await Post.findById(id);
@@ -54,16 +67,22 @@ export const updatePost = async (ctx: Context): Promise<*> => {
5467
url_slug: string,
5568
thumbnail: string,
5669
is_temp: boolean,
57-
}
70+
meta: any,
71+
};
5872

5973
const schema = Joi.object().keys({
60-
title: Joi.string().min(1).max(120),
74+
title: Joi.string()
75+
.min(1)
76+
.max(120),
6177
body: Joi.string().min(1),
62-
thumbnail: Joi.string().uri().allow(null),
78+
thumbnail: Joi.string()
79+
.uri()
80+
.allow(null),
6381
is_temp: Joi.boolean(),
6482
categories: Joi.array().items(Joi.string()),
6583
tags: Joi.array().items(Joi.string()),
6684
url_slug: Joi.string().max(130),
85+
meta: Joi.object(),
6786
});
6887

6988
if (!validateSchema(ctx, schema)) {
@@ -78,16 +97,16 @@ export const updatePost = async (ctx: Context): Promise<*> => {
7897
url_slug: urlSlug,
7998
thumbnail,
8099
is_temp: isTemp,
100+
meta,
81101
}: BodySchema = (ctx.request.body: any);
82102

83103
const generatedUrlSlug = `${title} ${generateSlugId()}`;
84104
const escapedUrlSlug = escapeForUrl(urlSlug || generatedUrlSlug);
85105

86-
87106
const { id } = ctx.params;
88107

89-
const urlSlugShouldChange = urlSlug !== ctx.post.url_slug
90-
|| (title && (ctx.post.title !== title));
108+
const urlSlugShouldChange =
109+
urlSlug !== ctx.post.url_slug || (title && ctx.post.title !== title);
91110

92111
// current !== received -> check urlSlugExistancy
93112
if (urlSlugShouldChange) {
@@ -110,6 +129,7 @@ export const updatePost = async (ctx: Context): Promise<*> => {
110129
url_slug: urlSlugShouldChange && escapedUrlSlug,
111130
thumbnail,
112131
is_temp: isTemp,
132+
meta,
113133
};
114134

115135
Object.keys(updateQuery).forEach((key) => {
@@ -125,8 +145,12 @@ export const updatePost = async (ctx: Context): Promise<*> => {
125145
const tagNames = currentTags.tags.map(tag => tag.name);
126146
const tagDiff = diff(tagNames.sort(), tags.sort()) || [];
127147

128-
const tagsToRemove = tagDiff.filter(info => info[0] === '-').map(info => info[1]);
129-
const tagsToAdd = tagDiff.filter(info => info[0] === '+').map(info => info[1]);
148+
const tagsToRemove = tagDiff
149+
.filter(info => info[0] === '-')
150+
.map(info => info[1]);
151+
const tagsToAdd = tagDiff
152+
.filter(info => info[0] === '+')
153+
.map(info => info[1]);
130154

131155
try {
132156
await PostsTags.removeTagsFromPost(id, tagsToRemove);
@@ -158,9 +182,14 @@ export const updatePost = async (ctx: Context): Promise<*> => {
158182

159183
// check which categories to remove or add
160184
const currentCategories = await ctx.post.getCategoryIds();
161-
const categoryDiff = diff(currentCategories.sort(), categories.sort()) || [];
162-
const categoriesToRemove = categoryDiff.filter(info => info[0] === '-').map(info => info[1]);
163-
const categoriesToAdd = categoryDiff.filter(info => info[0] === '+').map(info => info[1]);
185+
const categoryDiff =
186+
diff(currentCategories.sort(), categories.sort()) || [];
187+
const categoriesToRemove = categoryDiff
188+
.filter(info => info[0] === '-')
189+
.map(info => info[1]);
190+
const categoriesToAdd = categoryDiff
191+
.filter(info => info[0] === '+')
192+
.map(info => info[1]);
164193

165194
await PostsCategories.removeCategoriesFromPost(id, categoriesToRemove);
166195
await PostsCategories.addCategoriesToPost(id, categoriesToAdd);
@@ -195,7 +224,9 @@ export const deletePost = async (ctx: Context): Promise<*> => {
195224
try {
196225
// LATER ON: REMOVE COMMENTS
197226
await Promise.all([
198-
db.getQueryInterface().bulkDelete('posts_categories', { fk_post_id: post.id }),
227+
db
228+
.getQueryInterface()
229+
.bulkDelete('posts_categories', { fk_post_id: post.id }),
199230
db.getQueryInterface().bulkDelete('posts_tags', { fk_post_id: post.id }),
200231
db.getQueryInterface().bulkDelete('post_likes', { fk_post_id: post.id }),
201232
]);

velog-frontend/src/containers/saves/SavePostCardListContainer.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,16 @@ class SavePostCardListContainer extends Component<Props> {
8686
CommonActions.askRemove(postId);
8787
};
8888

89+
onConfirmRemove = async () => {
90+
const { removeId } = this.props;
91+
if (!removeId) return;
92+
CommonActions.removePost(removeId);
93+
ListingActions.removeTempPost(removeId);
94+
CommonActions.closeRemove();
95+
};
96+
8997
onCancelRemove = () => {
90-
console.log('하이');
91-
CommonActions.cancelRemove();
98+
CommonActions.closeRemove();
9299
};
93100

94101
render() {
@@ -101,7 +108,7 @@ class SavePostCardListContainer extends Component<Props> {
101108
title="임시 글 삭제"
102109
description="이 포스트를 정말로 삭제하시겠습니까?"
103110
confirmText="삭제"
104-
onConfirm={() => null}
111+
onConfirm={this.onConfirmRemove}
105112
onCancel={this.onCancelRemove}
106113
/>
107114
</Fragment>

velog-frontend/src/containers/write/WriteHeaderContainer.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import type { PostData, Category } from 'store/modules/write';
88
import { Prompt, withRouter, type ContextRouter } from 'react-router-dom';
99
import { compose } from 'redux';
1010
import Blocker from 'components/common/Blocker';
11+
import queryString from 'query-string';
12+
1113

1214
type Props = {
1315
title: string,
@@ -23,8 +25,17 @@ type Props = {
2325
class WriteHeaderContainer extends Component<Props> {
2426
timer = null;
2527

28+
loadPost = (id: string) => {
29+
WriteActions.getPostById(id);
30+
}
31+
2632
componentDidMount() {
2733
this.timer = setInterval(this.autoTempSave, 30000);
34+
// reads edit_id
35+
const query = queryString.parse(this.props.location.search);
36+
if (query.edit_id) {
37+
this.loadPost(query.edit_id);
38+
}
2839
}
2940

3041
componentWillUnmount() {

velog-frontend/src/lib/api/posts/index.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,11 @@ export const getTempPosts = ({ username, cursor }: GetTempPostsPayload) => {
113113
});
114114
return axios.get(`/posts/@${username}?${query}`);
115115
};
116+
117+
export const deletePost = (postId: string) => {
118+
return axios.delete(`/posts/${postId}`);
119+
};
120+
121+
export const getPostById = (postId: string) => {
122+
return axios.get(`/posts/${postId}`);
123+
};

velog-frontend/src/store/modules/common.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@ import { createAction, handleActions, type ActionType } from 'redux-actions';
33
import { applyPenders, type GenericResponseAction } from 'lib/common';
44
import * as CommonAPI from 'lib/api/common';
55
import produce from 'immer';
6+
import * as PostsAPI from 'lib/api/posts';
67

78
const GET_TAGS = 'common/GET_TAGS';
89
const SET_TAG_INFO = 'common/SET_TAG_INFO';
910
const GET_TAG_INFO = 'common/GET_TAG_INFO';
1011
const ASK_REMOVE = 'common/saves/ASK_REMOVE';
11-
const CONFIRM_REMOVE = 'common/saves/CONFIRM_REMOVE';
12-
const CANCEL_REMOVE = 'common/saves/CANCEL_REMOVE';
12+
const CLOSE_REMOVE = 'common/saves/CLOSE_REMOVE';
13+
const REMOVE_POST = 'common/saves/REMOVE_POST';
1314

1415
export type TagData = {
1516
name: string,
@@ -21,7 +22,8 @@ export const actionCreators = {
2122
setTagInfo: createAction(SET_TAG_INFO, (info: ?TagData) => info),
2223
getTagInfo: createAction(GET_TAG_INFO, CommonAPI.getTagInfo),
2324
askRemove: createAction(ASK_REMOVE, (postId: string) => postId),
24-
cancelRemove: createAction(CANCEL_REMOVE),
25+
closeRemove: createAction(CLOSE_REMOVE),
26+
removePost: createAction(REMOVE_POST, PostsAPI.deletePost),
2527
};
2628

2729
type GetTagsResponseAction = GenericResponseAction<TagData[], string>;
@@ -68,7 +70,7 @@ const reducer = handleActions(
6870
draft.saves.removeId = payload;
6971
});
7072
},
71-
[CANCEL_REMOVE]: (state) => {
73+
[CLOSE_REMOVE]: (state) => {
7274
return produce(state, (draft) => {
7375
draft.saves.ask = false;
7476
});

velog-frontend/src/store/modules/listing.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const PREFETCH_TAG_POSTS = 'listing/PREFETCH_TAG_POSTS';
1717
const CLEAR_TAG_POSTS = 'listing/CLEAR_TAG_POSTS';
1818
const GET_TEMP_POSTS = 'listing/GET_TEMP_POSTS';
1919
const PREFETCH_TEMP_POSTS = 'listing/PREFETCH_TEMP_POSTS';
20+
const REMOVE_TEMP_POST = 'listing/REMOVE_TEMP_POST';
2021

2122
// potential improvement :: remove duplicates
2223
export const actionCreators = {
@@ -33,6 +34,7 @@ export const actionCreators = {
3334
clearTagPosts: createAction(CLEAR_TAG_POSTS),
3435
getTempPosts: createAction(GET_TEMP_POSTS, PostsAPI.getTempPosts),
3536
prefetchTempPosts: createAction(PREFETCH_TEMP_POSTS, PostsAPI.getTempPosts),
37+
removeTempPost: createAction(REMOVE_TEMP_POST, (postId: string) => postId),
3638
};
3739

3840
export type PostItem = {
@@ -77,6 +79,7 @@ type PostsResponseAction = {
7779
data: PostItem[],
7880
},
7981
};
82+
type RemoveTempPostAction = ActionType<typeof actionCreators.removeTempPost>;
8083

8184
export interface ListingActionCreators {
8285
getRecentPosts(): any;
@@ -92,6 +95,7 @@ export interface ListingActionCreators {
9295
prefetchTempPosts(payload: PostsAPI.GetTempPostsPayload): any;
9396
clearTagPosts(): any;
9497
clearUserPosts(): any;
98+
removeTempPost(postId: string): any;
9599
}
96100

97101
const initialListingSet = {
@@ -138,6 +142,12 @@ const reducer = handleActions(
138142
};
139143
});
140144
},
145+
[REMOVE_TEMP_POST]: (state, { payload }: RemoveTempPostAction) => {
146+
return produce(state, (draft) => {
147+
if (!draft.temp.posts) return;
148+
draft.temp.posts = draft.temp.posts.filter(p => p.id !== payload);
149+
});
150+
},
141151
},
142152
initialState,
143153
);

velog-frontend/src/store/modules/write.js

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ const RESET_META = 'write/RESET_META';
5050
const LIST_TEMP_SAVES = 'write/LIST_TEMP_SAVES';
5151
const LOAD_TEMP_SAVE = 'write/LOAD_TEMP_SAVE';
5252

53+
const GET_POST_BY_ID = 'write/GET_POST_BY_ID';
54+
5355
let tempCategoryId = 0;
5456

5557
/* ACTION CREATOR */
@@ -96,6 +98,7 @@ export interface WriteActionCreators {
9698
resetMeta(): any;
9799
listTempSaves(postId: string): any;
98100
loadTempSave(payload: SavesAPI.LoadTempSavePayload): any;
101+
getPostById(postId: string): any;
99102
}
100103

101104
/* EXPORT ACTION CREATORS */
@@ -144,6 +147,7 @@ export const actionCreators = {
144147
resetMeta: createAction(RESET_META),
145148
listTempSaves: createAction(LIST_TEMP_SAVES, SavesAPI.getTempSaveList),
146149
loadTempSave: createAction(LOAD_TEMP_SAVE, SavesAPI.loadTempSave),
150+
getPostById: createAction(GET_POST_BY_ID, PostsAPI.getPostById),
147151
};
148152

149153
export type BriefTempSaveInfo = {
@@ -156,22 +160,6 @@ export type TempSaveData = BriefTempSaveInfo & {
156160
body: string,
157161
};
158162

159-
/* ACTION FLOW TYPE */
160-
type EditFieldAction = ActionType<typeof actionCreators.editField>;
161-
type SetThumbnailAction = ActionType<typeof actionCreators.setThumbnail>;
162-
type ToggleCategoryAction = ActionType<typeof actionCreators.toggleCategory>;
163-
type InsertTagAction = ActionType<typeof actionCreators.insertTag>;
164-
type RemovetagAction = ActionType<typeof actionCreators.removeTag>;
165-
type ToggleEditCategoryAction = ActionType<typeof actionCreators.toggleEditCategory>;
166-
type ChangeCategoryNameAction = ActionType<typeof actionCreators.changeCategoryName>;
167-
type HideCategoryAction = ActionType<typeof actionCreators.hideCategory>;
168-
type ReorderCategoryAction = ActionType<typeof actionCreators.reorderCategory>;
169-
type SetUploadMaskAction = ActionType<typeof actionCreators.setUploadMask>;
170-
type SetTempDataAction = ActionType<typeof actionCreators.setTempData>;
171-
type SetMetaValueAction = ActionType<typeof actionCreators.setMetaValue>;
172-
type ListTempSavesResponseAction = GenericResponseAction<BriefTempSaveInfo[], null>;
173-
type LoadTempSaveResponseAction = GenericResponseAction<TempSaveData, null>;
174-
175163
/* STATE TYPES */
176164
export type Category = {
177165
id: string,
@@ -249,6 +237,24 @@ export type Write = {
249237
changed: boolean,
250238
};
251239

240+
/* ACTION FLOW TYPE */
241+
type EditFieldAction = ActionType<typeof actionCreators.editField>;
242+
type SetThumbnailAction = ActionType<typeof actionCreators.setThumbnail>;
243+
type ToggleCategoryAction = ActionType<typeof actionCreators.toggleCategory>;
244+
type InsertTagAction = ActionType<typeof actionCreators.insertTag>;
245+
type RemovetagAction = ActionType<typeof actionCreators.removeTag>;
246+
type ToggleEditCategoryAction = ActionType<typeof actionCreators.toggleEditCategory>;
247+
type ChangeCategoryNameAction = ActionType<typeof actionCreators.changeCategoryName>;
248+
type HideCategoryAction = ActionType<typeof actionCreators.hideCategory>;
249+
type ReorderCategoryAction = ActionType<typeof actionCreators.reorderCategory>;
250+
type SetUploadMaskAction = ActionType<typeof actionCreators.setUploadMask>;
251+
type SetTempDataAction = ActionType<typeof actionCreators.setTempData>;
252+
type SetMetaValueAction = ActionType<typeof actionCreators.setMetaValue>;
253+
type ListTempSavesResponseAction = GenericResponseAction<BriefTempSaveInfo[], null>;
254+
type LoadTempSaveResponseAction = GenericResponseAction<TempSaveData, null>;
255+
type GetPostByIdResponseAction = GenericResponseAction<PostData, null>;
256+
257+
252258
const initialState: Write = {
253259
body: '',
254260
thumbnail: null,
@@ -569,4 +575,16 @@ export default applyPenders(reducer, [
569575
});
570576
},
571577
},
578+
{
579+
type: GET_POST_BY_ID,
580+
onSuccess: (state: Write, { payload }: GetPostByIdResponseAction) => {
581+
return produce(state, (draft) => {
582+
draft.changed = false;
583+
draft.postData = payload.data;
584+
draft.submitBox.tags = payload.data.tags;
585+
draft.body = payload.data.body;
586+
draft.title = payload.data.title;
587+
});
588+
},
589+
},
572590
]);

0 commit comments

Comments
 (0)