개인정보-컴플라이언스-웹애플리케이션(6) - (자가진단 설문) 백엔드 코드

2025. 1. 26. 17:11프로젝트

728x90
반응형

자가진단 설문은 사용자가 시스템을 등록하고 그 시스템을 자가진단 설문을 하는 기능입니다.

코드는 다음과 같습니다. 

 

import express from "express";
import pool from "../db/connection.js"; // DB 연결 파일

const router = express.Router();

// Self-assessment 저장
const handleSelfAssessmentSave = async (req, res) => {
  const {
    organization,
    userGroup,
    personalInfoSystem,
    memberInfoHomepage,
    externalDataProvision = "없음",
    cctvOperation,
    taskOutsourcing,
    personalInfoDisposal,
    systemId,
  } = req.body;

  const user_id = req.session.user?.id;
  if (!user_id) {
    return res.status(401).json({ message: "로그인이 필요합니다." });
  }

  if (!organization || !userGroup || !systemId) {
    return res
      .status(400)
      .json({ message: "필수 입력 항목이 누락되었습니다." });
  }

  try {
    const query = `
      INSERT INTO self_assessment (
        user_id, system_id, organization, user_scale, personal_info_system,
        member_info_homepage, external_data_provision, cctv_operation,
        task_outsourcing, personal_info_disposal
      ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
      ON DUPLICATE KEY UPDATE
        organization = VALUES(organization),
        user_scale = VALUES(user_scale),
        personal_info_system = VALUES(personal_info_system),
        member_info_homepage = VALUES(member_info_homepage),
        external_data_provision = VALUES(external_data_provision),
        cctv_operation = VALUES(cctv_operation),
        task_outsourcing = VALUES(task_outsourcing),
        personal_info_disposal = VALUES(personal_info_disposal)
    `;

    const values = [
      user_id,
      systemId,
      organization,
      userGroup,
      personalInfoSystem,
      memberInfoHomepage,
      externalDataProvision,
      cctvOperation,
      taskOutsourcing,
      personalInfoDisposal,
    ];

    await pool.query(query, values);
    res.status(201).json({ message: "Self-assessment saved successfully." });
  } catch (err) {
    console.error("Self-assessment 저장 실패:", err.message);
    res
      .status(500)
      .json({ message: "Internal server error.", error: err.message });
  }
};

// 정량 데이터 저장
const handleQuantitativeSave = async (req, res) => {
  const { quantitativeResponses } = req.body;

  if (!quantitativeResponses || !Array.isArray(quantitativeResponses)) {
    return res
      .status(400)
      .json({ message: "Invalid quantitative responses format." });
  }

  try {
    const query = `
      INSERT INTO quantitative (
        question_number, unit, evaluation_method, score, question,
        legal_basis, criteria_and_references, file_upload, response,
        additional_comment, feedback, system_id
      ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
      ON DUPLICATE KEY UPDATE
        unit = VALUES(unit),
        evaluation_method = VALUES(evaluation_method),
        score = VALUES(score),
        legal_basis = VALUES(legal_basis),
        criteria_and_references = VALUES(criteria_and_references),
        file_upload = VALUES(file_upload),
        response = VALUES(response),
        additional_comment = VALUES(additional_comment),
        feedback = VALUES(feedback)
    `;

    for (const {
      questionNumber,
      unit,
      evaluationMethod,
      score,
      question,
      legalBasis,
      criteriaAndReferences,
      fileUpload,
      response: answer,
      additionalComment,
      feedback,
      systemId,
    } of quantitativeResponses) {
      // 기본값 설정
      await pool.query(query, [
        questionNumber, // 필수
        unit || "단위 없음", // 기본값
        evaluationMethod || "정량평가", // 기본값
        score || 0, // 기본값
        question || "질문 없음", // 기본값
        legalBasis || "근거 법령 없음", // 기본값
        criteriaAndReferences || "평가기준 없음", // 기본값
        fileUpload || null, // 파일 업로드는 null 허용
        answer || "응답 없음", // 기본값
        additionalComment || "추가 의견 없음", // 기본값
        feedback || "피드백 없음", // 기본값
        systemId, // 필수
      ]);
    }

    res
      .status(200)
      .json({ message: "Quantitative responses saved successfully." });
  } catch (error) {
    console.error("Error saving quantitative responses:", error.message);
    res
      .status(500)
      .json({ message: "Internal server error.", error: error.message });
  }
};

