cleanup: strip remaining comment noise

This commit is contained in:
“Naeel”
2026-04-30 07:53:58 +04:00
parent 0c7fd14a3a
commit a4c825db60
12 changed files with 62 additions and 275 deletions
+25
View File
@@ -135,6 +135,16 @@
Ожидаемый результат: Ожидаемый результат:
- единообразный русскоязычный комментарийный слой там, где комментарии реально остаются - единообразный русскоязычный комментарийный слой там, где комментарии реально остаются
### Этап E. Дочистка явных хвостов
Сделать:
- удалить закомментированный `onRequest` и старые Taffy-заготовки из `v1/Application.cfc`
- убрать остатки debug-комментариев и лишних пояснений из `v1/resources/instance_operation_run.cfc`
- перепроверить, что логика не изменилась
Ожидаемый результат:
- source-файлы без явного мусора и без затронутого runtime
### Этап E. Сводный документ ### Этап E. Сводный документ
Сделать: Сделать:
@@ -152,6 +162,21 @@
- подготовить список вопросов по неоднозначным местам - подготовить список вопросов по неоднозначным местам
- отдельно указать, какие решения были приняты по умолчанию без уточнения заказчика - отдельно указать, какие решения были приняты по умолчанию без уточнения заказчика
### Этап G. Дочистка remaining source-файлов
Сделать:
- убрать декоративные и старые комментарии из оставшихся прикладных `v1/*` файлов
- отдельно дочистить `v1/Application.cfc` от закомментированного кода и явного мусора
- проверить, что `git diff --check` остаётся чистым
Ожидаемый результат:
- текущий набор source-файлов без явных comment-hash остатков и без сломанной логики
Результат:
- большая часть remaining source-файлов очищена от декоративных комментариев
- `v1/Application.cfc` очищен от закомментированного кода и старых debug-хвостов
- `git diff --check` после правок остаётся чистым
## Принятые допущения на текущий момент ## Принятые допущения на текущий момент
1. Работу нужно вести в отдельной ветке, а не в `dev`. 1. Работу нужно вести в отдельной ветке, а не в `dev`.
+14 -132
View File
@@ -68,7 +68,6 @@
<cffunction name="rethrow" returntype="void"> <cffunction name="rethrow" returntype="void">
<!--- https://www.raymondcamden.com/2004/03/09/3089633C-9FA0-606B-3F540AE9642A795F --->
<cftry> <cftry>
<cfcatch> <cfcatch>
<cfrethrow/> <cfrethrow/>
@@ -148,50 +147,10 @@
</cfcatch> </cfcatch>
</cftry> </cftry>
</cffunction> </cffunction>
<!--- <cffunction name="onRequest">
<cfargument name="template" type="string" required="true"/>
<cfset request.startTickCount=getTickCount()/>
<!---<cfheader name="Access-Control-Allow-Origin" value="*"/>--->
<cfreturn super.onRequest(template) />
</cffunction> --->
<cfscript> <cfscript>
function onTaffyRequest(verb, cfc, requestArguments, mimeExt, headers){ function onTaffyRequest(verb, cfc, requestArguments, mimeExt, headers){
/* https://docs.taffy.io/#/3.5.0 */
/*
//allow white-listed requests through
if (cfc == "login"){
return true;
}
//otherwise require a device token
if (!structKeyExists(requestArguments, "deviceToken")){
return newRepresentation().noData().withStatus(401, "Authentication Required");
//and make sure it's valid
}else if (!validateToken(requestArguments.deviceToken)){
return newRepresentation().noData().withStatus(403, "Not Authorized");
}
//return representationOf(requestArguments);
//if a token is included, and valid, allow the request to continue
return true;
*/
////////////////////////////////////////////////
// самым грубым образом получаем данные от IDP, не обрабатывая исключения
//if (variables.framework.allowCrossDomain EQ "") {
//corsHeaders(); // *** нужно, чтобы variables.framework.allowCrossDomain="" иначе задвоятся заголовки
//}
//if (UCase(arguments.verb) EQ 'OPTIONS') return newRepresentation().noData().withStatus("204","No Data").withHeaders({"Content-Type":"application/json;charset=utf-8"});
request.stand=this.getStand(); request.stand=this.getStand();
request.iam_service_url=this.iamServiceUrl; request.iam_service_url=this.iamServiceUrl;
@@ -210,49 +169,39 @@
var authUrl = "#this.iamServiceUrl#/auth/user"; var authUrl = "#this.iamServiceUrl#/auth/user";
var httpService = new http(method = "GET", charset = "utf-8", url = #authUrl#, timeout="5"); var httpService = new http(method = "GET", charset = "utf-8", url = #authUrl#, timeout="5");
httpService.addParam(type = "HEADER", name = "Accept", value = "application/json"); httpService.addParam(type = "HEADER", name = "Accept", value = "application/json");
httpService.addParam(type = "HEADER", name = "Authorization", value = "#request.auth_header#"); //passthrough httpService.addParam(type = "HEADER", name = "Authorization", value = "#request.auth_header#");
//writedump(authUrl);abort;
var resp = httpService.send(); var resp = httpService.send();
//if (resp.status_code NEQ 200) throw("IDP response not OK");
//writedump(resp);abort;
var prefix = resp.getPrefix(); var prefix = resp.getPrefix();
if (prefix.status_code NEQ 200) { if (prefix.status_code NEQ 200) {
//writedump(authUrl);
//writedump(resp);
var iamStatusCode = (isValid("integer", prefix.status_code)) ? val(prefix.status_code) : 500; var iamStatusCode = (isValid("integer", prefix.status_code)) ? val(prefix.status_code) : 500;
return representationOf( {"IAM URL"=#authUrl#, "idpResponse"=resp} ).withStatus(iamStatusCode); return representationOf( {"IAM URL"=#authUrl#, "idpResponse"=resp} ).withStatus(iamStatusCode);
//abort;
//throw("IDP response not OK");
} }
result = prefix.filecontent; result = prefix.filecontent;
//writedump(result);abort;
} catch (e) { } catch (e) {
return representationOf( {"exception"=e, "idpResponse"=result} ).withStatus(200); return representationOf( {"exception"=e, "idpResponse"=result} ).withStatus(200);
} }
//writeDump(result); abort;
try { try {
var idpUserData=deserializeJson(result); var idpUserData=deserializeJson(result);
"arguments.requestArguments.companyUid"=idpUserData.userInfo.companyId;//GUID! "arguments.requestArguments.companyUid"=idpUserData.userInfo.companyId;
"arguments.requestArguments.usrUid"=idpUserData.userInfo.contactId;//userId; //GUID! "arguments.requestArguments.usrUid"=idpUserData.userInfo.contactId;
var usrCustomerInfo=getUsrCustomerInfo(idpUserData.userInfo.contactId, idpUserData.userInfo.companyId); var usrCustomerInfo=getUsrCustomerInfo(idpUserData.userInfo.contactId, idpUserData.userInfo.companyId);
} catch (e) { } catch (e) {
return representationOf( {"exception.Message"=e.Message, "exception.Detail"=e.Detail, "idpResponse"=result} ).withStatus(422); return representationOf( {"exception.Message"=e.Message, "exception.Detail"=e.Detail, "idpResponse"=result} ).withStatus(422);
} }
//dump(idpUserData);dump(usrCustomerInfo);abort;
if (lCase(arguments.cfc) EQ 'user') { if (lCase(arguments.cfc) EQ 'user') {
if (structIsEmpty(usrCustomerInfo)) return representationOf("User information not found").withStatus(404); if (structIsEmpty(usrCustomerInfo)) return representationOf("User information not found").withStatus(404);
} }
if (lCase(arguments.cfc) EQ 'notification_ls') { //*** костыль: для нотификаций можно адресоваться к пользователю без контракта if (lCase(arguments.cfc) EQ 'notification_ls') {
if (structIsEmpty(usrCustomerInfo)) { if (structIsEmpty(usrCustomerInfo)) {
"arguments.requestArguments.usrId"=-1; //Integer! "arguments.requestArguments.usrId"=-1;
"arguments.requestArguments.contragentId"=-1; //Integer "arguments.requestArguments.contragentId"=-1;
"arguments.requestArguments.contractId"=-1; //Integer "arguments.requestArguments.contractId"=-1;
"arguments.requestArguments.specificationId"=-1; //Integer "arguments.requestArguments.specificationId"=-1;
"arguments.requestArguments.isImpersonated"=false; "arguments.requestArguments.isImpersonated"=false;
"arguments.requestArguments.clientID"=""; "arguments.requestArguments.clientID"="";
"arguments.requestArguments.login"=""; "arguments.requestArguments.login"="";
@@ -261,17 +210,17 @@
} }
} }
if (structIsEmpty(usrCustomerInfo)) return representationOf("Cannot find default specification for current user #result#").withStatus(422); //это создает довольно много лишних движений при отладке if (structIsEmpty(usrCustomerInfo)) return representationOf("Cannot find default specification for current user #result#").withStatus(422);
"arguments.requestArguments.usrId"=usrCustomerInfo.usrId; //Integer "arguments.requestArguments.usrId"=usrCustomerInfo.usrId;
"arguments.requestArguments.contragentId"=usrCustomerInfo.contragentId; //Integer "arguments.requestArguments.contragentId"=usrCustomerInfo.contragentId;
"arguments.requestArguments.contractId"=usrCustomerInfo.contractId; //Integer "arguments.requestArguments.contractId"=usrCustomerInfo.contractId;
"arguments.requestArguments.specificationId"=usrCustomerInfo.specificationId; //Integer "arguments.requestArguments.specificationId"=usrCustomerInfo.specificationId;
try { try {
"arguments.requestArguments.isImpersonated"=idpUserData.impersonation.is_impersonated; "arguments.requestArguments.isImpersonated"=idpUserData.impersonation.is_impersonated;
} catch (e) { } catch (e) {
"arguments.requestArguments.isImpersonated"=false; // так себе решение, надо было бы NULL "arguments.requestArguments.isImpersonated"=false;
} }
try { try {
@@ -300,7 +249,6 @@
<cffunction name="checkAuth"> <cffunction name="checkAuth">
<!---https://www.sjoerdlangkemper.nl/2018/09/12/authorization-header-and-cors/--->
<cfset var jwtHelper=CreateObject("component","lib.jwt").init()/> <cfset var jwtHelper=CreateObject("component","lib.jwt").init()/>
<cfset var headers=#GetHttpRequestData().headers#/> <cfset var headers=#GetHttpRequestData().headers#/>
<cftry> <cftry>
@@ -308,7 +256,6 @@
<cfset var token=jwtHelper.decode(token=rawToken, key=request.config.IDP_certificate.keys[1], algorithms='RS256')/> <cfset var token=jwtHelper.decode(token=rawToken, key=request.config.IDP_certificate.keys[1], algorithms='RS256')/>
<cfset var login=token.preferred_username/> <cfset var login=token.preferred_username/>
<!---отрезаем первичный домен --->
<cfset login=ReplaceNoCase(login,"#request.config.auth_domain_suffix#","")/> <cfset login=ReplaceNoCase(login,"#request.config.auth_domain_suffix#","")/>
<cfquery name="local.qUsr"> <cfquery name="local.qUsr">
select usr_id from usr where login=<cfqueryparam cfsqltype="cf_sql_varchar" value="#login#"/> select usr_id from usr where login=<cfqueryparam cfsqltype="cf_sql_varchar" value="#login#"/>
@@ -340,7 +287,6 @@
<cffunction name="getUsrCustomerInfo"> <cffunction name="getUsrCustomerInfo">
<!--- Может быть имперсонирована компания, а может контакт,
при этом если имперсонируется компания, то спецификацию и контракт нужно брать по компании при этом если имперсонируется компания, то спецификацию и контракт нужно брать по компании
Кстати, зачем нужен вообще юзер, если компания всегда доступна, а вся информация висит на ней Кстати, зачем нужен вообще юзер, если компания всегда доступна, а вся информация висит на ней
Для того, чтобы разрешить ключ в целочисленный ключ CMDB---> Для того, чтобы разрешить ключ в целочисленный ключ CMDB--->
@@ -348,18 +294,13 @@
<cfargument name="contragentUid"/> <cfargument name="contragentUid"/>
<cfif !isValid('guid',arguments.usrUid)> <cfif !isValid('guid',arguments.usrUid)>
<cfthrow message="Invalid user uuid" detail="uuid=(#arguments.usrUid#) is not a valid UUID"/><!--- тут спорно, можно было бы и 400 и 500, но исключения из этой функции не дифференцированы по типам --->
</cfif> </cfif>
<cfif !isValid('guid',arguments.contragentUid)> <cfif !isValid('guid',arguments.contragentUid)>
<cfthrow message="Invalid contragent uuid" detail="uuid=(#arguments.contragentUid#) is not a valid UUID"/> <cfthrow message="Invalid contragent uuid" detail="uuid=(#arguments.contragentUid#) is not a valid UUID"/>
</cfif> </cfif>
<!--- глупейшее определение спецификации по умолчанию (надо переделать, чтобы создавалась, или вообще просто записывать факты без спеки). Но помним, что при постановке на тестирование цены еше не фиксированы --->
<!--- заметим, что у нас контрагент может быть определен параллельно, от IDP --->
<cfset local={}/> <cfset local={}/>
<!--- Во избежании потери времени при отладке временно сделаем создание дефолтового контракта и спецификации, если их нет --->
<!--- *** хватается первый попавшийся контракт и спецификация --->
<cfquery name="local.qGetContragentInfo"> <cfquery name="local.qGetContragentInfo">
select z.contragent_id, c.contract_id, s.specification_id select z.contragent_id, c.contract_id, s.specification_id
@@ -372,7 +313,6 @@
</cfquery> </cfquery>
<cfif local.qGetContragentInfo.recordCount EQ 0> <cfif local.qGetContragentInfo.recordCount EQ 0>
<!--- диагностика (тут можно не переживать за производительность, история редкая) --->
<cfquery name="local.qGetContragent"> <cfquery name="local.qGetContragent">
select z.contragent_id select z.contragent_id
from contragent z from contragent z
@@ -414,7 +354,6 @@
</cfif> </cfif>
<!--- <cfdump var=#local.qGetCustomerInfo#/><cfabort/> --->
<cfreturn { <cfreturn {
"usrId"=#local.qGetUserInfo.usr_id#, "usrId"=#local.qGetUserInfo.usr_id#,
"contragentId"=#local.qGetContragentInfo.contragent_id#, "contragentId"=#local.qGetContragentInfo.contragent_id#,
@@ -426,7 +365,6 @@
<cffunction name="corsHeaders"> <cffunction name="corsHeaders">
<!--- *** фрагмент взят из taffy/core/api.cfc и немного переписан --->
<cfset var _taffyRequest=request._taffyRequest/> <cfset var _taffyRequest=request._taffyRequest/>
<cfset local={}/> <cfset local={}/>
@@ -441,11 +379,9 @@
<cfheader name="Access-Control-Allow-Origin" value="#_taffyRequest.headers.origin#" /> <cfheader name="Access-Control-Allow-Origin" value="#_taffyRequest.headers.origin#" />
<cfheader name="Access-Control-Allow-Methods" value="#local.allowVerbs#" /> <cfheader name="Access-Control-Allow-Methods" value="#local.allowVerbs#" />
<!--- Why do we parrot back these headers? See: https://github.com/atuttle/Taffy/issues/144 --->
<cfif not structKeyExists(_taffyRequest.headers, "Access-Control-Request-Headers")> <cfif not structKeyExists(_taffyRequest.headers, "Access-Control-Request-Headers")>
<cfheader name="Access-Control-Allow-Headers" value="Origin, Authorization, X-CSRF-Token, X-Requested-With, Content-Type, X-HTTP-Method-Override, Accept, Referrer, User-Agent" /> <cfheader name="Access-Control-Allow-Headers" value="Origin, Authorization, X-CSRF-Token, X-Requested-With, Content-Type, X-HTTP-Method-Override, Accept, Referrer, User-Agent" />
<cfelse> <cfelse>
<!--- parrot back all of the request headers to allow the request to continue (can we improve on this?) --->
<cfset local.allowedHeaders = {} /> <cfset local.allowedHeaders = {} />
<cfloop list="Origin,Authorization,X-CSRF-Token,X-Requested-With,Content-Type,X-HTTP-Method-Override,Accept,Referrer,User-Agent" index="local.h"> <cfloop list="Origin,Authorization,X-CSRF-Token,X-Requested-With,Content-Type,X-HTTP-Method-Override,Accept,Referrer,User-Agent" index="local.h">
<cfset local.allowedHeaders[local.h] = 1 /> <cfset local.allowedHeaders[local.h] = 1 />
@@ -459,14 +395,9 @@
</cfif> </cfif>
</cffunction> </cffunction>
<!--- :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: --->
<!--- :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: --->
<!--- Overriding TAFFY short-circuit logic (taffy/core/api.cfc) --->
<cffunction name="onRequest" output="true" returntype="boolean"> <cffunction name="onRequest" output="true" returntype="boolean">
<cfargument name="targetPage" type="string" required="true" /> <cfargument name="targetPage" type="string" required="true" />
<cfset request.startTickCount=getTickCount()/><!--- *** --->
<cfset var _taffyRequest = {} /> <cfset var _taffyRequest = {} />
<cfset var local = {} /> <cfset var local = {} />
@@ -478,12 +409,10 @@
<cfset m = _taffyRequest.metrics /> <cfset m = _taffyRequest.metrics />
<cfset m.init = getTickCount() /> <cfset m.init = getTickCount() />
<!--- enable/disable debug output per settings --->
<cfif not structKeyExists(url, application._taffy.settings.debugKey)> <cfif not structKeyExists(url, application._taffy.settings.debugKey)>
<cfsetting showdebugoutput="false" /> <cfsetting showdebugoutput="false" />
</cfif> </cfif>
<!--- display api dashboard if requested --->
<cfif <cfif
NOT structKeyExists(url,application._taffy.settings.endpointURLParam) NOT structKeyExists(url,application._taffy.settings.endpointURLParam)
AND NOT structKeyExists(form,application._taffy.settings.endpointURLParam) AND NOT structKeyExists(form,application._taffy.settings.endpointURLParam)
@@ -509,14 +438,12 @@
</cfif> </cfif>
</cfif> </cfif>
<!--- get request details --->
<cfset m.beforeParse = getTickCount() /> <cfset m.beforeParse = getTickCount() />
<cfset local.parsed = parseRequest() /> <cfset local.parsed = parseRequest() />
<cfset m.afterParse = getTickCount() /> <cfset m.afterParse = getTickCount() />
<cfset structAppend(_taffyRequest, local.parsed) /> <cfset structAppend(_taffyRequest, local.parsed) />
<cfset m.parseTime = m.afterParse - m.beforeParse /> <cfset m.parseTime = m.afterParse - m.beforeParse />
<!--- CORS headers (so that CORS can pass even if the resource throws an exception) --->
<cfset local.allowVerbs = uCase(structKeyList(_taffyRequest.matchDetails.methods)) /> <cfset local.allowVerbs = uCase(structKeyList(_taffyRequest.matchDetails.methods)) />
<cfif (application._taffy.settings.allowCrossDomain eq true or len(application._taffy.settings.allowCrossDomain) gt 0) <cfif (application._taffy.settings.allowCrossDomain eq true or len(application._taffy.settings.allowCrossDomain) gt 0)
AND listFindNoCase('PUT,PATCH,DELETE,OPTIONS',_taffyRequest.verb) AND listFindNoCase('PUT,PATCH,DELETE,OPTIONS',_taffyRequest.verb)
@@ -525,14 +452,8 @@
</cfif> </cfif>
<cfif structKeyExists(_taffyRequest.headers, "origin") AND (application._taffy.settings.allowCrossDomain eq true or len(application._taffy.settings.allowCrossDomain) gt 0)> <cfif structKeyExists(_taffyRequest.headers, "origin") AND (application._taffy.settings.allowCrossDomain eq true or len(application._taffy.settings.allowCrossDomain) gt 0)>
<cfif application._taffy.settings.allowCrossDomain eq true> <cfif application._taffy.settings.allowCrossDomain eq true>
<!--- <cfheader name="Access-Control-Allow-Origin" value="*" /> ---><!--- *** dirty hack 2024-10-23 17:59:43--->
<cfheader name="Access-Control-Allow-Origin" value="#_taffyRequest.headers.origin#" /> <cfheader name="Access-Control-Allow-Origin" value="#_taffyRequest.headers.origin#" />
<cfelse> <cfelse>
<!---
The Access-Control-Allow-Origin header can only have 1 value so we check to see if the Origin header is
in the list of origins specified in the config setting and parrot back the Origin header if so.
We also need to add the Access-Control-Allow-Credentials header and set it to true for those type requests
--->
<cfset local.domains = listToArray( application._taffy.settings.allowCrossDomain, ', ;' )> <cfset local.domains = listToArray( application._taffy.settings.allowCrossDomain, ', ;' )>
<cfif structKeyExists(_taffyRequest.headers, "origin")> <cfif structKeyExists(_taffyRequest.headers, "origin")>
<cfloop from="1" to="#arrayLen( local.domains )#" index="local.i"> <cfloop from="1" to="#arrayLen( local.domains )#" index="local.i">
@@ -545,11 +466,9 @@
</cfif> </cfif>
</cfif> </cfif>
<cfheader name="Access-Control-Allow-Methods" value="#local.allowVerbs#" /> <cfheader name="Access-Control-Allow-Methods" value="#local.allowVerbs#" />
<!--- Why do we parrot back these headers? See: https://github.com/atuttle/Taffy/issues/144 --->
<cfif not structKeyExists(_taffyRequest.headers, "Access-Control-Request-Headers")> <cfif not structKeyExists(_taffyRequest.headers, "Access-Control-Request-Headers")>
<cfheader name="Access-Control-Allow-Headers" value="Origin, Authorization, X-CSRF-Token, X-Requested-With, Content-Type, X-HTTP-Method-Override, Accept, Referrer, User-Agent" /> <cfheader name="Access-Control-Allow-Headers" value="Origin, Authorization, X-CSRF-Token, X-Requested-With, Content-Type, X-HTTP-Method-Override, Accept, Referrer, User-Agent" />
<cfelse> <cfelse>
<!--- parrot back all of the request headers to allow the request to continue (can we improve on this?) --->
<cfset local.allowedHeaders = {} /> <cfset local.allowedHeaders = {} />
<cfloop list="Origin,Authorization,X-CSRF-Token,X-Requested-With,Content-Type,X-HTTP-Method-Override,Accept,Referrer,User-Agent" index="local.h"> <cfloop list="Origin,Authorization,X-CSRF-Token,X-Requested-With,Content-Type,X-HTTP-Method-Override,Accept,Referrer,User-Agent" index="local.h">
<cfset local.allowedHeaders[local.h] = 1 /> <cfset local.allowedHeaders[local.h] = 1 />
@@ -562,14 +481,11 @@
</cfif> </cfif>
</cfif> </cfif>
<!--- global headers --->
<cfset addHeaders(getGlobalHeaders()) /> <cfset addHeaders(getGlobalHeaders()) />
<!---
Now we know everything we need to know to service the request. let's service it! Now we know everything we need to know to service the request. let's service it!
---> --->
<!--- ...after we let the api developer know all of the request details first... --->
<cfset m.beforeOnTaffyRequest = getTickCount() /> <cfset m.beforeOnTaffyRequest = getTickCount() />
<cfset _taffyRequest.continue = onTaffyRequest( <cfset _taffyRequest.continue = onTaffyRequest(
_taffyRequest.verb _taffyRequest.verb
@@ -584,7 +500,6 @@
<cfset m.otrTime = m.afterOnTaffyRequest - m.beforeOnTaffyRequest /> <cfset m.otrTime = m.afterOnTaffyRequest - m.beforeOnTaffyRequest />
<cfif not structKeyExists(_taffyRequest, "continue")> <cfif not structKeyExists(_taffyRequest, "continue")>
<!--- developer forgot to return true --->
<cfthrow <cfthrow
message="Error in your onTaffyRequest method" message="Error in your onTaffyRequest method"
detail="Your onTaffyRequest method returned no value. Expected: Return TRUE or call noData()/representationOf()." detail="Your onTaffyRequest method returned no value. Expected: Return TRUE or call noData()/representationOf()."
@@ -593,19 +508,14 @@
</cfif> </cfif>
<cfif isObject(_taffyRequest.continue)> <cfif isObject(_taffyRequest.continue)>
<!--- inspection complete but request has been aborted by developer; return custom response --->
<cfset _taffyRequest.result = duplicate(_taffyRequest.continue) /> <cfset _taffyRequest.result = duplicate(_taffyRequest.continue) />
<cfset structDelete(_taffyRequest, "continue")/> <cfset structDelete(_taffyRequest, "continue")/>
<cfset m.resourceTime = 0 /> <cfset m.resourceTime = 0 />
<cfelse> <cfelse>
<!--- inspection complete and request allowed by developer --->
<!--- handle requests for simulated responses --->
<cfif structKeyExists(_taffyRequest.requestArguments, application._taffy.settings.simulateKey) and _taffyRequest.requestArguments[application._taffy.settings.simulateKey] eq application._taffy.settings.simulatePassword> <cfif structKeyExists(_taffyRequest.requestArguments, application._taffy.settings.simulateKey) and _taffyRequest.requestArguments[application._taffy.settings.simulateKey] eq application._taffy.settings.simulatePassword>
<!--- is there a simulated response? --->
<cfset sampler = 'sample#_taffyRequest.method#Response' /> <cfset sampler = 'sample#_taffyRequest.method#Response' />
<cfif structKeyExists(_taffyRequest.matchDetails.metadata, sampler)> <cfif structKeyExists(_taffyRequest.matchDetails.metadata, sampler)>
<!--- get simulated response --->
<cfinvoke <cfinvoke
component="#application._taffy.factory.getBean(_taffyRequest.matchDetails.beanName)#" component="#application._taffy.factory.getBean(_taffyRequest.matchDetails.beanName)#"
method="#sampler#" method="#sampler#"
@@ -613,13 +523,10 @@
/> />
<cfset _taffyRequest.result = rep(_taffyRequest.result) /> <cfset _taffyRequest.result = rep(_taffyRequest.result) />
<cfelse> <cfelse>
<!--- no method for simulated response, so return 400 --->
<cfset _taffyRequest.result = noData().withStatus(400, "No Sample Response Available") /> <cfset _taffyRequest.result = noData().withStatus(400, "No Sample Response Available") />
</cfif> </cfif>
<cfelse> <cfelse>
<!--- send request to service --->
<cfif structKeyExists(_taffyRequest.matchDetails.methods, _taffyRequest.verb)> <cfif structKeyExists(_taffyRequest.matchDetails.methods, _taffyRequest.verb)>
<!--- check the cache before we call the resource --->
<cfset m.cacheCheckTime = getTickCount() /> <cfset m.cacheCheckTime = getTickCount() />
<cfset local.cacheKey = getCacheKey( <cfset local.cacheKey = getCacheKey(
_taffyRequest.matchDetails.beanName _taffyRequest.matchDetails.beanName
@@ -637,7 +544,6 @@
<cfelse> <cfelse>
<cfset structDelete(m, "cacheCheckTime") /> <cfset structDelete(m, "cacheCheckTime") />
</cfif> </cfif>
<!--- returns a representation-object --->
<cfset m.beforeResource = getTickCount() /> <cfset m.beforeResource = getTickCount() />
<cfinvoke <cfinvoke
component="#application._taffy.factory.getBean(_taffyRequest.matchDetails.beanName)#" component="#application._taffy.factory.getBean(_taffyRequest.matchDetails.beanName)#"
@@ -654,7 +560,6 @@
errorcode="taffy.resources.ResourceReturnsNothing" errorcode="taffy.resources.ResourceReturnsNothing"
/> />
</cfif> </cfif>
<!--- If the type returned is not an instance of baseSerializer, wrap it with a call to rep().
This way we can directly return the object instead of a serializer from resource actions. ---> This way we can directly return the object instead of a serializer from resource actions. --->
<cfif !isInstanceOf(_taffyRequest.result, "taffy.core.baseSerializer")> <cfif !isInstanceOf(_taffyRequest.result, "taffy.core.baseSerializer")>
<cfset _taffyRequest.result = rep(_taffyRequest.result) /> <cfset _taffyRequest.result = rep(_taffyRequest.result) />
@@ -666,11 +571,9 @@
</cfif> </cfif>
</cfif> </cfif>
<cfelseif NOT listFind(local.allowVerbs,_taffyRequest.verb)> <cfelseif NOT listFind(local.allowVerbs,_taffyRequest.verb)>
<!--- if the verb is not implemented, refuse the request --->
<cfheader name="ALLOW" value="#local.allowVerbs#" /> <cfheader name="ALLOW" value="#local.allowVerbs#" />
<cfset throwError(405, "Method Not Allowed") /> <cfset throwError(405, "Method Not Allowed") />
<cfelse> <cfelse>
<!--- create dummy response for cross domain OPTIONS request --->
<cfset _taffyRequest.resultHeaders = structNew() /> <cfset _taffyRequest.resultHeaders = structNew() />
<cfset _taffyRequest.statusArgs = structNew() /> <cfset _taffyRequest.statusArgs = structNew() />
<cfset _taffyRequest.statusArgs.statusCode = 200 /> <cfset _taffyRequest.statusArgs.statusCode = 200 />
@@ -679,17 +582,14 @@
</cfif> </cfif>
</cfif> </cfif>
<!--- make sure the requested mime type is available --->
<cfif not mimeSupported(_taffyRequest.returnMimeExt)> <cfif not mimeSupported(_taffyRequest.returnMimeExt)>
<cfset throwError(400, "Requested format not available (#_taffyRequest.returnMimeExt#)") /> <cfset throwError(400, "Requested format not available (#_taffyRequest.returnMimeExt#)") />
</cfif> </cfif>
<cfif structKeyExists(_taffyRequest,'result')> <cfif structKeyExists(_taffyRequest,'result')>
<!--- get status code --->
<cfset _taffyRequest.statusArgs = structNew() /> <cfset _taffyRequest.statusArgs = structNew() />
<cfset _taffyRequest.statusArgs.statusCode = _taffyRequest.result.getStatus() /> <cfset _taffyRequest.statusArgs.statusCode = _taffyRequest.result.getStatus() />
<cfset _taffyRequest.statusArgs.statusText = _taffyRequest.result.getStatusText() /> <cfset _taffyRequest.statusArgs.statusText = _taffyRequest.result.getStatusText() />
<!--- get custom headers --->
<cfinvoke <cfinvoke
component="#_taffyRequest.result#" component="#_taffyRequest.result#"
method="getHeaders" method="getHeaders"
@@ -701,13 +601,10 @@
<cfcontent reset="true" type="#getReturnMimeAsHeader(_taffyRequest.returnMimeExt)#; charset=utf-8" /> <cfcontent reset="true" type="#getReturnMimeAsHeader(_taffyRequest.returnMimeExt)#; charset=utf-8" />
<cfheader statuscode="#_taffyRequest.statusArgs.statusCode#" statustext="#_taffyRequest.statusArgs.statusText#" /> <cfheader statuscode="#_taffyRequest.statusArgs.statusCode#" statustext="#_taffyRequest.statusArgs.statusText#" />
<!--- headers --->
<cfset addHeaders(_taffyRequest.resultHeaders) /> <cfset addHeaders(_taffyRequest.resultHeaders) />
<!--- add ALLOW header for current resource, which describes available verbs --->
<cfheader name="ALLOW" value="#local.allowVerbs#" /> <cfheader name="ALLOW" value="#local.allowVerbs#" />
<!--- metrics headers that should always apply --->
<cfheader name="X-TIME-IN-PARSE" value="#m.parseTime#" /> <cfheader name="X-TIME-IN-PARSE" value="#m.parseTime#" />
<cfheader name="X-TIME-IN-ONTAFFYREQUEST" value="#m.otrTime#" /> <cfheader name="X-TIME-IN-ONTAFFYREQUEST" value="#m.otrTime#" />
<cfif structKeyExists(m, "resourceTime")> <cfif structKeyExists(m, "resourceTime")>
@@ -730,7 +627,6 @@
<cfset local.exposeHeaderList = listAppend(local.exposeHeaderList, "Etag") /> <cfset local.exposeHeaderList = listAppend(local.exposeHeaderList, "Etag") />
</cfif> </cfif>
<cfloop list="#local.exposeHeaderList#" index="local.exposeHeader"> <cfloop list="#local.exposeHeaderList#" index="local.exposeHeader">
<!--- filter out default simple response headers: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers --->
<cfif not listFindNoCase("Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma", local.exposeHeader)> <cfif not listFindNoCase("Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma", local.exposeHeader)>
<cfset local.exposeHeaderValue = listAppend(local.exposeHeaderValue, local.exposeHeader) /> <cfset local.exposeHeaderValue = listAppend(local.exposeHeaderValue, local.exposeHeader) />
</cfif> </cfif>
@@ -740,13 +636,11 @@
</cfif> </cfif>
</cfif> </cfif>
<!--- result data --->
<cfif structKeyExists(_taffyRequest,'result')> <cfif structKeyExists(_taffyRequest,'result')>
<cfset _taffyRequest.resultType = _taffyRequest.result.getType() /> <cfset _taffyRequest.resultType = _taffyRequest.result.getType() />
<cfset local.resultSerialized = '' /> <cfset local.resultSerialized = '' />
<cfif _taffyRequest.resultType eq "textual"> <cfif _taffyRequest.resultType eq "textual">
<!--- serialize the representation's data into the requested mime type --->
<cfset _taffyRequest.metrics.beforeSerialize = getTickCount() /> <cfset _taffyRequest.metrics.beforeSerialize = getTickCount() />
<cfinvoke <cfinvoke
component="#_taffyRequest.result#" component="#_taffyRequest.result#"
@@ -757,16 +651,12 @@
<cfset m.serializeTime = m.afterSerialize - m.beforeSerialize /> <cfset m.serializeTime = m.afterSerialize - m.beforeSerialize />
<cfheader name="X-TIME-IN-SERIALIZE" value="#m.serializeTime#" /> <cfheader name="X-TIME-IN-SERIALIZE" value="#m.serializeTime#" />
<!--- apply jsonp wrapper if requested --->
<cfif structKeyExists(_taffyRequest, "jsonpCallback")> <cfif structKeyExists(_taffyRequest, "jsonpCallback")>
<cfset _taffyRequest.resultSerialized = _taffyRequest.jsonpCallback & "(" & _taffyRequest.resultSerialized & ");" /> <cfset _taffyRequest.resultSerialized = _taffyRequest.jsonpCallback & "(" & _taffyRequest.resultSerialized & ");" />
</cfif> </cfif>
<!--- don't return data if etags are enabled and the data hasn't changed --->
<cfif application._taffy.settings.useEtags and _taffyRequest.verb eq "GET"> <cfif application._taffy.settings.useEtags and _taffyRequest.verb eq "GET">
<!--- etag values are quoted per: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag --->
<cfif structKeyExists(server, "lucee")> <cfif structKeyExists(server, "lucee")>
<!--- hashCode() will not work for lucee, see issue #354 --->
<cfset _taffyRequest.serverEtag = '"' & hash(_taffyRequest.resultSerialized) & '"' /> <cfset _taffyRequest.serverEtag = '"' & hash(_taffyRequest.resultSerialized) & '"' />
<cfelse> <cfelse>
<cfset _taffyRequest.serverEtag = '"' & _taffyRequest.result.getData().hashCode() & '"' /> <cfset _taffyRequest.serverEtag = '"' & _taffyRequest.result.getData().hashCode() & '"' />
@@ -797,7 +687,6 @@
<cfif _taffyRequest.resultSerialized neq ('"' & '"')> <cfif _taffyRequest.resultSerialized neq ('"' & '"')>
<cfset local.resultSerialized = _taffyRequest.resultSerialized /> <cfset local.resultSerialized = _taffyRequest.resultSerialized />
</cfif> </cfif>
<!--- debug output --->
<cfif structKeyExists(url, application._taffy.settings.debugKey)> <cfif structKeyExists(url, application._taffy.settings.debugKey)>
<cfset local.debug = true /> <cfset local.debug = true />
</cfif> </cfif>
@@ -833,7 +722,6 @@
<cfset local.result = _taffyRequest.result.getData() /> <cfset local.result = _taffyRequest.result.getData() />
</cfif> </cfif>
<!--- ...after the service has finished... --->
<cfset m.beforeOnTaffyRequestEnd = getTickCount() /> <cfset m.beforeOnTaffyRequestEnd = getTickCount() />
<cfset onTaffyRequestEnd( <cfset onTaffyRequestEnd(
_taffyRequest.verb _taffyRequest.verb
@@ -853,7 +741,6 @@
<cfif len(trim(local.resultSerialized))> <cfif len(trim(local.resultSerialized))>
<cfoutput>#local.resultSerialized#</cfoutput> <cfoutput>#local.resultSerialized#</cfoutput>
</cfif> </cfif>
<!--- debug output --->
<cfif local.debug> <cfif local.debug>
<cfoutput><h3>Request Details:</h3><cfdump var="#_taffyRequest#"></cfoutput> <cfoutput><h3>Request Details:</h3><cfdump var="#_taffyRequest#"></cfoutput>
</cfif> </cfif>
@@ -862,9 +749,4 @@
</cffunction> </cffunction>
<!--- <cffunction name="checkForLocalDebug">
<cfreturn fileExists("#GetDirectoryFromPath(GetCurrentTemplatePath())#/etc/local-debug")>
</cffunction> --->
</cfcomponent> </cfcomponent>
+2 -65
View File
@@ -1,120 +1,57 @@
component /*https://www.bennadel.com/blog/2976-trying-to-generate-cryptographically-strong-random-tokens-in-coldfusion.htm*/ component
output = false output = false
hint = "Генерирует случайные токены с помощью Java SecureRandom." hint = "Генерирует случайные токены с помощью Java SecureRandom."
{ {
/**
* Инициализирует генератор токенов.
*
* @output false
*/
public any function init() { public any function init() {
// Реализация генератора, используемая для построения случайных токенов.
// SHA1PRNG не является алгоритмом по умолчанию во всех реализациях JVM,
// поэтому он задается явно для предсказуемого поведения.
generator = createObject( "java", "java.security.SecureRandom" ) generator = createObject( "java", "java.security.SecureRandom" )
.getInstance( .getInstance(
javaCast( "string", "SHA1PRNG" ), javaCast( "string", "SHA1PRNG" ),
javaCast( "string", "SUN" ) javaCast( "string", "SUN" )
) )
; ;
// После инициализации нужно сгенерировать случайный байт,
// чтобы генератор сам засеялся через общий источник seed.
// Это может блокироваться до накопления достаточной энтропии,
// поэтому операция выполняется при инициализации, а не при первом использовании.
generator.nextBytes( charsetDecode( " ", "utf-8" ) ); generator.nextBytes( charsetDecode( " ", "utf-8" ) );
// Момент следующего пересева генератора.
// Это снижает риск слишком долгой работы с одним и тем же seed.
reseedAt = getNextReseedAt(); reseedAt = getNextReseedAt();
return( this ); return( this );
} }
// Публичные методы.
/**
* Генерирует криптографически стойкий токен из заданного числа случайных байтов.
* Байт-массив кодируется в форму, пригодную для использования в URL.
*
* @byteCount Количество случайных байтов для генерации токена.
* @output false
*/
public string function nextToken( numeric byteCount = 32 ) { public string function nextToken( numeric byteCount = 32 ) {
// Проверяем, нужен ли пересев генератора.
if ( now() >= reseedAt ) { if ( now() >= reseedAt ) {
// Пересев выполняется под lock, чтобы уменьшить гонки между потоками.
// Если lock не получен вовремя, поток продолжает работу с текущим состоянием генератора.
lock lock
name = "TokenGenerator.reseedCheck" name = "TokenGenerator.reseedCheck"
type = "exclusive" type = "exclusive"
timeout = 1 timeout = 1
throwOnTimeout = false throwOnTimeout = false
{ {
// Повторная проверка внутри lock: другой поток мог уже обновить seed.
if ( now() >= reseedAt ) { if ( now() >= reseedAt ) {
reseedAt = getNextReseedAt(); reseedAt = getNextReseedAt();
// Новый seed добавляется к уже существующему внутреннему состоянию генератора.
generator.setSeed( generator.generateSeed( javaCast( "int", 32 ) ) ); generator.setSeed( generator.generateSeed( javaCast( "int", 32 ) ) );
} }
} }
} }
// Создаем буфер байтов, в который будут записаны случайные значения.
var byteBuffer = charsetDecode( repeatString( " ", byteCount ), "utf-8" ); var byteBuffer = charsetDecode( repeatString( " ", byteCount ), "utf-8" );
generator.nextBytes( byteBuffer ); generator.nextBytes( byteBuffer );
return( encodeBytes( byteBuffer ) ); return( encodeBytes( byteBuffer ) );
} }
// Приватные методы.
/**
* Кодирует массив байтов в строку токена.
*
* @bytes Кодируемый массив байтов.
* @output false
*/
private string function encodeBytes( required binary bytes ) { private string function encodeBytes( required binary bytes ) {
var token = binaryEncode( bytes, "base64" ); // *** вот поэтому длина отличается от заявленной var token = binaryEncode( bytes, "base64" );
// мы хотим убрать все спецсимволы, потому что мы используем токен в качестве псевдослучайного суффикса
token = replace( token, "+", "a", "all" ); token = replace( token, "+", "a", "all" );
token = replace( token, "/", "b", "all" ); token = replace( token, "/", "b", "all" );
token = replace( token, "=", "c", "all" ); token = replace( token, "=", "c", "all" );
return( token ); return( token );
} }
/**
* Вычисляет время следующего пересева генератора.
*
* @output false
*/
private date function getNextReseedAt() { private date function getNextReseedAt() {
return( dateAdd( "h", 1, now() ) ); return( dateAdd( "h", 1, now() ) );
} }
} }
+1 -4
View File
@@ -5,7 +5,6 @@
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/> <cfset this.helper=CreateObject("component","lib.rest_api_helper")/>
</cfsilent> </cfsilent>
<!---спецификация полей, пригодных для фильтрации (?и сортировки)--->
<cfset this.fieldsSpec={ <cfset this.fieldsSpec={
svc_id={prefix="r", type="integer"}, svc_id={prefix="r", type="integer"},
resource_realm_id={prefix="r", type="integer"}, resource_realm_id={prefix="r", type="integer"},
@@ -24,11 +23,9 @@
<cfset local={}/> <cfset local={}/>
<!---разбор и проверка параметров запроса--->
<cftry> <cftry>
<cfset this.helper.validateField(arguments, "svcId", "integer")/> <cfset this.helper.validateField(arguments, "svcId", "integer")/>
<!---мы мирно игнорируем поля, отсутствующие в спецификации, что позволяет не делать исключения для orderBy и т.п.--->
<cfset var filter=this.helper.parseFilterParams(this.fieldsSpec)/> <cfset var filter=this.helper.parseFilterParams(this.fieldsSpec)/>
<cfcatch type="invalidParamValue"> <cfcatch type="invalidParamValue">
+2 -2
View File
@@ -55,8 +55,8 @@
<cfargument name="bookmarkUid" type="string" required=true hint="type:guid"/> <cfargument name="bookmarkUid" type="string" required=true hint="type:guid"/>
<cfargument name="bookmark" type="string" required=false hint="type:string"/> <cfargument name="bookmark" type="string" required=false hint="type:string"/>
<cfargument name="descr" type="string" required=false hint="type:string (no cleanup here!)"/> <cfargument name="descr" type="string" required=false hint="type:string (no cleanup here!)"/>
<cfargument name="url" type="string" required=false hint="type:string description: url"/><!--- чистить против XSS ---> <cfargument name="url" type="string" required=false hint="type:string description: url"/>
<cfargument name="iconUrl" type="string" required=false hint="type:string description: url иконки"/><!--- чистить против XSS ---> <cfargument name="iconUrl" type="string" required=false hint="type:string description: url иконки"/>
<cfargument name="sort" type="string" required=false hint="type:integer description: целое число для сортировки"/> <cfargument name="sort" type="string" required=false hint="type:integer description: целое число для сортировки"/>
<cfargument name="isEnabled" type="string" required=false hint="type:boolean description: вкл"/> <cfargument name="isEnabled" type="string" required=false hint="type:boolean description: вкл"/>
+4 -9
View File
@@ -5,7 +5,6 @@
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/> <cfset this.helper=CreateObject("component","lib.rest_api_helper")/>
</cfsilent> </cfsilent>
<!---спецификация полей, пригодных для фильтрации (?и сортировки)--->
<cfset this.fieldsSpec={ <cfset this.fieldsSpec={
bookmark_uid={prefix="b", type="guid"}, bookmark_uid={prefix="b", type="guid"},
dt_created={prefix="b", type="date"}, dt_created={prefix="b", type="date"},
@@ -20,8 +19,6 @@
} }
/> />
<!--- предполагается показывать букмарки только "настоящим" клиентам, поэтому используем contragent_id как признак своих--->
<cffunction name="get" hint="Список букмарков"> <cffunction name="get" hint="Список букмарков">
<cfargument name="pageSize" type="string" hint="type:integer" default="100"/> <cfargument name="pageSize" type="string" hint="type:integer" default="100"/>
<cfargument name="page" type="string" hint="type:integer" default="1"/> <cfargument name="page" type="string" hint="type:integer" default="1"/>
@@ -31,12 +28,10 @@
<cftry> <cftry>
<!---разбор и проверка параметров запроса--->
<cftry> <cftry>
<cfset this.helper.validateField(arguments, "pageSize", "integer")/> <cfset this.helper.validateField(arguments, "pageSize", "integer")/>
<cfset this.helper.validateField(arguments, "page", "integer")/> <cfset this.helper.validateField(arguments, "page", "integer")/>
<!---мы мирно игнорируем поля, отсутствующие в спецификации, что позволяет не делать исключения для orderBy и т.п.--->
<cfset var filter=this.helper.parseFilterParams(this.fieldsSpec)/> <cfset var filter=this.helper.parseFilterParams(this.fieldsSpec)/>
<cfcatch type="invalidParamValue"> <cfcatch type="invalidParamValue">
@@ -68,7 +63,7 @@
from bookmark b from bookmark b
where 1=1 <m:filter_build filter=#filter#/> where 1=1 <m:filter_build filter=#filter#/>
AND (b.contragent_id = <cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.contragentId# null=#!isNumeric(arguments.contragentId)#/> AND (b.contragent_id = <cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.contragentId# null=#!isNumeric(arguments.contragentId)#/>
OR b.contragent_id=-1)/*общая букмарка*/ OR b.contragent_id=-1)
order by b.contragent_id desc, b.sort asc order by b.contragent_id desc, b.sort asc
limit #maxrows# limit #maxrows#
</cfquery> </cfquery>
@@ -108,10 +103,10 @@
<cffunction name="post" hint="Создание нового букмарка."> <cffunction name="post" hint="Создание нового букмарка.">
<cfargument name="bookmark" type="string" required=true hint="type:string description: заголовок"/><!--- чистить против XSS ---> <cfargument name="bookmark" type="string" required=true hint="type:string description: заголовок"/>
<cfargument name="descr" type="string" required=false default="" hint="type:boolean description: пользовательское примечание"/> <cfargument name="descr" type="string" required=false default="" hint="type:boolean description: пользовательское примечание"/>
<cfargument name="url" type="string" required=false default="" hint="type:string description: url"/><!--- чистить против XSS ---> <cfargument name="url" type="string" required=false default="" hint="type:string description: url"/>
<cfargument name="iconUrl" type="string" required=false default="" hint="type:string description: url иконки"/><!--- чистить против XSS ---> <cfargument name="iconUrl" type="string" required=false default="" hint="type:string description: url иконки"/>
<cfargument name="sort" type="string" required=false default="100" hint="type:integer description: целое число для сортировки"/> <cfargument name="sort" type="string" required=false default="100" hint="type:integer description: целое число для сортировки"/>
<cfargument name="isEnabled" type="string" required=false default="1" hint="type:boolean description: вкл"/> <cfargument name="isEnabled" type="string" required=false default="1" hint="type:boolean description: вкл"/>
@@ -5,7 +5,6 @@
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/> <cfset this.helper=CreateObject("component","lib.rest_api_helper")/>
</cfsilent> </cfsilent>
<!--- Спецификация полей, пригодных для фильтрации и сортировки --->
<cfset this.fieldsSpec={ <cfset this.fieldsSpec={
service_param_id={prefix="p", type="cf_sql_integer"} service_param_id={prefix="p", type="cf_sql_integer"}
,service_id={prefix="p", type="cf_sql_integer"} ,service_id={prefix="p", type="cf_sql_integer"}
@@ -50,8 +49,6 @@
} }
/> />
<!--- предполагается показывать букмарки только "настоящим" клиентам, поэтому используем contragent_id как признак своих--->
<cffunction name="get" hint="Каталог конкретных услуг"> <cffunction name="get" hint="Каталог конкретных услуг">
<cfargument name="pageSize" type="string" hint="type:integer" default="100"/> <cfargument name="pageSize" type="string" hint="type:integer" default="100"/>
<cfargument name="page" type="string" hint="type:integer" default="1"/> <cfargument name="page" type="string" hint="type:integer" default="1"/>
@@ -61,12 +58,10 @@
<cftry> <cftry>
<!--- Разбор и проверка параметров запроса --->
<cftry> <cftry>
<cfset this.helper.validateField(arguments, "pageSize", "integer")/> <cfset this.helper.validateField(arguments, "pageSize", "integer")/>
<cfset this.helper.validateField(arguments, "page", "integer")/> <cfset this.helper.validateField(arguments, "page", "integer")/>
<!--- Поля вне спецификации игнорируются, чтобы не добавлять отдельные исключения для orderBy и похожих параметров. --->
<cfset var filter=this.helper.parseFilterParams(this.fieldsSpec)/> <cfset var filter=this.helper.parseFilterParams(this.fieldsSpec)/>
<cfcatch type="invalidParamValue"> <cfcatch type="invalidParamValue">
+4 -11
View File
@@ -53,7 +53,6 @@
).withStatus(404)/> ).withStatus(404)/>
</cfif> </cfif>
<!--- Проверяем наличие запущенных операций на данном инстансе --->
<cfquery name="local.qCheckStarted" result="local.result"> <cfquery name="local.qCheckStarted" result="local.result">
select io.dt_submit, io.dt_finish, io.dt_start, io.submit_result, io.status_url select io.dt_submit, io.dt_finish, io.dt_start, io.submit_result, io.status_url
from instance_operation io from instance_operation io
@@ -87,10 +86,10 @@
<cfset local.cfsParamChecker = CreateObject("component", "instance_operation_cfs_param_ls")/> <cfset local.cfsParamChecker = CreateObject("component", "instance_operation_cfs_param_ls")/>
<cfloop query=#local.qCheckCfsParams#> <cfloop query=#local.qCheckCfsParams#>
<cfif (local.qCheckCfsParams.is_required GT 0 AND NOT len(local.qCheckCfsParams.instance_operation_cfs_param_uid) GT 0)><!--- check CFS param existence ---> <cfif (local.qCheckCfsParams.is_required GT 0 AND NOT len(local.qCheckCfsParams.instance_operation_cfs_param_uid) GT 0)>
<cfreturn representationOf(this.helper.formatMessage("required CFS parameter #local.qCheckCfsParams.svc_operation_cfs_param# (#local.qCheckCfsParams.svc_operation_cfs_param_id#) is missing", "Missing required CFS parameter")).withStatus(422)/> <cfreturn representationOf(this.helper.formatMessage("required CFS parameter #local.qCheckCfsParams.svc_operation_cfs_param# (#local.qCheckCfsParams.svc_operation_cfs_param_id#) is missing", "Missing required CFS parameter")).withStatus(422)/>
<cfelse><!--- validate CFS param---> <cfelse>
<cfif isValid("guid",qCheckCfsParams.instance_operation_cfs_param_uid)><!--- довольно неуклюжий фикс ошибки для нового параметра. Можно было подставить 00000000-0000-0000-0000-000000000000, все равно дальше подставляется ---> <cfif isValid("guid",qCheckCfsParams.instance_operation_cfs_param_uid)>
<cfset local.cfsParamChecker.checkParam(local.qCheckCfsParams.svc_operation_cfs_param_id, qCheckCfsParams.param_value, arguments.usrId, qCheckCfsParams.instance_operation_cfs_param_uid)/> <cfset local.cfsParamChecker.checkParam(local.qCheckCfsParams.svc_operation_cfs_param_id, qCheckCfsParams.param_value, arguments.usrId, qCheckCfsParams.instance_operation_cfs_param_uid)/>
<cfelse> <cfelse>
<cfset local.cfsParamChecker.checkParam(local.qCheckCfsParams.svc_operation_cfs_param_id, qCheckCfsParams.param_value, arguments.usrId)/> <cfset local.cfsParamChecker.checkParam(local.qCheckCfsParams.svc_operation_cfs_param_id, qCheckCfsParams.param_value, arguments.usrId)/>
@@ -163,12 +162,10 @@
join svc_operation_cfs_param socp on (iocp.svc_operation_cfs_param_id=socp.svc_operation_cfs_param_id) join svc_operation_cfs_param socp on (iocp.svc_operation_cfs_param_id=socp.svc_operation_cfs_param_id)
join svc_operation_param sop on (socp.svc_operation_id=sop.svc_operation_id AND socp.svc_operation_cfs_param=sop.svc_operation_param) join svc_operation_param sop on (socp.svc_operation_id=sop.svc_operation_id AND socp.svc_operation_cfs_param=sop.svc_operation_param)
where iocp.instance_operation_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceOperationUid#"/> where iocp.instance_operation_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceOperationUid#"/>
/*PostgreSQL specific*/
ON CONFLICT (instance_operation_uid,param) ON CONFLICT (instance_operation_uid,param)
DO UPDATE SET param_value = EXCLUDED.param_value; DO UPDATE SET param_value = EXCLUDED.param_value;
</cfquery> </cfquery>
<!--- так яснее, но можно было все в один запрос --->
<cfquery name="qWriteRfsParamsFromDefaults"> <cfquery name="qWriteRfsParamsFromDefaults">
insert into instance_operation_param (instance_operation_uid,param,param_value) insert into instance_operation_param (instance_operation_uid,param,param_value)
select select
@@ -176,8 +173,7 @@
,sop.svc_operation_param ,sop.svc_operation_param
,sop.default_value ,sop.default_value
from svc_operation_param sop from svc_operation_param sop
where sop.svc_operation_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#qSvcOperation.svc_operation_id#"/> AND length(sop.default_value)>0 /***null will be better*/ where sop.svc_operation_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#qSvcOperation.svc_operation_id#"/> AND length(sop.default_value)>0
/*PostgreSQL specific*/
ON CONFLICT (instance_operation_uid,param) ON CONFLICT (instance_operation_uid,param)
DO NOTHING; DO NOTHING;
</cfquery> </cfquery>
@@ -220,7 +216,6 @@
<cfset var submit_url="#qInstanceOperation.url_prefix##qInstanceOperation.version##qInstanceOperation.url_suffix#"/> <cfset var submit_url="#qInstanceOperation.url_prefix##qInstanceOperation.version##qInstanceOperation.url_suffix#"/>
</cfif> </cfif>
<!--- *** тут нужно бы указать, кто запустил операцию --->
<cfquery name="qMarkOperationStart"> <cfquery name="qMarkOperationStart">
update instance_operation update instance_operation
set dt_submit=<cfqueryparam cfsqltype="cf_sql_timestamp" value=#now()#/> set dt_submit=<cfqueryparam cfsqltype="cf_sql_timestamp" value=#now()#/>
@@ -307,7 +302,6 @@
,<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.param#"/> ,<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.param#"/>
,<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.val#"/> ,<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.val#"/>
) )
/*PostgreSQL specific*/
ON CONFLICT (instance_operation_uid,param) ON CONFLICT (instance_operation_uid,param)
DO UPDATE SET param_value = EXCLUDED.param_value; DO UPDATE SET param_value = EXCLUDED.param_value;
</cfquery> </cfquery>
@@ -429,7 +423,6 @@
where io.instance_operation_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceOperationUid#" null=#!isValid("guid",arguments.instanceOperationUid)#/> where io.instance_operation_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceOperationUid#" null=#!isValid("guid",arguments.instanceOperationUid)#/>
</cfquery> </cfquery>
<!--- проверяем доступ к RFS параметру resourceRealm данной операции --->
<cfquery name="local.qCheckResourceRealmAccess"> <cfquery name="local.qCheckResourceRealmAccess">
select r.resource_realm_id, r.resource_realm, iop.param, iop.param_value, a.contract_id, a.is_enabled select r.resource_realm_id, r.resource_realm, iop.param, iop.param_value, a.contract_id, a.is_enabled
from resource_realm r from resource_realm r
-6
View File
@@ -5,7 +5,6 @@
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/> <cfset this.helper=CreateObject("component","lib.rest_api_helper")/>
</cfsilent> </cfsilent>
<!---спецификация полей, пригодных для фильтрации (?и сортировки)--->
<cfset this.fieldsSpec={ <cfset this.fieldsSpec={
dt_created={prefix="n", type="date"}, dt_created={prefix="n", type="date"},
dt_updated={prefix="n", type="date"}, dt_updated={prefix="n", type="date"},
@@ -17,9 +16,6 @@
external_code={prefix="n", type="string"} external_code={prefix="n", type="string"}
} }
/> />
<cffunction name="get" hint="Список уведомлений"> <cffunction name="get" hint="Список уведомлений">
<cfargument name="pageSize" type="string" hint="type:integer" default="100"/> <cfargument name="pageSize" type="string" hint="type:integer" default="100"/>
<cfargument name="page" type="string" hint="type:integer" default="1"/> <cfargument name="page" type="string" hint="type:integer" default="1"/>
@@ -28,12 +24,10 @@
<cftry> <cftry>
<cfset local={}/> <cfset local={}/>
<!---разбор и проверка параметров запроса--->
<cftry> <cftry>
<cfset this.helper.validateField(arguments, "pageSize", "integer")/> <cfset this.helper.validateField(arguments, "pageSize", "integer")/>
<cfset this.helper.validateField(arguments, "page", "integer")/> <cfset this.helper.validateField(arguments, "page", "integer")/>
<!---мы мирно игнорируем поля, отсутствующие в спецификации, что позволяет не делать исключения для orderBy и т.п.--->
<cfset var filter=this.helper.parseFilterParams(this.fieldsSpec)/> <cfset var filter=this.helper.parseFilterParams(this.fieldsSpec)/>
<cfcatch type="invalidParamValue"> <cfcatch type="invalidParamValue">
+1 -4
View File
@@ -5,7 +5,6 @@
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/> <cfset this.helper=CreateObject("component","lib.rest_api_helper")/>
</cfsilent> </cfsilent>
<!---спецификация полей, пригодных для фильтрации (?и сортировки)--->
<cfset this.fieldsSpec={ <cfset this.fieldsSpec={
resource_realm_id={prefix="r", type="integer"}, resource_realm_id={prefix="r", type="integer"},
resource_realm_type_id={prefix="r", type="integer"}, resource_realm_type_id={prefix="r", type="integer"},
@@ -24,12 +23,10 @@
<cfset local={}/> <cfset local={}/>
<!---разбор и проверка параметров запроса--->
<cftry> <cftry>
<cfset this.helper.validateField(arguments, "pageSize", "integer")/> <cfset this.helper.validateField(arguments, "pageSize", "integer")/>
<cfset this.helper.validateField(arguments, "page", "integer")/> <cfset this.helper.validateField(arguments, "page", "integer")/>
<!---мы мирно игнорируем поля, отсутствующие в спецификации, что позволяет не делать исключения для orderBy и т.п.--->
<cfset var filter=this.helper.parseFilterParams(this.fieldsSpec)/> <cfset var filter=this.helper.parseFilterParams(this.fieldsSpec)/>
<cfcatch type="invalidParamValue"> <cfcatch type="invalidParamValue">
@@ -69,7 +66,7 @@
OR a.contract_id=0) OR a.contract_id=0)
AND a.is_enabled) AND a.is_enabled)
where 1=1 <m:filter_build filter=#filter#/> where 1=1 <m:filter_build filter=#filter#/>
order by <m:order_build sortCollection=#this.helper.parseNumericOrder(local.titleMap, arguments.orderBy)# fieldCount=0/><!---no sort length limit---> order by <m:order_build sortCollection=#this.helper.parseNumericOrder(local.titleMap, arguments.orderBy)# fieldCount=0/>
limit #maxrows# limit #maxrows#
</cfquery> </cfquery>
+1 -4
View File
@@ -5,7 +5,6 @@
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/> <cfset this.helper=CreateObject("component","lib.rest_api_helper")/>
</cfsilent> </cfsilent>
<!---спецификация полей, пригодных для фильтрации (?и сортировки)--->
<cfset this.fieldsSpec={ <cfset this.fieldsSpec={
resource_realm_type_id={prefix="r", type="integer"}, resource_realm_type_id={prefix="r", type="integer"},
resource_realm_type={prefix="r", type="string"} resource_realm_type={prefix="r", type="string"}
@@ -20,12 +19,10 @@
<cfset local={}/> <cfset local={}/>
<!---разбор и проверка параметров запроса--->
<cftry> <cftry>
<cfset this.helper.validateField(arguments, "pageSize", "integer")/> <cfset this.helper.validateField(arguments, "pageSize", "integer")/>
<cfset this.helper.validateField(arguments, "page", "integer")/> <cfset this.helper.validateField(arguments, "page", "integer")/>
<!---мы мирно игнорируем поля, отсутствующие в спецификации, что позволяет не делать исключения для orderBy и т.п.--->
<cfset var filter=this.helper.parseFilterParams(this.fieldsSpec)/> <cfset var filter=this.helper.parseFilterParams(this.fieldsSpec)/>
<cfcatch type="invalidParamValue"> <cfcatch type="invalidParamValue">
@@ -50,7 +47,7 @@
</m:field_set> </m:field_set>
from resource_realm_type t from resource_realm_type t
where 1=1 <m:filter_build filter=#filter#/> where 1=1 <m:filter_build filter=#filter#/>
order by <m:order_build sortCollection=#this.helper.parseNumericOrder(local.titleMap, arguments.orderBy)# fieldCount=0/><!---no sort length limit---> order by <m:order_build sortCollection=#this.helper.parseNumericOrder(local.titleMap, arguments.orderBy)# fieldCount=0/>
limit #maxrows# limit #maxrows#
</cfquery> </cfquery>
@@ -1,23 +1,4 @@
<cfcomponent extends="taffy.core.resource" taffy:uri="/svcOperationCfsSubparams/compute/{svcOperationCfsSubparamId}" hint="вычисляет выражение в поле expression"> <cfcomponent extends="taffy.core.resource" taffy:uri="/svcOperationCfsSubparams/compute/{svcOperationCfsSubparamId}" hint="вычисляет выражение в поле expression">
<!---
вычисляет выражение в поле expression
для этого нужен контекст - как минимум, сохраненные параметры, но это не работает при создании нового инстанса,
поэтому нужно инициализировать контекст и набивать его всей необходимой информацией
что особенно важно для зависимых параметров - нам нужно положить в контекст все параметры, от которых мы зависим
чтобы знать, какие параметры передавать - конструкцией для параметра предусмотрено поле depends_on_params (надо будет его сделать вычисляемым), а для субпараметра пока не
--->
<!--- Все методы неявно получают
arguments.usrId
arguments.contragentId
arguments.contractId
arguments.specificationId
arguments.requestArguments.usrId=usrCustomerInfo.usrId; //Integer!
arguments.requestArguments.contragentId=usrCustomerInfo.contragentId; //Integer
arguments.requestArguments.contractId=usrCustomerInfo.contractId; //Integer
arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //Integer
--->
<cfsilent> <cfsilent>
<cfimport prefix="m" taglib="../lib"/> <cfimport prefix="m" taglib="../lib"/>
@@ -26,17 +7,13 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
<cffunction name="get" hint="вычисление возможных значений cубпараметра CFS параметра операции, в текущем контексте"> <cffunction name="get" hint="вычисление возможных значений cубпараметра CFS параметра операции, в текущем контексте">
<!--- <cfargument name="instanceOperationCfsParamUid" type="string" required=true hint="type:guid"/> а вот ни фига--->
<!--- *** Важно: мы должны уметь посчитать параметр, если он не сохранен, то есть мы знаем его класс, а не инстанс --->
<!--- Вероятно, нам не очень нужно вычислять набор значений для инстанса параметра, мы всегда знаем класс --->
<!--- контест: --->
<cfargument name="svcOperationCfsSubparamId" type="string" required=true hint="type:integer"/> <cfargument name="svcOperationCfsSubparamId" type="string" required=true hint="type:integer"/>
<cfargument name="keys" type="string" default={} hint="type:json keys we depend on: of the param uid itself, or operation uid, instance uid, service operation cfs param - if not all entities intstantiated yet"/> <cfargument name="keys" type="string" default={} hint="type:json keys we depend on: of the param uid itself, or operation uid, instance uid, service operation cfs param - if not all entities intstantiated yet"/>
<cfargument name="params" type="string" default="{}" hint="type:json any posted parameters we depend on"/> <cfargument name="params" type="string" default="{}" hint="type:json any posted parameters we depend on"/>
<cftry> <cftry>
<cfset this.helper.validateField(arguments, "svcOperationCfsSubparamId", "integer")/> <cfset this.helper.validateField(arguments, "svcOperationCfsSubparamId", "integer")/>
<cfset this.helper.validateField(arguments, "keys", "json")/> <!--- *** может, не лучшая идея передавать ключ в контексте ---> <cfset this.helper.validateField(arguments, "keys", "json")/>
<cfset this.helper.validateField(arguments, "params", "json")/> <cfset this.helper.validateField(arguments, "params", "json")/>
<cfcatch type="invalidParamValue"> <cfcatch type="invalidParamValue">
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/> <cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
@@ -44,12 +21,12 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
</cftry> </cftry>
<cfset local={}/> <cfset local={}/>
<cfset "local.expression" = ""/> <!--- нет смысла выносить это в поля класса, оно нужно только локально ---> <cfset "local.expression" = ""/>
<cfset "local.calculatedValueList" = ""/> <cfset "local.calculatedValueList" = ""/>
<cfset "local.keys" = deserializeJson(arguments.keys)/> <cfset "local.keys" = deserializeJson(arguments.keys)/>
<cfset "local.params" = deserializeJson(arguments.params)/> <cfset "local.params" = deserializeJson(arguments.params)/>
<cfset "local.keys.svcOperationCfsSubparamId" = arguments.svcOperationCfsSubparamId/> <!--- *** сомнительное дело гонять аргументы туда-сюда ---><!--- *** по-моему, не используется, поэтому достанем svcOperationCfsParamId прямо тут ---> <cfset "local.keys.svcOperationCfsSubparamId" = arguments.svcOperationCfsSubparamId/>
<cfquery name="local.qCfsSubparam" result="local.result"> <cfquery name="local.qCfsSubparam" result="local.result">
select select
@@ -69,15 +46,14 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
</cfif> </cfif>
<cfset "local.expression"=local.qCfsSubparam.expression/> <cfset "local.expression"=local.qCfsSubparam.expression/>
<cfset "local.keys.svcOperationCfsParamId" = local.qCfsSubparam.svc_operation_cfs_param_id/> <cfset "local.keys.svcOperationCfsParamId" = local.qCfsSubparam.svc_operation_cfs_param_id/>
<!--- *** можно обратить внимание, что мы инстанциируем не субпараметр, а параметр (цинично пользуясь их функциональной идентичностью... но некрасиво) --->
<cfif len(local.expression)> <cfif len(local.expression)>
<cfset local.calculatedValueList=createObject("component","lib.expression_parser") <cfset local.calculatedValueList=createObject("component","lib.expression_parser")
.eval( .eval(
local.expression, local.expression,
{/*context*/ {
component:"resources.instance_operation_cfs_param", /*param, not subparam*/ component:"resources.instance_operation_cfs_param",
keys:#local.keys#, keys:#local.keys#,
params:#local.params# params:#local.params#
} }
@@ -86,12 +62,11 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
<cfelse> <cfelse>
<cfreturn representationOf(this.helper.formatMessage("Expression Not Found")).withStatus(404)/> <cfreturn representationOf(this.helper.formatMessage("Expression Not Found")).withStatus(404)/>
</cfif> </cfif>
<!--- Тут нам еще придется сформатировать лист в массив. Но обошлось довольно просто --->
<cfset var out=structNew("linked")/> <cfset var out=structNew("linked")/>
<cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/> <cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/>
<cfset "out.values" = listToArray(local.calculatedValueList)/> <cfset "out.values" = listToArray(local.calculatedValueList)/>
<cfset "out.runDurationMs"=getTickCount() - request.startTickCount/> <cfset "out.runDurationMs"=getTickCount() - request.startTickCount/>
<cfreturn representationOf(out) /> <cfreturn representationOf(out) />
</cffunction><!--- get ---> </cffunction>
</cfcomponent> </cfcomponent>