이제 Admin 을 마무리해보자.
먼저 API 수정이닷!!
PATCH /menu
메뉴 수정 API 는 이미 있고 잘 동작하는지 테스트만 했다.
<script>
// 무조건 _id 기준
// query 와 data 변수는 무조건 request body 로 전달되어야 함.
export const patch = async (query, data) => {
let success = false;
try {
const _id = query._id;
if (_id.length === 0) {
return false;
}
await MenuModel.findOneAndUpdate({ _id }, { $set: data });
success = true;
} catch (e) {
console.error(e);
}
return success;
};
</script>
DELETE /menu
하나의 메뉴를 삭제할때는 아래 사항들을 고려해야 한다.
일단 target 메뉴들과 target 메뉴들에 딸린 모든 자식 메뉴들을 찾는 함수를 만들자.
for
문을 돌면서 array
안에 있는 메뉴의 children 메뉴들을 찾고, 찾은 children 메뉴들을 다시 array
에 집어 넣는 로직이다.
<script>
// target 메뉴들 + 자신의 모든 자식 메뉴들을 array 로 리턴
export const getMenusAndAllChildren = async query => {
let targets = [];
let children = [];
try {
targets = await MenuModel.find(query);
children = [...targets];
for (let i = 0; i < children.length; i++) {
if (children[i].children?.length > 0) {
const newChildren = await MenuModel.find({_id: children[i].children});
children = [...children, ...newChildren];
}
}
children = children.slice(targets.length);
} catch (e) {
console.error(e);
targets = [];
children = [];
}
return { targets, children };
}
</script>
이제 getMenusAndAllChildren
을 호출해 모든 target 메뉴들을 찾아 삭제하자.
getMenusAndAllChildren
을 호출해 모든 target 메뉴들을 가져와서 mongoDB 의 deleteMany
를 호출해주면 끝이다. (https://www.mongodb.com/docs/manual/reference/method/db.collection.deleteMany/ 참조)
<script>
export const remove = async body => {
let success = false;
try {
const _id = body._id;
if (_id.length === 0) {
return false;
}
// 타겟의 자식 메뉴들까지 다 지우기
let { targets, children } = await getMenusAndAllChildren({ _id });
const allTarget = [...targets, ...children].map(t => t._id);
await MenuModel.deleteMany({_id: allTarget});
......
};
</script>
이제 최초 target 메뉴들의 부모 메뉴들에서 target 메뉴들의 정보를 지우자.
정확히는 부모 메뉴들의 children 에서 target 메뉴들의 _id 를 제거하고 부모 메뉴들을 업데이트 한다.
이후 Article.js
내 remove
함수 (여기서는 removeArticle
로 재명명) 를 호출해 모든 target 메뉴에 속하는 글들을 싹 삭제한다.
Article.js
내 remove
함수에 대해서는 다음 단락을 참조~.
<script>
import { remove as removeArticle } from './Article.js';
...
// 무조건 _id 기준, "" 아니면 ["", ...]
export const remove = async body => {
...
const parentMap = {};
// 타겟의 부모 메뉴에서 자기 자신 지우기
for (let i = 0; i < targets.length; i++) {
const target = targets[i];
if (target.parent) {
if (!parentMap[target.parent]) {
parentMap[target.parent] = await MenuModel.findById(target.parent);
}
const parentMenu = parentMap[target.parent];
// ObjectId 타입이기 때문에 equals 로만 비교함
parentMenu.children = parentMenu.children.filter(id => !id.equals(target._id));
}
}
for (let key in parentMap) {
const parentMenu = parentMap[key];
await parentMenu.save();
}
// 타겟들의 글 삭제
removeArticle({parent: allTarget});
success = true;
} catch (e) {
console.error(e);
}
return success;
};
</script>
DELELTE /article
글 삭제는 메뉴 삭제처럼 복잡하진 않다.
query 로 넘어온 _id 를 찾아서 삭제하면 끝.
다만 위 단락에서 언급한대로 메뉴 삭제시 target 메뉴에 속한 글들을 삭제하는 기능이 필요하기에... parent 까지 query 로 받을 수 있게 개발함.
<script>
// 무조건 _id or parent 로만 , "" or ["", ...]
export const remove = async body => {
let success = false;
try {
const query = {};
const { _id, parent } = body;
if (_id) {
query._id = _id;
}
if (parent) {
query.parent = parent;
}
const targets = await ArticleModel.find(query);
await ArticleModel.deleteMany({_id: targets.map(t => t._id)});
success = true;
} catch (e) {
console.error(e);
}
return success;
};
</script>
PATCH /article
특이할만한 부분은 없음.
<script>
// 무조건 _id 로
// TODO 검증은 나중에
export const patch = async (query, data) => {
let success = false;
try {
const _id = query?._id;
if (_id.length === 0) {
return false;
}
await ArticleModel.findOneAndUpdate({ _id }, { $set: data });
success = true;
} catch (e) {
console.error(e);
}
return success;
};
</script>
전부 다 정상적으로 동작하는 것 확인했다.
이제 이 api 들을 FE 에서 호출하기만 하면 됨~.