// 정성 데이터 저장
const handleQualitativeSave = async (req, res) => {
  const { qualitativeResponses } = req.body;

  // 데이터 유효성 검사
  if (!qualitativeResponses || !Array.isArray(qualitativeResponses)) {
    return res
      .status(400)
      .json({ message: "Invalid qualitative responses format." });
  }

  try {
    // SQL 쿼리 정의
    const query = `
      INSERT INTO qualitative (
        question_number, response, additional_comment, system_id, user_id, 
        indicator, indicator_definition, evaluation_criteria, reference_info, file_path
      ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
      ON DUPLICATE KEY UPDATE
        response = VALUES(response),
        additional_comment = VALUES(additional_comment),
        indicator = VALUES(indicator),
        indicator_definition = VALUES(indicator_definition),
        evaluation_criteria = VALUES(evaluation_criteria),
        reference_info = VALUES(reference_info),
        file_path = VALUES(file_path)
    `;

    // 반복적으로 데이터베이스 작업 수행
    for (const {
      questionNumber,
      response,
      additionalComment,
      systemId,
      userId,
      indicator,
      indicatorDefinition,
      evaluationCriteria,
      referenceInfo,
      filePath,
    } of qualitativeResponses) {
      // 데이터 삽입/업데이트
      await pool.query(query, [
        questionNumber,
        response,
        additionalComment || "", // 기본값: 빈 문자열
        systemId,
        userId,
        indicator || "", // 기본값: 빈 문자열
        indicatorDefinition || "", // 기본값: 빈 문자열
        evaluationCriteria || "", // 기본값: 빈 문자열
        referenceInfo || "", // 기본값: 빈 문자열
        filePath || null, // 기본값: null
      ]);
    }

    // 성공 응답
    res
      .status(200)
      .json({ message: "All qualitative responses saved successfully." });
  } catch (error) {
    // 에러 처리
    console.error("Error saving qualitative responses:", error.message);
    res
      .status(500)
      .json({ message: "Internal server error.", error: error.message });
  }
};


// 정량 데이터 가져오기
const getQuantitativeData = async (req, res) => {
  const { systemId } = req.query;

  if (!systemId) {
    return res.status(400).json({ message: "System ID is required." });
  }

  try {
    const query = `
      SELECT question_number, unit, evaluation_method, score, question,
             legal_basis, criteria_and_references, file_upload, response,
             additional_comment, feedback
      FROM quantitative
      WHERE system_id = ?
    `;
    const [results] = await pool.query(query, [systemId]);
    res.status(200).json(results);
  } catch (error) {
    console.error("Error fetching quantitative data:", error.message);
    res
      .status(500)
      .json({ message: "Internal server error.", error: error.message });
  }
};

// 정성 데이터 가져오기
const getQualitativeData = async (req, res) => {
  const { systemId } = req.query;

  if (!systemId) {
    return res.status(400).json({ message: "System ID is required." });
  }

  try {
    const query = `
      SELECT question_number, indicator, indicator_definition, evaluation_criteria,
             reference_info, response, additional_comment, file_path
      FROM qualitative
      WHERE system_id = ?
    `;
    const [results] = await pool.query(query, [systemId]);
    res.status(200).json(results);
  } catch (error) {
    console.error("Error fetching qualitative data:", error.message);
    res
      .status(500)
      .json({ message: "Internal server error.", error: error.message });
  }
};

export {
  handleSelfAssessmentSave,
  handleQuantitativeSave,
  handleQualitativeSave,
  getQuantitativeData,
  getQualitativeData,
};

 

이 코드는 자가진단(Self-assessment), 정량(Quantitative), 정성(Qualitative) 데이터를 저장하고 조회하는 API입니다.

 

