diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/serviceapidescriptions.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/serviceapidescriptions.py index c2ff0506e213114e89ed5d6d2a52334ae6c09275..6b3ab35db00b6fdf63afaa6fbf611a306ca9474d 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/serviceapidescriptions.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/serviceapidescriptions.py @@ -24,6 +24,31 @@ publisher_ops = Publisher() service_api_not_found_message = "Service API not found" +def find_duplicate_service_by_api_name_and_aef( + collection, + api_name, + aef_profiles, + excluded_api_id=None): + duplicate_query = {"api_name": api_name} + aef_ids = set() + for profile in aef_profiles or []: + if isinstance(profile, dict): + aef_id = profile.get("aef_id") + else: + aef_id = getattr(profile, "aef_id", None) + + if aef_id: + aef_ids.add(aef_id) + + aef_ids = sorted(aef_ids) + + if aef_ids: + duplicate_query["aef_profiles.aef_id"] = {"$in": aef_ids} + if excluded_api_id: + duplicate_query["api_id"] = {"$ne": excluded_api_id} + + return collection.find_one(duplicate_query), aef_ids + def return_negotiated_supp_feat_dict(supp_feat): final_supp_feat = bin(int(supp_feat, 16) & int(SUPPORTED_FEATURES_HEX, 16))[2:].zfill(TOTAL_FEATURES)[::-1] @@ -122,19 +147,31 @@ class PublishServiceOperations(Resource): try: current_app.logger.debug("Publishing service") - service = mycol.find_one( - {"api_name": serviceapidescription.api_name}) + serviceapidescription_dict = serviceapidescription.to_dict() + service, aef_ids = find_duplicate_service_by_api_name_and_aef( + mycol, + serviceapidescription.api_name, + serviceapidescription_dict.get("aef_profiles")) if service is not None: + if aef_ids: + current_app.logger.error( + "Service already registered with same api_name/aef_id pair") + return forbidden_error( + detail="Already registered service with same api name and aef id", + cause="Found service with same api name and aef id") + current_app.logger.error( "Service already registered with same api name") - return forbidden_error(detail="Already registered service with same api name", cause="Found service with same api name") + return forbidden_error( + detail="Already registered service with same api name", + cause="Found service with same api name") api_id = secrets.token_hex(15) serviceapidescription.api_id = api_id + serviceapidescription_dict["api_id"] = api_id rec = dict() rec['apf_id'] = apf_id rec['onboarding_date'] = datetime.now() - serviceapidescription_dict = serviceapidescription.to_dict() if vendor_specific: serviceapidescription_dict = add_vend_spec_fields( @@ -155,7 +192,7 @@ class PublishServiceOperations(Resource): res = make_response(object=clean_n_camel_case( serviceapidescription_dict), status=201) - res.headers['Location'] = f"https://{os.getenv("CAPIF_HOSTNAME")}/published-apis/v1/{str(apf_id)}/service-apis/{str(api_id)}" + res.headers['Location'] = f"https://{os.getenv('CAPIF_HOSTNAME')}/published-apis/v1/{str(apf_id)}/service-apis/{str(api_id)}" if res.status_code == 201: current_app.logger.info("Service published") @@ -311,6 +348,26 @@ class PublishServiceOperations(Resource): service_api_description["apf_id"] = serviceapidescription_old["apf_id"] service_api_description["onboarding_date"] = serviceapidescription_old["onboarding_date"] service_api_description["api_id"] = serviceapidescription_old["api_id"] + + service_with_same_identity, aef_ids = find_duplicate_service_by_api_name_and_aef( + mycol, + service_api_description.get("api_name", serviceapidescription_old.get("api_name")), + service_api_description.get("aef_profiles", serviceapidescription_old.get("aef_profiles")), + excluded_api_id=service_api_description["api_id"]) + if service_with_same_identity is not None: + if aef_ids: + current_app.logger.error( + "Service already registered with same api_name/aef_id pair") + return forbidden_error( + detail="Already registered service with same api name and aef id", + cause="Found service with same api name and aef id") + + current_app.logger.error( + "Service already registered with same api name") + return forbidden_error( + detail="Already registered service with same api name", + cause="Found service with same api name") + service_api_description["supported_features"] = return_negotiated_supp_feat_dict(service_api_description["supported_features"])["Final"] if not return_negotiated_supp_feat_dict(service_api_description.get("supported_features"))["ApiStatusMonitoring"] and service_api_description.get("api_status", None) is not None: @@ -400,6 +457,26 @@ class PublishServiceOperations(Resource): api_status = patch_service_api_description.get("api_status", None) supported_features = patch_service_api_description.get("supported_features", None) patch_service_api_description = clean_empty(patch_service_api_description) + + service_with_same_identity, aef_ids = find_duplicate_service_by_api_name_and_aef( + mycol, + serviceapidescription_old.get("api_name"), + patch_service_api_description.get("aef_profiles", serviceapidescription_old.get("aef_profiles")), + excluded_api_id=serviceapidescription_old.get("api_id")) + if service_with_same_identity is not None: + if aef_ids: + current_app.logger.error( + "Service already registered with same api_name/aef_id pair") + return forbidden_error( + detail="Already registered service with same api name and aef id", + cause="Found service with same api name and aef id") + + current_app.logger.error( + "Service already registered with same api name") + return forbidden_error( + detail="Already registered service with same api name", + cause="Found service with same api name") + if api_status: patch_service_api_description["api_status"]=api_status if supported_features: