176 custom url parser in rest_api_helper
This commit is contained in:
+1
-1
@@ -51,7 +51,7 @@
|
||||
|
||||
//variables.framework.docs={};
|
||||
variables.framework.docs.APIName="svc-api";
|
||||
variables.framework.docs.APIVersion="0.175"; /*$ git config --global --unset user.password*/
|
||||
variables.framework.docs.APIVersion="0.176"; /*$ git config --global --unset user.password*/
|
||||
|
||||
variables.framework.globalHeaders = structNew();
|
||||
variables.framework.globalHeaders["Access-Control-Expose-Headers"] = "Location";
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<!--- v0.03 2024-11-27 --->
|
||||
<!--- v0.04 2025-11-20 columns--->
|
||||
<!--- v0.05 2025-11-20 multiple field entries in filter, filter became array instead of structure--->
|
||||
<!--- v0.06 2025-11-22 custom url parser used to prevent comma collision in lists--->
|
||||
|
||||
<cffunction name="empty2null"
|
||||
access="public"
|
||||
@@ -77,6 +78,62 @@
|
||||
|
||||
|
||||
<cffunction name="parseFilterParams"
|
||||
returntype="array"
|
||||
output="true"
|
||||
hint="Parse and collect filter params from URL. For operators see filter_build">
|
||||
<cfargument name="params" type="struct" required="true" />
|
||||
<!--- используется альтернативный парсер query_string, чтобы не путать запятые в значении с разделителями списка list --->
|
||||
<!--- имена полей в URL в snake_case или camelCase, имена колонок в snake_case --->
|
||||
<!--- token example minSize=NEQ:2--->
|
||||
|
||||
<cfset var local = {}/><!--- *** --->
|
||||
<cfset var out = []/>
|
||||
<cfset var urlParams = parseQs()/>
|
||||
|
||||
<cfloop collection=#params# index="local.item">
|
||||
|
||||
<cfset var urlParamName=snake2camel(lCase(local.item))/>
|
||||
<cfif structKeyExists(urlParams,urlParamName)>
|
||||
|
||||
<cfloop array=#urlParams[urlParamName]# item="local.rawValue"><!--- when parameter occures in URL more than once, its values compose a comma delimited list --->
|
||||
<cfset var operator="EQ"/>
|
||||
<cfset var value=#local.rawValue#/>
|
||||
<cfif listLen(local.rawValue,":") GT 1>
|
||||
<cfset var operator=listGetAt(local.rawValue,1,":")/>
|
||||
<cfset var value=listGetAt(local.rawValue,2,":")/>
|
||||
</cfif>
|
||||
<cfif !isValid(ARGUMENTS.params[local.item].type,value)>
|
||||
<cfthrow type="invalidParamValue" message="Filter parameter #urlParamName# value is not a valid #ARGUMENTS.params[local.item].type#"/><!---не выводим значение, чтобы исключить XSS--->
|
||||
</cfif>
|
||||
|
||||
<cfif structKeyExists(ARGUMENTS.params[local.item], "expression") AND len(ARGUMENTS.params[local.item].expression)>
|
||||
<cfset var expr="#ARGUMENTS.params[local.item].expression#"/>
|
||||
<cfelse>
|
||||
<cfset var expr=local.item/>
|
||||
</cfif>
|
||||
|
||||
<cfif structKeyExists(ARGUMENTS.params[local.item], "prefix") AND len(ARGUMENTS.params[local.item].prefix)>
|
||||
<cfset var fieldName="#ARGUMENTS.params[local.item].prefix#.#expr#"/>
|
||||
<cfelse>
|
||||
<cfset var fieldName=#expr#/>
|
||||
</cfif>
|
||||
|
||||
<cfif structKeyExists(ARGUMENTS.params[local.item], "list") AND ARGUMENTS.params[local.item].list GT 0>
|
||||
<cfset var list=ARGUMENTS.params[local.item].list />
|
||||
<cfelse>
|
||||
<cfset var list=false />
|
||||
</cfif>
|
||||
|
||||
<cfset var rec={field=#fieldName#, val=#value#, ftype=#ARGUMENTS.params[local.item].type#, compare=#operator#, list=#list#}/>
|
||||
<cfset arrayAppend(out, rec)/>
|
||||
</cfloop>
|
||||
</cfif>
|
||||
|
||||
</cfloop>
|
||||
<cfreturn out/>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="parseFilterParamsV1"
|
||||
returntype="array"
|
||||
output="true"
|
||||
hint="parse and collect filter params, for operators see filter_build">
|
||||
@@ -411,4 +468,49 @@
|
||||
<cfreturn false/>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="parseQsToNVArray"
|
||||
returntype="array"
|
||||
output="false"
|
||||
hint="Parse query string. Returns an array of name-value pairs">
|
||||
<cfargument name="qs" type="string" default=#CGI.QUERY_STRING#/>
|
||||
<cfreturn
|
||||
arrayMap(
|
||||
CreateObject("java", "org.apache.http.client.utils.URLEncodedUtils")
|
||||
.parse(
|
||||
CreateObject("java", "java.net.URI").init("http://localhost?#arguments.qs#"),
|
||||
'UTF-8'
|
||||
),
|
||||
function(v) {
|
||||
return {"name"=v.getName(),"value"=v.getValue()}
|
||||
}
|
||||
)
|
||||
/>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="parseQs"
|
||||
returntype="struct"
|
||||
output="false"
|
||||
hint="Parse query string. Returns a map of arrays instead of lists to prevent delimiter problem">
|
||||
<cfargument name="qs" type="string" default=#CGI.QUERY_STRING#/>
|
||||
<cfreturn
|
||||
arrayReduce(
|
||||
CreateObject("java", "org.apache.http.client.utils.URLEncodedUtils")
|
||||
.parse(
|
||||
CreateObject("java", "java.net.URI").init("http://localhost?#arguments.qs#"),
|
||||
'UTF-8'
|
||||
),
|
||||
function(struct, nvPair) {
|
||||
if (structKeyExists(struct, nvPair.getName())) {
|
||||
arrayAppend(struct[nvPair.getName()],nvPair.getValue())
|
||||
} else {
|
||||
structInsert(struct, nvPair.getName(), [nvPair.getValue()])
|
||||
}
|
||||
return struct;
|
||||
},
|
||||
{}
|
||||
)
|
||||
/>
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
@@ -6,7 +6,7 @@
|
||||
</cfsilent>
|
||||
|
||||
<!---спецификация полей, пригодных для фильтрации (и сортировки)--->
|
||||
<cfset this.fieldsSpec={
|
||||
<cfset this.fieldsSpec = {
|
||||
"instance_operation_uid"={prefix="o", type="guid"},
|
||||
"instance_uid"={prefix="o", type="guid"},
|
||||
"dt_created"={prefix="o", type="date"},
|
||||
@@ -27,9 +27,9 @@
|
||||
"display_name"={prefix="e", type="string"},
|
||||
"service_id"={prefix="e", type="integer"},
|
||||
"svc"={prefix="v", type="string"},
|
||||
"operation"={prefix="o", type="string"},
|
||||
"duration"={expression="extract('epoch' from coalesce(o.dt_finish,CURRENT_TIMESTAMP)- o.dt_start)", type="numeric"}
|
||||
}
|
||||
/>
|
||||
}/>
|
||||
|
||||
|
||||
<!--- <cffunction name="post" hint="Создание новой операции с параметрами. Принимаются CFS параметры, генерируются RFS параметры. Запускается операция отдельным вызовом. До запуска CFS параметры могут корректироваться (а надо?). Запущенная операция навсегда становится Read Only (при желании можем реализовать ее клонирование). Можем реализовать корректировку параметров, но непонятно, зачем. Когда мы конфигурируем инстанс, на самом деле мы задаем CFS параметры операции create. Можно править параметры, а можно пересоздать операцию с новыми параметрами. Предусмотреть удаление (метод DELETE) незапущенной операции?"> --->
|
||||
|
||||
Reference in New Issue
Block a user