zioinfo-mail/zioinfo/js/valid.biz.js
DESKTOP-TKLFCPR\ython e228faabf5 feat(itsm): G-1~G-12 확장 기능 + 하네스/봇/설치스크립트 구현
G-1: 메신저 Webhook Relay + _send_to_room 실제 httpx 호출 구현
G-2: POST /api/tasks/bulk SR 대량작업 엔드포인트 (최대 100건)
G-3: 라이선스 만료 알림 스케줄러 (매일 09:00 KST)
G-4: 체험판 upgrade_banner 필드 + license.py 배너 로직
G-5: core/auto_rca.py + incidents/problem auto-rca 엔드포인트
G-6: core/deploy_impact.py + vibe impact-analysis 엔드포인트
G-7: core/ticket_classifier.py + SR 생성 시 AI 분류 + ai-suggestion API
G-8: VulnPatchRecord 모델 + vuln_scan 패치추적 4개 엔드포인트
G-9: core/jira_sync.py + gateway Jira/Confluence 연동 엔드포인트
G-10: core/push_notify.py + routers/push.py + PushSubscription 모델
G-11: approvals 다중승인 (위임/서명/기한초과/마감연장)
G-12: alembic.ini + migrations/ + cicd/migrate_to_postgres.sh

하네스: guardia-orchestrator 확장기능 Phase 반영
봇명령어: /sr /status /license /bulk 슬래시 명령어 추가
설치스크립트: setup/ (Ubuntu, CentOS, RHEL, Windows) --test 옵션 포함

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 18:18:52 +09:00

572 lines
13 KiB
JavaScript

