@app.route('/room/<room_id>', methods=['GET']) def get_given_room(room_id): room = room_service.find(room_id) return dumps(room) @app.route('/room/<room_id>', methods=['DELETE']) def delete_room(room_id): room = room_service.delete(room_id) return (dumps({'message': 'Room deleted'}), 200) @app.route("/room", methods=['POST']) @validate_params(Param('name', JSON, str), Param('capacity', JSON, int)) def create_room(name, capacity): room = Room(request.json) room_service.create(room) return (dumps({'message': 'Room created'}), 201) @app.route("/room/<room_id>", methods=['PUT']) @validate_params(Param('room_id', PATH, str), Param('name', JSON, str, required=False), Param('capacity', JSON, int, required=False)) def edit_room(room_id, name, capacity): room = Room(request.json) room.set_id(room_id) room_service.edit(room) return (dumps({'message': 'Edited Room'}), 204)
class ProductListView(MethodView): """ Presentation Layer Attributes: product_list_service : ProductListService 클래스 database : app.config['DB']에 담겨있는 정보(데이터베이스 관련 정보) Author: 김민구 History: 2020-12-29(김민구): 초기 생성 2020-12-31(김민구): 에러 문구 변경 / 하나의 이벤트에 대한 배너와 상품들을 반환하는 작업으로 수정 """ def __init__(self, services, database): self.product_list_service = services.product_list_service self.database = database @validate_params( Param('offset', GET, int, required=False, default=0), Param('limit', GET, int, required=False, default=30) ) def get(self, *args): """ GET 메소드: 전체 상품 리스트 조회 Args: offset = 0부터 시작 limit = 30 Author: 김민구 Returns: 상품 리스트 조회 성공 200, { 'message': 'success', 'result': { "event": { 'id' : 1, 'banner_image' : 'url' }, "product_list" : [ { 'image': 'url', 'seller_id': 1, 'seller_name': '둘리', 'product_id': 1, 'product_name': '성보의 하루', 'origin_price': 10000.0, 'discount_rate': 0.1, 'discounted_price': 9000.0, 'sales_count': 30 }, ] } } Raises: 400, {'message': 'invalid_parameter', 'error_message': '[데이터]가(이) 유효하지 않습니다.'} : 잘못된 요청값 400, {'message': 'key_error', 'error_message': format(e)} : 잘못 입력된 키값 500, { 'message': 'database_connection_fail', 'error_message': '서버에 알 수 없는 에러가 발생했습니다.' } : 커넥션 종료 실패 500, {'message': 'database_error', 'error_message': '서버에 알 수 없는 에러가 발생했습니다.'} : 데이터베이스 에러 500, {'message': 'internal_server_error', 'error_message': format(e)}) : 서버 에러 History: 2020-12-30(김민구): 초기 생성 2020-12-31(김민구): 에러 문구 변경 / 이벤트에 해당하는 상품 리스트 반환으로 수정 Notes: offset을 받아서 한 페이지당 하나의 이벤트만 출력 이벤트가 없을 시 빈 리스트 반환 """ connection = None try: data = { 'offset': args[0], 'limit': args[1] } connection = get_connection(self.database) result = self.product_list_service.product_list_logic(connection, data) return jsonify({'message': 'success', 'result': result}) except Exception as e: traceback.print_exc() raise e finally: try: if connection is not None: connection.close() except Exception: raise DatabaseCloseFail('서버에 알 수 없는 에러가 발생했습니다.')
class DestinationView(MethodView): def __init__(self, service, database): self.service = service self.database = database @signin_decorator(False) def get(self): """GET 메소드: 해당 유저에 대한 배송지 정보 받아오기 유저에 관련된 모든 배송지 정보를 조회 및 반환한다. Args: g.account_id : 데코레이터에서 넘겨받은 유저 정보 g.permission_type_id: 권한정보 Author: 김기용 Returns: 200, {'message': 'success', 'result': 유저 배송지 정보들}: 배송지 조회 성공 Raises: 400, {'message': 'key error', 'errorMessage': '키 값이 일치하지 않습니다.'} 500, {'message': 'unable to close database', 'errorMessage': '커넥션 종료 실패'}: 500, {'message': 'internal server error', 'errorMessage': format(e)}) History: 2020-12-29(김기용): 초기 생성 2021-01-02(김기용): 데코레이터 수정 """ connection = None try: data = dict() if 'account_id' in g: data['account_id'] = g.account_id if 'permission_type_id' in g: data['permission_type_id'] = g.permission_type_id connection = get_connection(self.database) destination_detail = self.service.get_destination_detail_by_user_service(connection, data) return {'message': 'success', 'result': destination_detail} except Exception as e: raise e finally: try: if connection: connection.close() except Exception: raise DatabaseCloseFail('서버에서 알 수 없는 에러가 발생했습니다.') @signin_decorator(True) @validate_params( Param('recipient', JSON, str), Param('phone', JSON, str, rules=[PhoneRule()]), Param('address1', JSON, str), Param('address2', JSON, str), Param('post_number', JSON, str, rules=[PostalCodeRule()]), ) def post(self, *args): """POST 메소드: 배송지 추가 사용자가 입력한 배송지 정보를 받아 데이터베이스에 추가한다. 최대 배송지 생성 개수는 5개이다. Args: args: 'recipient' : 수신자 'phone' : 폰번호 'address1' : 메인주소 'address2' : 상세주소 'post_number': 우편번호 g.account_id : 데코레이터에서 넘겨받은 어카운트 아이디 g.permission_type_id: 데코레이터에서 넘겨받은 권한 아이디 Author: 김기용 Returns: 201, {'message': 'success'}: 배송지 생성 성공 Raises: 400, {'message': 'invalid_parameter', 'error_message': '[데이터]가(이) 유효하지 않습니다.'} 500, {'message': 'unable_to_close_database', 'errorMessage': '커넥션 종료 실패'} 500, {'message': 'internal_server_error', 'errorMessage': format(e)}) History: 2020-12-28(김기용): 초기 생성 2020-12-29(김기용): 데코레이터 추가 2020-12-30(김기용): 수정된 데코레이터반영: 데코레이터에서 permission_type 을 받음 2021-01-02(김기용): 수정된 데코레이터 반영: signin_decorator(True) """ connection = None try: data = { 'user_id': g.account_id, 'permission_type_id': g.permission_type_id, 'recipient': args[0], 'phone': args[1], 'address1': args[2], 'address2': args[3], 'post_number': args[4], } connection = get_connection(self.database) self.service.create_destination_service(connection, data) connection.commit() return {'message': 'success'} except Exception as e: connection.rollback() raise e finally: try: if connection: connection.close() except Exception: raise DatabaseCloseFail('서버에서 알 수 없는 에러가 발생했습니다.') @signin_decorator(True) @validate_params( Param('destination_id', JSON, str, rules=[NumberRule()]), Param('recipient', JSON, str), Param('phone', JSON, str, rules=[PhoneRule()]), Param('address1', JSON, str), Param('address2', JSON, str), Param('post_number', JSON, str, rules=[PostalCodeRule()]), Param('default_location', JSON, str, rules=[IsDeleteRule()]) ) def patch(self, *args): """ PATCH 메소드: 배송지 정보 수정 사용자가 입력한 배송지 정보를 받아 수정한다. Args: 'destination_id' : 배송지 아이디 'recipient' : 수신자 'phone' : 폰번호 'address1' : 메인주소 'address2' : 상세주소 'post_number' : 우편번호 'default_location': 기본 배송지 g.account_id : 데코레이터에서 넘겨받은 어카운트 아이디 g.permission_type_id: 데코레이터에서 넘겨받은 권한 아이디 Author: 김기용 Returns: {'message':'success'} Raises: 500, {'message': 'unable to close database', 'errorMessage': '커넥션 종료 실패'} 500, {'message': 'internal server error', 'errorMessage': format(e)}) """ connection = None try: data = dict() data['destination_id'] = args[0] data['recipient'] = args[1] data['phone'] = args[2] data['address1'] = args[3] data['address2'] = args[4] data['post_number'] = args[5] data['default_location'] = args[6] data['account_id'] = g.account_id data['permission_type_id'] = g.permission_type_id connection = get_connection(self.database) self.service.update_destination_info_service(connection, data) connection.commit() return {'message': 'success'} except Exception as e: connection.rollback() raise e finally: try: if connection: connection.close() except Exception: raise DatabaseCloseFail('서버에서 알 수 없는 에러가 발생했습니다') @signin_decorator(True) @validate_params( Param('destination_id', JSON, str, rules=[NumberRule()]) ) def delete(self, *args): """DELETE 메소드: 배송지 삭제 Args: 'destination_id': 배송지 아이디 g.account_id : 데코레이터에서 넘겨받은 account_id g.permission_type_id : 데코레이터에서 넘겨받은 권한 아이디 Author: 김기용 Returns: 200, {'message': 'success'}: 배송지 삭제 성공 Raises: 500, {'message': 'unable_to_close_database', 'errorMessage': '커넥션 종료 실패'} 500, {'message': 'internal_server_error', 'errorMessage': format(e)}): 서버 에러 History: 2020-12-29(김기용): 초기 생성 2020-12-30(김기용): 데코레이터 추가 """ connection = None try: data = dict() data['destination_id'] = args[0] data['account_id'] = g.account_id data['permission_type_id'] = g.permission_type_id connection = get_connection(self.database) self.service.delete_destination_service(connection, data) connection.commit() return {'message': 'success'} except Exception as e: connection.rollback() raise e finally: try: if connection: connection.close() except Exception: raise DatabaseCloseFail('서버에서 알 수 없는 에러가 발생했습니다')
def create_event_endpoints(event_service, Session): #Blueprint 설정 event_app = Blueprint('event_app', __name__, url_prefix='/api/events') @event_app.route('', methods=['GET']) @validate_params( Param('is_displayed', GET, int, required=False), Param('limit', GET, int, required=False, default=30), Param('offset', GET, int, required=False), ) def select_event_list(*args): """ event_list select endpoint 로직 args: *args: is_displayed : 진행중인 이벤트인지 구분 여부 limit : pagination 을 위한 파라미터 offset : pagination 을 위한 파라미터 returns : event_list return Authors: 권창식 History: 2020-10-10 (권창식): 초기 생성 """ session = Session() try: event_info = { 'is_displayed': args[0], 'limit': args[1], 'offset': args[2] } get_event_list = event_service.select_event_list( event_info, session) if not get_event_list: return jsonify({'message': 'EMPTY_DATA'}), 400 return jsonify({'data': get_event_list}), 200 except exc.InvalidRequestError: return jsonify({'message': 'INVALID_URL'}), 400 except exc.ProgrammingError: return jsonify({'message': 'ERROR_IN_SQL_SYNTAX'}), 500 except Exception as e: return jsonify({'message': f'{e}'}), 500 finally: session.close() @event_app.route('/detail', methods=['GET']) @validate_params(Param('id', GET, int, required=False)) def select_event_detail(*args): """ 상품 정보 전달 API 여러 상품 정보가 필요한 페이지에서 쿼리 파라미터로 필터링에 사용될 값을 받아 필터링된 상품의 데이터들을 표출합니다. args: *args: id : event_id returns : event에 해당하는 정보 return Authors: 권창식 History: 2020-10-10 (권창식): 초기 생성 """ session = Session() try: event_info = {'id': args[0]} get_event_detail, get_event_button = event_service.select_event_detail( event_info, session) if not get_event_detail: return jsonify({'event_detail': 'EMPTY_DATA'}), 400 if not get_event_button: return jsonify({ 'event_button': 0, "event_detail": get_event_detail }), 200 return jsonify({ "event_detail": get_event_detail, "event_button": get_event_button }), 200 except exc.InvalidRequestError: return jsonify({'message': 'INVALID_URL'}), 400 except exc.ProgrammingError: return jsonify({'message': 'ERROR_IN_SQL_SYNTAX'}), 500 except Exception as e: return jsonify({'message': f'{e}'}), 500 finally: session.close() @event_app.route('/products', methods=['GET']) @validate_params( Param('id', GET, int, required=True), Param('button_id', GET, int, required=True), Param('limit', GET, int, required=False, default=30), Param('offset', GET, int, required=False), ) def select_event_products(*args): """ 상품 정보 전달 API 여러 상품 정보가 필요한 페이지에서 쿼리 파라미터로 필터링에 사용될 값을 받아 필터링된 상품의 데이터들을 표출합니다. args: *args: id : event_id 정보 button_id : button_id 정보 limit : pagination 을 위한 파라미터 offset : pagination 을 위한 파라미터 returns : event_products return Authors: 권창식 History: 2020-10-10 (권창식): 초기 생성 """ session = Session() try: event_info = { 'id': args[0], 'button_id': args[1], 'limit': args[2], 'offset': args[3] } get_event_products = event_service.select_event_products( event_info, session) if not get_event_products: return jsonify({'message': 'EMPTY_DATA'}), 400 return jsonify({"event_product": get_event_products}), 200 except exc.InvalidRequestError: return jsonify({'message': 'INVALID_URL'}), 400 except exc.ProgrammingError: return jsonify({'message': 'ERROR_IN_SQL_SYNTAX'}), 500 except Exception as e: return jsonify({'message': f'{e}'}), 500 finally: session.close() return event_app
class StoreOrderView(MethodView): """ Presentation Layer Attributes: database: app.config['DB']에 담겨있는 정보(데이터베이스 관련 정보) service: CartItemService 클래스 Author: 고수희 History: 2020-12-30(고수희): 초기 생성 """ def __init__(self, service, database): self.service = service self.database = database @signin_decorator(True) @validate_params(Param('order_id', PATH, int)) def get(self, *args): """ GET 메소드: 해당 유저가 직전에 마친 결제 정보를 조회 결제가 완료된 페이지에서 확인하는 정보다. order_id에 해당되는 결제 상품 정보를 테이블에서 조회 후 가져옴 Args: args = ('account_id', 'cart_id') Author: 고수희 Returns: #통화에 대한 정의와 정수로 변환 { "message": "success", "result": { "order_number": "20210101000001000", "total_price": 8000.0 } } Raises: 400, {'message': 'key error', 'errorMessage': 'key_error'} : 잘못 입력된 키값 400, {'message': 'cart item does not exist error', 'errorMessage': 'cart_item_does_not_exist'} : 장바구니 상품 정보 조회 실패 400, {'message': 'unable to close database', 'errorMessage': 'unable_to_close_database'}: 커넥션 종료 실패 500, {'message': 'internal server error', 'errorMessage': format(e)}) : 서버 에러 History: 2020-12-28(고수희): 초기 생성 2020-12-30(고수희): 1차 수정 - 데코레이터 추가, 사용자 권한 체크 2021-01-02(고수희): decorator 수정 """ data = { "order_id": args[0], "user_id": g.account_id, "user_permission": g.permission_type_id } try: connection = get_connection(self.database) store_order_info = self.service.get_store_order_service( connection, data) return jsonify({'message': 'success', 'result': store_order_info}) except Exception as e: raise e finally: try: if connection: connection.close() except Exception: raise DatabaseCloseFail('database close fail')
return json_util.dumps(db.clients.find_one({'_id': client_object_id})) @app.route('/engagements') def engagements(): return json_util.dumps(db.engagements.find({})) @app.route('/engagements/<engagement_id>') def engagements_by_id(engagement_id): engagement_object_id = ObjectId(engagement_id) return json_util.dumps(db.engagements.find_one({'_id': engagement_object_id})) @app.route('/interactions') @validate_params( Param(name='engagementId', param_type=GET, value_type=str, required=True, rules=[rules.ObjectIdRule()]), Param(name='startDate', param_type=GET, value_type=int, required=False, rules=[rules.UnixTimestampRule()]), Param(name='endDate', param_type=GET, value_type=int, required=False, rules=[rules.UnixTimestampRule()]) ) def interactions(engagement_id:str, start_date:int, end_date:int): date_filter = {} db_query = { 'engagementId': ObjectId(engagement_id), } if start_date is not None: date_filter['$gte'] = datetime.fromtimestamp(start_date/1000.0, timezone.utc) if end_date is not None: date_filter['$lt'] = datetime.fromtimestamp(end_date/1000.0, timezone.utc)
class ProductManageDetailView(MethodView): """ Presentation Layer Attributes: service : ProductManageDetailView 클래스 database : app.config['DB']에 담겨있는 정보(데이터베이스 관련 정보) Author: 심원두 History: 2021-01-02(심원두): 초기 작성 """ def __init__(self, service, database): self.service = service self.database = database @signin_decorator() @validate_params( Param('product_code', PATH, str, required=True, rules=[NotEmpty(), MaxLength(20)]), ) def get(self, *args): """GET 메소드: 상품 코드에 해당하는 상품 정보를 불러온다. Args: 'product_code' : 상품 코드 Author: 심원두 Returns: return {"message": "success", "result": result} Raises: 500, {'message': 'product does not exist', 'errorMessage': 'product_does_not_exist'} : 상품 정보 취득 실패 500, {'message': 'product image not exist', 'errorMessage': 'product_image_not_exist'}: 상품 이미지 정보 취득 실패 500, {'message': 'stock info not exist', 'errorMessage': 'stock_does_not_exist'}: 옵션 정보 취득 실패 History: 2021-01-02(심원두): 초기 작성 """ try: data = {'product_code': request.view_args['product_code']} connection = get_connection(self.database) result = self.service.detail_product_service(connection, data) return jsonify({'message': 'success', 'result': result}) except Exception as e: raise e finally: try: if connection: connection.close() except Exception: raise DatabaseCloseFail('database close fail')
class AnswerView(MethodView): def __init__(self, service, database): self.service = service self.database = database @validate_params(Param('enquiry_id', PATH, int, required=True)) def get(self, *args): data = {'enquiry_id': args[0]} try: connection = get_connection(self.database) result = self.service.get_answer_service(connection, data) return jsonify({'message': 'success', 'result': result}) except Exception as e: raise e finally: try: if connection: connection.close() except Exception: raise DatabaseCloseFail('database close fail') @validate_params(Param('enquiry_id', PATH, int), Param('answer', JSON, str)) def post(self, *args): data = {'enquiry_id': args[0], 'answer': args[1]} try: connection = get_connection(self.database) self.service.post_answer_service(connection, data) connection.commit() return {'message': 'success'} except Exception as e: raise e finally: try: if connection: connection.close() except Exception: raise DatabaseCloseFail('database close fail') @validate_params(Param('enquiry_id', PATH, int), Param('answer', JSON, str)) def put(self, *args): data = {'enquiry_id': args[0], 'answer': args[1]} try: connection = get_connection(self.database) self.service.put_answer_service(connection, data) connection.commit() return {'message': 'success'} except Exception as e: raise e finally: try: if connection: connection.close() except Exception: raise DatabaseCloseFail('database close fail') @validate_params( Param('enquiry_id', PATH, int), ) def delete(self, *args): data = {'enquiry_id': args[0]} try: connection = get_connection(self.database) self.service.delete_answer_service(connection, data) connection.commit() return {'message': 'success'} except Exception as e: raise e finally: try: if connection: connection.close() except Exception: raise DatabaseCloseFail('database close fail')
def create_qna_endpoints(qna_service, Session): qna_app = Blueprint('qna_app', __name__, url_prefix='/api/qnas') @qna_app.route('/qna', methods=['POST', 'DELETE']) @login_required def qna(): """ question 작성 API 사용자가 입력한 문의를 데이터베이스에 입력합니다. returns : 200: question 데이터베이스 입력 400: KEY_ERROR, DELETE_FAILED 500: Exception Authors: 고지원 History: 2020-09-26 (고지원): 초기 생성 2020-09-28 (고지원): 수정 - delete 메소드 추가 - 로그인 데코레이터 추가 2020-10-05 (고지원): 삭제하려는 유저와 문의한 유저가 같은 유저인지 확인하는 코드 추가 """ session = Session() try: if request.method == 'POST': # 문의 입력을 위한 데이터를 받는다. qna_info = { 'type_id': request.json['type_id'], 'user_id': g.user_id['user_id'], 'product_id': request.json['product_id'], 'content': request.json['content'], 'is_private': request.json['is_private'] } qna_service.insert_question(qna_info, session) session.commit() return jsonify({'message': 'INSERT_SUCCESS'}), 200 # 삭제하려는 유저와 문의한 유저가 일치하는지 id 를 통해 확인 question_info = { 'question_id': request.args.get('question_id'), 'user_id': g.user_id['user_id'] } row_count = qna_service.delete_question(question_info, session) # 유저 아이디가 매칭될 경우 row_count = 1, token의 유저 id 와 삭제하려는 유저의 id 가 다를 경우 0 if row_count == 0: return jsonify({'message': 'DELETE_FAILED'}), 400 session.commit() return jsonify({'message': 'DELETE_SUCCESS'}), 200 except KeyError: return jsonify({'message': 'KEY_ERROR'}), 400 except Exception as e: session.rollback() return jsonify({'message': f'{e}'}), 500 finally: session.close() @qna_app.route('', methods=['GET']) @validate_params(Param('limit', GET, int, default=100, required=False), Param('offset', GET, int, required=False), Param('product_id', GET, int, required=True)) def qnas(*args): """ QnA 리스트 전달 API product_id 에 따른 QnA 리스트를 표출합니다. args: product_id: 상품의 pk returns : 200: QnA 리스트 500: Exception Authors: 고지원 History: 2020-09-27 (고지원): 초기 생성 2020-09-30 (고지원): 파라미터 유효성 검사 추가 2020-10-05 (고지원): pagination 추가 2020-10-12 (고지원): 삭제를 위해 로그인 한 유저의 아이디와 함께 반환하도록 수정 """ session = Session() try: qna_info = dict() # pagination qna_info['limit'] = args[0] qna_info['offset'] = args[1] # 상품 상세페이지 상품 아이디 qna_info['product_id'] = args[2] # 로그인한 유저의 문의인지 판단하기 위해 토큰을 통해 id를 가져온다. access_token = request.headers.get('Authorization') if access_token: payload = jwt.decode(access_token, SECRET_KEY, ALGORITHM) else: payload = None body = { 'login_user_id': payload, 'qna': [dict(qna) for qna in qna_service.get_qnas(qna_info, session)] } return jsonify(body), 200 except Exception as e: return jsonify({'message': f'{e}'}), 500 finally: session.close() @qna_app.route('/user', methods=['GET']) @login_required @validate_params( Param('limit', GET, int, default=100, required=False), Param('offset', GET, int, required=False), Param('product_id', GET, int, required=False), Param('is_answered', GET, int, rules=[Enum(0, 1)], required=False), ) def user_qnas(*args): """ 로그인한 user 의 QnA 리스트 전달 API user_id, product_id 에 따른 QnA 리스트를 표출합니다. args : *args: product_id: 상품의 pk is_answered: 답변, 미답변 여부 판단위한 파라미터 g.user_id: 데코레이터에서 넘어온 user 의 pk returns : 200: QnA 리스트 500: Exception Authors: 고지원 History: 2020-09-29 (고지원): 초기 생성 2020-09-30 (고지원): 파라미터 유효성 검사 추가 2020-10-06 (고지원): 로그인 데코레이터에서 id 가져와 해당 유저의 문의만 보여주도록 수정 """ session = Session() try: qna_info = dict() # pagination qna_info['limit'] = args[0] qna_info['offset'] = args[1] # 상품 아이디 (특정 상품의 상세페이지에서 내가 쓴 문의 필터링을 위해) qna_info['product_id'] = args[2] # 유저의 아이디 qna_info['user_id'] = g.user_id['user_id'] # 답변 여부 qna_info['is_answered'] = args[3] body = [ dict(qna) for qna in qna_service.get_qnas(qna_info, session) ] return jsonify(body), 200 except Exception as e: return jsonify({'message': f'{e}'}), 500 finally: session.close() return qna_app
from flask_login import current_user from .. import db from ..models import Message, LastMessage, User from . import api from .errors import forbidden from flask_request_validator import (PATH, JSON, Param, Pattern, validate_params) from html import escape from datetime import datetime import dateutil.parser from flask_images import resized_img_src @api.route('/message/get_news', methods=['POST']) @validate_params( Param('uuid', JSON, str, required=True), Param('count', JSON, int, required=False), Param('last_id', JSON, int, required=False), ) def get_news(uuid: str, count: int, last_id: int): """Lấy các tin nhắn mới uuid: uuid của người dùng count: số tin nhắn cần lấy last_id: lấy các tin nhắn mới hơn tin nhắn có id là last_id Có count và không có last_id: lấy count tin nhắn mới nhất (kể cả tin nhắn đã đọc lẫn chưa đọc) Ngược lại có last_id: lấy tất cả tin nhắn mới hơn last_id Đánh dấu tất cả tin nhắn lấy được là đã đọc""" u = User.query.filter_by(uuid=uuid).first_or_404() if last_id is None and count:
class EnquiryView(MethodView): def __init__(self, service, database): self.service = service self.database = database @validate_params(Param('product_name', JSON, str, required=False), Param('id', JSON, str, required=False), Param('seller_name', JSON, str, required=False), Param('membership_number', JSON, str, required=False), Param('is_answered', JSON, str, required=False), Param('type', JSON, str, required=False), Param('start_date', JSON, str, required=False), Param('end_date', JSON, str, required=False), Param('page', JSON, int, required=True, rules=[PageRule()]), Param('length', JSON, int, required=True), Param('response_date', JSON, int, required=False)) def get(self, *args): data = { 'product_name': args[0], 'id': args[1], 'seller_name': args[2], 'membership_number': args[3], 'is_answered': args[4], 'type': args[5], 'start_date': args[6], 'end_date': args[7], 'page': args[8], 'length': args[9], 'response_date': args[10] } try: connection = get_connection(self.database) enquiries = self.service.get_enquiry_service(connection, data) return jsonify({'message': 'success', 'result': enquiries}) except Exception as e: raise e finally: try: if connection: connection.close() except Exception: raise DatabaseCloseFail('database close fail') @validate_params(Param('enquiry_id', JSON, int, required=True)) def delete(self, *args): data = {'enquiry_id': args[0]} try: connection = get_connection(self.database) self.service.delete_enquiry_service(connection, data) connection.commit() return {'message': 'success'} except Exception as e: raise e finally: try: if connection: connection.close() except Exception: raise DatabaseCloseFail('database close fail')
from flask import jsonify, request, url_for, abort from flask_login import current_user from .. import db from ..models import User from . import api from .errors import forbidden from flask_request_validator import (PATH, JSON, Param, Pattern, validate_params) from html import escape from datetime import datetime import dateutil.parser from geopy import distance @api.route('/user/coordinates', methods=['POST']) @validate_params(Param('latitude', JSON, float, required=True), Param('longitude', JSON, float, required=True), Param('timestamp', JSON, str, required=False)) def coordinates(latitude, longitude, timestamp): """"Lấy tọa độ người dùng latitude: vĩ độ longtitude: kinh độ timestamp: thời gian lấy tọa độ""" #Nếu tọa độ mới cách tọa độ cũ hơn 100m if distance.distance( (latitude, longitude), current_user.coordinates).km > 0.1: #Cập nhật tọa độ mới current_user.coordinates = (latitude, longitude) db.session.commit() #Tính khoảng cách của người dùng đến các người dùn khác
def create_order_endpoints(order_service, Session): # Blueprint 설정 order_app = Blueprint("order_app", __name__, url_prefix="/api/order") @order_app.route("", methods=["POST"], endpoint="insert_order") @login_required @validate_params( Param("total_payment", JSON, int, required=True), Param("shipping_memo", JSON, str, required=True), Param("orderer_name", JSON, str, required=True), Param("orderer_phone", JSON, str, required=True), Param("orderer_email", JSON, str, required=True), Param("receiver_name", JSON, str, required=True), Param("receiver_phone", JSON, str, required=True), Param("receiver_address", JSON, str, required=True), Param("product_id", JSON, int, required=True), Param("price", JSON, int, required=True), Param("option_color", JSON, str, required=True), Param("option_size", JSON, str, required=True), Param("units", JSON, int, required=True), ) def insert_orders(*args, **kwargs): session = Session() try: order_info = request.json user_id = g.user_id order_service.insert_orders(order_info, user_id, session) session.commit() return jsonify({"message": "SUCCESS"}), 200 except Exception as e: session.rollback() return jsonify({"message": f"{e}"}), 500 finally: session.close() @order_app.route("/item", methods=["GET"], endpoint="select_order_item_info") @login_required def select_order_item_info(): session = Session() try: user_id = g.user_id get_order_item_info = order_service.select_order_item(user_id, session) if not get_order_item_info: return jsonify({"message": "EMPTY_DATA"}), 400 return jsonify({"data": get_order_item_info}), 200 except Exception as e: session.rollback() return jsonify({"message": f"{e}"}), 500 finally: session.close() @order_app.route("/cancel", methods=["POST"], endpoint="insert_cancel_reason") @login_required def insert_cancel_reason(): session = Session() try: cancel_info = request.json user_id = g.user_id order_service.insert_cancel_reason(cancel_info, user_id, session) session.commit() return jsonify({"message": "SUCCESS"}), 200 except Exception as e: session.rollback() return jsonify({"message": f"{e}"}), 500 finally: session.close() @order_app.route("/refund", methods=["POST"], endpoint="insert_refund_reason") @login_required def insert_refund_reason(): session = Session() try: refund_info = request.json user_id = g.user_id order_service.insert_refund_reason(refund_info, user_id, session) session.commit() return jsonify({"message": "SUCCESS"}), 200 except Exception as e: session.rollback() return jsonify({"message": f"{e}"}), 500 finally: session.close() @order_app.route("/refundCancel", methods=["POST"], endpoint="insert_refund_cancel") @login_required def insert_refund_cancel(): session = Session() try: refund_cancel_info = request.json user_id = g.user_id order_service.insert_refund_cancel(refund_cancel_info, user_id, session) session.commit() return jsonify({"message": "SUCCESS"}), 200 except Exception as e: session.rollback() return jsonify({"message": f"{e}"}), 500 finally: session.close() return order_app
cookies = dict(sessionToken=g.user_token) reserve_data = { 'quantity': request.args.get('quantity') if 'quantity' in request.args else 1, 'schedule_id': schedule_id, 'pickup_time': DEFAULT_PICK_UP_TIME, 'source': SOURCE, } response = requests.post(RESERVATIONS_URL, data=json.dumps(reserve_data), headers=HEADERS, cookies=cookies) return json.dumps({'success': response.ok}), response.status_code, {'ContentType': 'application/json'} @bp.route('/<city_id>', defaults={'neighborhood_id': None}, methods=['GET']) @bp.route('/<city_id>/<neighborhood_id>', methods=['GET']) @validate_params( Param('city_id', PATH, str, required=True), Param('neighborhood_id', PATH, str, required=False), Param('sortedByDistanceFrom', GET, str, required=False) ) def find_meal(city_id, neighborhood_id, sorted_by_distance_from): res = requests.get(MENU_URL % city_id, headers=HEADERS) if 'schedules' not in res.json(): return jsonify(error=404, text=str("Did not find any schedules")), 404 schedules = res.json()['schedules'] if neighborhood_id is None: eligible_schedules = schedules else: eligible_schedules = [schedule for schedule in schedules if schedule['restaurant']['neighborhood']['id'] == neighborhood_id]
class SignInView(MethodView): """ Presentation Layer Attributes: user_service : UserService 클래스 database : app.config['DB']에 담겨있는 정보(데이터베이스 관련 정보) Author: 김민구 History: 2020-12-29(김민구): 초기 생성 2020-12-31(김민구): 에러 문구 변경 2021-01-02(김민구): 데이터 조작 에러 추가 """ def __init__(self, services, database): self.user_service = services.user_service self.database = database @validate_params( Param('username', JSON, str), Param('password', JSON, str) ) def post(self, *args): """ POST 메소드: 유저 로그인 Args: args = ('username', 'password') Author: 김민구 Returns: 200, {'message': 'success', 'token': token} : 유저 로그인 성공 Raises: 400, {'message': 'invalid_parameter', 'errorMessage': '[데이터]가(이) 유효하지 않습니다.'} : 잘못된 요청값 400, {'message': 'key_error', 'error_message': format(e)} : 잘못 입력된 키값 403, {'message': 'invalid_user', 'error_message': '로그인에 실패했습니다.'} : 로그인 실패 500, {'message': 'create_token_denied', 'error_message': '로그인에 실패했습니다.'} : 토큰 생성 실패 500, { 'message': 'database_connection_fail', 'error_message': '서버에 알 수 없는 에러가 발생했습니다.' } : 커넥션 종료 실패 500, {'message': 'database_error', 'error_message': '서버에 알 수 없는 에러가 발생했습니다.'} : 데이터베이스 에러 500, {'message': 'internal_server_error', 'error_message': format(e)}) : 서버 에러 History: 2020-12-29(김민구): 초기 생성 2020-12-31(김민구): 에러 문구 변경 2021-01-02(김민구): 데이터 조작 에러 추가 """ connection = None try: data = { 'username': args[0], 'password': args[1] } connection = get_connection(self.database) token = self.user_service.sign_in_logic(data, connection) return jsonify({'message': 'success', 'token': token}), 200 except Exception as e: traceback.print_exc() raise e finally: try: if connection is not None: connection.close() except Exception: raise DatabaseCloseFail('서버에 알 수 없는 에러가 발생했습니다.')
from models import Clothes_image from database import DB_Manager from datetime import datetime, timedelta app = Flask(__name__) DBManager = DB_Manager() CORS(app) @app.route('/') def index(): return "Hello" @app.route('/api/check/id', methods=['GET']) @validate_params( Param('userid', GET, str, rules=[Pattern(r'^[a-z0-9]+$')], required=True), ) def check_id(*request_element): userid = request_element[0] check = User.query.filter_by(userid=userid).first() if check is None: return {'id': True} else: return {'id': False} @app.route('/api/register', methods=['POST']) @validate_params( Param('userid', JSON, str, rules=[Pattern(r'^[a-z0-9]+$')], required=True), Param('passwd', JSON, str, rules=[Pattern(r'[a-zA-Z0-9_-]')], required=True),
class SignUpView(MethodView): """ Presentation Layer Attributes: user_service : UserService 클래스 database : app.config['DB']에 담겨있는 정보(데이터베이스 관련 정보) Author: 김민구 History: 2020-12-28(김민구): 초기 생성 / bcrypt 까지 완료 2020-12-29(김민구): 각 Param에 rules 추가, 에러 구문 수정 2020-12-31(김민구): 모든 service를 담고 있는 services 클래스로 유연하게 처리 / 에러 문구 변경 2021-01-02(김민구): 데이터 조작 에러 추가 """ def __init__(self, services, database): self.user_service = services.user_service self.database = database @validate_params( Param('username', JSON, str, rules=[UsernameRule()]), Param('password', JSON, str, rules=[PasswordRule()]), Param('phone', JSON, str, rules=[PhoneRule()]), Param('email', JSON, str, rules=[EmailRule()]) ) def post(self, *args): """POST 메소드: 유저생성 Args: args = ('username', 'password', 'phone', 'email') Author: 김민구 Returns: 200, {'message': 'success'} : 유저 생성 성공 Raises: 400, {'message': 'invalid_parameter', 'errorMessage': '[데이터]가(이) 유효하지 않습니다.'} : 잘못된 요청값 400, {'message': 'key_error', 'error_message': format(e)} : 잘못 입력된 키값 403, {'message': 'user_already_exist', 'error_message': '이미 사용중인 [데이터] 입니다.'} : 중복 유저 존재 500, { 'message': 'database_connection_fail', 'error_message': '서버에 알 수 없는 에러가 발생했습니다.' } : 커넥션 종료 실패 500, {'message': 'database_error', 'error_message': '서버에 알 수 없는 에러가 발생했습니다.'} : 데이터베이스 에러 500, {'message': 'data_manipulation_fail', 'error_message': '유저 등록을 실패하였습니다.'} : 데이터 조작 에러 500, {'message': 'internal_server_error', 'error_message': format(e)}) : 서버 에러 History: 2020-12-28(김민구): 초기 생성 2020-12-31(김민구): 에러 문구 변경 2021-01-02(김민구): 데이터 조작 에러 추가 """ connection = None try: data = { 'username': args[0], 'password': args[1], 'phone': args[2], 'email': args[3] } connection = get_connection(self.database) self.user_service.sign_up_logic(data, connection) connection.commit() return jsonify({'message': 'success'}), 200 except Exception as e: traceback.print_exc() connection.rollback() raise e finally: try: if connection is not None: connection.close() except Exception: raise DatabaseCloseFail('서버에 알 수 없는 에러가 발생했습니다.')
class BoardView: board_app = Blueprint('board_app', __name__, url_prefix='/board') @board_app.route("", methods=["POST"], endpoint='make_board') @login_required @validate_params(Param('name', JSON, str, rules=[MaxLength(20)])) def make_board(*args): user_info = g.user_info if user_info.get('auth_type_id') != 1: return jsonify({'message': 'UNAUTHORIZED_ACTION'}), 400 board_info = {'uploader': user_info['user_id'], 'name': args[0]} board_service = BoardService() result = board_service.make_board(board_info) return result @board_app.route("", methods=["GET"], endpoint='get_board_list') @login_required @validate_params(Param('offset', GET, int, required=False), Param('limit', GET, int, required=False), Param('name', GET, str, required=False)) def get_board_list(*args): board_info = { 'offset': args[0] if args[0] else 0, 'limit': args[1] if args[1] else 10, 'name': args[2] } board_service = BoardService() boards = board_service.get_board_list(board_info) return jsonify({'board_list': boards}), 200 @board_app.route("/<int:board_id>", methods=["PUT"], endpoint='edit_board') @login_required @validate_params(Param('board_id', PATH, int), Param('name', JSON, str, rules=[MaxLength(20)])) def edit_board(*args): user_info = g.user_info if user_info.get('auth_type_id') != 1: return jsonify({'message': 'UNAUTHORIZED_ACTION'}), 400 board_info = { 'modifier': user_info['user_id'], 'board_id': args[0], 'new_name': args[1] } board_service = BoardService() result = board_service.edit_board(board_info) return result @board_app.route("/<int:board_id>", methods=["DELETE"], endpoint='delete_board') @login_required @validate_params(Param('board_id', PATH, int), Param('is_deleted', JSON, int)) def delete_board(*args): user_info = g.user_info if user_info.get('auth_type_id') != 1: return jsonify({'message': 'UNAUTHORIZED_ACTION'}), 400 board_info = { 'modifier': user_info['user_id'], 'board_id': args[0], } if args[1] == 1: board_info['is_deleted'] = True else: return jsonify({'message': 'INVALID_ACTION'}), 400 board_service = BoardService() result = board_service.delete_board(board_info) return result @board_app.route("/<int:board_id>", methods=["POST"], endpoint='make_article') @login_required @validate_params(Param('board_id', PATH, int), Param('title', JSON, str, rules=[MaxLength(200)]), Param('content', JSON, str, rules=[MaxLength(10000)])) def make_article(*args): user_info = g.user_info article_info = { 'board_id': args[0], 'uploader': user_info['user_id'], 'title': args[1], 'content': args[2] } board_service = BoardService() result = board_service.make_article(article_info) return result @board_app.route("/<int:board_id>", methods=["GET"], endpoint='get_article_list') @login_required @validate_params(Param('board_id', PATH, int), Param('offset', GET, int, required=False), Param('limit', GET, int, required=False), Param('title', GET, str, required=False), Param('uploader', GET, str, required=False)) def get_article_list(*args): article_info = { 'board_id': args[0], 'offset': args[1] if args[1] else 0, 'limit': args[2] if args[2] else None, 'title': args[3], 'uploader': args[4] } board_service = BoardService() articles = board_service.get_article_list(article_info) return jsonify({'article_list': articles}), 200 @board_app.route("/<int:board_id>/<int:article_id>", methods=["GET"], endpoint='get_article_detail') @login_required @validate_params(Param('board_id', PATH, int), Param('article_id', PATH, int)) def get_article_detail(*args): article_info = {'board_id': args[0], 'article_id': args[1]} board_service = BoardService() result = board_service.get_article_detail(article_info) return result @board_app.route("/<int:board_id>/<int:article_id>", methods=["PUT"], endpoint='edit_article') @login_required @validate_params(Param('board_id', PATH, int), Param('article_id', PATH, int), Param('title', JSON, str, rules=[MaxLength(200)]), Param('content', JSON, str, rules=[MaxLength(10000)])) def edit_article(*args): user_info = g.user_info article_info = { 'board_id': args[0], 'article_id': args[1], 'new_title': args[2], 'new_content': args[3], 'modifier': user_info['user_id'], 'auth_type_id': user_info['auth_type_id'] } board_service = BoardService() result = board_service.edit_article(article_info) return result @board_app.route("/<int:board_id>/<int:article_id>", methods=["DELETE"], endpoint='delete_article') @login_required @validate_params(Param('board_id', PATH, int), Param('article_id', PATH, int), Param('is_deleted', JSON, int)) def delete_article(*args): user_info = g.user_info article_info = { 'board_id': args[0], 'article_id': args[1], 'modifier': user_info['user_id'], 'auth_type_id': user_info['auth_type_id'] } if args[2] == 1: article_info['is_deleted'] = True else: return jsonify({'message': 'INVALID_ACTION'}), 400 board_service = BoardService() result = board_service.delete_article(article_info) return result @board_app.route("/recent-articles", methods=["GET"], endpoint='get_recent_board_article') @login_required @validate_params( Param('offset', GET, int, required=False), Param('limit', GET, int, required=False), ) def get_recent_board_article(*args): board_info = {'offset': 0, 'limit': None} board_service = BoardService() board_list = board_service.get_board_list(board_info) for board in board_list: article_info = { 'board_id': board['id'], 'offset': args[0] if args[0] else 0, 'limit': args[1] if args[1] else 2 } article_list = board_service.get_article_list(article_info) board['recent_article_list'] = article_list return jsonify({'dashboard': board_list})
class ProductManageSearchView(MethodView): """ Presentation Layer Attributes: service : MainCategoryListService 클래스 database : app.config['DB']에 담겨있는 정보(데이터베이스 관련 정보) Author: 심원두 History: 2020-12-31(심원두): 초기 작성 2021-01-03(심원두): 상품 리스트 검색 기능 구현 """ def __init__(self, service, database): self.service = service self.database = database @signin_decorator() @validate_params( Param('lookup_start_date', GET, str, required=False, rules=[DateRule(), NotEmpty()]), Param('lookup_end_date', GET, str, required=False, rules=[DateRule(), NotEmpty()]), Param('seller_name', GET, str, required=False, rules=[DefaultRule(), NotEmpty(), MaxLength(20)]), Param('product_name', GET, str, required=False, rules=[DefaultRule(), NotEmpty(), MaxLength(100)]), Param('product_id', GET, str, required=False, rules=[NumberRule(), NotEmpty()]), Param('product_code', GET, str, required=False, rules=[DefaultRule(), NotEmpty(), MaxLength(20)]), Param('is_sale', GET, int, required=False, rules=[Enum(1, 2)]), Param('is_display', GET, int, required=False, rules=[Enum(1, 2)]), Param('is_discount', GET, int, required=False, rules=[Enum(1, 2)]), Param('page_number', GET, int, required=True, rules=[PageRule()]), Param('limit', GET, int, required=True, rules=[Enum(10, 20, 50)])) def get(self, *args): """GET 메소드: 특정 조건에 해당하는 상품 리스트를 조회한다. Args: 'lookup_start_date' : 조회 시작 기간 'lookup_end_date' : 조회 종료 기간 'seller_name' : 셀러명 'product_name' : 상품명 'product_id' : 상품 아이디 'product_code' : 상품 코드 'seller_attribute_type_id : 셀러 속성 'is_sale' : 할인 여부 'is_display' : 진열 여부 'is_discount' : 할인 여부 'page_number' : 페이지 번호 'limit' : 한 화면에 보여줄 상품의 갯수 Author: 심원두 Returns: return {"message": "success", "result": result} Raises: 400, {'message': 'key error', 'errorMessage': 'key_error' + format(e)} : 잘못 입력된 키값 400, {'message': 'both date field required', 'errorMessage': 'both_date_field_required'}: 필수 값 유효성 체크 에러 400, {'message': 'start date is greater than end date', 'errorMessage': 'start_date_is_greater_than_end_date'}: 날짜 비교 유효성 체크 에러 400, {'message': 'invalid seller attribute type', 'errorMessage': 'invalid_seller_attribute_type'}: 셀러 타입 유효성 체크 에러 History: 2020-12-31(심원두): 초기생성 2021-01-03(심원두): 상품 리스트 검색 기능 구현, Login Decorator 구현 예정 """ try: search_condition = { 'seller_id': g.account_id if g.permission_type_id == 2 else None, 'lookup_start_date': request.args.get('lookup_start_date', None), 'lookup_end_date': request.args.get('lookup_end_date', None), 'seller_name': request.args.get('seller_name', None), 'product_name': request.args.get('product_name', None), 'product_id': request.args.get('product_id', None), 'product_code': request.args.get('product_code', None), 'seller_attribute_type_ids': json.loads(request.args.get('seller_attribute_type_id')) if request.args.get('seller_attribute_type_id') else None, 'is_sale': request.args.get('is_sale', None), 'is_display': request.args.get('is_display', None), 'is_discount': request.args.get('is_discount', None), 'page_number': request.args.get('page_number'), 'limit': request.args.get('limit') } search_condition_back_to_front = { 'lookup_start_date': search_condition['lookup_start_date'], 'lookup_end_date': search_condition['lookup_end_date'], 'seller_name': search_condition['seller_name'], 'product_name': search_condition['product_name'], 'product_id': search_condition['product_id'], 'product_code': search_condition['product_code'], 'seller_attribute_type': search_condition['seller_attribute_type_ids'], 'is_sale': 0 if search_condition['is_sale'] is None else int( search_condition['is_sale']), 'is_display': 0 if search_condition['is_display'] is None else int( search_condition['is_display']), 'is_discount': 0 if search_condition['is_discount'] is None else int( search_condition['is_discount']), 'page_number': int(search_condition['page_number']), 'limit': int(search_condition['limit']) } connection = get_connection(self.database) result = self.service.search_product_service( connection, search_condition) result['search_condition'] = search_condition_back_to_front return jsonify({'message': 'success', 'result': result}) except KeyError as e: traceback.print_exc() raise e except Exception as e: traceback.print_exc() raise e finally: try: if connection: connection.close() except Exception: raise DatabaseCloseFail('database close fail')
def create_product_endpoints(product_service, Session): product_app = Blueprint('product_app', __name__, url_prefix='/api/product') @product_app.route('/products', methods = ['GET'], endpoint='products') @login_required(Session) @validate_params( Param('filterLimit', GET, int, default=10, required=False), Param('page', GET, int, required=False), Param('exhibitionYn', GET, int, rules=[Enum(0, 1)], required=False), Param('exhibitionYn', GET, int, rules=[Enum(0, 1)], required=False), Param('sellYn', GET, int, rules=[Enum(0, 1)], required=False), Param('mdSeNo', GET, int, required=False), Param('selectFilter', GET, str, rules=[Enum('productName', 'productNo', 'productCode')], required=False), Param('filterKeyword', GET, required=False), Param('mdName', GET, required=False), Param('filterDateFrom', GET, str, rules=[Pattern(r"^\d\d\d\d-\d{1,2}-\d{1,2}$")], required=False), Param('filterDateTo', GET, str, rules=[Pattern(r"^\d\d\d\d-\d{1,2}-\d{1,2}$")], required=False) ) def products(*args): """ 상품 정보 리스트 전달 API 쿼리 파라미터로 필터링에 사용될 값을 받아 필터링된 상품의 데이터 리스트를 표출합니다. args: *args: filterLimit: pagination 을 위한 파라미터 page: pagination 을 위한 파라미터 exhibitionYn: 진열 여부 discountYn: 할인 여부 sellYn: 판매 여부 mdSeNo: 셀러 속성 id selectFilter: 상품 검색 시 상품 명, 코드, 번호 중 어떤 것을 선택했는지 판단 위한 파라미터 filterKeyword: 상품 검색을 위한 파라미터 mdName: 셀러 이름 검색을 위한 파라미터 filterDateFrom: 조회 기간 시작 filterDateTo: 조회 기간 끝 returns : 200: 상품 리스트 500: Exception Authors: 고지원 History: 2020-10-01 (고지원): 초기 생성 """ try: session = Session() # 필터링을 위한 딕셔너리 filter_dict = dict() # pagination filter_dict['filterLimit'] = args[0] filter_dict['page'] = args[1] # 진열 여부 filter_dict['exhibitionYn'] = args[2] # 할인 여부 filter_dict['discountYn'] = args[3] # 판매 여부 filter_dict['sellYn'] = args[4] # 셀러 속성 filter_dict['mdSeNo'] = args[5] # 상품 검색 filter_dict['selectFilter'] = args[6] # 상품 검색어 filter_dict['filterKeyword'] = args[7] # 셀러 검색어 filter_dict['mdName'] = args[8] # 조회 기간 시작 filter_dict['filterDateFrom'] = args[9] # 조회 기간 끝 filter_dict['filterDateTo'] = args[10] # 상품 정보 products = product_service.get_products(filter_dict, session) # 상품 쿼리 결과 count count_info = product_service.get_product_count(filter_dict, session) body = { 'orders' : [dict(product) for product in products], 'page_number' : count_info.p_count, 'total_order_number' : round(count_info.p_count / filter_dict['filterLimit']) } return jsonify(body), 200 except exc.ProgrammingError: return jsonify(({'message': 'ERROR_IN_SQL_SYNTAX'})), 500 except Exception as e: traceback.print_exc() return jsonify({'message': f'{e}'}), 500 finally: session.close() @product_app.route('/<int:product_id>', methods=['GET'], endpoint='product') @login_required(Session) def product(product_id): """ 상품 수정 시 기존 등록 정보 전달 API path parameter 로 id 받아 해당 상품의 데이터 표출합니다. args: product_id : 상품의 id returns : 200: 상품 정보 500: Exception Authors: 고지원 History: 2020-10-01 (고지원): 초기 생성 """ session = Session() try: # 상품 데이터 body = dict(product_service.get_product(product_id, session)) return jsonify(body), 200 except exc.ProgrammingError: return jsonify({'message': 'ERROR_IN_SQL_SYNTAX'}), 500 except AttributeError: return jsonify({'message': 'THERE_IS_NO_PRODUCT_DATA'}), 400 except Exception as e: return jsonify({'message': f'{e}'}), 500 finally: session.close() @product_app.route('/history', methods=['GET'], endpoint='product_history') @login_required(Session) def product_history(): """ 상품 수정 이력 전달 API 점 이력으로 관리하는 상품의 수정 이력을 표출합니다. args: product_id : 상품의 id returns : 200: 상품의 수정 이력 리스트 500: Exception Authors: 고지원 History: 2020-10-10 (고지원): 초기 생성 """ session = Session() try: product_id = request.args.get('product_id') body = [dict(history) for history in product_service.get_product_history(product_id, session)] return jsonify(body), 200 except exc.ProgrammingError: return jsonify({'message': 'ERROR_IN_SQL_SYNTAX'}), 500 except Exception as e: return jsonify({'message': f'{e}'}), 500 finally: session.close() @product_app.route('/excel', methods=['GET'], endpoint='make_excel') @login_required(Session) @validate_params( Param('product_id', GET, list, required=False) ) def make_excel(*args): """ 상품 정보 엑셀 다운로드 API 전체 상품 또는 선택 상품의 정보를 excel 파일로 다운로드 합니다. args: product_id : 상품의 id 리스트 returns : 200: Excel 파일 다운 500: Exception Authors: 고지원 History: 2020-10-02 (고지원): 초기 생성 """ session = Session() try: # 선택한 상품들의 id를 list 로 받는다. id_list = args[0] # service 의 make_excel 함수를 호출한다. product_service.make_excel(id_list, session) return jsonify({'message': 'SUCCESS'}), 200 except exc.ProgrammingError: traceback.print_exc() return jsonify({'message': 'ERROR_IN_SQL_SYNTAX'}), 500 except Exception as e: traceback.print_exc() return jsonify({'message': f'{e}'}), 500 finally: session.close() @product_app.route('/seller', methods=['GET'], endpoint='sellers') @login_required(Session) @validate_params( Param('q', GET, str, required = True) ) def sellers(*args): """ 셀러 리스트 전달 API query parameter 를 받아 필터링된 셀러 리스트 데이터를 표출합니다. args: *args: name: 셀러명 검색을 위한 쿼리 스트링 returns : 200: 셀러 리스트 500: Exception Authors: 고지원 History: 2020-10-04 (고지원): 초기 생성 """ session = Session() try: # 필터링을 위한 딕셔너리 seller_dict = dict() seller_dict['name'] = args[0] # 셀러 데이터 body = [dict(seller) for seller in product_service.get_sellers(seller_dict, session)] return jsonify(body), 200 except exc.ProgrammingError: return jsonify({'message': 'ERROR_IN_SQL_SYNTAX'}), 500 except Exception as e: return jsonify({'message': f'{e}'}), 500 finally: session.close() @product_app.route('/category', methods=['GET'], endpoint='product_categories') @login_required(Session) def product_categories(): """ 1차, 2차 카테고리 정보 전달 API 셀러의 속성 아이디를 받아 1차 카테고리, 1차 카테고리 아이디를 받아 2차 카테고리 정보를 전달합니다. args: seller_attr_id: 셀러의 속성 id f_category_id: 1차 카테고리 id returns : 200: 1차 또는 2차 카테고리 정보 500: Exception Authors: 고지원 History: 2020-10-04 (고지원): 초기 생성 """ session = Session() try: # 셀러 속성 아이디 또는 1차 카테고리 아이디를 받는다. seller_attr_id = request.args.get('seller_attr_id') f_category_id = request.args.get('f_category_id') # 셀러 속성 아이디가 들어왔을 경우 1차 카테고리 정보를 반환 if seller_attr_id: body = [dict(cat) for cat in product_service.get_first_categories(seller_attr_id, session)] return jsonify(body), 200 # 1차 카테고리 아이디가 들어왔을 경우 2차 카테고리 정보를 반환 body = [dict(cat)for cat in product_service.get_second_categories(f_category_id, session)] return jsonify(body), 200 except exc.ProgrammingError: return jsonify({'message': 'ERROR_IN_SQL_SYNTAX'}), 500 except Exception as e: return jsonify({'message': f'{e}'}), 500 finally: session.close() @product_app.route('', methods=['POST'], endpoint='insert_product') @login_required(Session) def insert_product(): """ 상품 정보 등록 API returns : 200: 상품 정보를 데이터베이스에 저장 400: NAME_CANNOT_CONTAIN_QUOTATION_MARK, START_DATE_CANNOT_BE_EARLIER_THAN_END_DATE, CANNOT_SET_MORE_THAN_20, CANNOT_SET_LESS_THAN_10, DISCOUNT_RANGE_CAN_BE_SET_FROM_0_TO_99, DUPLICATE_DATA, INVALID_REQUEST 500: Exception, ERROR_IN_SQL_SYNTAX Authors: 고지원 History: 2020-10-03 (고지원): 초기 생성 2020-10-04 (고지원): 상품 정보 입력 시 제한 사항 에러 추가 2020-10-10 (고지원): 여러 개의 이미지를 업로드 할 수 있도록 수정 2020-10-12 (고지원): 에러 발생 시 세션 rollback 과 함께 s3 에 업로드 된 이미지도 삭제되도록 수정 """ session = Session() image_urls = '' is_success = False try: # 상품명에 ' 또는 " 포함 되었는지 체크 pattern = re.compile('[\"\']') if pattern.search(request.form['name']): return jsonify({'message': 'NAME_CANNOT_CONTAIN_QUOTATION_MARK'}), 400 # 할인 시작일이 할인 종료일보다 빠를 경우 if request.form['discount_start_date'] > request.form['discount_end_date']: return jsonify({'message': 'START_DATE_CANNOT_BE_EARLIER_THAN_END_DATE'}), 400 # 최소 수량 또는 최대 수량이 20을 초과할 경우 if int(request.form['min_unit']) > 20 or int(request.form['max_unit']) > 20: return jsonify({'message': 'CANNOT_SET_MORE_THAN_20'}), 400 # 판매가가 10원 미만일 경우 if int(request.form['price']) < 10: return jsonify({'message': 'CANNOT_SET_LESS_THAN_10'}), 400 # 할인률이 0 ~ 99% 가 아닐 경우 if int(request.form['discount_rate']) not in range(0, 99): return jsonify({'message': 'DISCOUNT_RANGE_CAN_BE_SET_FROM_0_TO_99'}), 400 # 상품 코드 product_code = str(uuid.uuid4()) # S3 이미지 저장 images = list() # 1~5 개의 이미지를 가져온다. for idx in range(1, 6): image = request.files.get(f'image_{idx}', None) if image: images.append(image) image_urls = product_service.upload_image(product_code, images) # 반환된 image_urls 가 허용되지 않은 확장자일 경우 400 에러 메시지를 반환한다. if 400 in image_urls: return image_urls # 상품 입력을 위한 데이터를 받는다. product_info = { 'seller_id': request.form['seller_id'], 'is_on_sale': request.form['is_on_sale'], 'is_displayed': request.form['is_displayed'], 'name': request.form['name'], 'simple_description': request.form['simple_description'], 'detail_description': request.form['detail_description'], 'price': request.form['price'], 'is_definite': request.form['is_definite'], 'discount_rate': request.form['discount_rate'], 'discount_price': request.form['discount_price'], 'min_unit': request.form['min_unit'], 'max_unit': request.form['max_unit'], 'is_stock_managed': request.form['is_stock_managed'], 'stock_number': request.form['stock_number'], 'first_category_id': request.form['first_category_id'], 'second_category_id': request.form['second_category_id'], 'modifier_id': request.form['modifier_id'], 'images': image_urls, 'discount_start_date': request.form['discount_start_date'], 'discount_end_date': request.form['discount_end_date'], 'product_code': product_code } product_service.insert_product(product_info, session) session.commit() is_success = True return jsonify({'message': 'SUCCESS'}), 200 except KeyError: return jsonify({'message': 'KEY_ERROR'}), 400 except exc.IntegrityError: return jsonify({'message': 'INTEGRITY_ERROR'}), 400 except exc.InvalidRequestError: return jsonify({'message': 'INVALID_REQUEST'}), 400 except exc.ProgrammingError: return jsonify({'message': 'ERROR_IN_SQL_SYNTAX'}), 500 except Exception as e: return jsonify({'message': f'{e}'}), 500 finally: if is_success is False: session.rollback() delete_image_in_s3(image_urls, None) session.close() @product_app.route('/update', methods=['POST'], endpoint='update_product') @login_required(Session) def update_product(): """ 상품 정보 수정 API returns : 200: 상품 정보를 데이터베이스에 저장 400: NAME_CANNOT_CONTAIN_QUOTATION_MARK, START_DATE_CANNOT_BE_EARLIER_THAN_END_DATE, CANNOT_SET_MORE_THAN_20, CANNOT_SET_LESS_THAN_10, DISCOUNT_RANGE_CAN_BE_SET_FROM_0_TO_99, DUPLICATE_DATA, INVALID_REQUEST 500: Exception, ERROR_IN_SQL_SYNTAX Authors: 고지원 History: 2020-10-10 (고지원): 초기 생성 """ session = Session() is_success = False try: # 상품 입력을 위한 데이터를 받는다. old_images = request.form['images'].split(',') product_info = { 'product_id': request.form['product_id'], 'product_code': request.form['product_code'], 'seller_id': request.form['seller_id'], 'is_on_sale': request.form['is_on_sale'], 'is_displayed': request.form['is_displayed'], 'name': request.form['name'], 'simple_description': request.form['simple_description'], 'detail_description': request.form['detail_description'], 'price': request.form['price'], 'is_definite': request.form['is_definite'], 'discount_rate': request.form['discount_rate'], 'discount_price': request.form['discount_price'], 'min_unit': request.form['min_unit'], 'max_unit': request.form['max_unit'], 'is_stock_managed': request.form['is_stock_managed'], 'stock_number': request.form['stock_number'], 'first_category_id': request.form['first_category_id'], 'second_category_id': request.form['second_category_id'], 'modifier_id': g.seller_info['seller_no'], 'images': old_images, 'discount_start_date': request.form['discount_start_date'], 'discount_end_date': request.form['discount_end_date'] } # S3 이미지 저장 images = list() # 1~5 개의 이미지를 가져온다. for idx in range(1, 6): image = request.files.get(f'image_{idx}', None) if image: images.append(image) new_images = product_service.upload_image(product_info['product_code'], images) # 반환된 image_urls 가 허용되지 않은 확장자일 경우 400 에러 메시지를 반환한다. if 400 in new_images: return new_images product_info['new_images'] = new_images product_service.update_product(product_info, session) session.commit() is_success = True return jsonify({'message': 'SUCCESS'}), 200 except KeyError: return jsonify({'message': 'KEY_ERROR'}), 400 except exc.IntegrityError: return jsonify({'message': 'INTEGRITY_DATA'}), 400 except exc.InvalidRequestError: return jsonify({'message': 'INVALID_REQUEST'}), 400 except exc.ProgrammingError: return jsonify({'message': 'ERROR_IN_SQL_SYNTAX'}), 500 except Exception as e: return jsonify({'message': f'{e}'}), 500 finally: if is_success is False: session.rollback() delete_image_in_s3(old_images, new_images) session.close() return product_app
class SampleUserView(MethodView): """ Presentation Layer Attributes: database: app.config['DB']에 담겨있는 정보(데이터베이스 관련 정보) service : TestUserService 클래스 Author: 홍길동 History: 2020-20-20(홍길동): 초기 생성 2020-20-21(홍길동): 1차 수정 2020-20-22(홍길동): 2차 수정 """ def __init__(self, service, database): self.service = service self.database = database @validate_params( Param('user_id', JSON, str, rules=[NumberRule()]), ) def get(self, *args): data = {'user_id': args[0]} """GET 메소드: 해당 유저의 정보를 조회. user_id 에 해당되는 유저를 테이블에서 조회 후 가져온다. Args: args = ('user_id, ) Author: 홍길동 Returns: return {"message": "success", "result": [{"age": "18", "gender": "남자", "id": 12, "name": "홍길동"}]} Raises: 400, {'message': 'key error', 'errorMessage': 'key_error'} : 잘못 입력된 키값 400, {'message': 'user does not exist error', 'errorMessage': 'user_does_not_exist'} : 유저 정보 조회 실패 400, {'message': 'unable to close database', 'errorMessage': 'unable_to_close_database'}: 커넥션 종료 실패 500, {'message': 'internal server error', 'errorMessage': format(e)}) : 서버 에러 History: 2020-20-20(홍길동): 초기 생성 2020-20-21(홍길동): 1차 수정 2020-20-22(홍길동): 2차 수정 """ try: connection = get_connection(self.database) user = self.service.get_sample_user_service(connection, data) return jsonify({'message': 'success', 'result': user}), 200 except Exception as e: raise e finally: try: if connection: connection.close() except Exception: raise DatabaseCloseFail('database close fail') @validate_params(Param('name', JSON, str, rules=[AlphabeticRule()]), Param('gender', JSON, str, rules=[GenderRule()]), Param('age', JSON, str, rules=[NumberRule()])) def post(self, *args): data = {'name': args[0], 'gender': args[1], 'age': args[2]} """POST 메소드: 유저생성 Args: args = ('name', 'gender', 'age') Author: 홍길동 Returns: 200, {'message': 'success'} : 유저 생성 성공 Raises: 400, {'message': 'key error', 'errorMessage': 'key_error'} : 잘못 입력된 키값 400, {'message': 'user create error', 'errorMessage': 'user_create_error'} : 유저 생성 실패 403, {'message': 'user already exist', errorMessage': 'already_exist'} : 중복 유저 생성 실패 400, {'message': 'unable to close database', 'errorMessage': 'unable_to_close_database'}: 커넥션 종료 실패 500, {'message': 'internal server error', 'errorMessage': format(e)}) : 서버 에러 History: 2020-20-20(홍길동): 초기 생성 2020-20-21(홍길동): 1차 수정 2020-20-22(홍길동): 2차 수정 """ try: connection = get_connection(self.database) self.service.post_sample_user_service(connection, data) connection.commit() return {'message': 'success'} except Exception as e: connection.rollback() raise e finally: try: if connection: connection.close() except Exception: raise DatabaseCloseFail('database close fail') @validate_params(Param('user_id', JSON, str), Param('age', JSON, str, rules=[NumberRule()])) def patch(self, *args): data = {'user_id': args[0], 'age': args[1]} """PATCH 메소드: 유저 정보 수정 Args: args = ('user_id', 'age') Author: 홍길동 Returns: 200, {'message': 'success'} : 유저 생성 성공 Raises: 400, {'message': 'key error', 'errorMessage': 'key_error'} : 잘못 입력된 키값 400, {'message': 'unable to update', 'errorMessage': 'unable_to_update'} : 유저 정보 수정 실패 400, {'message': 'unable to close database', 'errorMessage': 'unable_to_close_database'}: 커넥션 종료 실패 500, {'message': 'internal server error', 'errorMessage': format(e)}) : 서버 에러 History: 2020-20-20(홍길동): 초기 생성 2020-20-21(홍길동): 1차 수정 2020-20-22(홍길동): 2차 수정 """ try: connection = get_connection(self.database) self.service.patch_sample_user_service(connection, data) connection.commit() return {'message': 'success'} except Exception as e: connection.rollback() raise e finally: try: if connection: connection.close() except Exception: raise DatabaseCloseFail('database close fail')
class MyPageEnquiryListView(MethodView): """ Presentation Layer Attributes: product_enquiry_list_service : ProductEnquiryService 클래스 database : app.config['DB']에 담겨있는 정보(데이터베이스 관련 정보) Author: 김민구 History: 2020-01-04(김민구): 초기 생성 """ def __init__(self, services, database): self.product_enquiry_list_service = services.product_enquiry_list_service self.database = database @signin_decorator() @validate_params( Param('type', GET, str, required=False, default='all', rules=[EnquiryAnswerTypeRule()]), Param('offset', GET, int, required=False, default=0), Param('limit', GET, int, required=False, default=5)) def get(self, *args): """ GET 메소드: 유저의 Q&A 리스트 조회 Args: offset = 5단위 limit = 5 type = wait 혹은 complete 혹은 all Author: 김민구 Returns: Q&A 리스트 조회 성공 200, { 'message': 'success', 'result': { "enquiries": [ { "answer": { "account_id": 2, "content": "답변드릴게요", "created_at": "2021-01-04 12:38:12", "enquiry_id": 102, "id": 52, "seller_name": "나는셀러2" }, "content": "임시질문인데요2(답변감사합니다)", "created_at": "2021-01-04 11:31:26", "enquiry_id": 102, "enquiry_type_id": 1, "enquiry_type_name": "상품 문의", "is_completed": 1, "is_secret": 0, "product_id": 1, "user_id": 152 } ] } } Raises: 400, {'message': 'invalid_parameter', 'error_message': '[데이터]가(이) 유효하지 않습니다.'} : 잘못된 요청값 400, {'message': 'key_error', 'error_message': format(e)} : 잘못 입력된 키값 500, { 'message': 'database_connection_fail', 'error_message': '서버에 알 수 없는 에러가 발생했습니다.' } : 커넥션 종료 실패 500, {'message': 'database_error', 'error_message': '서버에 알 수 없는 에러가 발생했습니다.'} : 데이터베이스 에러 500, {'message': 'internal_server_error', 'error_message': format(e)}) : 서버 에러 History: 2020-01-04(김민구): 초기 생성 Notes: type이 wait라면 미답변 Q&A만 보여주고 complete라면 답변 완료된 Q&A, all이라면 모든 Q&A를 보여준다. """ connection = None try: data = { 'type': args[0], 'offset': args[1], 'limit': args[2], 'user_id': g.account_id } connection = get_connection(self.database) result = self.product_enquiry_list_service.my_page_enquiry_list_logic( connection, data) return jsonify({'message': 'success', 'result': result}) except Exception as e: traceback.print_exc() raise e finally: try: if connection is not None: connection.close() except Exception: raise DatabaseCloseFail('서버에 알 수 없는 에러가 발생했습니다.')
app = Flask(__name__) CORS(app) mongo = DBManager() auth = Authentication() token = None @app.route('/') def hello_world(): return 'Hello World!' @app.route('/api/login', methods=['POST']) @validate_params( Param('user_id', JSON, str, rules=[Pattern(r'^[a-z0-9]+$')], required=True), # 소문자와 숫자만 가능 Param('user_pwd', JSON, str, required=True)) def login(*request_elements): user_id = request_elements[0] user_pwd = request_elements[1] user_info = mongo.get_user_info(user_id) if user_info is not None: if user_pwd == user_info['user_pwd']: auth.token_recreation(user_id) json_request = { 'login': '******', 'user_id': user_id, 'level': user_info['level'], 'token': auth.token_get(user_id) } resp = make_response(json_request)
@validate_params(Param('cities', GET, list), Param('countries', GET, dict)) def get(self, cities, countries): return Response(json.dumps({ 'cities': [cities, cities.__class__.__name__], 'countries': [countries, countries.__class__.__name__], }), mimetype='application/json') type_composite = CompositeRule(Enum('type1', 'type2')) @app.route('/main/<string:key>/<string:uuid>', methods=['POST']) @validate_params( Param('key', PATH, str, rules=[Enum('key1', 'key2')]), Param('uuid', PATH, str, rules=[Pattern(r'^[a-z-_.]{8,10}$')]), Param('sure', GET, bool, False), Param('sys', FORM, str, rules=[Pattern(r'^[a-z.]{3,6}$')]), Param('types', FORM, str, rules=type_composite), Param('price', FORM, float, False), Param('cities', FORM, list, False), Param('dql', FORM, dict, False), Param('default', FORM, dict, False, default=lambda: ['test']), ) def route_form(key, uuid, sure, sys, types, price, cities, dql, default): return json.dumps([ [key, key.__class__.__name__], [uuid, uuid.__class__.__name__], [sure, sure.__class__.__name__], [sys, sys.__class__.__name__],
class StoreOrderAddView(MethodView): """ Presentation Layer Attributes: database: app.config['DB']에 담겨있는 정보(데이터베이스 관련 정보) service : StoreOrderService 클래스 Author: 고수희 History: 2020-12-30(고수희): 초기 생성 """ def __init__(self, service, database): self.service = service self.database = database @signin_decorator(True) @validate_params( Param('cartId', JSON, int), Param('productId', JSON, int), Param('stockId', JSON, int), Param('quantity', JSON, int), Param('originalPrice', JSON, int), Param('sale', JSON, str, rules=[DecimalRule()]), Param('discountedPrice', JSON, int), Param('totalPrice', JSON, int), Param('soldOut', JSON, bool), Param('senderName', JSON, str), Param('senderPhone', JSON, str, rules=[PhoneRule()]), Param('senderEmail', JSON, str, rules=[EmailRule()]), Param('recipientName', JSON, str), Param('recipientPhone', JSON, str, rules=[PhoneRule()]), Param('address1', JSON, str), Param('address2', JSON, str), Param('postNumber', JSON, str, rules=[PostalCodeRule()]), Param('deliveryId', JSON, int), Param('deliveryMemo', JSON, str, required=False), ) def post(self, *args): """POST 메소드: 장바구니 상품 생성 Args: args = ( 'user_id', 'user_permission', 'cart_id', 'product_id', 'stock_id', 'quantity', 'original_price', 'sale', 'discounted_price', 'total_price', 'sold_out', 'sender_name', 'sender_phone', 'sender_email', 'recipient_name', 'recipient_phone', 'address1', 'address2', 'post_number', 'delivery_memo_type_id', 'delivery_content' ) Author: 고수희 Returns: 200, {'message': 'success'} : 결제 성공 Raises: 400, {'message': 'key error', 'errorMessage': 'key_error'} : 잘못 입력된 키값 400, {'message': 'unable to close database', 'errorMessage': 'unable_to_close_database'} : 커넥션 종료 실패 403, {'message': 'customer permission denied', 'errorMessage': 'customer_permission_denied'} : 사용자 권한이 아님 500, {'message': 'internal server error', 'errorMessage': format(e)}) : 서버 에러 History: 2020-12-30(고수희): 초기 생성 """ data = { 'user_id': g.account_id, 'user_permission': g.permission_type_id, 'cart_id': args[0], 'product_id': args[1], 'stock_id': args[2], 'quantity': args[3], 'original_price': args[4], 'sale': args[5], 'discounted_price': args[6], 'total_price': args[7], 'sold_out': args[8], 'sender_name': args[9], 'sender_phone': args[10], 'sender_email': args[11], 'recipient_name': args[12], 'recipient_phone': args[13], 'address1': args[14], 'address2': args[15], 'post_number': args[16], 'delivery_memo_type_id': args[17], 'delivery_content': args[18], } try: connection = get_connection(self.database) order_id = self.service.post_order_service(connection, data) connection.commit() return { 'message': 'success', 'result': { "order_id": order_id } }, 201 except Exception as e: connection.rollback() raise e finally: try: if connection: connection.close() except Exception: raise DatabaseCloseFail('database close fail')
def test_types(self): param_int = Param('test', FORM, int) param_list = Param('test', FORM, list) param_dict = Param('test', FORM, dict) param_bool = Param('test', FORM, bool) param_none = Param('test', FORM) self.assertEqual(1, param_int.value_to_type('1')) self.assertEqual(True, param_bool.value_to_type('1')) self.assertEqual(True, param_bool.value_to_type('true')) self.assertEqual(True, param_bool.value_to_type('True')) self.assertEqual(False, param_bool.value_to_type('0')) self.assertEqual(False, param_bool.value_to_type('false')) self.assertEqual(False, param_bool.value_to_type('False')) self.assertEqual(['Minsk', 'Prague', 'Berlin'], param_list.value_to_type('Minsk, Prague, Berlin')) self.assertEqual({ 'country': 'Belarus', 'capital': 'Minsk' }, param_dict.value_to_type('country: Belarus, capital: Minsk')) data = {'test': {'test': ['test1', 'test2']}} self.assertEqual(data, param_none.value_to_type(data))
from DB.models.user import User, db from auth.jwt import encode_auth_token from auth.decorators import username_password_auth, bcrypt from validators.email_validater import EmailRule from validators.validator_rules import ( Pattern, MinLength, MaxLength ) @app.route('/users', methods=["POST"]) @validate_params( Param('username', JSON, str, required=True, rules=[MaxLength(80), MinLength(5), Pattern(r"^[a-zA-Z\d]+$", error="Invalid username. can`t have white spaces and can only contain letters and numbers")]), Param('email', JSON, str, required=True, rules=[EmailRule()]), Param('password', JSON, str, required=True, rules=[MinLength(6, error='Invalid length. Min length = 1'), Pattern(r'^[a-zA-Z\d@$.!-_%*#?&]*$', error='Invalid password. a pasword is a combination of lower and upper case digits and one of special car @$.!-_%*#?&')]) ) def create_user(username, email, password): # check if user name is available user = User.query.filter_by(username=username).first() if user is not None: return { 'statusCode': 409, 'message': 'A user with the user name `{}` exists'.format(username) }
def create_product_endpoints(product_service, Session): product_app = Blueprint("product_app", __name__, url_prefix="/api/products") @product_app.route("/category", methods=["GET"]) def product_category(): session = Session() try: # 메뉴 데이터 categories = product_service.get_menu(None, session) # 각 카테고리를 저장하기 위한 리스트 second_category, first_category, main_category = [], [], [] # JOIN 을 하며 생기는 중복을 제거하기 위해서 중복 체크 후 리스트에 저장 for category in categories: # 1. (메인 카테고리의 id, 이름) 이 main_category 에 없을 경우 append if (category.m_id, category.main_category_name) not in main_category: main_category.append((category.m_id, category.main_category_name)) # 2. (1차 카테고리의 id, 이름, 이에 해당하는 메인 카테고리의 id) 가 first_category 에 없을 경우 append if ( category.f_id, category.first_category_name, category.main_category_id, ) not in first_category: first_category.append( (category.f_id, category.first_category_name, category.main_category_id) ) # 3. (2차 카테고리의 id, 이름, 이에 해당하는 1차 카테고리의 id) 가 second_category 에 없을 경우 append second_category.append( (category.s_id, category.second_category_name, category.first_category_id) ) # 카테고리의 계층 구조를 전달하기 위한 JSON 형식 body = [ { # 메인 카테고리의 id 와 이름 "id": m_menu[0], m_menu[1]: [ { # 1차 카테고리의 id 와 이름 "id": f_menu[0], f_menu[1]: [ { # 2차 카테고리의 id 와 이름 "id": s_menu[0], "name": s_menu[1], } for s_menu in second_category if s_menu[2] == f_menu[0] ], } for f_menu in first_category if f_menu[2] == m_menu[0] ], } for m_menu in main_category ] return jsonify(body), 200 except Exception as e: return jsonify({"message": f"{e}"}), 500 finally: session.close() @product_app.route("", methods=["GET"]) @validate_params( Param("limit", GET, int, default=100, required=False), Param("offset", GET, int, required=False), Param("main_category_id", GET, int, rules=[Enum(4, 5, 6)], required=False), Param("first_category_id", GET, int, required=False), Param("second_category_id", GET, int, required=False), Param("is_promotion", GET, int, rules=[Enum(0, 1)], required=False), Param("select", GET, int, rules=[Enum(0, 1)], required=False), Param("q", GET, str, required=False), Param("all_items", GET, int, rules=[Enum(1)], required=False), ) def products(*args): session = Session() try: # args[2]: 메인 카테고리의 pk, args[8]: 전체 상품을 보여줄 지 판단하는 파라미터, args[3]: 1차 카테고리의 pk, args[4]: 2차 카테고리의 pk if args[2] == 5 or args[2] == 6 and not args[8] and not args[3] and not args[4]: # 특정 메인 카테고리 아이디 (5: 브랜드, 6: 뷰티) 파라미터만 들어올 경우 베스트 상품, 추천 상품 데이터 등을 전달 body = { "best_items": [], "brand_items": [], "recommended_items": [], "category_items": [], } # 1. 파라미터로 들어온 카테고리의 id (args[2]) 에 따라 특정 셀러를 지정하고 상품 5개만 가져오기 위해 선언, # 2. 특정 1차 카테고리 아이디로 필터링된 상품 리스트를 가져오기 위해 선언 if args[2] == 5: f_cat_list = (12, 13, 14, 15, 16, 17, 18) seller_id = 30 else: f_cat_list = (23, 24, 25, 26, 27, 28) seller_id = 359 for f_cat_id in f_cat_list: # 1. 첫 번째 카테고리 상품 5개 씩 보여주기 위한 필터 f_category_filter = {"first_category_id": f_cat_id, "limit": 5} # 2. 카테고리의 id, name 과 함께 상품 리스트를 반환한다. category_products = { "category_id": f_cat_id, "category_name": product_service.get_menu(f_cat_id, session)[ 0 ].first_category_name, "product": product_service.get_products(f_category_filter, session), } body["category_items"].append(category_products) # Best 상품 필터 - 해당하는 메인 카테고리의 상품 중 판매량 순 10개만 가져오기 위해 선언 best_prod_filter = { "main_category_id": args[2], "limit": 10, } best_products = product_service.get_products(best_prod_filter, session) # 추천 상품 필터 - 할인율 기준 recommended_prod_filter = { "main_category_id": args[2], "limit": 30, "discount_rate": 1, } recommended_products = product_service.get_products( recommended_prod_filter, session ) # 특정 셀러 상품 리스트 필터 seller_filter = {"main_category_id": args[2], "seller_id": seller_id} brand_products = product_service.get_products(seller_filter, session) body["best_items"] = best_products body["brand_items"] = brand_products body["recommended_items"] = recommended_products return body # 필터링을 위한 딕셔너리 filter_dict = dict() # pagination filter_dict["limit"] = args[0] filter_dict["offset"] = args[1] # 카테고리 filter_dict["main_category_id"] = args[2] filter_dict["first_category_id"] = args[3] filter_dict["second_category_id"] = args[4] # 세일 filter_dict["is_promotion"] = args[5] # 판매량순, 최신순 filter_dict["select"] = args[6] # 검색 필터 filter_dict["q"] = args[7] # 메인 카테고리의 모든 상품 필터 filter_dict["all_items"] = args[8] body = dict() # 상품 데이터 body["products"] = product_service.get_products(filter_dict, session) # 검색어가 들어올 경우 전달하는 셀러 정보 if filter_dict["q"]: # 필터링된 셀러 리스트를 가져오기 위한 필터 seller_info = dict() seller_info["name"] = filter_dict["q"] seller_info["limit"] = 100 # 검색된 셀러 리스트 정의 sellers = dict() # 검색어에 해당하는 셀러의 리스트 seller_list = [ dict(seller) for seller in product_service.get_sellers(seller_info, session) ] # 셀러 검색 결과 개수 sellers["count"] = len(seller_list) # 셀러 데이터 sellers["seller_list"] = seller_list body["sellers"] = sellers return jsonify(body), 200 except Exception as e: return jsonify({"message": f"{e}"}), 500 finally: session.close() @product_app.route("/product/<int:product_id>", methods=["GET"]) def product(product_id): session = Session() try: # 상품 데이터 body = dict(product_service.get_product(product_id, session)) return jsonify(body), 200 except Exception as e: return jsonify({"message": f"{e}"}), 500 finally: session.close() @product_app.route("/seller", methods=["GET"]) @validate_params( Param("limit", GET, int, default=100, required=False), Param("offset", GET, int, required=False), Param("main_category_id", GET, int, rules=[Enum(4, 5, 6)], required=False), Param("select", GET, int, rules=[Enum(0, 1)], default=1, required=False), ) def sellers(*args): session = Session() try: # 필터링을 위한 딕셔너리 seller_dict = dict() seller_dict["limit"] = args[0] seller_dict["offset"] = args[1] seller_dict["main_category_id"] = args[2] seller_dict["select"] = args[3] # 셀러 데이터 body = [dict(seller) for seller in product_service.get_sellers(seller_dict, session)] return jsonify(body), 200 except Exception as e: return jsonify({"message": f"{e}"}), 500 finally: session.close() return product_app
def product_endpoints(app, services, get_session): product_service = services.product_service @app.route("/product/register", methods=['GET']) @login_required def get_register_product(): """ 상품 등록 API 상품 등록 페이지에 들어갔을 때 불러오는 데이터 Returns: 200 : data_list ( type : dict ) 500 : Exception """ session = None try: session = get_session() data_list = product_service.get_category_color_size(session) return jsonify(data_list), 200 except NoDataException as e: session.rollback() return jsonify({'message': 'no data 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("/product/register", methods=['POST']) @login_required @validate_params(Param('sub_categories_id', JSON, int), Param('name', JSON, str), Param('main_image', JSON, str), Param('is_sell', JSON, int, rules=[Enum(0, 1)]), Param('is_display', JSON, int, rules=[Enum(0, 1)]), Param('is_discount', JSON, int, rules=[Enum(0, 1)]), Param('price', JSON, int), Param('detail', JSON, str), Param('maximum_sell_count', JSON, int), Param('minimum_sell_count', JSON, int), Param('options', JSON, list), Param('discount_rate', JSON, int, required=False), Param('discount_start_date', JSON, str, required=False), Param('discount_end_date', JSON, str, required=False), Param('simple_information', JSON, str, required=False), Param('manufacturer', JSON, str, required=False), Param('manufacture_date', JSON, str, required=False), Param('origin', JSON, str, required=False), Param('image_list', JSON, list, required=False)) def post_register_product(*args): """ 상품 등록 API Body 로 상품 데이터를 받아 상품 등록하기 Args: *args: sub_categories_id : 2차 카테고리 id name : 상품명 main_image : 상품 메인 이미지 is_sell : 판매 여부 is_display : 진열 여부 is_discount : 할인 여부 price : 상품 가격 detail : 상품 상세정보 maximum_sell_count : 최대 판매 수량 minimum_sell_count : 최소 판매 수량 options : 리스트. [{ 컬러 id, 사이즈 id, 재고관리여부, 재고수량 }] discount_rate : 할인율 discount_start_date : 할인 시작 날짜 discount_end_date : 할인 마지막 날짜 simple_information : 한줄 상품 설명 manufacturer : 제조사 manufacture_date : 제조일자 origin : 원산지 image_list : 서브이미지 리스트 Returns: 200 : success, 상품 등록에 성공했을 때 400 : key error , 옵션리스트 안에 컬러아이디, 사이즈아이디, 재고관리여부 중 하나라도 없을 때 500 : Exception """ session = None try: session = get_session() # 바디에 담긴 부분 유효성 검사 후에 딕셔너리로 만들기 product_data = { 'sub_categories_id': args[0], 'name': args[1], 'main_image': args[2], 'is_sell': args[3], 'is_display': args[4], 'is_discount': args[5], 'price': args[6], 'detail': args[7], 'maximum_sell_count': args[8], 'minimum_sell_count': args[9], 'options': args[10], 'discount_rate': args[11], 'discount_start_date': args[12], 'discount_end_date': args[13], 'simple_information': args[14], 'manufacturer': args[15], 'manufacture_date': args[16], 'origin': args[17], 'image_list': args[18], 'seller_id': g.seller_id } # 옵션 안의 리스트의 키값들이 None 일 때 에러 발생 for options in product_data['options']: if options['color_id'] is None or options[ 'size_id'] is None or options[ 'is_inventory_manage'] is None: return jsonify({'message': 'option data not exist'}), 400 product_service.post_register_product(product_data, session) 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("/category/<int:category_id>", methods=['GET']) @login_required def get_sub_category_list(category_id): """ 2차 카테고리 불러오기 상품 등록 페이지에서 1차 카테고리를 선택했을 때 해당하는 2차 카테고리 리스트 불러오기 Args: category_id: 1차 카테고리 id Returns: 200 : category_list ( type : dict ) 500 : Exception """ session = None try: session = get_session() category_list = product_service.get_sub_categories( category_id, session) return jsonify(category_list), 200 except Exception as e: session.rollback() return jsonify({'message': '{}'.format(e)}), 500 finally: if session: session.close() @app.route("/product/update/<int:product_id>", methods=['GET']) @login_required @validate_params(Param('product_id', PATH, int)) def get_update_product(product_id): """ 상품 상세페이지 ( 수정 ) 상품 수정 페이지 들어갔을 때 등록되어 있는 상품 데이터 가져오기 Args: product_id: 상품 id Returns: 200 : product_data ( type : dict ) 500 : Exception """ session = None try: session = get_session() product_data = product_service.get_product(product_id, session) return jsonify(product_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("/product/update/<int:product_id>", methods=['PUT']) @login_required @validate_params(Param('product_id', PATH, int), Param('sub_categories_id', JSON, int), Param('name', JSON, str), Param('main_image', JSON, str), Param('is_sell', JSON, int, rules=[Enum(0, 1)]), Param('is_display', JSON, int, rules=[Enum(0, 1)]), Param('is_discount', JSON, int, rules=[Enum(0, 1)]), Param('price', JSON, int), Param('detail', JSON, str), Param('maximum_sell_count', JSON, int), Param('minimum_sell_count', JSON, int), Param('options', JSON, list), Param('discount_rate', JSON, int, required=False), Param('discount_start_date', JSON, str, required=False), Param('discount_end_date', JSON, str, required=False), Param('simple_information', JSON, str, required=False), Param('manufacturer', JSON, str, required=False), Param('manufacture_date', JSON, str, required=False), Param('origin', JSON, str, required=False), Param('image_list', JSON, list, required=False)) def put_update_product(*args): """ 상품 데이터 수정 API Path parameter 로 상품 id를 받고 Body 로 상품 데이터를 받아 데이터 업데이트하기 Args: *args: product_id : 상품 id sub_categories_id : 2차 카테고리 id name : 상품명 main_image : 상품 메인 이미지 is_sell : 판매 여부 is_display : 진열 여부 is_discount : 할인 여부 price : 상품 가격 detail : 상품 상세 정보 maximum_sell_count : 최대 판매 수량 minimum_sell_count : 최소 판매 수량 options : 옵션리스트 ( 컬러아이디, 사이즈아이디, 재고관리여부, 재고수량 ) discount_rate : 할인율 discount_start_date : 할인 시작 날짜 discount_end_date : 할인 마지막 날짜 simple_information : 상품 한줄 정보 manufacturer : 제조사 manufacture_date : 제조 날짜 origin : 원산지 image_list : 서브 이미지 리스트 Returns: 200 : success, 상품 데이터 업데이트에 성공했을 때 400 : 옵션리스트에 컬러아이디, 사이즈아이디, 재고관리여부가 하나라도 없을 때 500 : Exception """ session = None try: session = get_session() # 수정할 상품 데이터 딕셔너리로 만들기 product_data = { 'product_id': args[0], 'sub_categories_id': args[1], 'name': args[2], 'main_image': args[3], 'is_sell': args[4], 'is_display': args[5], 'is_discount': args[6], 'price': args[7], 'detail': args[8], 'maximum_sell_count': args[9], 'minimum_sell_count': args[10], 'options': args[11], 'discount_rate': args[12], 'discount_start_date': args[13], 'discount_end_date': args[14], 'simple_information': args[15], 'manufacturer': args[16], 'manufacture_date': args[17], 'origin': args[18], 'image_list': args[19], 'seller_id': g.seller_id } # 옵션 안의 키값들이 None 이면 에러 발생 for options in product_data['options']: if options['color_id'] is None or options[ 'size_id'] is None or options[ 'is_inventory_manage'] is None: return jsonify({'message': 'option data not exist'}), 400 product_service.post_update_product(product_data, 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("/product/management", methods=['GET']) @login_required @validate_params(Param('limit', GET, int, required=False), Param('offset', GET, int, required=False), Param('is_sell', GET, int, rules=[Enum(0, 1)], required=False), Param('is_discount', GET, int, rules=[Enum(0, 1)], required=False), Param('is_display', GET, int, rules=[Enum(0, 1)], required=False), Param('name', GET, str, required=False), Param('code_number', GET, int, required=False), Param('product_number', GET, str, required=False), Param('start_date', GET, str, required=False), Param('end_date', GET, str, required=False), Param('seller_property_id', GET, int, required=False), Param('brand_name_korean', GET, str, required=False)) def management_product(*args): """ 상품 관리 리스트 API 쿼리 파라미터로 필터링 조건들을 받아서 필터링 조건에 따라서 등록되어 있는 상품 리스트를 가져오기 Args: *args: limit : pagination 범위 offset : pagination 시작 번호 is_sell : 판매 여부 is_discount : 할인 여부 is_display : 진열 여부 name : 상품명 code_number : 상품 코드 번호 product_number : 상품 id start_date : 해당날짜 이후에 등록된 상품 end_date : 해당날짜 이전에 등록된 상품 seller_property_id : 셀러 속성 id ( 로드샵, 마켓 등 ) brand_name_korean : 브랜드명 ( 한글 ) Returns: 200 : product_list ( type : dict ) 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], 'is_sell': args[2], 'is_discount': args[3], 'is_display': args[4], 'name': args[5], 'code_number': args[6], 'product_number': args[7], 'start_date': args[8], 'end_date': args[9], 'seller_property_id': args[10], 'brand_name_korean': args[11], 'seller_id': g.seller_id } product_list = product_service.get_product_list( query_string_list, session) return jsonify(product_list) except Exception as e: session.rollback() return jsonify({'message': '{}'.format(e)}), 500 finally: if session: session.close()
class SellerStatusView(MethodView): """ Presentation Layer Attributes: database: app.config['DB']에 담겨있는 정보(데이터베이스 관련 정보) service : SellerInfoService 클래스 Author: 이영주 History: 2021-01-03(이영주): 초기 생성 """ def __init__(self, service, database): self.service = service self.database = database @validate_params( Param('account_id', JSON, str, required=True, rules=[DefaultRule()]), Param('seller_status_type_id', JSON, str, required=True, rules=[DefaultRule()]), Param('seller_id', JSON, str, required=True, rules=[DefaultRule()]), Param('updater_id', JSON, str, required=True, rules=[DefaultRule()])) def patch(self, *args): """PATCH 메소드: 셀러 상태 정보 수정 Args: Author: 이영주 Returns: 200, {'message': 'success'} : 셀러 정보변경 Raises: 400, {'message': 'key error', 'errorMessage': 'key_error'} : 잘못 입력된 키값 400, {'message': 'unable to update', 'errorMessage': 'unable_to_update'} : 셀러 정보 수정 실패 400, {'message': 'unable to close database', 'errorMessage': 'unable_to_close_database'}: 커넥션 종료 실패 500, {'message': 'internal server error', 'errorMessage': format(e)}) : 서버 에러 History: 2021-01-03(이영주): 초기 생성 """ try: data = { 'account_id': args[0], 'seller_status_type_id': args[1], 'seller_id': args[2], 'updater_id': args[3] } connection = get_connection(self.database) self.service.patch_seller_status(connection, data) self.service.patch_seller_history(connection, data) connection.commit() return {'message': 'success'} except Exception as e: connection.rollback() raise e finally: try: if connection: connection.close() except Exception: raise DatabaseCloseFail('database close fail')