1. 자가진단 Self-assessment

const handleSelfAssessmentSave = async (req, res) => {
  const {
    organization,
    userGroup,
    personalInfoSystem,
    memberInfoHomepage,
    externalDataProvision = "없음",
    cctvOperation,
    taskOutsourcing,
    personalInfoDisposal,
    systemId,
  } = req.body;

  const user_id = req.session.user?.id;
  if (!user_id) {
    return res.status(401).json({ message: "로그인이 필요합니다." });
  }

  if (!organization || !userGroup || !systemId) {
    return res
      .status(400)
      .json({ message: "필수 입력 항목이 누락되었습니다." });
  }

  try {
    const query = `
      INSERT INTO self_assessment (
        user_id, system_id, organization, user_scale, personal_info_system,
        member_info_homepage, external_data_provision, cctv_operation,
        task_outsourcing, personal_info_disposal
      ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
      ON DUPLICATE KEY UPDATE
        organization = VALUES(organization),
        user_scale = VALUES(user_scale),
        personal_info_system = VALUES(personal_info_system),
        member_info_homepage = VALUES(member_info_homepage),
        external_data_provision = VALUES(external_data_provision),
        cctv_operation = VALUES(cctv_operation),
        task_outsourcing = VALUES(task_outsourcing),
        personal_info_disposal = VALUES(personal_info_disposal)
    `;

    const values = [
      user_id,
      systemId,
      organization,
      userGroup,
      personalInfoSystem,
      memberInfoHomepage,
      externalDataProvision,
      cctvOperation,
      taskOutsourcing,
      personalInfoDisposal,
    ];

    await pool.query(query, values);
    res.status(201).json({ message: "Self-assessment saved successfully." });
  } catch (err) {
    console.error("Self-assessment 저장 실패:", err.message);
    res
      .status(500)
      .json({ message: "Internal server error.", error: err.message });
  }
};

Self-assessment 저장 하는 코드

const {
  organization,
  userGroup,
  personalInfoSystem,
  memberInfoHomepage,
  externalDataProvision = "없음",
  cctvOperation,
  taskOutsourcing,
  personalInfoDisposal,
  systemId,
} = req.body;

 

req.body 를 통해 프론트 부분에서 사용자가 입력한 값들을 저장합니다.

const user_id = req.session.user?.id;
if (!user_id) {
  return res.status(401).json({ message: "로그인이 필요합니다." });
}

 

세션에서 user_id를 가져와 사용자를 인증합니다.

const query = `
  INSERT INTO self_assessment (
    user_id, system_id, organization, user_scale, personal_info_system,
    member_info_homepage, external_data_provision, cctv_operation,
    task_outsourcing, personal_info_disposal
  ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
  ON DUPLICATE KEY UPDATE
    organization = VALUES(organization),
    user_scale = VALUES(user_scale),
    personal_info_system = VALUES(personal_info_system),
    member_info_homepage = VALUES(member_info_homepage),
    external_data_provision = VALUES(external_data_provision),
    cctv_operation = VALUES(cctv_operation),
    task_outsourcing = VALUES(task_outsourcing),
    personal_info_disposal = VALUES(personal_info_disposal)
`;
ON DUPLICATE KEY UPDATE
  organization = VALUES(organization),
  user_scale = VALUES(user_scale),
  personal_info_system = VALUES(personal_info_system),
  member_info_homepage = VALUES(member_info_homepage),
  external_data_provision = VALUES(external_data_provision),
  cctv_operation = VALUES(cctv_operation),
  task_outsourcing = VALUES(task_outsourcing),
  personal_info_disposal = VALUES(personal_info_disposal)

ON DUPLICATE KEY UPDATE
중복된 키(PRIMARY KEY나 UNIQUE KEY)가 발견되면, 데이터를 삽입하지 않고 지정된 컬럼을 업데이트합니다.
이 기능은 새로운 데이터를 삽입하려 할 때, 중복 문제가 발생해도 기존 데이터를 덮어쓸 수 있게 합니다.

 

2. 정량 데이터 저장 handleQuantitativeSave

const handleQuantitativeSave = async (req, res) => {
  const { quantitativeResponses } = req.body;

  if (!quantitativeResponses || !Array.isArray(quantitativeResponses)) {
    return res
      .status(400)
      .json({ message: "Invalid quantitative responses format." });
  }

  try {
    const query = `
      INSERT INTO quantitative (
        question_number, unit, evaluation_method, score, question,
        legal_basis, criteria_and_references, file_upload, response,
        additional_comment, feedback, system_id
      ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
      ON DUPLICATE KEY UPDATE
        unit = VALUES(unit),
        evaluation_method = VALUES(evaluation_method),
        score = VALUES(score),
        legal_basis = VALUES(legal_basis),
        criteria_and_references = VALUES(criteria_and_references),
        file_upload = VALUES(file_upload),
        response = VALUES(response),
        additional_comment = VALUES(additional_comment),
        feedback = VALUES(feedback)
    `;

    for (const {
      questionNumber,
      unit,
      evaluationMethod,
      score,
      question,
      legalBasis,
      criteriaAndReferences,
      fileUpload,
      response: answer,
      additionalComment,
      feedback,
      systemId,
    } of quantitativeResponses) {
      // 기본값 설정
      await pool.query(query, [
        questionNumber, // 필수
        unit || "단위 없음", // 기본값
        evaluationMethod || "정량평가", // 기본값
        score || 0, // 기본값
        question || "질문 없음", // 기본값
        legalBasis || "근거 법령 없음", // 기본값
        criteriaAndReferences || "평가기준 없음", // 기본값
        fileUpload || null, // 파일 업로드는 null 허용
        answer || "응답 없음", // 기본값
        additionalComment || "추가 의견 없음", // 기본값
        feedback || "피드백 없음", // 기본값
        systemId, // 필수
      ]);
    }

    res
      .status(200)
      .json({ message: "Quantitative responses saved successfully." });
  } catch (error) {
    console.error("Error saving quantitative responses:", error.message);
    res
      .status(500)
      .json({ message: "Internal server error.", error: error.message });
  }
};

 