/*-------------------------------------------------------------------+
* 1. 파일명: valid.biz.js
* 2. 설 명: 업무로직과 관련한 유효성 점검 함수를 정의한다.
* 3. 의존성: util.js, string.js
* 4. 작성자:
* 5. 작성일: 2006.10.11.
-------------------------------------------------------------------*/
/**
* E 메일 주소 형식이 맞는지 검사하여 맞으면 true,
* 형식에 맞지 않으면 false를 돌려 준다.
*/
function checkEmail(email) {
if ( isEmpty(email) ) return true;
var emailRegEx = /^[-\w]+@[-\w]+(\.[-\w]+){1,3}\s*$/g;
return emailRegEx.test(email);
}
function checkEmailObj(emailObj) {
return checkEmail(emailObj.value);
}
function validateEmail(email, fieldName) {
if ( fieldName == undefined ) fieldName = "E메일";
var valid = checkEmail(email);
if ( ! valid ) {
showMessage(fieldName + " 항목의 값은 E 메일의 형식에 맞지 않습니다.");
}
return valid;
}
function validateEmailObj(emailObj) {
var valid = validateEmail(emailObj.value);
if ( ! valid ) {
emailObj.focus();
}
return valid;
}
/* 전화번호용 지역번호 목록 */
var tpLocalNoList = [
"02" ,
"031", "032", "033",
"041", "042", "043",
"051", "052", "053", "054", "055",
"061", "062", "063", "064"
];
/**
* Text형 입력 폼의 값이 올바른 전화번호(핸드폰 번호가 아닌)인지 확인하여
* 올바르면 true를, 그렇지 않으면 적절한 메세지를 뿌려주고 false를 돌려 준다.
* 전화번호의 각 요소는 대쉬(-)로 구별된 것으로 가정한다.
*
* @date 2004-02-02
* @param obj 전화번호를 입력 받는 Text형 입력폼
*/
function checkTelNoObj(obj) {
return checkTelNo(obj.value);
}
/**
* 주어진 값이 올바른 전화번호(핸드폰 번호가 아닌)인지 확인하여
* 올바르면 0를, 그렇지 않으면 적절한 음수를 돌려 준다.
* 전화번호의 각 요소는 구별자(-)가 없는 것으로 가정한다.
*
* 오류시 돌려주는 음수의 의미는 다음과 같다.
* <ul>
* <li>-1 : 숫자와 대쉬(-) 이외의 문자 사용</li>
* <li>-2 : 전화번호의 형식에 맞지 않음</li>
* <li>-4 : 지역번호가 사용하지 않는 번호임</li>
* <li>-8 : 국번호 자릿수가 3, 4자리가 아님</li>
* <li>-16 : 맨 뒤 번호 자릿수가 4자리가 아님</li>
* </ul>
*
* @date 2004-02-02
* @param phoneNo 검사하려는 전화번호 값
*/
function checkTelNo(phoneNo) {
// 빈값이면 검사하지 않는다.
if ( trim(phoneNo) == "" ) return 0;
phoneNo = removeChar(phoneNo, '-');
if ( isNaN(phoneNo) ) return -1;
/* 형식에 문자가 있는지 검사한다. */
//var tpNoRegExp = /^(0[1-9]{1,2}-)?[\d]{3,4}-[\d]{4}$/;
var tpNoRegExp = /^(02|0[3-6][1-5])?[1-9][\d]{6,7}$/;
if ( ! tpNoRegExp.test(phoneNo) ) return -2;
/* 각 요소를 자른다. */
var localNo = ""; // 지역번호
var areaNo = ""; // 국번
var restNo = ""; // 기타 번호
var hasLocalNo = ( phoneNo.length >= 9 && phoneNo.length <= 11 );
/* 지역번호가 유무에 따라 처리. */
if ( hasLocalNo ) {
/* 지역번호가 있을 때. */
/* 지역번호가 02인가? */
if ( phoneNo.indexOf("02") == 0 ) {
localNo = "02";
areaNo = ( phoneNo.length == 9
? phoneNo.substr(2, 3) : phoneNo.substr(2, 4) );
restNo = phoneNo.substr(2 + areaNo.length);
}
else {
localNo = phoneNo.substr(0, 3);
areaNo = ( phoneNo.length == 10
? phoneNo.substr(3, 3) : phoneNo.substr(3, 4) );
restNo = phoneNo.substr(3 + areaNo.length);
}
}
else {
/* 지역번호가 없을 때. */
areaNo = ( phoneNo.length == 7
? phoneNo.substr(0, 3) : phoneNo.substr(0, 4) );
restNo = phoneNo.substr(areaNo.length);
}
/* 지역 번호가 있을 때만 처리한다. */
if ( hasLocalNo ) {
/* 유효한 지역번호가 아니면 오류이다. */
var isExistsLocalNo = existsInArray(tpLocalNoList, localNo);
if ( ! isExistsLocalNo ) {
return -4;
}
}
// 국번호가 3자리에서 4자리인지 검사한다.
if ( areaNo.length != 3 && areaNo.length != 4 ) {
return -8;
}
// 나머지 번호를 검사한다.
if ( restNo.length != 4 ) {
return -16;
}
return 0;
}
/**
* 주어진 값이 올바른 전화번호(핸드폰 번호가 아닌)인지 확인하여
* 올바르면 0를, 그렇지 않으면 적절한 메세지를 뿌려주고 false를 돌려 준다.
* 전화번호의 각 요소는 대쉬(-)로 구별된 것으로 가정한다.
*
* @date 2004-02-02
* @param phoneNo 검사하려는 전화번호 값
*/
function validateTelNoObj(obj, fieldName) {
var validResult = validateTelNo(obj.value, fieldName);
if ( validResult < 0 ) {
obj.focus();
}
return validResult;
}
/**
* 주어진 값이 올바른 전화번호(핸드폰 번호가 아닌)인지 확인하여
* 올바르면 0를, 그렇지 않으면 적절한 메세지를 뿌려주고 false를 돌려 준다.
* 전화번호의 각 요소는 대쉬(-)로 구별된 것으로 가정한다.
*
* @date 2004-02-02
* @param phoneNo 검사하려는 전화번호 값
*/
function validateTelNo(phoneNo, fieldName) {
var validResult = checkTelNo(phoneNo);
/* fieldName이 정의되어 있지 않다면 "전화번호"로 한다. */
if ( fieldName == undefined ) fieldName = "전화번호";
var msg = "";
switch ( validResult ) {
case -1 :
msg = fieldName + "은(는) 숫자만 이용해서 입력해야 합니다.";
break;
case -2 :
msg = fieldName + "의 형식에 맞지 않습니다.\n\n"
+ "[지역번호][국번3,4자리][번호4자리]\n"
+ "혹은 [국번3,4자리][번호4자리]";
break;
case -4 :
msg = "지역번호가 현재 사용하지 않는 번호입니다.";
break;
case -8 :
msg = "국번호는 3자리나 4자리이어야 합니다.";
break;
case -16 :
msg = "맨 뒤 번호는 4자리를 입력해야 합니다.";
break;
}
if ( validResult < 0 ) {
alert(msg);
}
return validResult;
}
/**
* 전화(혹은 팩스)번호의 값을 확인하여 유효한 경우이면 형식화한다.
*/
function formatTelNoObjIfValid(obj, fieldName) {
if ( validateTelNo(obj.value, fieldName) == 0 ) {
/* 유효한 값이면 형식화한다. */
formatTelNoObj(obj);
}
else {
/* 유효하지 않은 값이면 잡아 둔다. */
obj.focus();
}
}
/* 핸드폰용 지역번호 목록 */
var hpLocalNoList = [
"010", "011", "016", "017", "018", "019"
];
/**
* Text형 입력 폼의 값이 올바른 핸드폰(핸드폰 번호가 아닌)인지 확인하여
* 올바르면 true를, 그렇지 않으면 적절한 메세지를 뿌려주고 false를 돌려 준다.
* 핸드폰 번호의 각 요소는 대쉬(-)로 구별된 것으로 가정한다.
*
* @date 2004-02-02
* @param obj 핸드폰 번호를 입력 받는 Text형 입력폼
*/
function checkHpNoObj(obj) {
return checkHpNo(obj.value);
}
/**
* 주어진 값이 올바른 핸드폰 번호(일반 전화번호가 아닌)인지 확인하여
* 올바르면 true를, 그렇지 않으면 적절한 메세지를 뿌려주고 false를 돌려 준다.
* 핸드폰 번호의 각 요소는 대쉬(-)로 구별된 것으로 가정한다.
*
* @date 2004-02-02
* @param phoneNo 검사하려는 핸드폰 번호값
*/
function checkHpNo(phoneNo) {
// 빈값이면 검사하지 않는다.
if ( trim(phoneNo) == "" ) return 0;
phoneNo = removeChar(phoneNo, '-');
if ( isNaN(phoneNo) ) {
return -1;
}
/* 형식에 문자가 있는지 검사한다. */
//var hpNoRegExp = /^01[016789]-[\d]{3,4}-[\d]{4}$/;
var hpNoRegExp = /^01[016789][\d]{7,8}$/;
if ( ! hpNoRegExp.test(phoneNo) ) return -2;
// 각 요소를 자른다.
var localNo = phoneNo.substr(0, 3);; // 지역번호
var areaNo = ( phoneNo.length == 10
? phoneNo.substr(3, 3) : phoneNo.substr(3, 4) ); // 국번
var restNo = phoneNo.substr(3 + areaNo.length); // 기타 번호
// 유효한 지역번호가 아니면 오류이다.
var isExistsLocalNo = existsInArray(hpLocalNoList, localNo);
if ( ! isExistsLocalNo ) {
return -4;
}
// 국번호가 3자리에서 4자리인지 검사한다.
if ( areaNo.length != 3 && areaNo.length != 4 ) {
return -8;
}
// 나머지 번호를 검사한다.
if ( restNo.length != 4 ) {
return -16;
}
return 0;
}
/**
* 주어진 값이 올바른 전화번호(핸드폰 번호가 아닌)인지 확인하여
* 올바르면 0를, 그렇지 않으면 적절한 메세지를 뿌려주고 false를 돌려 준다.
* 전화번호의 각 요소는 대쉬(-)로 구별된 것으로 가정한다.
*
* @date 2004-02-02
* @param phoneNo 검사하려는 전화번호 값
*/
function validateHpNoObj(obj, fieldName) {
var validResult = validateHpNo(obj.value, fieldName);
if ( validResult < 0 ) {
obj.focus();
}
return validResult;
}
/**
* 주어진 값이 올바른 전화번호(핸드폰 번호가 아닌)인지 확인하여
* 올바르면 0를, 그렇지 않으면 적절한 메세지를 뿌려주고 false를 돌려 준다.
* 전화번호의 각 요소는 대쉬(-)로 구별된 것으로 가정한다.
*
* @date 2004-02-02
* @param phoneNo 검사하려는 전화번호 값
*/
function validateHpNo(phoneNo, fieldName) {
var validResult = checkHpNo(phoneNo);
/* fieldName이 정의되어 있지 않다면 "핸드폰 번호"로 한다. */
if ( fieldName == undefined ) fieldName = "핸드폰 번호";
var msg = "";
switch ( validResult ) {
case -1 :
msg = fieldName + "은(는) 숫자만 이용해서 입력해야 합니다.";
break;
case -2 :
msg = fieldName + "의 형식([지역번호 3자리][국번3,4자리][번호4자리])에 "
+ " 맞지 않습니다.";
break;
case -4 :
msg = "지역번호가 현재 사용하지 않는 번호입니다.";
break;
case -8 :
msg = "국번호는 3자리나 4자리이어야 합니다.";
break;
case -16 :
msg = "맨 뒤 번호는 4자리를 입력해야 합니다.";
break;
}
if ( validResult < 0 ) {
alert(msg);
}
return validResult;
}
/**
* 핸드폰 번호의 값을 확인하여 유효한 경우이면 형식화한다.
*/
function formatHpNoObjIfValid(obj, fieldName) {
if ( validateHpNo(obj.value, fieldName) == 0 ) {
/* 유효한 값이면 형식화한다. */
formatHpNoObj(obj);
}
else {
/* 유효하지 않은 값이면 잡아 둔다. */
obj.focus();
}
}
function validateContactNoObj(obj, fieldName) {
var result = validateContactNo(obj.value, fieldName);
if ( result < 0 ) obj.focus();
return result;
}
/**
* 연락처의 번호가 유효한지 검사한다.
* 연락처는 전화번호, 팩스번호, 핸드폰 번호를 모두 통칭하여 말한다.
*
* @param contactNo 유효성을 검증할 연락처 번호.
* @param fieldName 유효성을 검증할 항목명. 없으면 "연락처"를 사용한다.
*/
function validateContactNo(contactNo, fieldName) {
if ( contactNo == "" ) return 0;
/* fieldName이 정의되지 않았다면 "연락처"를 사용한다. */
if ( fieldName == undefined ) fieldName = "연락처";
/* 전화/팩스 번호인지, 핸드폰 번호인지를 판단한다.
-1 : 알수 없음.
-2 : 지역번호 정보 없음.
1 : 전화/팩스번호.
2 : 핸드폰 번호. */
var whichTypeNo = findWhichTypeNo(contactNo);
var result = -1;
if ( whichTypeNo == -1 || whichTypeNo == -2 || whichTypeNo == 1 ) {
/* 알수없음이거나 지역번호가 없음 일반전화 지역번호이면 전화번호로 검사. */
result = validateTelNo(contactNo, fieldName);
}
else if ( whichTypeNo == 2 ) {
/* 핸드폰 번호이면 핸드폰 번호로 검사 */
result = validateHpNo(contactNo, fieldName);
}
return result;
}
/**
* 연락처의 번호가 구체적으로 어떤 번호인지
* 판단하여 돌려 준다.
*
* -1 : 알수 없음.
* -2 : 지역번호 정보 없음.
* 1 : 전화/팩스번호.
* 2 : 핸드폰 번호.
*/
function findWhichTypeNo(contactNo) {
var whichTypeNo = -1;
/* 형식이 맞는지 검사하여 맞지 않으면 알수 없음. */
var contactNoRegExp = /^(0[1-9]{1,2}-)?[\d]{3,4}-[\d]{4}$/;
if ( ! contactNoRegExp.test(contactNo) ) return -1;
var tempArr = contactNo.split("-");
/* 길이가 2이면 지역번호 없음. */
if ( tempArr.length == 2 ) return -2;
/* 전화지역번호에 있나? */
if ( existsInArray(tpLocalNoList, contactNo) ) {
whichTypeNo = 1;
}
/* 핸드폰지역번호에 있나? */
else if ( existsInArray(hpLocalNoList, contactNo) ) {
whichTypeNo = 2;
}
return whichTypeNo;
}
/**
* Text형 입력폼의 값이 유효한 주민등록번호 인지를
* 점검하여 유효하면 true를 돌려주고 유효하지 않으면
* 적절한 메세지를 보여준 다음 false를 돌려준다.
* 파라미터인 obj2가 넘어오지 않으면 obj1에 주민등록번호
* 전체가 담겨 있는 것으로 가정하며, obj2가 넘어오면
* 앞 6자리는 obj1에 뒤 7자리는 obj2에 담겨 있는 것으로
* 가정한다.
*
* @작성일 2004-02-05
* @param obj1 전체 주민등록번호 혹은 주민등록번호
* 앞 6자리를 담고 있는 Text형 입력폼 객체
* @param obj2 주민등록번호 뒤 7자리를 담고 있는 Text형 입력폼 객체
*/
function checkSSNObj(obj1, obj2) {
var valid = true;
if ( obj2 == undefined ) {
valid = checkSSN(obj1.value);
}
else {
valid = checkSSN(obj1.value, obj2.value);
}
return valid;
}
/**
* 주민등록번호 유효성 여부를 점검하여 유효하면 true를
* 유효하지 않으면 적절한 메세지를 보여주고 false를 돌려준다.
* 파라미터의 갯수에 따라 그 의미가 조금 달라진다.
* ssn2가 정의되지 않았으면, 대쉬(-)의 여부에
* 상관없이 ssn1에 전체 주민등록번호가 담겨있는 것으로
* 가정하고, ssn2가 정의되어 있으면 ssn1에 앞 6자리
* ssn2에 뒤 7자리로 넘어오는 것으로 가정한다.
*
* @작성일 2004-02-05
* @param ssn1 전체 주민등록번호 혹은 주민등록번호 앞 6자리
* @param ssn2 주민등록번호 뒤 7자리
*/
function checkSSN(ssn1, ssn2) {
var ssn = "";
if ( ssn2 == undefined ) {
ssn = ssn1;
}
else {
ssn = ssn1 + "-" + ssn2;
}
// 주민번호의 형태와 7번째 자리(성별) 유효성 검사
var ssnRegEx = /^\d{6}-[1234]\d{6}$/;
if ( ! ssnRegEx.test(ssn)) {
alert("잘못된 주민등록번호입니다.");
return false;
}
// 날짜 유효성 검사
var birthYear = (ssn.charAt(7) <= "2") ? "19" : "20";
birthYear += ssn.substr(0, 2);
var birthMonth = ssn.substr(2, 2) - 1;
var birthDate = ssn.substr(4, 2);
var birth = new Date(birthYear, birthMonth, birthDate);
if ( birth.getYear() % 100 != ssn.substr(0, 2)
|| birth.getMonth() != birthMonth
|| birth.getDate() != birthDate ) {
alert("잘못된 주민등록번호입니다.");
return false;
}
// Check Sum 코드의 유효성 검사
var buf = new Array(13);
for (var i = 0; i < 6; i++) {
buf[i] = parseInt(ssn.charAt(i));
}
for (var i = 6; i < 13; i++) {
buf[i] = parseInt(ssn.charAt(i + 1));
}
var multipliers = [2,3,4,5,6,7,8,9,2,3,4,5];
var sum = 0;
for (var i = 0; i < 12; i++) {
sum += (buf[i] *= multipliers[i]);
}
if ( (11 - (sum % 11) ) % 10 != buf[12] ) {
alert("잘못된 주민등록번호입니다.");
return false;
}
return true;
}