Admin 관련 API 수정

손대중·2022년 8월 7일
0

이제 Admin 을 마무리해보자.

먼저 API 수정이닷!!

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.jsremove 함수 (여기서는 removeArticle 로 재명명) 를 호출해 모든 target 메뉴에 속하는 글들을 싹 삭제한다.

Article.jsremove 함수에 대해서는 다음 단락을 참조~.

<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 에서 호출하기만 하면 됨~.

0개의 댓글