Commit 14faeca8 authored by Muhammad Umair Khan's avatar Muhammad Umair Khan
Browse files

add query parameter filtering to MEC 021 Mobility Service GET request

parent 7fee507d
Loading
Loading
Loading
Loading
+313 −15
Original line number Diff line number Diff line
@@ -148,6 +148,19 @@ func notImplemented(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusNotImplemented)
}

type RegisterationInfoList struct {
	Registrations []RegistrationInfo
	Filters       *FilterParameters
}

type FilterParameters struct {
	filter          string
	all_fields      string
	fields          string
	exclude_fields  string
	exclude_default string
}

// Init - App Mobility Service initialization
func Init() (err error) {

@@ -1205,8 +1218,10 @@ func subscriptionLinkListSubscriptionsGet(w http.ResponseWriter, r *http.Request
	u, _ := url.Parse(r.URL.String())
	q := u.Query()
	validQueryParams := []string{"subscriptionType"}
	if !validateQueryParams(q, validQueryParams) {
		w.WriteHeader(http.StatusBadRequest)
	err := validateQueryParams(q, validQueryParams)
	if err != nil {

		errHandlerProblemDetails(w, err.Error(), http.StatusBadRequest)
		return
	}

@@ -1475,18 +1490,46 @@ func appMobilityServiceByIdDELETE(w http.ResponseWriter, r *http.Request) {
func appMobilityServiceGET(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json; charset=UTF-8")

	// Validate query parameters
	u, _ := url.Parse(r.URL.String())
	q := u.Query()
	validParams := []string{"filter", "All_fields", "Fields", "Exclude_fields", "Exclude_default"}
	err := validateQueryParams(q, validParams)
	if err != nil {
		print("Query Parameter error")
		errHandlerProblemDetails(w, err.Error(), http.StatusBadRequest)
		return
	}

	// Parse query parameters
	filters := q.Get("filter")
	allFields := q.Get("all_fields")
	// field := q["fields"]
	// excludeFields := q["exclude_fields"]
	// excludeDefault := q.Get("exclude_default")

	regInfoList := &RegisterationInfoList{
		Filters: &FilterParameters{
			filter:     filters,
			all_fields: allFields,
		},
		Registrations: make([]RegistrationInfo, 0),
	}

	// Get all AMS Registration Info
	regInfoList := make([]RegistrationInfo, 0)
	//regInfoList := make([]RegistrationInfo, 0)
	key := baseKey + "svc:*:info"
	err := rc.ForEachJSONEntry(key, populateRegInfoList, &regInfoList)

	err = rc.ForEachJSONEntry(key, populateRegInfoList, regInfoList)

	if err != nil {
		log.Error(err.Error())
		errHandlerProblemDetails(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Send response
	jsonResponse, err := json.Marshal(regInfoList)
	// Prepare & send response
	jsonResponse, err := json.Marshal(regInfoList.Registrations)
	if err != nil {
		log.Error(err.Error())
		errHandlerProblemDetails(w, err.Error(), http.StatusInternalServerError)
@@ -1498,21 +1541,275 @@ func appMobilityServiceGET(w http.ResponseWriter, r *http.Request) {
}

func populateRegInfoList(key string, jsonEntry string, response interface{}) error {
	regInfoList := response.(*[]RegistrationInfo)
	if regInfoList == nil {
		return errors.New("Response not defined")
	data := response.(*RegisterationInfoList)
	if data == nil {
		return errors.New("response not defined")
	}

	// Retrieve registration info from DB
	var regInfo RegistrationInfo
	err := json.Unmarshal([]byte(jsonEntry), &regInfo)
	println("keysss", key)
	if err != nil {
		return err
	}
	*regInfoList = append(*regInfoList, regInfo)

	// Filter services
	if data.Filters != nil {

		if data.Filters.filter != "" {

			filterField := data.Filters.filter
			// Split filterField into operator, attribute, and value
			filterField = strings.Trim(filterField, "()")
			filterParts := strings.SplitN(filterField, ",", 3)
			if len(filterParts) != 3 {
				return nil
			}
			operator := filterParts[0]
			attribute := filterParts[1]
			value := filterParts[2]

			// Apply filters based on attribute
			switch attribute {
			case "appMobilityServiceId":
				if !applyStringFilter(operator, regInfo.AppMobilityServiceId, value) {
					return nil
				}

			case "serviceConsumerId.appInstanceId":
				if !applyStringFilter(operator, regInfo.ServiceConsumerId.AppInstanceId, value) {
					return nil
				}

			case "serviceConsumerId.mepId":
				if !applyStringFilter(operator, regInfo.ServiceConsumerId.MepId, value) {
					return nil
				}

			case "deviceInformation.associateId":
				matched := false
				for _, deviceInfo := range regInfo.DeviceInformation {
					if applyStringFilter(operator, deviceInfo.AssociateId.Value, value) {
						matched = true
						break
					}
				}
				if !matched {
					return nil
				}

			// case "deviceInformation.contextTransferState":
			// 	matched := false
			// 	for _, deviceInfo := range regInfo.DeviceInformation {
			// 		if applyEnumFilter(operator, string(deviceInfo.ContextTransferState.val), value) {
			// 			matched = true
			// 			break
			// 		}
			// 	}
			// 	if !matched {
			// 		return fmt.Errorf("filter mismatch: deviceInformation.contextTransferState")
			// 	}

			case "expiryTime":
				expiryTime, err := strconv.ParseUint(value, 10, 32)
				if err != nil {
					return nil
				}
				if !applyNumericFilter(operator, uint32(regInfo.ExpiryTime), uint32(expiryTime)) {
					return nil
				}

			default:
				return nil
			}

		}

	}
	data.Registrations = append(data.Registrations, regInfo)
	return nil
}

// Helper functions for applying filters
func applyStringFilter(operator, fieldValue, filterValue string) bool {
	switch operator {
	case "eq":
		return fieldValue == filterValue
	case "neq":
		return fieldValue != filterValue
	case "cont":
		return strings.Contains(fieldValue, filterValue)
	case "ncont":
		return !strings.Contains(fieldValue, filterValue)
	case "in":
		values := strings.Split(filterValue, ",")
		for _, v := range values {
			if fieldValue == v {
				return true
			}
		}
		return false
	case "nin":
		values := strings.Split(filterValue, ",")
		for _, v := range values {
			if fieldValue == v {
				return false
			}
		}
		return true
	case "gt":
		return fieldValue > filterValue
	case "gte":
		return fieldValue >= filterValue
	case "lt":
		return fieldValue < filterValue
	case "lte":
		return fieldValue <= filterValue
	default:
		return false
	}
}

func applyEnumFilter(operator, fieldValue, filterValue string) bool {
	return applyStringFilter(operator, fieldValue, filterValue)
}

func applyNumericFilter(operator string, fieldValue, filterValue uint32) bool {
	switch operator {
	case "eq":
		return fieldValue == filterValue
	case "neq":
		return fieldValue != filterValue
	case "gt":
		return fieldValue > filterValue
	case "gte":
		return fieldValue >= filterValue
	case "lt":
		return fieldValue < filterValue
	case "lte":
		return fieldValue <= filterValue
	default:
		return false
	}
}

// Original
// func populateRegInfoList(key string, jsonEntry string, response interface{}) error {
// 	data := response.(*RegisterationInfoList)
// 	if data == nil {
// 		return errors.New("response not defined")
// 	}

// 	// Retrieve registration info from DB
// 	var regInfo RegistrationInfo
// 	err := json.Unmarshal([]byte(jsonEntry), &regInfo)
// 	println("keysss", key)
// 	if err == nil {
// 		return err
// 	}

// 	// Filter services
// 	if data.Filters != nil {

// 		if data.Filters.filter != "" {
// 			filterField := data.Filters.filter
// 			if regInfo.AppMobilityServiceId == "" || (filterField != regInfo.AppMobilityServiceId) {
// 				return nil
// 			}
// 		}

// 	}

// 	data.Registrations = append(data.Registrations, regInfo)
// 	return nil
// }

// filterRegistrationInfo applies filtering based on the provided filters.
// func filterRegistrationInfo(regInfoList []RegistrationInfo, filters []string) []RegistrationInfo {
// 	var filteredList []RegistrationInfo

// 	for _, regInfo := range regInfoList {
// 		match := true

// 		// Iterate over filters to apply them one by one
// 		for _, filter := range filters {
// 			filterParts := strings.Split(filter, ":")
// 			if len(filterParts) != 2 {
// 				// Invalid filter format (e.g., "key:value")
// 				continue
// 			}
// 			key := filterParts[0]
// 			value := filterParts[1]

// 			// Apply filter based on key-value pairs
// 			switch key {
// 			case "appMobilityServiceId":
// 				if regInfo.AppMobilityServiceId != value {
// 					match = false
// 				}
// 			case "appInstanceId":
// 				if regInfo.ServiceConsumerId.AppInstanceId != value {
// 					match = false
// 				}
// 			case "mepId":
// 				if regInfo.ServiceConsumerId.MepId != value {
// 					match = false
// 				}
// 			case "associateId":
// 				// Check if any device has the associateId value
// 				found := false
// 				for _, device := range regInfo.DeviceInformation {
// 					if device.AssociateId == value {
// 						found = true
// 						break
// 					}
// 				}
// 				if !found {
// 					match = false
// 				}
// 			case "expiryTime":
// 				expiryTime, err := strconv.Atoi(value)
// 				if err != nil || regInfo.ExpiryTime != uint32(expiryTime) {
// 					match = false
// 				}
// 			default:
// 				// If filter key is not recognized, skip it
// 				continue
// 			}

// 			// If any filter condition doesn't match, we stop checking further
// 			if !match {
// 				break
// 			}
// 		}

// 		// If all filters matched, add to the result list
// 		if match {
// 			filteredList = append(filteredList, regInfo)
// 		}
// 	}

// 	return filteredList
// }

// func populateRegInfoList(key string, jsonEntry string, response interface{}) error {
// 	regInfoList := response.(*[]RegistrationInfo)
// 	if regInfoList == nil {
// 		return errors.New("Response not defined")
// 	}

// 	// Retrieve registration info from DB
// 	var regInfo RegistrationInfo
// 	err := json.Unmarshal([]byte(jsonEntry), &regInfo)
// 	if err != nil {
// 		return err
// 	}

// 	*regInfoList = append(*regInfoList, regInfo)
// 	return nil
// }

func cleanUp() {
	log.Info("Terminate all")

@@ -2324,21 +2621,22 @@ func delTrackedDevInfo(svcId string, address string) error {
	return nil
}

func validateQueryParams(params url.Values, validParamList []string) bool {
func validateQueryParams(params url.Values, validParams []string) error {
	for param := range params {
		found := false
		for _, validParam := range validParamList {
		for _, validParam := range validParams {
			if param == validParam {
				found = true
				break
			}
		}
		if !found {
			log.Error("Invalid query param: ", param)
			return false
			err := errors.New("Invalid query param: " + param)
			log.Error(err.Error())
			return err
		}
	}
	return true
	return nil
}

func validateQueryParamValue(val string, validValues []string) bool {