def to_json_response(self, http_code=200, http_msg="ok", error=None): """ Encode the json response for the resource wrapper ExecutableAlgoWs TODO: move that code up to a superclass ? same code than ExecutionalgoWs::to_json_response :param http_code: http code, optional: default 200 :type http_code: int :param http_msg: http message, optional: default "ok" :type http_msg: str :param error: optional error: if None: the error will be evaluated from wrapped ExecutionStatus :type error: BaseException subclass """ as_dict = self.to_dict() as_dict['http_code'] = http_code as_dict['http_msg'] = http_msg if error is not None: as_dict['error'] = ascii(str(error)) factory = DjangoHttpResponseFactory() if http_code == 200: response = factory.get_json_response_nominal(as_dict) else: response = factory.get_json_response_error( http_status_code=http_code, ikats_error=None, exception=None, data=as_dict) return response
def __get_json_list(http_request, dao_class, business_class, webservice_class, default_level_info, method_name): response_builder = DjangoHttpResponseFactory() try: if http_request.method == 'GET': str_info_level = http_request.GET.get('info_level', default=None) if str_info_level is None: info_level = default_level_info else: try: info_level = LevelInfo.parse(int(str_info_level)) except Exception as err_query: return response_builder.get_json_response_bad_request( ikats_error= "Bad value of query param named 'info_level' in %s" % method_name, exception=err_query) serializable_list = [ webservice_class(x.build_business()).to_dict(level=info_level) for x in dao_class.find_all_orm() ] # save = False because serializable_list is not a dict return JsonResponse(serializable_list, safe=False) else: return response_builder.get_json_response_bad_request( ikats_error="Bad http method: service %s expects GET" % method_name) except Exception as err: LOGGER.exception(err) return response_builder.get_json_response_internal_server_error( ikats_error="Unexpected server error in %s" % method_name, exception=err)
def get_custom_algo(http_request, customized_algo_id, query_dict): """ Reads the CustomizedAlgo specified :param http_request: the request :type http_request: HttpRequest :param customized_algo_id: the database ID of the CustomizedAlgo :type customized_algo_id: str of int :param query_dict: the query parameters :type query_dict: QueryDict :return: the Json response (nominal or error). :rtype: JsonResponse """ # Builds the response in blocks try: or except: response_builder = DjangoHttpResponseFactory() try: # info-level is used to adapt the returned content of resource my_level = HttpCommonsIkats.get_info_level(http_request, query_dict) my_id = CustomizedAlgoDao.parse_dao_id(customized_algo_id) buzz_custom_algo = CustomizedAlgoDao.find_business_elem_with_key( primary_key=my_id) LOG_WS_CUSTOM.info("Found customized algo with id=%s: %s", customized_algo_id, buzz_custom_algo) # CustomizedAlgoWs is wrapping the business resource # => manages the user rendering: json format, according to info-level ws_custom_algo = CustomizedAlgoWs(buzz_custom_algo) dict_custom_algo = ws_custom_algo.to_dict(level=my_level) my_response = JsonResponse(dict_custom_algo, safe=False) except CustomizedAlgoDao.DoesNotExist: # Example: customized_algo_id=99999999 is not matching a resource in database msg = "Does not exist: customized algo with id=%s" % customized_algo_id LOG_WS_CUSTOM.error(msg) my_response = response_builder.get_json_response_not_found( ikats_error=msg) except IkatsInputError as err: # Example: invalid info_level value in query params ... LOG_WS_CUSTOM.exception(err) msg = "Bad request in get_custom_algo with id={}".format( customized_algo_id) LOG_WS_CUSTOM.error(msg) my_response = response_builder.get_json_response_bad_request( ikats_error=msg, exception=err) except Exception as err: # Any unexpected error: database crash ... LOG_WS_CUSTOM.exception(err) msg = "Unexpected server error in get_custom_algo with id={}".format( customized_algo_id) LOG_WS_CUSTOM.error(msg) my_response = response_builder.get_json_response_internal_server_error( ikats_error=msg) return my_response
def not_allowed_method(http_request): """ Generates the "NOT ALLOWED METHOD" response :param http_request: the http request :type http_request: django.http.HttpRequest :return: the "NOT ALLOWED METHOD" response :rtype: JsonResponse """ msg = "Rejected HTTP method in the context: {}".format(http_request.path) LOG_WS_CUSTOM.error(msg) response_builder = DjangoHttpResponseFactory() return response_builder.get_json_response_bad_method(ikats_error=msg)
def get_implementation(http_request, id_implementation): """ Get the web service resource for ImplementationDao defined under the catalogue Example of requests: - "http://127.0.0.1:80/ikats/algo/catalogue/implementations/1" - "http://127.0.0.1:80/ikats/algo/catalogue/implementations/00001" :param http_request: request http :type http_request: django HttpQuery :param id_implementation: database primary key (number) :type id_implementation: str coding the integer value :return: implementationDao in a json format :rtype: JsonResponse """ response_builder = DjangoHttpResponseFactory() try: internal_id = int(id_implementation) business_obj = ImplementationDao.find_from_key(internal_id) if business_obj is None: return response_builder.get_json_response_not_found( "Implementation resource not found for id=%s" % str(internal_id)) ws_obj = ImplementationWs(business_obj) return JsonResponse(ws_obj.to_dict()) except Exception as err: LOGGER.exception(err) info = "WS: No such record: ImplementationDao id=%s" % ( id_implementation) LOGGER.error(info) return JsonResponse({ "error": { 'ikats_error': info, 'internal_error': ascii(str(err)) } })
def delete_custom_algo(http_request, customized_algo_id): """ Deletes the customized algorithm. :param http_request: the request :type http_request: HttpRequest :param customized_algo_id: the ID of the deleted resource :type customized_algo_id: int, str :return: the response :rtype: HttpResponse in nominal case, JsonResponse otherwise """ # http_request param is passed by django dispatcher even if not used response_builder = DjangoHttpResponseFactory() try: CustomFacade.delete_custom_algo(customized_algo_id) my_response = response_builder.response_empty_ok() except IkatsNotFoundError as not_found_err: LOG_WS_CUSTOM.exception(not_found_err) msg = "DELETE failed on CustomizedAlgo with id={}: resource not found" msg = msg.format(customized_algo_id) LOG_WS_CUSTOM.error(msg) my_response = response_builder.get_json_response_not_found( ikats_error=msg, exception=not_found_err) except Exception as err: # Example: database is down LOG_WS_CUSTOM.exception(err) msg = "DELETE failed on CustomizedAlgo with id={}: server error".format( customized_algo_id) LOG_WS_CUSTOM.error(msg) my_response = response_builder.get_json_response_internal_server_error( ikats_error=msg, exception=err) # Finally returned: nominal response or error response return my_response
def __get_json_with_name(http_request, searched_name, dao_class, webservice_class, default_level_info, method_name): response_builder = DjangoHttpResponseFactory() try: if http_request.method == 'GET': str_info_level = http_request.GET.get('info_level', default=None) if str_info_level is None: info_level = default_level_info else: try: info_level = LevelInfo.parse(int(str_info_level)) except Exception as err_query: return response_builder.get_json_response_bad_request( ikats_error= "Bad value of query param named 'info_level' in " + method_name, exception=err_query) serializable_list = [ webservice_class(x).to_dict(level=info_level) for x in dao_class.find_business_elem_with_name(searched_name) ] if len(serializable_list) > 1: my_detailed_error = "Unexpected multiple resources matched:" for json_item in serializable_list: my_detailed_error = " [db_id=" + json_item.model_business.db_id + "]" my_error = "Unexpected conflict in {0}: service should retrieve at most one resource, name={1} \ should match a unique resource".format( method_name, searched_name) return response_builder.get_json_response_conflict( ikats_error=my_error, exception=my_detailed_error) elif len(serializable_list) == 0: my_error = "Resource not found in {0} with name={1}".format( method_name, searched_name) return response_builder.get_json_response_not_found( ikats_error=my_error) # save = False => do not check that serializable_list[0] is dict return JsonResponse(serializable_list[0], safe=False) else: return response_builder.get_json_response_bad_request( ikats_error="Bad http method: service %s expects GET" % method_name) except Exception as err: return response_builder.get_json_response_internal_server_error( ikats_error="Unexpected server error in " + method_name, exception=err)
def write_custom_algo(http_request, customized_algo_id, operation_info, facade_function, nominal_http_status): """ Internal operation: factorized code for update/create operations on CustomizedAlgo :param http_request: the input request :type http_request: HttpRequest :param customized_algo_id: the parsed parameter from path pattern: string encoding the database key :type customized_algo_id: str or None :param operation_info: the internal message :type operation_info: str :param facade_function: the CRUD function called: facade_function codes either CREATE or UPDATE :type facade_function: function :param nominal_http_status: the returned code is either 201 (CREATE) or 200 (UPDATE) :type nominal_http_status: int :return: the response :rtype: JsonResponse """ response_builder = DjangoHttpResponseFactory() try: data = HttpCommonsIkats.load_json_from_request(http_request) LOG_WS_CUSTOM.debug("Starting %s CustomizedAlgo with posted_data=%s", operation_info, json.dumps(obj=data, indent=2)) # Translates object parsed from json into the business resource buzz_custom_algo = CustomJsonFacade.convert_to_business_custo_algo( data) if customized_algo_id: # ID path param defined inn update context only ... if (buzz_custom_algo.db_id is not None) and ( customized_algo_id != buzz_custom_algo.db_id): # ... not forbidden to specify the ID in the json content ... # but it must match the path parameter coding the ID # => here ids are not equal => raise error raise IkatsInputError( "Integrity error:" + " the ID from URL is different from the optional ID from posted data" ) my_key = CustomizedAlgoDao.parse_dao_id(customized_algo_id) # ... check that the resource exists in database CustomFacade.get_custom_algo(my_key) else: # No ID specified: CREATE mode # => check that no other custom algo have the same name search = CustomFacade.search_with_criteria( implem_id=None, name=buzz_custom_algo.name) if len(search) > 0: raise IkatsException("Conflict with existing name") # Called CRUD operation: facade_function is either CREATE or UPDATE # - see effective functions in the calling context of write_custom_algo (modified_buzz_custom_algo, check_status) = facade_function(buzz_custom_algo) if (check_status is None) or (not check_status.has_errors()): # Case when no error is detected in the definition of customized algorithm # if modified_buzz_custom_algo is None: # Server error dealt below ... raise IkatsException( "Unexpected result with undefined CustomizedAlgo, and empty error list" ) else: # Algo successfully written my_id = modified_buzz_custom_algo.db_id LOG_WS_CUSTOM.info("%s success: CustomizedAlgo with id=%s", operation_info, my_id) my_response = HttpResponseFactory.response_resource_written_ok( 'pattern_custom_algos_with_id', modified_buzz_custom_algo.db_id, nominal_http_status, http_request) LOG_WS_CUSTOM.info( "Success %s: CustomizedAlgo with url location=%s", operation_info, my_response.get('Location', "null")) else: # Deals with check errors: # - unexpected type of value, # - or value outside of configured domain context = "{} aborted: errors detected in the checker status:".format( operation_info) code = response_builder.BAD_REQUEST_HTTP_STATUS LOG_WS_CUSTOM.error(context) my_status = check_status.to_dict(data_info=data) LOG_WS_CUSTOM.error(json.dumps(obj=my_status, indent=2)) my_response = response_builder.get_json_response_error_with_data( http_status_code=code, http_msg=context, data_name="check_error", data=check_status.to_dict()) except IkatsInputError as input_err: # Example; any error detected in the request (different from conflict) LOG_WS_CUSTOM.exception(input_err) msg = ERR_CRUD_CUSTOM_ALGO % (operation_info, ": input error") LOG_WS_CUSTOM.error(msg) my_response = response_builder.get_json_response_bad_request( ikats_error=msg, exception=input_err) except IkatsNotFoundError as not_found_err: # Example: update: the resource does not exist # Example2: create: the referenced implementation does not exist LOG_WS_CUSTOM.exception(not_found_err) msg = ERR_CRUD_CUSTOM_ALGO % (operation_info, ": resource not found") LOG_WS_CUSTOM.error(msg) my_response = response_builder.get_json_response_not_found( ikats_error=msg, exception=not_found_err) except IkatsException as conflict_err: # Example: resource already created. LOG_WS_CUSTOM.exception(conflict_err) msg = ERR_CRUD_CUSTOM_ALGO % (operation_info, ": conflict error") LOG_WS_CUSTOM.error(msg) my_response = response_builder.get_json_response_conflict( ikats_error=msg, exception=conflict_err) except Exception as err: # Any other error: example: database is down LOG_WS_CUSTOM.exception(err) msg = ERR_CRUD_CUSTOM_ALGO % (operation_info, ": unexpected error") LOG_WS_CUSTOM.error(msg) my_response = response_builder.get_json_response_internal_server_error( ikats_error=msg, exception=err) # Finally returned: nominal response or error response return my_response
def find_custom_algos_for_implem(http_request, implementation_id): """ Finds all customized algo which are customizing specified implementation. :param http_request: the django request built by custom app, driven by its urls.py :type http_request: HttpRequest :param implementation_id: the identifier of the implementation :type implementation_id: int or parsable str :return: the Json response (nominal or error). :rtype: JsonResponse """ # Rejecting not allowed method cases: POST, PUT or DELETE if http_request.method != 'GET': return not_allowed_method(http_request) # ... dealing with the expected GET method # # Will help to build the response in try: or except: bodies response_builder = DjangoHttpResponseFactory() # Returned object my_response = None try: query_dict = http_request.GET # info-level is used to adapt the returned content of resource my_level = HttpCommonsIkats.get_info_level(http_request, query_dict, default=LevelInfo.SUMMARY) business_list = CustomFacade.search_with_criteria( implem_id=implementation_id) if len(business_list) > 0: ids = [x.db_id for x in business_list] LOG_WS_CUSTOM.info( "Found customized algo versions %s of implementation id=%s", ids, implementation_id) serializable_list = CustomJsonFacade.convert_to_ws_list_custom_algo( business_list, level=my_level) my_response = JsonResponse(serializable_list, safe=False) elif len(business_list) == 0: my_implem_key = ImplementationDao.parse_dao_id(implementation_id) try: ImplementationDao.find_business_elem_with_key( primary_key=my_implem_key) LOG_WS_CUSTOM.info( "Does not exist: customized algo of implementation id=%s", implementation_id) my_response = JsonResponse([], safe=False) except ImplementationDao.DoesNotExist: # Example: implementation_id does not exist in database msg = "Unknown Implementation ID={} occurred in find_custom_algos_for_implem" msg = msg.format(implementation_id) LOG_WS_CUSTOM.error(msg) my_response = response_builder.get_json_response_not_found( ikats_error=msg) except IkatsInputError as err: # Example: invalid info_level value in query params ... LOG_WS_CUSTOM.exception(err) msg = "Bad request in find_custom_algos_for_implem with id={}".format( implementation_id) LOG_WS_CUSTOM.error(msg) my_response = response_builder.get_json_response_bad_request( ikats_error=msg, exception=err) except Exception as err: # Example: database is down LOG_WS_CUSTOM.exception(err) msg = "Unexpected server error in find_custom_algos_for_implem with id={}".format( implementation_id) LOG_WS_CUSTOM.error(msg) my_response = response_builder.get_json_response_internal_server_error( ikats_error=msg) # Finally returned: nominal response or error response return my_response
def find_custom_algo(http_request, query_dict): """ Find all customized algo which are accepted by filter, according to the query parameters in url: name, label, desc. :param http_request: the django request built by custom app, driven by its urls.py :type http_request: HttpRequest :param query_dict: the query dictionary containing optional filtering criteria :type query_dict: QueryDict :return: the Json response (nominal or error). :rtype: JsonResponse """ # Builds the response in try: or except: blocks: response_builder = DjangoHttpResponseFactory() # Required for encoding messages in try: or except: blocks spec_crit = {} try: name = query_dict.get("name", None) label = query_dict.get("label", None) desc = query_dict.get("desc", None) # info-level is used to adapt the returned content of resource my_level = HttpCommonsIkats.get_info_level(http_request, query_dict, default=LevelInfo.SUMMARY) spec_crit = {'name': name, 'label': label, 'desc': desc} business_list = CustomFacade.search_with_criteria(name=name, label=label, desc_content=desc) if len(business_list) > 0: ids = [x.db_id for x in business_list] LOG_WS_CUSTOM.info( "Found customized algo for ids=%s, matching search criteria %s", ids, spec_crit) # Encodes the result in json format, list of resources with the defined info-level serializable_list = CustomJsonFacade.convert_to_ws_list_custom_algo( business_list, level=my_level) my_response = JsonResponse(serializable_list, safe=False) else: msg = "Does not exist: customized algo matching search criteria %s" % spec_crit LOG_WS_CUSTOM.error(msg) my_response = response_builder.get_json_response_not_found( ikats_error=msg) except IkatsInputError as err: # Example: invalid info_level value in query params ... LOG_WS_CUSTOM.exception(err) msg = "Bad request in find_custom_algo for criteria={}".format( spec_crit) LOG_WS_CUSTOM.error(msg) my_response = response_builder.get_json_response_bad_request( ikats_error=msg, exception=err) except Exception as err: # Any unexpected error: database crash ... LOG_WS_CUSTOM.exception(err) msg = "Unexpected server error in find_custom_algo for criteria={}".format( spec_crit) LOG_WS_CUSTOM.error(msg) my_response = response_builder.get_json_response_internal_server_error( ikats_error=msg) return my_response