class UserView: user_app = Blueprint('user_app', __name__, url_prefix='/user') @user_app.route("", methods=["POST"], endpoint='sign_up') @validate_params( Param('full_name', JSON, str, required=True), Param('email', JSON, str, required=True, rules=[Pattern(r'^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*.[a-zA-Z]{2,3}$')]), Param('password', JSON, str, rules=[MaxLength(80)]), Param('password', JSON, str, rules=[MinLength(4)]), Param('auth_type_id', JSON, int) ) def sign_up(*args): if args[4] not in range(1, 3): return jsonify({'message': 'INVALID_AUTH_TYPE'}), 400 user_info = { 'full_name': args[0], 'email': args[1], 'password': args[3], 'auth_type_id': args[4] } user_service = UserService() result = user_service.sigh_up(user_info) return result @user_app.route("/sign-in", methods=["POST"], endpoint='sign_in') @validate_params( Param('email', JSON, str, required=True, rules=[Pattern(r'^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*.[a-zA-Z]{2,3}$')]), Param('password', JSON, str, rules=[MaxLength(80)]), Param('password', JSON, str, rules=[MinLength(4)]) ) def sign_in(*args): user_info = { 'email': args[0], 'password': args[2] } user_service = UserService() result = user_service.sign_in(user_info) return result @user_app.route("/log-out", methods=["POST"], endpoint='log_out') @validate_params( Param('key', JSON, str) ) def log_out(*args): redis_key = args[0] user_service = UserService() result = user_service.log_out(redis_key) return result
def test_root_list_valid(self, value): param = JsonParam( { 'age': [Number()], 'name': [ MinLength(1), ], 'tags': JsonParam( {'name': [MinLength(1)]}, required=False, as_list=True) }, as_list=True) valid_value, errors = param.validate(deepcopy(value)) self.assertListEqual(value, valid_value) self.assertEqual(0, len(errors))
def seller_endpoints(app, services, get_session): seller_service = services.seller_service @app.route("/signup", methods=['POST']) @validate_params( Param('brand_crm_number', JSON, str, rules=[Pattern(r'^[0-9]{2,3}-[0-9]{3,4}-[0-9]{4}$')]), Param('password', JSON, str, rules=[Pattern(r'^(?=.*[0-9])(?=.*[A-Za-z])(?=.*[^a-zA-Z0-9]).{8,20}$')]), Param('phone_number', JSON, str, rules=[Pattern(r'^010-[0-9]{3,4}-[0-9]{4}$')]), Param('account', JSON, str, rules=[MinLength(5)]), Param('brand_name_korean', JSON, str), Param('brand_name_english', JSON, str), Param('seller_property_id', JSON, str) ) def sign_up(*args): """ 회원가입 API 회원가입을 위한 정보를 Body 에 받음 Args: *args: brand_crm_number : 브랜드 고객센터 번호 password : 비밀번호 phone_number : 담당자 핸드폰 번호 account : 계정 brand_name_korean : 브랜드명 ( 한글 ) brand_name_english : 브랜드명 ( 영어 ) seller_property_id : 셀러 속성 id ( 로드샵, 마켓 등 ) Returns: 200 : success , 회원가입 성공 시 400 : 같은 계정이 존재할 때, key error 500 : Exception """ session = None try: session = get_session() new_seller = { 'brand_crm_number': args[0], 'password': args[1], 'phone_number': args[2], 'account': args[3], 'brand_name_korean': args[4], 'brand_name_english': args[5], 'seller_property_id': args[6] } new_seller = seller_service.create_new_seller(new_seller, session) # 같은 계정이 이미 존재할 때 if new_seller == 'already exist': return jsonify({'message': 'account already exist'}), 400 session.commit() return jsonify({'message': 'success'}), 200 except KeyError: return jsonify({'message': 'key error'}), 400 except NoAffectedRowException as e: session.rollback() return jsonify({'message': 'no affected row error {}'.format(e.message)}), e.status_code except Exception as e: session.rollback() return jsonify({'message': '{}'.format(e)}), 500 finally: if session: session.close() @app.route("/login", methods=['POST']) @validate_params( Param('account', JSON, str), Param('password', JSON, str) ) def log_in(*args): """ Args: *args: account : 계정 password : 비밀번호 Returns: 200 : 로그인 성공 하면 access token 발행 400 : 계정이 존재하지 않을 때, 비밀번호가 틀렸을 때, soft delete 된 계정일 때, 셀러의 상태가 입점 대기 상태일 때 500 : Exception """ session = None try: session = get_session() seller = { 'account': args[0], 'password': args[1] } token = seller_service.enter_login(seller, session) # 계정이 존재하지 않을 때 if token == 'not exist': return jsonify({'message': 'account not exist'}), 400 # 비밀번호가 틀렸을 때 if token == 'wrong password': return jsonify({'message': 'wrong password'}), 400 # 소프트 딜리트 된 계정일 때 if token == 'deleted account': return jsonify({'message': 'account deleted'}), 400 # 셀러 상태가 입점 대기 일 때 ( seller_status_id = 1 ) if token == 'not authorized': return jsonify({'message': 'not authorized'}), 400 return jsonify({'access_token': token}) except KeyError: return jsonify({'message': 'key error'}), 400 except Exception as e: session.rollback() return jsonify({'message': '{}'.format(e)}), 500 finally: if session: session.close() @app.route("/mypage", methods=['GET']) @login_required def get_my_page(): """ 셀러정보관리(셀러) 셀러가 셀러 정보 관리를 들어갔을 때 등록된 셀러의 데이터 가져오기 Returns: 200 : seller_data ( type : dict ) 500 : Exception """ session = None try: session = get_session() seller_data = seller_service.get_my_page(g.seller_id, session) return jsonify(seller_data) except NoDataException as e: session.rollback() return jsonify({'message': 'no data {}'.format(e.message)}), e.status_code except Exception as e: session.rollback() return jsonify({'message': '{}'.format(e)}), 500 finally: if session: session.close() @app.route("/mypage", methods=['PUT']) @login_required @validate_params( Param('image', JSON, str), Param('simple_introduce', JSON, str), Param('brand_crm_number', JSON, str, rules=[Pattern(r'^[0-9]{2,3}-[0-9]{3,4}-[0-9]{4}$')]), Param('zip_code', JSON, int), Param('address', JSON, str), Param('detail_address', JSON, str), Param('brand_crm_open', JSON, str), Param('brand_crm_end', JSON, str), Param('delivery_information', JSON, str), Param('refund_exchange_information', JSON, str), Param('seller_status_id', JSON, int), Param('background_image', JSON, str, required=False), Param('detail_introduce', JSON, str, required=False), Param('is_brand_crm_holiday', JSON, int, rules=[Enum(0, 1)], required=False), Param('brand_name_korean', JSON, str), Param('brand_name_english', JSON, str), Param('manager_information', JSON, list) ) def put_my_page(*args): """ 셀러 정보 관리 (셀러 ) 셀러의 정보를 Body 로 받아서 데이터에 업데이트하기 Args: *args: image : 셀러 프로필 이미지 simple_introduce : 셀러 한줄 소개 brand_crm_number : 브랜드 고객센터 번호 zip_code : 우편번호 address : 주소 detail_address : 상세 주소 brand_crm_open : 고객센터 오픈시간 brand_crm_end : 고객센터 마감시간 delivery_information : 배송 정보 refund_exchange_information : 교환/환불 정보 seller_status_id : 셀러 상태 id ( 입점, 입점대기 등 ) background_image : 셀러페이지 배경이미지 detail_introduce : 셀러 상세 소개 is_brand_crm_holiday : 고객센터 주말 및 공휴일 운영 여부 brand_name_korean : 브랜드명 ( 한글 ) brand_name_english : 브랜드명 ( 영어 ) manager_information : 담당자 정보 ( 이름, 핸드폰 번호, 이메일 ) Returns: 200 : success, 셀러 데이터 업데이트 성공 시 400 : 담당자 정보 안에 이름, 핸드폰 번호, 이메일 중 하나라도 없을 때, 담당자 이메일 형식 맞지 않을 때, 담당자 핸드폰 번호 형식 맞지 않을 때 500 : Exception """ # 입력한 셀러 정보 받아서 데이터베이스에 넣기 session = None try: session = get_session() seller = { 'image': args[0], 'simple_introduce': args[1], 'brand_crm_number': args[2], 'zip_code': args[3], 'address': args[4], 'detail_address': args[5], 'brand_crm_open': args[6], 'brand_crm_end': args[7], 'delivery_information': args[8], 'refund_exchange_information': args[9], 'seller_status_id': args[10], 'background_image': args[11], 'detail_introduce': args[12], 'is_brand_crm_holiday': args[13], 'brand_name_korean': args[14], 'brand_name_english': args[15], 'manager_information': args[16], 'id': g.seller_id } for manager in seller['manager_information']: # 담당자 정보 안에 이름, 번호, 이메일이 없으면 에러 발생 if manager['name'] is None or manager['phone_number'] is None or manager['email'] is None: return jsonify({'message': 'no manager information data'}), 400 # 이메일 형식이 맞지 않을 때 에러 발생 if re.match(r'^([0-9a-zA-Z_-]+)@([0-9a-zA-Z_-]+)\.([0-9a-zA-Z_-]+)$', manager['email']) is None: return jsonify({'message': 'invalid email'}), 400 # 핸드폰 번호 형식이 맞지 않을 때 에러 발생 if re.match(r'^010-[0-9]{3,4}-[0-9]{4}$', manager['phone_number']) is None: return jsonify({'message': 'invalid phone number'}), 400 seller_service.post_my_page(seller, session) session.commit() return jsonify({'message': 'success'}), 200 except NoAffectedRowException as e: session.rollback() return jsonify({'message': 'no affected row error {}'.format(e.message)}), e.status_code except Exception as e: session.rollback() return jsonify({'message': '{}'.format(e)}), 500 finally: if session: session.close() @app.route("/master/management-seller", methods=['GET']) @login_required @validate_params( Param('limit', GET, int, required=False), Param('offset', GET, int, required=False), Param('number', GET, int, required=False), Param('account', GET, str, required=False), Param('brand_name_korean', GET, str, required=False), Param('brand_name_english', GET, str, required=False), Param('manager_name', GET, str, required=False), Param('manager_number', GET, str, rules=[Pattern(r'^010-[0-9]{3,4}-[0-9]{4}$')], required=False), Param('manager_email', GET, str, rules=[Pattern(r'^([0-9a-zA-Z_-]+)@([0-9a-zA-Z_-]+)\.([0-9a-zA-Z_-]+)$')], required=False), Param('status_id', GET, int, required=False), Param('property_id', GET, int, required=False), Param('start_date', GET, str, required=False), Param('end_date', GET, str, required=False) ) def get_management_seller(*args): """ 셀러 계정 관리 ( 마스터 ) API 쿼리 파라미터로 필터링 될 값을 받아서 필터링 한 후 리스트를 보내줌 Args: *args: limit : pagination 범위 offset : pagination 시작 번호 number : 셀러의 id account : 셀러의 계정 brand_name_korean : 브랜드명 ( 한글 ) brand_name_english : 브랜드명 ( 영어 ) manager_name : 담당자명 manager_number : 담당자 핸드폰 번호 manager_email : 담당자 이메일 status_id : 셀러의 상태 id ( 입점, 입점대기 등 ) property_id : 셀러의 속성 id ( 로드샵, 마켓 등 ) start_date : 해당 날짜 이후로 등록한 셀러 검색 end_date : 해당 날짜 이전에 등록한 셀러 검색 Returns: 200 : seller_list ( type : dict ) 400 : 마스터 계정이 아닌 경우 500 : Exception """ session = None try: session = get_session() # 쿼리스트링을 딕셔너리로 만들어 줌 query_string_list = { 'limit': 10 if args[0] is None else args[0], 'offset': 0 if args[1] is None else args[1], 'number': args[2], 'account': args[3], 'brand_name_korean': args[4], 'brand_name_english': args[5], 'manager_name': args[6], 'manager_number': args[7], 'email': args[8], 'seller_status_id': args[9], 'seller_property_id': args[10], 'start_date': args[11], 'end_date': args[12] } seller_list = seller_service.get_seller_list(query_string_list, g.seller_id, session) # 마스터 계정이 아닐 때 에러 발생 if seller_list == 'not authorized': return jsonify({'message': 'no master'}), 400 return jsonify(seller_list) except NoDataException as e: session.rollback() return jsonify({'message': 'no data {}'.format(e.message)}), e.status_code except Exception as e: session.rollback() return jsonify({'message': '{}'.format(e)}), 500 finally: if session: session.close() @app.route("/master/management-seller", methods=['PUT']) @login_required @validate_params( Param('seller_id', JSON, int), Param('button', JSON, int) ) def put_management_seller(seller_id, button): """ 마스터 셀러계정관리 API 마스터가 버튼을 눌러 셀러의 상태를 변경함 셀러의 상태가 변경될 때마다 슬랙 채널로 "(seller_id)번 셀러의 상태가 (status)로 변경되었습니다" 라는 메세지 전송 Args: seller_id: 셀러의 id button: 셀러의 상태 변경 버튼 ( 입점으로 변경, 휴점으로 변경 등 ) Returns: 200 : success, 셀러의 상태가 정상적으로 변경되었을 때 400 : 눌린 버튼과 셀러의 상태가 맞지 않을 때, 슬랙봇 메세지가 전송 실패되었을 때 500 : Exception """ session = None try: session = get_session() status = seller_service.post_seller_status(seller_id, button, session) # 버튼과 버튼이 눌리는 셀러의 속성이 맞지 않을 때 if status == 'invalid request': return jsonify({'message': 'invalid request'}), 400 # 슬랙봇 메세지가 전송실패되었을 때 if status == 'message fail': return jsonify({'message': 'message failed'}), 400 session.commit() return jsonify({'message': 'success'}), 200 except NoAffectedRowException as e: session.rollback() return jsonify({'message': 'no affected row error {}'.format(e.message)}), e.status_code except NoDataException as e: session.rollback() return jsonify({'message': 'no data {}'.format(e.message)}), e.status_code except Exception as e: session.rollback() return jsonify({'message': '{}'.format(e)}), 500 finally: if session: session.close() @app.route("/home", methods=['GET']) @login_required def get_home_seller(): """ 홈 API 로그인했을 때 나오는 홈 화면의 데이터 보내주기 Returns: 200 : data ( type : dict ) 500 : Exception """ session = None try: session = get_session() data = seller_service.get_home_data(session) return jsonify(data), 200 except Exception as e: session.rollback() return jsonify({'message': '{}'.format(e)}), 500 finally: if session: session.close() @app.route("/master/management-seller/<int:seller_id>", methods=['GET']) @login_required @validate_params( Param('seller_id', PATH, int) ) def get_master_seller_page(seller_id): """ 셀러계정관리 ( 마스터 ) 마스터가 셀러의 데이터 가져오기 Args: seller_id: 셀러 id Returns: 200 : seller_data ( type : dict ) 400 : 마스터 계정이 아닐 때 500 : Exception """ session = None try: session = get_session() seller_data = seller_service.get_seller_page(seller_id, session) # 마스터 계정이 아닐 때 에러 발생 if seller_data == 'not authorized': return jsonify({'message': 'not authorized'}), 400 return jsonify(seller_data) except NoDataException as e: session.rollback() return jsonify({'message': 'no data {}'.format(e.message)}), e.status_code except Exception as e: session.rollback() return jsonify({'message': '{}'.format(e)}), 500 finally: if session: session.close() @app.route("/master/management-seller/<int:seller_id>", methods=['PUT']) @login_required @validate_params( Param('seller_id', PATH, int), Param('image', JSON, str), Param('simple_introduce', JSON, str), Param('brand_crm_number', JSON, str, rules=[Pattern(r'^[0-9]{2,3}-[0-9]{3,4}-[0-9]{4}$')]), Param('zip_code', JSON, int), Param('address', JSON, str), Param('detail_address', JSON, str), Param('brand_crm_open', JSON, str), Param('brand_crm_end', JSON, str), Param('delivery_information', JSON, str), Param('refund_exchange_information', JSON, str), Param('seller_status_id', JSON, int), Param('background_image', JSON, str, required=False), Param('detail_introduce', JSON, str, required=False), Param('is_brand_crm_holiday', JSON, int, rules=[Enum(0, 1)]), Param('brand_name_korean', JSON, str), Param('brand_name_english', JSON, str), Param('manager_information', JSON, list), Param('seller_property_id', JSON, int) ) def put_master_seller_page(*args): """ 셀러 계정 관리 ( 마스터 ) Path parameter 로 셀러의 아이디를 받고 Body 로 셀러의 수정 데이터 받아서 수정하기 Args: *args: seller_id : 셀러 id image : 셀러의 프로필 이미지 simple_introduce : 셀러 한줄 소개 brand_crm_number : 고객센터 전화번호 zip_code : 우편번호 address : 주소 detail_address : 상세주소 brand_crm_open : 고객센터 오픈시간 brand_crm_end : 고객센터 마감시간 delivery_information : 배송 정보 refund_exchange_information : 교환/환불 정보 seller_status_id : 셀러 상태 id ( 입점, 입점 대기 등 ) background_image : 셀러 배경 이미지 detail_introduce : 셀러 상세 정보 is_brand_crm_holiday : 고객센터 휴일/공휴일 영업 여부 brand_name_korean : 브랜드명 ( 한글 ) brand_name_english : 브랜드명 ( 영어 ) manager_information : 담당자 정보 ( 이름, 핸드폰 번호, 이메일 ) seller_property_id : 셀러 속성 id ( 마켓, 로드샵 등 ) Returns: 200 : success, 데이터 수정하기 성공했을 때 400 : 담당자 정보에 이름, 핸드폰 번호, 이메일 중 하나라도 없을 때 , 이메일 형식이 맞지 않을 때, 핸드폰번호 형식이 맞지 않을 때 500 : Exception """ session = None try: session = get_session() # 셀러 데이터 받아서 딕셔너리로 만들기 seller = { 'id': args[0], 'image': args[1], 'simple_introduce': args[2], 'brand_crm_number': args[3], 'zip_code': args[4], 'address': args[5], 'detail_address': args[6], 'brand_crm_open': args[7], 'brand_crm_end': args[8], 'delivery_information': args[9], 'refund_exchange_information': args[10], 'seller_status_id': args[11], 'background_image': args[12], 'detail_introduce': args[13], 'is_brand_crm_holiday': args[14], 'brand_name_korean': args[15], 'brand_name_english': args[16], 'manager_information': args[17], 'seller_property_id': args[18] } # 담당자 정보 안에 이름, 번호, 이메일이 없으면 에러 발생 for manager in seller['manager_information']: if manager['name'] is None or manager['phone_number'] is None or manager['email'] is None: return jsonify({'message': 'no manager information data'}), 400 # 이메일 형식이 맞지 않을 때 에러 발생 if re.match(r'^([0-9a-zA-Z_-]+)@([0-9a-zA-Z_-]+)\.([0-9a-zA-Z_-]+)$', manager['email']) is None: return jsonify({'message': 'invalid email'}), 400 # 핸드폰 번호 형식이 맞지 않을 때 에러 발생 if re.match(r'^010-[0-9]{3,4}-[0-9]{4}$', manager['phone_number']) is None: return jsonify({'message': 'invalid phone number'}), 400 seller_service.put_master_seller_page(seller, session) session.commit() return jsonify({'message': 'success'}), 200 except NoAffectedRowException as e: session.rollback() return jsonify({'message': 'no affected row error {}'.format(e.message)}), e.status_code except Exception as e: session.rollback() return jsonify({'message': '{}'.format(e)}), 500 finally: if session: session.close()
class AccountView: account_app = Blueprint('account_app', __name__, url_prefix='/account') @account_app.route('signup/master', methods=['POST']) @validate_params( Param('email', JSON, str, rules=[Pattern(r'^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*.[a-zA-Z]{2,3}$')]), Param('password', JSON, str, rules=[MaxLength(80), MinLength(4)]), Param('account_type_id', JSON, int), Param('account_type_id', JSON, str, rules=[Pattern(r"^[1-2]{1}$")]), Param('name', JSON, str, rules=[Pattern(r"^[가-힣]{1,20}$")]), Param('master_code', JSON, str, required=True) ) def sign_up_master(*args): connection = None account_info = { 'email': args[0], 'password': args[1], 'account_type_id': args[2], 'name': args[4], 'master_code': args[5] } connection = connect_db() if connection: account_service = AccountService() try: account_service.signup_account(account_info, connection) if account_info['master_code'] != 'brandi_team1': connection.rollback() return jsonify({'MESSAGE': 'WRONG_MASTER_CODE'}) connection.commit() return jsonify({'MESSAGE': 'ACCOUNT_CREATED', }), 200 except Exception as e: connection.rollback() return jsonify({'MESSAGE': f'{e}'}), 400 finally: if connection: connection.close() @account_app.route('signup/seller', methods=['POST']) @validate_params( Param('email', JSON, str, rules=[Pattern(r'^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*.[a-zA-Z]{2,3}$')]), Param('password', JSON, str, rules=[MaxLength(80), MinLength(4)]), Param('account_type_id', JSON, int), Param('account_type_id', JSON, str, rules=[Pattern(r"^[1-2]{1}$")]), Param('service_number', JSON, str, rules=[Pattern(r"^[0-9]{11}$|^[0-9]{12}$")]), Param('seller_name_kr', JSON, str, rules=[Pattern(r"^[가-힣0-9]{1,20}$")]), Param('seller_name_en', JSON, str, rules=[Pattern( r"^[a-zA-Z0-9àáâäãåąčćęèéêëėįìíîïłńòóôöõøùúûüųūÿýżźñçčšžÀÁÂÄÃÅĄĆČĖĘÈÉÊËÌÍÎÏĮŁŃÒÓÔÖÕØÙÚÛÜŲŪŸÝŻŹÑßÇŒÆČŠŽ∂ð ,.'-]{1,20}$")]), Param('subcategory_id', JSON, str, rules=[Pattern(r"^[1-8]{1}$")]) ) def sign_up_seller(*args): connection = None try: account_info = { 'email': args[0], 'password': args[1], 'account_type_id': args[2], 'name': '미설정', 'service_number': args[4], 'seller_name_kr': args[5], 'seller_name_en': args[6], 'subcategory_id': args[7], 'seller_status_id': 1 } print(account_info) connection = connect_db() account_service = AccountService() account_service.signup_seller(account_info, connection) connection.commit() return jsonify({'MESSAGE': 'SUCCESS'}), 200 except Exception as e: connection.rollback() return jsonify({'MESSAGE': f'{e}'}), 400 finally: if connection: connection.close() @account_app.route('/signin', methods=['POST']) def sign_in(): connection = None try: connection = connect_db() login_data = request.json account_service = AccountService() token = account_service.signin(login_data, connection) return token except Exception as e: return jsonify({'MESSAGE': f'{e}'}), 400 finally: if connection: connection.close() @account_app.route('/seller_list', methods=['GET']) @login_validator @validate_params( Param('seller_id', GET, int, required=False), Param('account_id', GET, int, required=False), Param('email', GET, str, required=False), Param('seller_en', GET, str, required=False), Param('seller_kr', GET, str, required=False), Param('user_id', GET, int, required=False), Param('manager_name', GET, str, required=False), Param('manager_email', GET, str, required=False), Param('seller_status', GET, str, required=False), Param('manager_phone', GET, str, required=False), Param('seller_category', GET, str, required=False), Param('created_lower', GET, str, required=False), Param('created_upper', GET, str, required=False), Param('excel', GET, int, required=False), Param('page', GET, int, required=False), Param('limit', GET, int, required=False), Param('order_by', GET, str, required=False, rules=[Enum('asc', 'desc')]) ) def list_sellers(*args): db_connection = None user = g.token_info filter_info = { 'seller_id': args[0], 'account_id': args[1], 'email': args[2], 'seller_en': args[3], 'seller_kr': args[4], 'user_id': args[5], 'manager_name': args[6], 'manager_email': args[7], 'seller_status': args[8], 'manager_phone': args[9], 'seller_category': args[10], 'created_upper': args[11], 'created_lower': args[12], 'excel': args[13], 'page': args[14] if args[14] else 1, 'limit': args[15] if args[15] else 10, 'order_by': args[16] } try: connection = connect_db() account_service = AccountService() seller_list = account_service.filter_seller(filter_info, user, connection) return jsonify({'seller_list': seller_list}), 200 except Exception as e: return jsonify({'MESSAGE': f'{e}'}), 400 finally: connection.close() @account_app.route('edit', methods=['PATCH']) @login_validator @validate_params( Param('email', JSON, str, rules=[Pattern(r'^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*.[a-zA-Z]{2,3}$')], required=False), Param('password', JSON, str, rules=[MaxLength(80), MinLength(4)], required=False), Param('account_type_id', JSON, int, required=False), Param('account_type_id', JSON, str, rules=[Pattern(r"^[1-2]{1}$")], required=False), Param('name', JSON, str, rules=[Pattern(r"^[가-힣]{1,20}$")], required=False), Param('account_id', JSON, int, required=True), Param('is_active', JSON, int, required=False) ) def edit_account(*args): connection = None change_info = { 'email': args[0], 'password': args[1], 'account_type_id': args[2], 'name': args[4], 'id': args[5], 'is_active': args[6] } connection = connect_db() user = g.token_info if connection: account_service = AccountService() try: change_account = account_service.change_account_info(change_info, user, connection) connection.commit() return change_account except Exception as e: connection.rollback() return jsonify({'MESSAGE': f'{e}'}), 400 finally: connection.close() @account_app.route('edit_seller', methods=['PATCH']) @login_validator @validate_params( Param('subcategory_id', JSON, int, required=False), Param('seller_status_id', JSON, int, required=False), Param('seller_name_kr', JSON, str, rules=[Pattern(r"^[가-힣0-9]{1,20}$")], required=False), Param('seller_name_en', JSON, str, rules=[Pattern( r"^[a-zA-Z0-9àáâäãåąčćęèéêëėįìíîïłńòóôöõøùúûüųūÿýżźñçčšžÀÁÂÄÃÅĄĆČĖĘÈÉÊËÌÍÎÏĮŁŃÒÓÔÖÕØÙÚÛÜŲŪŸÝŻŹÑßÇŒÆČŠŽ∂ð ,.'-]{1,20}$")], required= False), Param('seller_number', JSON, str, rules=[Pattern(r"^[0-9]{11}$|^[0-9]{12}$")], required=False), Param('profile_pic_url', JSON, str, required=False), Param('short_desc', JSON, str, required=False), Param('long_desc', JSON, str, required=False), Param('open_time', JSON, str, rules=[Pattern('^(20)[\d]{2}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[0-1])$')], required= False), Param('close_time', JSON, str, rules=[Pattern('^(20)[\d]{2}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[0-1])$')], required= False), Param('delivery_policy', JSON, str, required=False), Param('return_policy', JSON, str, required=False), Param('zip_code', JSON, int, required=False), Param('address_1', JSON, str, required=False), Param('address_2', JSON, str, required=False), Param('is_open_weekend', JSON, int, required=False), Param('seller_id', JSON, int, required=True) ) def edit_seller(*args): connection = None change_info = { 'subcategory_id': args[0], 'seller_status_id': args[1], 'seller_name_kr': args[2], 'seller_name_en': args[3], 'seller_number': args[4], 'profile_pic_url': args[5], 'short_desc': args[6], 'long_desc': args[7], 'open_time': args[8], 'close_time': args[9], 'delivery_policy': args[10], 'return_policy': args[11], 'zip_code': args[12], 'address_1': args[13], 'address_2': args[14], 'is_open_weekend': args[15], 'seller_id': args[16] } connection = connect_db() user = g.token_info if connection: account_service = AccountService() try: change_account = account_service.change_seller_info(change_info, user, connection) connection.commit() return change_account except Exception as e: connection.rollback() return jsonify({'MESSAGE': f'{e}'}), 400 finally: connection.close() @account_app.route('change_seller_status', methods=['PATCH']) @login_validator @validate_params( Param('action_id', JSON, str), Param('status_id', JSON, str), Param('seller_id', JSON, str) ) def seller_actions(*args): connection = None status = { 'action_id': args[0], 'status_id': args[1], 'seller_id': args[2] } user = g.token_info connection = connect_db() if connection: try: account_service = AccountService() account_service.change_status(status, user, connection) connection.commit() return jsonify({'status_actions': 'SUCCESS'}), 200 except Exception as e: connection.rollback() return jsonify({'MESSAGE': f'{e}'}), 400 finally: connection.close()
class SellerView: """ 셀러 뷰 Authors: [email protected] (이소헌) History: 2020-03-25 ([email protected]): 초기 생성 """ seller_app = Blueprint('seller_app', __name__, url_prefix='/seller') @seller_app.route('', methods=['POST']) @validate_params( Param('login_id', JSON, str, rules=[Pattern(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9_-]{4,19}')]), Param('password', JSON, str, rules=[MaxLength(80)]), Param('password', JSON, str, rules=[MinLength(4)]), Param('contact_number', JSON, str, rules=[Pattern(r'^[0-9]{3}-{1}[0-9]{4}-{1}[0-9]{4}$')]), Param('seller_type_id', JSON, int), Param('name_kr', JSON, str, rules=[Pattern(r'^[가-힣a-zA-Z0-9\ ]{1,45}$')]), Param('name_en', JSON, str, rules=[Pattern(r'^[a-z\ ]{1,45}$')]), Param('center_number', JSON, str, rules=[Pattern(r'^[0-9]{2,3}-{1}[0-9]{3,4}-{1}[0-9]{4}$')]), Param( 'site_url', JSON, str, rules=[ Pattern( r"^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\(\)\*\+,;=.]+$" ) ]), Param('site_url', JSON, str, rules=[MaxLength(200)]), Param('kakao_id', JSON, str, required=False, rules=[Pattern(r'^[가-힣a-zA-Z0-9]{1,45}$')]), Param('insta_id', JSON, str, required=False, rules=[Pattern(r'^[a-zA-Z0-9]{1,45}$')]), Param('seller_type_id', JSON, str, rules=[Pattern(r"^[1-7]{1}$")])) def sign_up(*args): """ 계정 회원가입 엔드포인트 회원가입 엔드포인트 입니다. request.body 로 회원가입에 필요한 정보를 받고, 유효성 검사를 마친 정보를 account_info 에 담아 service 에 전달합니다. Args: *args: 유효성 검사를 통과한 파라미터 request.body: login_id 로그인 아이디 str password 비밀번호 str contact_number 담당자 번호 str seller_type_id 셀러 속성 아이디 int name_kr 셀러명 str name_en 셀러 영문명 str center_number 고객센터 번호 str site_url 사이트 URL str kakao_id 카카오 아이디 str required=False insta_id 인스타 아이디 str required=False Returns: http 응답코드 200: SUCCESS 셀러 회원가입 완료 400: EXISTING_LOGIN_ID, EXISTING_NAME_KR, EXISTING_NAME_EN, INVALID_KEY 500: NO_DATABASE_CONNECTION Authors: [email protected] (이종민) History: 2020-04-06 ([email protected]): 초기 생성 2020-04-07 ([email protected]): 'center_number'의 중간부분 유효성검사 허용 범위를 4글자->3~4글자로 변경 """ # validation 확인이 된 data 를 account_info 로 재정의 account_info = { 'login_id': args[0], 'password': args[1], 'contact_number': args[3], 'seller_type_id': args[4], 'name_kr': args[5], 'name_en': args[6], 'center_number': args[7], 'site_url': args[8], 'kakao_id': args[10], 'insta_id': args[11] } # 데이터베이스 연결 try: db_connection = get_db_connection() if db_connection: seller_service = SellerService() sign_up_result = seller_service.sign_up( account_info, db_connection) return sign_up_result else: return jsonify({'message': 'NO_DATABASE_CONNECTION'}), 500 except Exception as e: return jsonify({'message': f'{e}'}), 500 finally: try: db_connection.close() except Exception as e: return jsonify({'message': f'{e}'}), 500 @seller_app.route('/login', methods=['POST']) @validate_params(Param('login_id', JSON, str), Param('password', JSON, str)) def login(*args): """ 셀러 로그인 엔드포인트 셀러 로그인 엔드포인트 입니다. login_id 와 password 를 받습니다. request.body: login_id: 로그인 아이디 password: 로그인 비밀번호 Args: *args: 유효성 검사를 통과한 request.body 의 인자 Returns: 200: SUCCESS 로그인 성공 401: INVALID_PASSWORD, STATUS_1_CANT_LOGIN 500: NO_DATABASE_CONNECTION Authors: [email protected] (최예지) History: 2020-04-04 ([email protected]): 초기 생성 2020-04-04 ([email protected]): account_info 에 필요한 정보 담음, DB 열림닫힘 여부에 따라 실행되는 함수 작성 """ # validation 확인이 된 data 를 account_info 로 재정의 account_info = {'login_id': args[0], 'password': args[1]} try: # DB에 연결 db_connection = get_db_connection() if db_connection: # service 에 있는 SellerService 를 가져와서 seller_service 라는 인스턴스를 만듦 seller_service = SellerService() # 로그인 함수를 실행한 결과값을 login_result 에 저장 login_result = seller_service.login(account_info, db_connection) return login_result # DB가 열리지 않았을 경우 else: return jsonify({'message': 'NO_DATABASE_CONNECTION'}), 500 # 정의하지 않은 모든 error 를 잡아줌 except Exception as e: return jsonify({'message': f'{e}'}), 500 # try 랑 except 에 상관없이 무조건 실행 finally: try: db_connection.close() except Exception as e: return jsonify({'message': f'{e}'}), 500 @seller_app.route('', methods=['GET'], endpoint='get_all_sellers') @login_required @validate_params(Param('seller_account_no', GET, int, required=False), Param('login_id', GET, str, required=False), Param('name_en', GET, str, required=False), Param('name_kr', GET, str, required=False), Param('brandi_app_user_id', GET, int, required=False), Param('manager_name', GET, str, required=False), Param('manager_email', GET, str, required=False), Param('seller_status', GET, str, required=False), Param('manager_contact_number', GET, str, required=False), Param('seller_type_name', GET, str, required=False), Param('start_time', GET, str, required=False), Param('close_time', GET, str, required=False), Param('excel', GET, int, required=False), Param('offset', GET, int, required=False), Param('limit', GET, int, required=False)) def get_seller_list(*args): """ 가입된 모든 셀러 정보 리스트를 표출 유효성검사를 통과한 값을 request 에 넣어줌. Args: g.account_info: 데코레이터에서 넘겨받은 수정을 수행하는 계정 정보 g.account_info.seller_account_no: 검색 셀러 번호 g.account_info.account_no: 데코레이터에서 확인된 계정번호드 args: path parameter 를 통해서 들어온 검색 키워 Returns: seller_list_result: 가입된 모든 셀러 및 셀러 세부 정보 리스트로 표출(seller_service 에서 받은 리턴 값.) 400: seller_service 로 값을 넘겨줄 때 애러가나면 400 리턴 500: database 연결에 실패하면 500리턴 Authors: [email protected] (윤희철) History: 2020-04-03 ([email protected]): 초기 생성 2020-04-07 ([email protected]): 파라미터 유효성검사 추가 2020-04-10 ([email protected]): 애러 처리 추가 2020-04-14 ([email protected]): offset 과 limit 도 유효성검사 실시 """ # 유효성 확인 위해 기간 데이터 먼저 정의 start_time = args[10] close_time = args[11] # 두 값이 모두 들어왔을 때, 시작 기간이 종료 기간보다 늦으면 시작기간 = 종료기간 if start_time and close_time: if start_time > close_time: start_time = close_time # validation 을 통과한 값을 담을 딕셔너리를 만들어줌. valid_param = {} # valid_param 딕셔너리에 validation 을 통과한 query parameter 을 넣어줌. valid_param['seller_account_no'] = args[0] valid_param['login_id'] = args[1] valid_param['name_en'] = args[2] valid_param['name_kr'] = args[3] valid_param['brandi_app_user_id'] = args[4] valid_param['manager_name'] = args[5] valid_param['manager_email'] = args[6] valid_param['seller_status'] = args[7] valid_param['manager_contact_number'] = args[8] valid_param['seller_type_name'] = args[9] valid_param['start_time'] = start_time valid_param['close_time'] = close_time valid_param['excel'] = args[12] valid_param['offset'] = args[13] if args[13] else 0 valid_param['limit'] = args[14] if args[14] else 10 # 유저 정보를 g에서 읽어와서 service 에 전달 user = g.account_info # 데이터베이스 커넥션을 열어줌. try: db_connection = DatabaseConnection() if db_connection: seller_service = SellerService() seller_list_result = seller_service.get_seller_list( valid_param, user, db_connection) return seller_list_result else: return jsonify({'message': 'NO_DATABASE_CONNECTION'}), 500 except Exception as e: return jsonify({'message': f'{e}'}), 500 finally: try: db_connection.close() except Exception as e: return jsonify({'message': f'{e}'}), 500 @seller_app.route('/<int:parameter_account_no>', methods=['GET'], endpoint='get_seller_info') @login_required @validate_params( Param('parameter_account_no', PATH, int), Param('parameter_account_no', PATH, str, rules=[MaxLength(6)]), ) def get_seller_info(*args): """ 계정 셀러정보 표출 엔드포인트 셀러정보를 표출하는 엔드포인트 입니다. url 로 셀러정보를 확인하고 싶은 계정 번호를 받습니다. 셀러정보를 열람을 수행하려는 계정의 번호를 데코레이터로부터 받습니다. 열람 대상 셀러정보의 계정의 번호를 url parameter 로 받습니다. 받은 정보를 유효성 검사를 거친 후 account_info 로 저장해 service 로 넘겨줍니다. Args: *args: 유효성 검사를 통과한 파라미터 url parameter: parameter_account_no: 열람하고자 하는 셀러정보의 계정 번호 g.account_info: 데코레이터에서 넘겨받은(셀러정보를 열람을 수행하려는) 계정 정보 auth_type_id: 계정의 권한정보 account_no: 데코레이터에서 확인된 계정번호 Returns: http 응답코드 200: SUCCESS 셀러정보 겟 완료 400: INVALID_ACCOUNT_NO, INVALID_AUTH_TYPE_ID 403: NO_AUTHORIZATION 500: NO_DATABASE_CONNECTION, DB_CURSOR_ERROR, INVALID_KEY Authors: [email protected] (이종민) History: 2020-04-01 ([email protected]): 초기 생성 2020-04-02 ([email protected]): 파라미터 validation 추가, 데코레이터 적용 2020-04-03 ([email protected]): 주석 수정(메인문구, url parameter 수정) 2020-04-06 ([email protected]): url path 변경('/<int:parameter_account_no>/info' -> '/<int:parameter_account_no>') """ # validation 확인이 된 data 를 account_info 로 재정의 account_info = { 'parameter_account_no': args[0], 'auth_type_id': g.account_info['auth_type_id'], 'decorator_account_no': g.account_info['account_no'], } db_connection = get_db_connection() try: if db_connection: seller_service = SellerService() getting_seller_info_result = seller_service.get_seller_info( account_info, db_connection) return getting_seller_info_result else: return jsonify({'message': 'NO_DATABASE_CONNECTION'}), 500 except Exception as e: return jsonify({'message': f'{e}'}), 500 finally: try: db_connection.close() except Exception as e: return jsonify({'message': f'{e}'}), 500 @seller_app.route('/mypage', methods=['GET'], endpoint='get_my_page') @login_required def get_my_page(): """ 계정 셀러정보 표출 엔드포인트(my_page) mypage 셀러정보를 표출하는 엔드포인트 입니다. 로그인 데코레이터로 셀러의 계정 번호를 확인합니다. 확인된 계정 정보를 service 로 넘겨줍니다. g.account_info: 데코레이터에서 넘겨받은 계정 정보 auth_type_id: 계정의 권한정보 account_no: 데코레이터에서 확인된 계정번호 Returns: http 응답코드 200: SUCCESS 셀러정보 겟 완료 400: INVALID_ACCOUNT_NO, INVALID_AUTH_TYPE_ID 403: NO_AUTHORIZATION 500: NO_DATABASE_CONNECTION, DB_CURSOR_ERROR, INVALID_KEY Authors: [email protected] (이종민) History: 2020-04-08 ([email protected]): 초기 생성 """ # get_seller_info dao 를 같이 쓰기 위해 account_no를 아래와 같이 저장 account_info = { 'parameter_account_no': g.account_info['account_no'], 'auth_type_id': g.account_info['auth_type_id'] } try: db_connection = get_db_connection() if db_connection: seller_service = SellerService() getting_seller_info_result = seller_service.get_my_page( account_info, db_connection) return getting_seller_info_result else: return jsonify({'message': 'NO_DATABASE_CONNECTION'}), 500 except Exception as e: return jsonify({'message': f'{e}'}), 500 finally: try: db_connection.close() except Exception as e: return jsonify({'message': f'{e}'}), 500 @seller_app.route('/<int:parameter_account_no>', methods=['PUT'], endpoint='change_seller_info') @login_required @validate_params( Param('parameter_account_no', PATH, int), Param('seller_status_no', FORM, int), Param('seller_type_no', FORM, int), Param('name_kr', FORM, str, rules=[Pattern(r'^[가-힣a-zA-Z0-9\ ]{1,45}$')]), Param('name_en', FORM, str, rules=[Pattern(r'^[a-z\ ]{1,45}$')]), Param('background_image_url', FORM, str, required=False, rules=[MaxLength(200)]), Param('brandi_app_user_app_id', FORM, str, rules=[Pattern(r'^[가-힣a-zA-Z0-9]{1,45}$')]), Param('ceo_name', FORM, str, rules=[Pattern(r'^[가-힣a-zA-Z0-9]{1,45}$')]), Param('company_name', FORM, str, rules=[Pattern(r'^[가-힣a-zA-Z0-9]{1,45}$')]), Param('business_number', FORM, str, rules=[Pattern(r'^[0-9]{3}-{1}[0-9]{2}-{1}[0-9]{5}$')]), Param('online_business_number', FORM, str, rules=[MaxLength(45)]), Param('short_description', FORM, str, rules=[MaxLength(100)]), Param('long_description', FORM, str, required=False, rules=[MaxLength(200)]), Param('long_description', FORM, str, required=False, rules=[MinLength(10)]), Param('site_url', FORM, str, rules=[MaxLength(200)]), Param( 'site_url', FORM, str, rules=[ Pattern( r"^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\(\)\*\+,;=.]+$" ) ]), Param('manager_infos', FORM, str), Param('insta_id', FORM, str, rules=[Pattern(r"^[a-z0-9_\.]{1,45}$")]), Param('center_number', FORM, str, rules=[Pattern(r"^[0-9-]{1,14}$")]), Param('kakao_id', FORM, str, required=False, rules=[Pattern(r"^[가-힣a-zA-Z0-9_\.]{1,45}$")]), Param('yellow_id', FORM, str, required=False, rules=[Pattern(r"^[가-힣a-zA-Z0-9_\.]{1,45}$")]), Param('zip_code', FORM, str, rules=[Pattern(r"^[0-9]{5}$")]), Param('address', FORM, str, rules=[MaxLength(100)]), Param('detail_address', FORM, str, rules=[MaxLength(100)]), Param( 'weekday_start_time', FORM, str, rules=[ Pattern( r"^(00|0[0-9]|1[0-9]|2[0-3]):([0-9]|[0-5][0-9]):([0-9]|[0-5][0-9])$" ) ]), Param( 'weekday_end_time', FORM, str, rules=[ Pattern( r"^(00|0[0-9]|1[0-9]|2[0-3]):([0-9]|[0-5][0-9]):([0-9]|[0-5][0-9])$" ) ]), Param( 'weekend_start_time', FORM, str, required=False, rules=[ Pattern( r"^(00|0[0-9]|1[0-9]|2[0-3]):([0-9]|[0-5][0-9]):([0-9]|[0-5][0-9])$" ) ]), Param( 'weekend_end_time', FORM, str, required=False, rules=[ Pattern( r"^(00|0[0-9]|1[0-9]|2[0-3]):([0-9]|[0-5][0-9]):([0-9]|[0-5][0-9])$" ) ]), Param('bank_name', FORM, str, rules=[MaxLength(45)]), Param('bank_holder_name', FORM, str, rules=[MaxLength(45)]), Param('account_number', FORM, str, rules=[MaxLength(45)]), # int 를 str 로 인식해서 정규식 유효성 확인 Param('seller_status_no', FORM, str, rules=[Pattern(r"^[1-6]{1}$")]), Param('seller_type_no', FORM, str, rules=[Pattern(r"^[1-7]{1}$")]), # 이미지 url 이 들어올 경우 유효성 확인 Param( 'profile_image_url', FORM, str, required=False, rules=[ Pattern( r"^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\(\)\*\+,;=.]+$" ) ]), Param( 'certificate_image_url', FORM, str, required=False, rules=[ Pattern( r"^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\(\)\*\+,;=.]+$" ) ]), Param( 'online_business_image_url', FORM, str, required=False, rules=[ Pattern( r"^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\(\)\*\+,;=.]+$" ) ]), Param( 'background_image_url', FORM, str, required=False, rules=[ Pattern( r"^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\(\)\*\+,;=.]+$" ) ]), Param('profile_image_url', FORM, str, required=False, rules=[MaxLength(200)]), Param('certificate_image_url', FORM, str, required=False, rules=[MaxLength(200)]), Param('online_business_image_url', FORM, str, required=False, rules=[MaxLength(200)])) def change_seller_info(*args): """ 계정 셀러정보 수정 엔드포인트 셀러정보를 수정하는 엔드포인트 입니다. url 로 셀러정보를 수정하고 싶은 계정 번호를 받습니다. 셀러정보 수정을 수행하려는 계정의 정보를 데코레이터로부터 받습니다. 수정하려는 내용은 form 으로 받습니다. 받은 정보를 유효성 검사를 거친 후 account_info 로 저장해 service 로 넘겨줍니다. Args: *args: 유효성 검사를 통과한 파라미터 url parameter: parameter_account_no: 저장할 셀러정보의 계정 번호 g.account_info: 데코레이터에서 넘겨받은 수정을 수행하는 계정 정보 auth_type_id: 계정의 권한정보 account_no: 데코레이터에서 확인된 계정번호 form: seller_status_no 셀러 상태번호 int seller_type_no 셀러 속성번호 int name_kr 셀러 한글명 str 한글,영문,숫자 name_en 셀러 영문명 str required False 영문 소문자 brandi_app_user_app_id 브랜디앱 유저 아이디 str ceo_name 대표자명 str company_name 사업자명 str business_number 사업자번호 str 12자리 online_business_number 통신판매업번호 str short_description 셀러 한줄 소개 str long_description 셀러 상세 소개 str required False 10글자 이상 site_url 사이트 URL str manager_info: 담당자 정보 list [ { name 담당자명 str contact_number 담당자 핸드폰번호 str email 담당자 이메일 str } ] insta_id 인스타그램 아이디 str center_number 고객센터 전화번호 str kakao_id 카카오톡 아이디 str required False yellow_id 옐로우 아이디 str required False zip_code 우편번호 str address 주소 int detail_address 상세주소 str weekday_start_time 고객센터 운영 시작시간(주중) str weekday_end_time 고객센터 운영 종료시간(주중) str weekend_start_time 고객센터 운영 시작시간(주말) str required False weekend_end_time 고객센터 운영 종료시간(주말) str required False bank_name 정산은행 str bank_holder_name 계좌주 str account_number 계좌번호 str previous_seller_status_no 이전 셀러정보의 상태번호 int (상태변경이력 체크용) Returns: http 응답코드 200: SUCCESS 셀러정보 수정(새로운 이력 생성) 완료 400: INVALID_APP_ID (존재하지 않는 브랜디 앱 아이디 입력) 400: VALIDATION_ERROR_MANAGER_INFO, NO_SPECIFIC_MANAGER_INFO, INVALID_AUTH_TYPE_ID, NO_PROFILE_IMAGE, NO_CERTIFICATE_IMAGE NO_CHANGEABLE_STATUS, EXISTING_NAME_KR, EXISTING_NAME_EN 403: NO_AUTHORIZATION, NO_AUTHORIZATION_FOR_STATUS_CHANGE, NO_ONLINE_BUSINESS_IMAGE 500: INVALID_KEY, DB_CURSOR_ERROR, NO_DATABASE_CONNECTION Authors: [email protected] (이종민) [email protected] (윤희철) History: 2020-04-03 ([email protected]): 초기 생성 2020-04-04 ([email protected]): 이전 셀러 정보번호, 이전 셀러 정보 상태정보, 셀러 계정번호 추가 2020-04-06 ([email protected]): url path 변경('/<int:parameter_account_no>/info' -> '/<int:parameter_account_no>') 2020-04-08 ([email protected]): 마스터가 아닐 때 셀러 상태(입점 등)를 변경하려고 하면 에러 처리하는 내용 추가 2020-04-09 ([email protected]): 이미지 업로더 적용. 2020-04-09 ([email protected]): 이미지 파일을 새로 업로드하면, 이 파일을 저장한 s3 url 을 저장하고, 수정을 안해서 기존에 DB에 저장된 url 을 보내주면, 해당 url 을 저장함 필수값인 셀러 프로필, 등록증 2개가 들어오지 않으면 에러처리 2020-04-12 ([email protected]): 셀러용 이미지 업로더를 사용하는 것에서 공통 업로더를 사용하도록 변경 """ # manager_infos 유효성 확인을 확인하기 위해 따로 저장 manager_info_list = json.loads(args[16]) # manger_infos 리스트를 돌면서 각각의 유효성을 충족하는지 체크 for info in manager_info_list: name_validation = r'^[가-힣a-zA-Z0-9\ ]{1,45}$' contact_number_validation = r'^[0-9-]{1,14}$' email_validation = r'^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*.[a-zA-Z]{2,3}$' ranking_validation = r'^[1-3]{1}$' # 각 키가 들어왔는지 먼저 확인 if (info.get('name', None) and info.get('contact_number', None) and info.get('email', None) and info.get('ranking', None)): # 키가 모두 들어왔으면, 유효성을 만족하는지 확인 if (re.match(name_validation, info['name']) and re.match( contact_number_validation, info['contact_number']) and re.match(email_validation, info['email']) and re.match(ranking_validation, str(info['ranking']))): pass # 유효성을 만족시키지 못하면 에러 반환 else: return jsonify( {"message": "VALIDATION_ERROR_MANAGER_INFO"}), 400 # 키가 안들어오면 에러 반환 else: return jsonify({"message": "NO_SPECIFIC_MANAGER_INFO"}), 400 # 이미지 업로드 함수를 호출해서 이미지를 업로드하고 url 을 딕셔너리로 가져옴. image_upload = ImageUpload() seller_image = image_upload.upload_images(request) if (400 in seller_image) or (500 in seller_image): return seller_image # validation 확인이 된 data 를 account_info 로 재정의 account_info = { 'auth_type_id': g.account_info['auth_type_id'], 'decorator_account_no': g.account_info['account_no'], 'parameter_account_no': args[0], 'profile_image_url': seller_image.get('seller_profile_image', None), 'seller_status_no': args[1], 'seller_type_no': args[2], 'name_kr': args[3], 'name_en': args[4], 'brandi_app_user_app_id': args[6], 'ceo_name': args[7], 'company_name': args[8], 'business_number': args[9], 'certificate_image_url': seller_image.get('certificate_image', None), 'online_business_number': args[10], 'online_business_image_url': seller_image.get('online_business_image', None), 'background_image_url': seller_image.get('background_image', None), 'short_description': args[11], 'long_description': args[12], 'site_url': args[14], 'manager_infos': manager_info_list, 'insta_id': args[17], 'center_number': args[18], 'kakao_id': args[19], 'yellow_id': args[20], 'zip_code': args[21], 'address': args[22], 'detail_address': args[23], 'weekday_start_time': args[24], 'weekday_end_time': args[25], 'weekend_start_time': args[26], 'weekend_end_time': args[27], 'bank_name': args[28], 'bank_holder_name': args[29], 'account_number': args[30], } # file 로 이미지가 안들어올 경우, FORM 으로 받은 이미지 url 로 대체 if not account_info['profile_image_url']: account_info['profile_image_url'] = args[33] if not account_info['certificate_image_url']: account_info['certificate_image_url'] = args[34] if not account_info['online_business_image_url']: account_info['online_business_image_url'] = args[35] if not account_info['background_image_url']: account_info['background_image_url'] = args[36] # 이미지 url 필수값 3개가 안들어오면 에러 리턴 if not account_info['profile_image_url']: return jsonify({'message': 'NO_PROFILE_IMAGE'}), 400 if not account_info['certificate_image_url']: return jsonify({'message': 'NO_CERTIFICATE_IMAGE'}), 400 if not account_info['online_business_image_url']: return jsonify({'message': 'NO_ONLINE_BUSINESS_IMAGE'}), 400 # 데이터베이스 연결 try: db_connection = get_db_connection() if db_connection: seller_service = SellerService() changing_seller_info_result = seller_service.change_seller_info( account_info, db_connection) return changing_seller_info_result else: return jsonify({'message': 'NO_DATABASE_CONNECTION'}), 500 except Exception as e: return jsonify({'message': f'{e}'}), 500 finally: try: db_connection.close() except Exception as e: return jsonify({'message': f'{e}'}), 500 @seller_app.route('/<int:parameter_account_no>/password', methods=['PUT'], endpoint='change_password') @login_required @validate_params( Param('parameter_account_no', PATH, int), Param('original_password', JSON, str, required=False), Param('new_password', JSON, str), ) def change_password(*args): """ 계정 비밀번호 변경 엔드포인트 계정 비밀번호 변경 엔드포인트 입니다. 계정이 가진 권한에 따라 지정된 인자를 받아 비밀번호를 변경합니다. url 에 비밀번호를 바꿔야할 계정 번호를 받습니다. Args: *args: 유효성 검사를 통과한 파라미터 url parameter: parameter_account_no: 비밀번호가 바뀌어야할 계정 번호 g.account_info: 데코레이터에서 넘겨받은 계정 정보(비밀번호 변경을 수행하려는 계정) auth_type_id: 계정의 권한정보 account_no: 계정번호 request.body: request 로 전달 받은 정보 original_password: 기존 비밀번호(비밀번호 변경을 수행하는자가 셀러 권한일 경우에만 전달 받음) new_password: 변경하려는 새로운 비밀번호 Returns: http 응답코드 200: SUCCESS 비밀번호 변경 완료 400: VALIDATION_ERROR, INVALID_AUTH_TYPE_ID, NO_ORIGINAL_PASSWORD TOO_SHORT_PASSWORD, INVALID_PARAMETER_ACCOUNT_NO 401: INVALID_PASSWORD 403: NO_AUTHORIZATION 500: DB_CURSOR_ERROR, NO_DATABASE_CONNECTION Authors: [email protected] (이종민) History: 2020-03-31 ([email protected]): 초기 생성 2020-04-02 ([email protected]): 파라미터 validation 추가, 데코레이터 적용 2020-04-06 ([email protected]): url path 변경('/<int:parameter_account_no>' -> '/<int:parameter_account_no>/password') 2020-04-12 ([email protected]): 리팩토링 - 주석 수정 : 비밀번호 변경을 수행하려는 주체에 대해 명확히 명시 - 변경할 비밀번호 길이 제한 추가(4글자 이상) - 전달 인자 명칭을 명확히 하기 위해 변경(account_info -> change_info) """ # validation 확인이 된 data 를 change_info 로 재정의 change_info = { 'parameter_account_no': args[0], 'original_password': args[1], 'new_password': args[2], 'auth_type_id': g.account_info['auth_type_id'], 'decorator_account_no': g.account_info['account_no'] } # 셀러 권한일 때 original_password 가 없으면 에러반환 if change_info['auth_type_id'] == 2: if change_info['original_password'] is None: return jsonify({"message": "NO_ORIGINAL_PASSWORD"}), 400 # 변경할 비밀번호 길이가 4글자 미만이면 에러 반환 if len(change_info['new_password']) < 4: return jsonify({'message': 'TOO_SHORT_PASSWORD'}), 400 try: db_connection = get_db_connection() if db_connection: seller_service = SellerService() changing_password_result = seller_service.change_password( change_info, db_connection) return changing_password_result else: return jsonify({'message': 'NO_DATABASE_CONNECTION'}), 500 except Exception as e: return jsonify({'message': f'{e}'}), 500 finally: try: db_connection.close() except Exception as e: return jsonify({'message': f'{e}'}), 500 @seller_app.route('/<int:seller_account_id>/status', methods=['PUT'], endpoint='change_seller_status') @login_required @validate_params(Param('seller_account_id', PATH, int, required=False), Param('seller_status_id', JSON, int, required=False)) def change_seller_status(*args): """ 셀러 상태 변경 마스터 권한을 가진 어카운트가 셀러의 상태를 변경 하는 기능. path parameter 로 셀러 계정 번호를 받고 body 로 변경하고자 하는 셀러 상태 번호를 받는다. Args: args: 유효성 검사를 통과한 파라미터 리스트 seller_account_id: path parameter 를 통해서 들어온 셀러 계정 번호 seller_status_id: request body 를 통해서 들어온 Returns: status_change_result: seller_service 에서 넘겨받은 결과 값. 400: seller_service 의 클래스 호출 실패 또는 parameter 를 제대로 넘겨지주 못했을 경우 500: 데이터베이스 연결 실패 Authors: [email protected] (윤희철) History: 2020-04-05 ([email protected]): 초기 생성 2020-04-09 ([email protected]): 선분이력을 반영하여 상태변경 작성 """ # 유저정보를 가져와 서비스로 넘김 user = g.account_info # 유효성검사를 통과한 parameter 를 딕셔너리 담는다. target_seller_info = { 'seller_account_id': args[0], 'seller_status_id': args[1] } try: db_connection = DatabaseConnection() if db_connection: seller_service = SellerService() status_change_result = seller_service.change_seller_status( target_seller_info, user, db_connection) return status_change_result else: return jsonify({'message': 'NO_DATABASE_CONNECTION'}), 500 except Exception as e: return ({'message': f'{e}'}), 400
def test_root_list_invalid(self): param = JsonParam( { 'age': [Number()], 'name': [ MinLength(1), ], 'tags': JsonParam( {'name': [MinLength(1)]}, required=False, as_list=True) }, as_list=True) # invalid values _, errors = param.validate([ { 'age': 'ab', 'name': 'test' }, { 'age': 'c', 'name': '' }, { 'age': 15, 'name': 'good' }, ]) self.assertEqual(1, len(errors)) self.assertTrue(isinstance(errors[0], JsonError)) error = errors[0] self.assertListEqual(['root'], error.depth) self.assertTrue(2, len(error.errors)) self.assertTrue(error.errors[0], 1) self.assertTrue(error.errors[1], 2) self.assertTrue( isinstance(error.errors[0]['age'].errors[0], NumberError)) self.assertTrue( isinstance(error.errors[1]['age'].errors[0], NumberError)) self.assertTrue( isinstance(error.errors[1]['name'].errors[0], ValueMinLengthError)) # invalid type - dict instead list _, errors = param.validate({'age': 18, 'name': 'test'}) self.assertEqual(1, len(errors)) self.assertListEqual(['root'], errors[0].depth) self.assertTrue(isinstance(errors[0], JsonListExpectedError)) # invalid type - nested string instead list _, errors = param.validate([ { 'age': 27, 'name': 'test' }, { 'age': 15, 'name': 'good', 'tags': 'bad_type' }, ]) self.assertEqual(1, len(errors)) self.assertListEqual(['root', 'tags'], errors[0].depth) self.assertTrue(isinstance(errors[0], JsonListExpectedError))
class OrderView: order_app = Blueprint('order_app', __name__, url_prefix='/orders') @order_app.route('/filter_options/<order_status_id>', methods=['GET']) @validate_params( Param('order_status_id', PATH, int, rules=[Enum(1, 2, 3, 4, 5)])) @login_validator def get_filter_options(order_status_id): # 주문관리 페이지에서 셀러속성 리스트와 주문상태 변경 버튼 보내주는 엔드포인트 order_service = OrderService() connection = None try: connection = connect_db() filter_options = order_service.get_filter_options( connection, order_status_id) return jsonify(filter_options), 200 except Exception as e: return jsonify({"message": f'{e}'}), 400 finally: try: if connection: connection.close() except Exception as e: return jsonify({"message": f'{e}'}), 500 @order_app.route('', methods=['GET']) @validate_params( Param('order_status_id', GET, int, rules=[Enum(1, 2, 3, 4, 5)], required=True), Param('order_number', GET, str, rules=[Pattern('^[0-9]{16,}$')], required=False), Param('detailed_order_number', GET, str, rules=[Pattern('^[0-9]{17,}$')], required=False), Param('buyer_name', GET, str, rules=[Pattern('[\S]')], required=False), Param('phone_number', GET, str, rules=[Pattern('^[0-9]{11}$')], required=False), Param('seller_name', GET, str, rules=[Pattern('[\S]')], required=False), Param('product_name', GET, str, rules=[Pattern('[\S]')], required=False), Param( 'start_date', GET, str, rules=[ Pattern( '^(20)[\d]{2}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[0-1])$') ], required=False), Param( 'end_date', GET, str, rules=[ Pattern( '^(20)[\d]{2}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[0-1])$') ], required=False), # 셀러속성 다중선택 가능 Param('seller_type_id', GET, list, rules=[MinLength(1), MaxLength(7)], required=False), Param('limit', GET, int, rules=[Enum(10, 20, 50, 100, 150)], required=False), Param('order_by', GET, str, rules=[Enum('desc', 'asc')], required=False), Param('page', GET, int, required=False)) @login_validator def get_order_list(*args): # 주문상태별 주문 리스트 필터하여 보내주는 엔드포인트 order_service = OrderService() # page parameter에 0이나 음수가 들어올 경우 키에러 if args[12] and args[12] <= 0: return jsonify({"key error": "Page cannot be negative"}), 400 order_filter = { 'order_status_id': args[0], 'order_number': args[1], 'detailed_order_number': args[2], 'buyer_name': args[3], 'phone_number': args[4], 'seller_name': args[5], 'product_name': args[6], 'start_date': args[7], 'end_date': args[8], 'seller_type_id': args[9], # 디폴트값: 최신주문일순, 50개씩 보기 'limit': args[10] if args[10] else 50, 'order_by': args[11] if args[11] else 'desc', 'page': args[12] if args[12] else 1 } # 셀러일 경우 필터에 seller_id 추가 if g.token_info['account_type_id'] == 2: order_filter['seller_id'] = g.token_info['seller_id'] connection = None try: connection = connect_db() order_list = order_service.get_order_list(connection, order_filter) return jsonify(order_list), 200 except Exception as e: return jsonify({"message": f"{e}"}), 400 finally: try: if connection: connection.close() except Exception as e: return jsonify({"message": f"{e}"}), 500 @order_app.route('', methods=['POST']) @validate_params( Param('order_item_id', JSON, list, required=True), # 2: 상품준비 3: 배송중 Param('order_status_id', GET, int, rules=[Enum(2, 3)], required=True), # 1: 배송처리 2: 배송완료처리 Param('order_action_id', JSON, int, rules=[Enum(1, 2)], required=True)) @login_validator def update_order_status(*args): # 주문 id를 리스트로 받아서 일괄적으로 주문 상태를 업데이트하는 엔드포인트 order_service = OrderService() update_status = { 'editor_id': g.token_info['account_id'], 'order_item_id': args[0], 'order_status_id': args[1], 'order_action_id': args[2] } connection = None try: connection = connect_db() number_of_orders_updated = order_service.update_order_status( connection, update_status) connection.commit() return jsonify({ "message": f"{number_of_orders_updated} order(s) successfully updated" }), 201 except Exception as e: connection.rollback() return jsonify({"message": f"{e}"}), 400 finally: try: if connection: connection.close() except Exception as e: return jsonify({"message": f"{e}"}), 500 @order_app.route('/<order_item_id>', methods=['GET']) @validate_params(Param('order_item_id', PATH, int)) @login_validator def get_order_detail(order_item_id): # 주문 상세정보 가져오는 엔드포인트 order_service = OrderService() order_filter = {'order_item_id': order_item_id} # # 셀러일 경우 필터에 seller_id 추가 # if g.token_info['account_type_id'] == 2: # order_filter['seller_id'] = g.token_info['seller_id'] connection = None try: connection = connect_db() order_detail = order_service.get_order_detail( connection, order_filter) return jsonify(order_detail), 200 except Exception as e: return jsonify({"message": f"{e}"}), 400 finally: try: if connection: connection.close() except Exception as e: return jsonify({"message": f"{e}"}), 500 @order_app.route('/<order_item_id>', methods=['POST']) @validate_params(Param('order_item_id', PATH, int, required=True), Param('new_order_status_id', JSON, int, rules=[Enum(2, 3, 4, 5)], required=False), Param('phone_number', JSON, str, rules=[Pattern('^[0-9]{11}')], required=False), Param('address_1', JSON, str, rules=[Pattern('[\S]')], required=False), Param('address_2', JSON, str, rules=[Pattern('[\S]')], required=False), Param('zip_code', JSON, str, rules=[Pattern('^[0-9]{5}')], required=False), Param('delivery_instruction', JSON, str, required=False)) @login_validator def update_order_detail(*args): # 주문 상세정보(주문상태, 연락처, 배송지 정보)를 업데이트하고 업데이트된 정보를 리턴 order_service = OrderService() order_filter = {'order_item_id': args[0]} update_order = { 'editor_id': g.token_info['account_id'], 'order_item_id': args[0], 'new_order_status_id': args[1], 'phone_number': args[2], 'address_1': args[3], 'address_2': args[4], 'zip_code': args[5], 'delivery_instruction': args[6], } # 셀러일 경우 필터에 seller_id 추가 if g.token_info['account_type_id'] == 2: order_filter['seller_id'] = g.token_info['seller_id'] connection = None try: connection = connect_db() order_service.update_order_detail(connection, update_order) updated_order_detail = order_service.get_order_detail( connection, order_filter) connection.commit() return jsonify({"updated_order_detail": updated_order_detail}), 201 except Exception as e: connection.rollback() return jsonify({"message": f"{e}"}), 400 finally: try: if connection: connection.close() except Exception as e: return jsonify({"message": f"{e}"})