const handleQuantitativeSave = async (req, res) => {
  const { quantitativeResponses } = req.body;

 

이것도 마찬가지로 프론트쪽에서 사용자가 작성한 데이터를 저장합니다.

const query = `
  INSERT INTO quantitative (
    question_number, unit, evaluation_method, score, question,
    legal_basis, criteria_and_references, file_upload, response,
    additional_comment, feedback, system_id
  ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
  ON DUPLICATE KEY UPDATE
    unit = VALUES(unit),
    evaluation_method = VALUES(evaluation_method),
    score = VALUES(score),
    legal_basis = VALUES(legal_basis),
    criteria_and_references = VALUES(criteria_and_references),
    file_upload = VALUES(file_upload),
    response = VALUES(response),
    additional_comment = VALUES(additional_comment),
    feedback = VALUES(feedback)
`;

 

ON DUPLICATE KEY UPDATE
중복 키가 발생하면 데이터를 업데이트합니다.
VALUES(column_name): INSERT 쿼리에서 전달된 값을 참조하여 해당 컬럼을 업데이트합니다.

for (const {
      questionNumber,
      unit,
      evaluationMethod,
      score,
      question,
      legalBasis,
      criteriaAndReferences,
      fileUpload,
      response: answer,
      additionalComment,
      feedback,
      systemId,
    } of quantitativeResponses) {
      // 기본값 설정
      await pool.query(query, [
        questionNumber, // 필수
        unit || "단위 없음", // 기본값
        evaluationMethod || "정량평가", // 기본값
        score || 0, // 기본값
        question || "질문 없음", // 기본값
        legalBasis || "근거 법령 없음", // 기본값
        criteriaAndReferences || "평가기준 없음", // 기본값
        fileUpload || null, // 파일 업로드는 null 허용
        answer || "응답 없음", // 기본값
        additionalComment || "추가 의견 없음", // 기본값
        feedback || "피드백 없음", // 기본값
        systemId, // 필수
      ]);
    }

 

 

 

quantitativeResponses의 첫 번째 데이터 객체를 읽습니다.
해당 데이터를 query와 함께 데이터베이스에 삽입하거나 업데이트합니다.
모든 데이터가 처리될 때까지 배열의 각 객체에 대해 위 작업을 반복합니다.

 

3. 정성 데이터 저장 handleQualitativeSave

const handleQualitativeSave = async (req, res) => {
  const { qualitativeResponses } = req.body;

  // 데이터 유효성 검사
  if (!qualitativeResponses || !Array.isArray(qualitativeResponses)) {
    return res
      .status(400)
      .json({ message: "Invalid qualitative responses format." });
  }

  try {
    // SQL 쿼리 정의
    const query = `
      INSERT INTO qualitative (
        question_number, response, additional_comment, system_id, user_id, 
        indicator, indicator_definition, evaluation_criteria, reference_info, file_path
      ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
      ON DUPLICATE KEY UPDATE
        response = VALUES(response),
        additional_comment = VALUES(additional_comment),
        indicator = VALUES(indicator),
        indicator_definition = VALUES(indicator_definition),
        evaluation_criteria = VALUES(evaluation_criteria),
        reference_info = VALUES(reference_info),
        file_path = VALUES(file_path)
    `;

    // 반복적으로 데이터베이스 작업 수행
    for (const {
      questionNumber,
      response,
      additionalComment,
      systemId,
      userId,
      indicator,
      indicatorDefinition,
      evaluationCriteria,
      referenceInfo,
      filePath,
    } of qualitativeResponses) {
      // 데이터 삽입/업데이트
      await pool.query(query, [
        questionNumber,
        response,
        additionalComment || "", // 기본값: 빈 문자열
        systemId,
        userId,
        indicator || "", // 기본값: 빈 문자열
        indicatorDefinition || "", // 기본값: 빈 문자열
        evaluationCriteria || "", // 기본값: 빈 문자열
        referenceInfo || "", // 기본값: 빈 문자열
        filePath || null, // 기본값: null
      ]);
    }

    // 성공 응답
    res
      .status(200)
      .json({ message: "All qualitative responses saved successfully." });
  } catch (error) {
    // 에러 처리
    console.error("Error saving qualitative responses:", error.message);
    res
      .status(500)
      .json({ message: "Internal server error.", error: error.message });
  }
};

 

정량 데이터 저장 코드와 같은 구조로 for if 문으로 반복적으로 

요청 데이터의 배열(qualitativeResponses)을 순회하며 각 객체를 처리합니다.
객체의 값을 구조 분해 할당으로 개별 변수에 저장합니다.

 

4. (정량, 정성) 데이터 가져오기

// 정량 데이터 가져오기
const getQuantitativeData = async (req, res) => {
  const { systemId } = req.query;

  if (!systemId) {
    return res.status(400).json({ message: "System ID is required." });
  }

  try {
    const query = `
      SELECT question_number, unit, evaluation_method, score, question,
             legal_basis, criteria_and_references, file_upload, response,
             additional_comment, feedback
      FROM quantitative
      WHERE system_id = ?
    `;
    const [results] = await pool.query(query, [systemId]);
    res.status(200).json(results);
  } catch (error) {
    console.error("Error fetching quantitative data:", error.message);
    res
      .status(500)
      .json({ message: "Internal server error.", error: error.message });
  }
};

// 정성 데이터 가져오기
const getQualitativeData = async (req, res) => {
  const { systemId } = req.query;

  if (!systemId) {
    return res.status(400).json({ message: "System ID is required." });
  }

  try {
    const query = `
      SELECT question_number, indicator, indicator_definition, evaluation_criteria,
             reference_info, response, additional_comment, file_path
      FROM qualitative
      WHERE system_id = ?
    `;
    const [results] = await pool.query(query, [systemId]);
    res.status(200).json(results);
  } catch (error) {
    console.error("Error fetching qualitative data:", error.message);
    res
      .status(500)
      .json({ message: "Internal server error.", error: error.message });
  }
};