cleanup: remove reasoning comments and translate helper docs
This commit is contained in:
@@ -312,3 +312,94 @@
|
|||||||
- сделать второй проход по прикладным файлам
|
- сделать второй проход по прикладным файлам
|
||||||
- удалить комментарии в формате рассуждений там, где они явно не нужны для понимания текущей логики
|
- удалить комментарии в формате рассуждений там, где они явно не нужны для понимания текущей логики
|
||||||
- отдельно обработать `v1/Application.cfc` как специальный случай
|
- отдельно обработать `v1/Application.cfc` как специальный случай
|
||||||
|
|
||||||
|
## Обновление: второй проход по комментариям-рассуждениям
|
||||||
|
|
||||||
|
Дата фиксации: 2026-04-29 20:45:13 +0400.
|
||||||
|
|
||||||
|
### Что сделано
|
||||||
|
|
||||||
|
Во втором проходе очищались не version-header блоки, а именно комментарии в стиле внутренних сомнений, оценок и рассуждений автора.
|
||||||
|
|
||||||
|
Обработаны файлы:
|
||||||
|
- `v1/lib/field_set.cfm`
|
||||||
|
- `v1/lib/order_build.cfm`
|
||||||
|
- `v1/resources/svc_default.cfc`
|
||||||
|
- `v1/lib/rest_api_helper.cfc`
|
||||||
|
|
||||||
|
Удалялись в первую очередь такие типы комментариев:
|
||||||
|
- сомнения автора в корректности подхода
|
||||||
|
- эмоциональные оценки вроде "некрасиво"
|
||||||
|
- внутренние заметки вида "не уверен", "не нравится", "странно"
|
||||||
|
- краткие следы от отладочных/временных рассуждений
|
||||||
|
|
||||||
|
### Что не удалялось
|
||||||
|
|
||||||
|
- технические комментарии, поясняющие назначение параметров и смысл структуры данных
|
||||||
|
- комментарии, нужные для понимания формата вызова или ограничений API
|
||||||
|
- комментарии, которые пока относятся к будущему этапу перевода, а не удаления
|
||||||
|
|
||||||
|
### Проверка
|
||||||
|
|
||||||
|
После второго прохода измененные файлы проверены на ошибки.
|
||||||
|
Результат:
|
||||||
|
- синтаксических ошибок не обнаружено
|
||||||
|
|
||||||
|
### Промежуточный вывод
|
||||||
|
|
||||||
|
Эта стратегия работает лучше, чем агрессивная массовая чистка: можно постепенно отделять лишние авторские рассуждения от реально полезных технических пояснений.
|
||||||
|
|
||||||
|
### Следующий шаг
|
||||||
|
|
||||||
|
- перевести оставшиеся английские комментарии в уже обработанных небольших файлах
|
||||||
|
- отдельно обработать `v1/lib/TokenGenerator.cfc`, где комментарии почти полностью англоязычные
|
||||||
|
- затем перейти к следующей группе прикладных файлов
|
||||||
|
|
||||||
|
## Обновление: дополнительные commented-out блоки и перевод комментариев
|
||||||
|
|
||||||
|
Дата фиксации: 2026-04-29 20:48:58 +0400.
|
||||||
|
|
||||||
|
### Что сделано перед переводом
|
||||||
|
|
||||||
|
Перед этапом перевода был выполнен еще один безопасный шаг:
|
||||||
|
- удалены крупные закомментированные legacy-блоки в `v1/lib/rest_api_helper.cfc`
|
||||||
|
- удален закомментированный альтернативный блок base64url-преобразования в `v1/lib/TokenGenerator.cfc`
|
||||||
|
|
||||||
|
Причина:
|
||||||
|
- переводить комментарии вокруг уже неиспользуемого мертвого кода не имеет смысла
|
||||||
|
- сначала убирается то, что точно не участвует в runtime
|
||||||
|
|
||||||
|
### Что переведено на русский
|
||||||
|
|
||||||
|
Перевод выполнен в следующих файлах:
|
||||||
|
- `v1/lib/TokenGenerator.cfc`
|
||||||
|
- `v1/lib/field.cfm`
|
||||||
|
- `v1/lib/order_build.cfm`
|
||||||
|
- `v1/lib/filter_build.cfm`
|
||||||
|
- `v1/lib/rest_api_helper.cfc`
|
||||||
|
|
||||||
|
Переводились:
|
||||||
|
- `hint`-описания функций и компонентов
|
||||||
|
- английские технические комментарии
|
||||||
|
- внутренние пояснения о поведении генератора токенов и helper-логики
|
||||||
|
|
||||||
|
Что сознательно не переводилось:
|
||||||
|
- runtime-сообщения ошибок и исключений
|
||||||
|
- публичные текстовые значения, которые могут участвовать в API-контракте
|
||||||
|
|
||||||
|
### Проверка
|
||||||
|
|
||||||
|
После удаления закомментированных блоков и после перевода комментариев проверены измененные файлы.
|
||||||
|
Результат:
|
||||||
|
- синтаксических ошибок не обнаружено
|
||||||
|
|
||||||
|
### Промежуточный вывод
|
||||||
|
|
||||||
|
На этом этапе уже очищен и приведен к более однородному виду значимый кусок вспомогательного слоя `v1/lib`.
|
||||||
|
Это хорошая база перед переходом к более рискованным файлам уровня `Application.cfc` и крупных `resources/*.cfc`.
|
||||||
|
|
||||||
|
### Следующий шаг
|
||||||
|
|
||||||
|
- посмотреть текущее diff-состояние cleanup-ветки
|
||||||
|
- зафиксировать сделанные этапы в коммитах
|
||||||
|
- затем перейти к следующей группе файлов, начиная с наиболее контролируемых resource-компонентов
|
||||||
|
|||||||
+26
-61
@@ -1,19 +1,18 @@
|
|||||||
component /*https://www.bennadel.com/blog/2976-trying-to-generate-cryptographically-strong-random-tokens-in-coldfusion.htm*/
|
component /*https://www.bennadel.com/blog/2976-trying-to-generate-cryptographically-strong-random-tokens-in-coldfusion.htm*/
|
||||||
output = false
|
output = false
|
||||||
hint = "I generate random tokens using Java's SecureRandom class."
|
hint = "Генерирует случайные токены с помощью Java SecureRandom."
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* I initialize the token generator.
|
* Инициализирует генератор токенов.
|
||||||
*
|
*
|
||||||
* @output false
|
* @output false
|
||||||
*/
|
*/
|
||||||
public any function init() {
|
public any function init() {
|
||||||
|
|
||||||
// I am the generator implementation used to generate the random token data.
|
// Реализация генератора, используемая для построения случайных токенов.
|
||||||
// --
|
// SHA1PRNG не является алгоритмом по умолчанию во всех реализациях JVM,
|
||||||
// NOTE: The SHA1PRNG is not the default in all implementations of the JVM. As
|
// поэтому он задается явно для предсказуемого поведения.
|
||||||
// such, we're defining the algorithm explicitly to keep this code consistent.
|
|
||||||
generator = createObject( "java", "java.security.SecureRandom" )
|
generator = createObject( "java", "java.security.SecureRandom" )
|
||||||
.getInstance(
|
.getInstance(
|
||||||
javaCast( "string", "SHA1PRNG" ),
|
javaCast( "string", "SHA1PRNG" ),
|
||||||
@@ -21,22 +20,14 @@ component /*https://www.bennadel.com/blog/2976-trying-to-generate-cryptographica
|
|||||||
)
|
)
|
||||||
;
|
;
|
||||||
|
|
||||||
// Now that we've initialized the random generator, we have to generate a random
|
// После инициализации нужно сгенерировать случайный байт,
|
||||||
// byte of data. This will ensure that the random generator is self-seeded using
|
// чтобы генератор сам засеялся через общий источник seed.
|
||||||
// a shared seed generator.
|
// Это может блокироваться до накопления достаточной энтропии,
|
||||||
// --
|
// поэтому операция выполняется при инициализации, а не при первом использовании.
|
||||||
// CAUTION: Since the underlying seed generator reads from sources of entropy,
|
|
||||||
// this may hang until enough entropy has been collected. This is another good
|
|
||||||
// reason to do it during initialization time rather than at first-use time.
|
|
||||||
generator.nextBytes( charsetDecode( " ", "utf-8" ) );
|
generator.nextBytes( charsetDecode( " ", "utf-8" ) );
|
||||||
|
|
||||||
// I hold the future date at which time the generator should be reseeded in order
|
// Момент следующего пересева генератора.
|
||||||
// to keep it unpredictable.
|
// Это снижает риск слишком долгой работы с одним и тем же seed.
|
||||||
// --
|
|
||||||
// NOTE: This doesn't affect the randomness of the values. But, the thinking
|
|
||||||
// is that the longer the generator is producing values using the same seed,
|
|
||||||
// the more likely an attacker is to be able to determine the original seed by
|
|
||||||
// passively observing generated values.
|
|
||||||
reseedAt = getNextReseedAt();
|
reseedAt = getNextReseedAt();
|
||||||
|
|
||||||
return( this );
|
return( this );
|
||||||
@@ -44,34 +35,23 @@ component /*https://www.bennadel.com/blog/2976-trying-to-generate-cryptographica
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ---
|
// Публичные методы.
|
||||||
// PUBLIC METHODS.
|
|
||||||
// ---
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* I generate "cryptographically strong" random token strings that are based on the
|
* Генерирует криптографически стойкий токен из заданного числа случайных байтов.
|
||||||
* given number of random bytes. The random bytes are subsequently encoded using a
|
* Байт-массив кодируется в форму, пригодную для использования в URL.
|
||||||
* base64url character-set so that they are URL-safe and can be used in a variety of
|
|
||||||
* contexts. And, since base65url is a case-sensitive schema, the tokens will
|
|
||||||
* naturally be case-sensitive.
|
|
||||||
*
|
*
|
||||||
* @byteCount I am the number of random bytes used to generate the token.
|
* @byteCount Количество случайных байтов для генерации токена.
|
||||||
* @output false
|
* @output false
|
||||||
*/
|
*/
|
||||||
public string function nextToken( numeric byteCount = 32 ) {
|
public string function nextToken( numeric byteCount = 32 ) {
|
||||||
|
|
||||||
// Check to see if the generator needs to be reseeded (using a double-check
|
// Проверяем, нужен ли пересев генератора.
|
||||||
// locking approach to reduce the bottleneck).
|
|
||||||
if ( now() >= reseedAt ) {
|
if ( now() >= reseedAt ) {
|
||||||
|
|
||||||
// Synchronize the reseeding.
|
// Пересев выполняется под lock, чтобы уменьшить гонки между потоками.
|
||||||
// --
|
// Если lock не получен вовремя, поток продолжает работу с текущим состоянием генератора.
|
||||||
// NOTE: From what I have read, I DON'T BELIEVE that .generateSeed() will
|
|
||||||
// ever hang with the SHA1PRNG algorithm. However, it is unclear to me. As
|
|
||||||
// such, I'm using [throwOnTimeout = false] so that parallel threads won't
|
|
||||||
// error if the lock cannot be obtained in a timely manner and will just
|
|
||||||
// fall through to using the generator with the pre-seeding state.
|
|
||||||
lock
|
lock
|
||||||
name = "TokenGenerator.reseedCheck"
|
name = "TokenGenerator.reseedCheck"
|
||||||
type = "exclusive"
|
type = "exclusive"
|
||||||
@@ -79,27 +59,21 @@ component /*https://www.bennadel.com/blog/2976-trying-to-generate-cryptographica
|
|||||||
throwOnTimeout = false
|
throwOnTimeout = false
|
||||||
{
|
{
|
||||||
|
|
||||||
// Perform double-check - generator may have already been reseeded by
|
// Повторная проверка внутри lock: другой поток мог уже обновить seed.
|
||||||
// a parallel request.
|
|
||||||
if ( now() >= reseedAt ) {
|
if ( now() >= reseedAt ) {
|
||||||
|
|
||||||
reseedAt = getNextReseedAt();
|
reseedAt = getNextReseedAt();
|
||||||
|
|
||||||
// NOTE: Once the generator was seeded internally, this re-seeding
|
// Новый seed добавляется к уже существующему внутреннему состоянию генератора.
|
||||||
// will only ever "add to" the existing seed. As such, this is still
|
|
||||||
// building on top of the original randomness and calling this, on
|
|
||||||
// interval, this will never reduce randomness.
|
|
||||||
generator.setSeed( generator.generateSeed( javaCast( "int", 32 ) ) );
|
generator.setSeed( generator.generateSeed( javaCast( "int", 32 ) ) );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // END: Lock.
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the byte buffer into which the random bytes will be written. Since
|
// Создаем буфер байтов, в который будут записаны случайные значения.
|
||||||
// there's no "correct" way to generate a byte array in ColdFusion, we can
|
|
||||||
// generate a string of the desired length and then decode it into bytes.
|
|
||||||
var byteBuffer = charsetDecode( repeatString( " ", byteCount ), "utf-8" );
|
var byteBuffer = charsetDecode( repeatString( " ", byteCount ), "utf-8" );
|
||||||
|
|
||||||
generator.nextBytes( byteBuffer );
|
generator.nextBytes( byteBuffer );
|
||||||
@@ -109,27 +83,18 @@ component /*https://www.bennadel.com/blog/2976-trying-to-generate-cryptographica
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ---
|
// Приватные методы.
|
||||||
// PRIVATE METHODS.
|
|
||||||
// ---
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* I encode the given byte array using the base64url character-set.
|
* Кодирует массив байтов в строку токена.
|
||||||
*
|
*
|
||||||
* @bytes I am the byte array being encoded.
|
* @bytes Кодируемый массив байтов.
|
||||||
* @output false
|
* @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" ); // *** вот поэтому длина отличается от заявленной
|
||||||
|
|
||||||
// Replace the characters that are not allowed in the base64url format. The
|
|
||||||
// characters [+, /, =] are removed for URL-based base64 values because they
|
|
||||||
// have significant meaning in the context of URL paths and query-strings.
|
|
||||||
/*token = replace( token, "+", "-", "all" );
|
|
||||||
token = replace( token, "/", "_", "all" );
|
|
||||||
token = replace( token, "=", "", "all" ); */
|
|
||||||
|
|
||||||
// мы хотим убрать все спецсимволы, потому что мы используем токен в качестве псевдослучайного суффикса
|
// мы хотим убрать все спецсимволы, потому что мы используем токен в качестве псевдослучайного суффикса
|
||||||
token = replace( token, "+", "a", "all" );
|
token = replace( token, "+", "a", "all" );
|
||||||
@@ -142,7 +107,7 @@ component /*https://www.bennadel.com/blog/2976-trying-to-generate-cryptographica
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* I calculate the next date of reseeding.
|
* Вычисляет время следующего пересева генератора.
|
||||||
*
|
*
|
||||||
* @output false
|
* @output false
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<cfsilent></cfsilent>
|
<cfsilent></cfsilent>
|
||||||
<!--- Используется в селекте для структурирования списка полей. Выводит вместо себя список через запятую, экспортирует Map со структурами выражение+заголовок, с ключом, соответствующим имени колонки в селекте (ключ вычисляется регулярным выражением) --->
|
<!--- Используется в селекте для структурирования списка полей. Выводит вместо себя список через запятую и экспортирует Map со структурами expression+title с ключом, соответствующим имени колонки в селекте. --->
|
||||||
|
|
||||||
<cfset var local={}/> <!--- *** есть опасения, что это не будет работать в модуле .cfm (вообще var ведет себе странно) --->
|
<cfset var local={}/>
|
||||||
<cfif thisTag.executionMode is "end">
|
<cfif thisTag.executionMode is "end">
|
||||||
|
|
||||||
<cfparam name="ATTRIBUTES.titleMapOut" default=""/>
|
<cfparam name="ATTRIBUTES.titleMapOut" default=""/>
|
||||||
@@ -19,11 +19,9 @@
|
|||||||
|
|
||||||
<cfset i=0/>
|
<cfset i=0/>
|
||||||
<cfloop array=#thisTag.fieldsArray# index="field">
|
<cfloop array=#thisTag.fieldsArray# index="field">
|
||||||
<!--- <cfdump var=#field#/> --->
|
|
||||||
<cfif len(#field.name#) EQ 0
|
<cfif len(#field.name#) EQ 0
|
||||||
OR listLen(ATTRIBUTES.fieldsToInclude) EQ 0
|
OR listLen(ATTRIBUTES.fieldsToInclude) EQ 0
|
||||||
OR listFindNoCase(ATTRIBUTES.fieldsToInclude,field.name)>
|
OR listFindNoCase(ATTRIBUTES.fieldsToInclude,field.name)>
|
||||||
<!--- пытаемся сохранить прежнюю логику - поля без имени не выбрасываются, но не попадают в titleMap --->
|
|
||||||
<cfset i=i+1/>
|
<cfset i=i+1/>
|
||||||
<cfset local.expressionList=listAppend(#local.expressionList#, #field.expression#)/>
|
<cfset local.expressionList=listAppend(#local.expressionList#, #field.expression#)/>
|
||||||
<cfset local.nameList=listAppend(#local.nameList#, #field.name#)/>
|
<cfset local.nameList=listAppend(#local.nameList#, #field.name#)/>
|
||||||
@@ -52,7 +50,7 @@
|
|||||||
<cfset "CALLER.#ATTRIBUTES.nameListOut#"=#local.nameList#/>
|
<cfset "CALLER.#ATTRIBUTES.nameListOut#"=#local.nameList#/>
|
||||||
</cfif>
|
</cfif>
|
||||||
|
|
||||||
<cfif len(ATTRIBUTES.listOut)><!--- *** некрасиво --->
|
<cfif len(ATTRIBUTES.listOut)>
|
||||||
<cfset "CALLER.#ATTRIBUTES.listOut#"=local.expressionList/>
|
<cfset "CALLER.#ATTRIBUTES.listOut#"=local.expressionList/>
|
||||||
<cfif ATTRIBUTES.listOutKeepContent>
|
<cfif ATTRIBUTES.listOutKeepContent>
|
||||||
<cfset thisTag.generatedContent=preserveSingleQuotes(local.expressionList)/>
|
<cfset thisTag.generatedContent=preserveSingleQuotes(local.expressionList)/>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<cfsilent>
|
<cfsilent>
|
||||||
<!--- build query sort string --->
|
<!--- Формирует строку сортировки для запроса --->
|
||||||
|
|
||||||
<cfparam name="ATTRIBUTES.sortCollection" type="any">
|
<cfparam name="ATTRIBUTES.sortCollection" type="any">
|
||||||
<cfparam name="ATTRIBUTES.fieldCount" type="integer" default=0>
|
<cfparam name="ATTRIBUTES.fieldCount" type="integer" default=0>
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
<cfset querySort="">
|
<cfset querySort="">
|
||||||
<cfset i=1 />
|
<cfset i=1 />
|
||||||
<cfloop collection=#ATTRIBUTES.sortCollection# index="item"><!--- *** Не уверен, что все будет хорошо, когда sortCollection - array, не перепутаются ли поля, порядок важен --->
|
<cfloop collection=#ATTRIBUTES.sortCollection# index="item">
|
||||||
<cftry>
|
<cftry>
|
||||||
<cfset sort=ATTRIBUTES.sortCollection[item] />
|
<cfset sort=ATTRIBUTES.sortCollection[item] />
|
||||||
<cfif (i LE ATTRIBUTES.fieldCount) OR (ATTRIBUTES.fieldCount LE 0)>
|
<cfif (i LE ATTRIBUTES.fieldCount) OR (ATTRIBUTES.fieldCount LE 0)>
|
||||||
|
|||||||
+23
-92
@@ -1,18 +1,17 @@
|
|||||||
<cfcomponent
|
<cfcomponent
|
||||||
displayname="ReST API helper"
|
displayname="ReST API helper"
|
||||||
output="true"
|
output="true"
|
||||||
hint="Static helper methods for ReST API">
|
hint="Статические вспомогательные методы для ReST API">
|
||||||
|
|
||||||
<cffunction name="empty2null"
|
<cffunction name="empty2null"
|
||||||
access="public"
|
access="public"
|
||||||
returntype="any"
|
returntype="any"
|
||||||
output="false"
|
output="false"
|
||||||
hint="replace empty field with null">
|
hint="Заменяет пустое поле на null">
|
||||||
|
|
||||||
<cfargument name="value" type="any" required="true" />
|
<cfargument name="value" type="any" required="true" />
|
||||||
|
|
||||||
<cfif isSimpleValue(ARGUMENTS.value) AND isEmpty(ARGUMENTS.value)><!---*** некорректно, но просто, пустые строки превращает в нулл--->
|
<cfif isSimpleValue(ARGUMENTS.value) AND isEmpty(ARGUMENTS.value)>
|
||||||
<!--- нам не нужно, чтобы пустые массивы превращались в нулл. Наверное, и структуры тоже --->
|
|
||||||
<cfreturn javacast('null','')/>
|
<cfreturn javacast('null','')/>
|
||||||
<cfelse>
|
<cfelse>
|
||||||
<cfreturn ARGUMENTS.value />
|
<cfreturn ARGUMENTS.value />
|
||||||
@@ -23,7 +22,7 @@
|
|||||||
<cffunction name="passThrough"
|
<cffunction name="passThrough"
|
||||||
returntype="any"
|
returntype="any"
|
||||||
output="false"
|
output="false"
|
||||||
hint="just return argument">
|
hint="Возвращает аргумент без изменений">
|
||||||
<cfargument name="x" type="ANY" required="true"/>
|
<cfargument name="x" type="ANY" required="true"/>
|
||||||
<cfreturn #ARGUMENTS.x#/>
|
<cfreturn #ARGUMENTS.x#/>
|
||||||
</cffunction>
|
</cffunction>
|
||||||
@@ -33,7 +32,7 @@
|
|||||||
access="public"
|
access="public"
|
||||||
returntype="any"
|
returntype="any"
|
||||||
output="false"
|
output="false"
|
||||||
hint="put data into struct, replace empty fields with null">
|
hint="Записывает данные в структуру, заменяя пустые поля на null">
|
||||||
|
|
||||||
<cfargument name="struct" type="struct" required="true" />
|
<cfargument name="struct" type="struct" required="true" />
|
||||||
<cfargument name="key" type="string" required="true" />
|
<cfargument name="key" type="string" required="true" />
|
||||||
@@ -65,9 +64,7 @@
|
|||||||
|
|
||||||
<cfif queryColumnExists(ARGUMENTS.query, local.col)>
|
<cfif queryColumnExists(ARGUMENTS.query, local.col)>
|
||||||
<cfset obj[ARGUMENTS.fieldNameDecorator(local.col)]=empty2null(formatter(ARGUMENTS.query[local.col][ARGUMENTS.query.currentRow]))/>
|
<cfset obj[ARGUMENTS.fieldNameDecorator(local.col)]=empty2null(formatter(ARGUMENTS.query[local.col][ARGUMENTS.query.currentRow]))/>
|
||||||
<!--- *** преобразование пустой строки в null преобразует в нулл также пустые списки, что искажает факт --->
|
|
||||||
</cfif>
|
</cfif>
|
||||||
<!---*** не уверен в надежности конструкции во всех реализациях CF, контекст query передастся ли--->
|
|
||||||
</cfloop>
|
</cfloop>
|
||||||
|
|
||||||
<cfreturn ARGUMENTS.struct/>
|
<cfreturn ARGUMENTS.struct/>
|
||||||
@@ -78,13 +75,10 @@
|
|||||||
<cffunction name="parseFilterParams"
|
<cffunction name="parseFilterParams"
|
||||||
returntype="array"
|
returntype="array"
|
||||||
output="true"
|
output="true"
|
||||||
hint="Parse and collect filter params from URL. For operators see filter_build">
|
hint="Разбирает и собирает параметры фильтра из URL. Операторы задаются в filter_build">
|
||||||
<cfargument name="params" type="struct" required="true" />
|
<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 local = {}/>
|
||||||
<cfset var out = []/>
|
<cfset var out = []/>
|
||||||
<cfset var urlParams = parseQs()/>
|
<cfset var urlParams = parseQs()/>
|
||||||
|
|
||||||
@@ -93,7 +87,7 @@
|
|||||||
<cfset var urlParamName=snake2camel(lCase(local.item))/>
|
<cfset var urlParamName=snake2camel(lCase(local.item))/>
|
||||||
<cfif structKeyExists(urlParams,urlParamName)>
|
<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 --->
|
<cfloop array=#urlParams[urlParamName]# item="local.rawValue"><!--- Если параметр встречается в URL несколько раз, его значения образуют список через запятую. --->
|
||||||
<cfset var operator="EQ"/>
|
<cfset var operator="EQ"/>
|
||||||
<cfset var value=#local.rawValue#/>
|
<cfset var value=#local.rawValue#/>
|
||||||
<cfif listLen(local.rawValue,":") GT 1>
|
<cfif listLen(local.rawValue,":") GT 1>
|
||||||
@@ -134,12 +128,10 @@
|
|||||||
<cffunction name="parseFilterParamsV1"
|
<cffunction name="parseFilterParamsV1"
|
||||||
returntype="array"
|
returntype="array"
|
||||||
output="true"
|
output="true"
|
||||||
hint="parse and collect filter params, for operators see filter_build">
|
hint="Разбирает и собирает параметры фильтра; операторы задаются в filter_build">
|
||||||
<!---e.g. duration=NEQ:2--->
|
|
||||||
<!---*** add test for multiple values--->
|
|
||||||
<cfargument name="params" type="struct" required="true" /><!--- имена полей и колонок в snake_case --->
|
<cfargument name="params" type="struct" required="true" /><!--- имена полей и колонок в snake_case --->
|
||||||
|
|
||||||
<cfset var local = {}/><!--- *** --->
|
<cfset var local = {}/>
|
||||||
<cfset var out = []/>
|
<cfset var out = []/>
|
||||||
|
|
||||||
<cfloop collection=#params# index="local.item">
|
<cfloop collection=#params# index="local.item">
|
||||||
@@ -147,7 +139,7 @@
|
|||||||
<cfset var urlParamName=snake2camel(lCase(local.item))/>
|
<cfset var urlParamName=snake2camel(lCase(local.item))/>
|
||||||
<cfif structKeyExists(URL,urlParamName)>
|
<cfif structKeyExists(URL,urlParamName)>
|
||||||
|
|
||||||
<cfloop list=#URL[urlParamName]# item="local.rawValue"><!--- when parameter occures in URL more than once, its values compose a comma delimited list --->
|
<cfloop list=#URL[urlParamName]# item="local.rawValue"><!--- Если параметр встречается в URL несколько раз, его значения образуют список через запятую. --->
|
||||||
<cfset var operator="EQ"/>
|
<cfset var operator="EQ"/>
|
||||||
<cfset var value=#local.rawValue#/>
|
<cfset var value=#local.rawValue#/>
|
||||||
<cfif listLen(local.rawValue,":") GT 1>
|
<cfif listLen(local.rawValue,":") GT 1>
|
||||||
@@ -189,7 +181,7 @@
|
|||||||
<cffunction name="parseOrderBy"
|
<cffunction name="parseOrderBy"
|
||||||
returntype="struct"
|
returntype="struct"
|
||||||
output="false"
|
output="false"
|
||||||
hint="parse and collect sort order param"><!--- deprecated --->
|
hint="Разбирает и собирает параметр сортировки"><!--- Устаревший метод --->
|
||||||
|
|
||||||
<cfargument name="params" type="struct" required="true" />
|
<cfargument name="params" type="struct" required="true" />
|
||||||
<cfargument name="orderBy" type="string" required="true" />
|
<cfargument name="orderBy" type="string" required="true" />
|
||||||
@@ -203,7 +195,7 @@
|
|||||||
<cfcase value="ASC"><cfset var asc=true/></cfcase>
|
<cfcase value="ASC"><cfset var asc=true/></cfcase>
|
||||||
<cfcase value="DESC"><cfset var asc=false/></cfcase>
|
<cfcase value="DESC"><cfset var asc=false/></cfcase>
|
||||||
<cfdefaultcase>
|
<cfdefaultcase>
|
||||||
<cfthrow type="InvalidParamValue" message="Invalid orderBy format" detail="orderBy suffix should be '.asc' or '.desc'" /><!---*** XSS vulnerability, so we would not show the suffix--->
|
<cfthrow type="InvalidParamValue" message="Invalid orderBy format" detail="orderBy suffix should be '.asc' or '.desc'" /><!--- Суффикс не возвращается пользователю, чтобы не расширять XSS-поверхность. --->
|
||||||
</cfdefaultcase>
|
</cfdefaultcase>
|
||||||
</cfswitch>
|
</cfswitch>
|
||||||
<cfelse>
|
<cfelse>
|
||||||
@@ -223,7 +215,7 @@
|
|||||||
<cffunction name="parseNumericOrder"
|
<cffunction name="parseNumericOrder"
|
||||||
returntype="array"
|
returntype="array"
|
||||||
output="false"
|
output="false"
|
||||||
hint="parse and collect sort order param with numeric notation">
|
hint="Разбирает и собирает параметр сортировки в числовой нотации">
|
||||||
|
|
||||||
<cfargument name="fieldSet" type="struct" required="true" />
|
<cfargument name="fieldSet" type="struct" required="true" />
|
||||||
<cfargument name="orderBy" type="string" required="true" />
|
<cfargument name="orderBy" type="string" required="true" />
|
||||||
@@ -237,7 +229,7 @@
|
|||||||
<cfcase value="ASC"><cfset var asc=true/></cfcase>
|
<cfcase value="ASC"><cfset var asc=true/></cfcase>
|
||||||
<cfcase value="DESC"><cfset var asc=false/></cfcase>
|
<cfcase value="DESC"><cfset var asc=false/></cfcase>
|
||||||
<cfdefaultcase>
|
<cfdefaultcase>
|
||||||
<cfthrow type="InvalidParamValue" message="Invalid orderBy format" detail="orderBy suffix should be '.asc' or '.desc'" /><!---*** XSS vulnerability, so we would not show the suffix--->
|
<cfthrow type="InvalidParamValue" message="Invalid orderBy format" detail="orderBy suffix should be '.asc' or '.desc'" /><!--- Суффикс не возвращается пользователю, чтобы не расширять XSS-поверхность. --->
|
||||||
</cfdefaultcase>
|
</cfdefaultcase>
|
||||||
</cfswitch>
|
</cfswitch>
|
||||||
<cfelse>
|
<cfelse>
|
||||||
@@ -252,35 +244,9 @@
|
|||||||
</cfloop>
|
</cfloop>
|
||||||
<cfreturn out/>
|
<cfreturn out/>
|
||||||
</cffunction>
|
</cffunction>
|
||||||
|
<!--- Больше не используется --->
|
||||||
|
|
||||||
<!---<cffunction name="snake2camel"
|
|
||||||
access="public"
|
|
||||||
returntype="any"
|
|
||||||
output="false"
|
|
||||||
hint="convert snake style name to camel style name">
|
|
||||||
|
|
||||||
<cfargument name="snake" type="string" required="true" />
|
|
||||||
|
|
||||||
<cfset var snake=ARGUMENTS.snake/>
|
|
||||||
<cfset var camel=""/>
|
|
||||||
<cfset var pos=1/>
|
|
||||||
<cfloop condition="true">
|
|
||||||
<cfset next=reFind("(_[a-z])", snake, pos, false)/>
|
|
||||||
<cfif NOT next GT 0>
|
|
||||||
<cfbreak/>
|
|
||||||
</cfif>
|
|
||||||
<cfset camel="#camel##mid(snake,pos,next-pos)##uCase(mid(snake,next+1,1))#"/>
|
|
||||||
<cfset pos=next+2/>
|
|
||||||
</cfloop>
|
|
||||||
<cfset camel="#camel##mid(snake,pos,len(snake))#"/>
|
|
||||||
|
|
||||||
<cfreturn #camel#/>
|
|
||||||
</cffunction>--->
|
|
||||||
|
|
||||||
<!---not used any more--->
|
|
||||||
<cffunction name="query4json" access="public" returntype="any" output="false"
|
<cffunction name="query4json" access="public" returntype="any" output="false"
|
||||||
hint="Converts query to an array of structs. Key names are lowercase. Empty fields are treated as nulls">
|
hint="Преобразует query в массив структур. Имена ключей приводятся к нижнему регистру, пустые поля считаются null">
|
||||||
|
|
||||||
<cfargument name="Query" type="query" required="true" />
|
<cfargument name="Query" type="query" required="true" />
|
||||||
|
|
||||||
@@ -308,7 +274,7 @@
|
|||||||
access="public"
|
access="public"
|
||||||
returntype="any"
|
returntype="any"
|
||||||
output="false"
|
output="false"
|
||||||
hint="convert snake style name to camel style name">
|
hint="Преобразует имя в стиле snake_case в camelCase">
|
||||||
<cfargument name="snake" type="string" required="true" />
|
<cfargument name="snake" type="string" required="true" />
|
||||||
<cfreturn #reReplace(ARGUMENTS.snake,"_([a-z])","\u\1","ALL")#/>
|
<cfreturn #reReplace(ARGUMENTS.snake,"_([a-z])","\u\1","ALL")#/>
|
||||||
</cffunction>
|
</cffunction>
|
||||||
@@ -318,7 +284,7 @@
|
|||||||
access="public"
|
access="public"
|
||||||
returntype="any"
|
returntype="any"
|
||||||
output="false"
|
output="false"
|
||||||
hint="convert camel style name to snake style name">
|
hint="Преобразует имя в стиле camelCase в snake_case">
|
||||||
<cfargument name="snake" type="string" required="true" />
|
<cfargument name="snake" type="string" required="true" />
|
||||||
<cfreturn #reReplace(ARGUMENTS.snake,"([A-Z])","_\l\1","ALL")#/>
|
<cfreturn #reReplace(ARGUMENTS.snake,"([A-Z])","_\l\1","ALL")#/>
|
||||||
</cffunction>
|
</cffunction>
|
||||||
@@ -327,7 +293,7 @@
|
|||||||
access="public"
|
access="public"
|
||||||
returntype="any"
|
returntype="any"
|
||||||
output="true"
|
output="true"
|
||||||
hint="formats Exception for display">
|
hint="Форматирует сообщение для вывода">
|
||||||
|
|
||||||
<cfargument name="message" type="string" required="true" />
|
<cfargument name="message" type="string" required="true" />
|
||||||
<cfargument name="title" type="string" required="false" />
|
<cfargument name="title" type="string" required="false" />
|
||||||
@@ -342,7 +308,7 @@
|
|||||||
access="public"
|
access="public"
|
||||||
returntype="any"
|
returntype="any"
|
||||||
output="true"
|
output="true"
|
||||||
hint="formats Exception for display">
|
hint="Форматирует исключение для вывода">
|
||||||
|
|
||||||
<cfargument name="ex" type="struct" required="true" />
|
<cfargument name="ex" type="struct" required="true" />
|
||||||
<cfargument name="title" type="string" required="false" />
|
<cfargument name="title" type="string" required="false" />
|
||||||
@@ -357,7 +323,7 @@
|
|||||||
access="public"
|
access="public"
|
||||||
returntype="any"
|
returntype="any"
|
||||||
output="true"
|
output="true"
|
||||||
hint="formats Bad Request Exception">
|
hint="Форматирует ошибку Bad Request">
|
||||||
|
|
||||||
<cfargument name="ex" type="struct" required="true" />
|
<cfargument name="ex" type="struct" required="true" />
|
||||||
|
|
||||||
@@ -366,41 +332,6 @@
|
|||||||
<cfreturn {type="about:blank", title="Bad Request", detail="#detail#"}/>
|
<cfreturn {type="about:blank", title="Bad Request", detail="#detail#"}/>
|
||||||
</cffunction>
|
</cffunction>
|
||||||
|
|
||||||
<!---<cffunction name="wrapResultSet"
|
|
||||||
access="public"
|
|
||||||
returntype="any"
|
|
||||||
output="true"
|
|
||||||
hint="format resultset as json">
|
|
||||||
|
|
||||||
<cfargument name="qRead" type="query" required="true" />
|
|
||||||
<cfargument name="titleMap" type="struct" required="true" />
|
|
||||||
<cfargument name="startrow" type="integer" required="false" default="1" />
|
|
||||||
|
|
||||||
<cfset var resultSet=[]/>
|
|
||||||
<cfloop query=#ARGUMENTS.qRead# startRow=#ARGUMENTS.startrow#>
|
|
||||||
<cfset var rec={}/>
|
|
||||||
|
|
||||||
<cfset appendRecord(rec, "", ARGUMENTS.titleMap, ARGUMENTS.qRead, snake2camel)/>
|
|
||||||
<cfset arrayAppend(resultSet, rec)/>
|
|
||||||
</cfloop>
|
|
||||||
|
|
||||||
<cfset var out={
|
|
||||||
pageSize=
|
|
||||||
}/>
|
|
||||||
|
|
||||||
|
|
||||||
<cfcontent type="application/json"/>
|
|
||||||
<cfoutput>{
|
|
||||||
"pageSize":#pageSize#,
|
|
||||||
"page":#page#,
|
|
||||||
"orderBy":"#orderBy#",
|
|
||||||
"size":"#arrayLen(resultSet)#",
|
|
||||||
"total":"#qTotal.cnt#",
|
|
||||||
"results":#serializeJson(resultSet)#,
|
|
||||||
"queryDurationMs":#queryDurationMs#, <cfset runDurationMs=getTickCount()-request.startTickCount/>
|
|
||||||
"runDurationMs":#runDurationMs#
|
|
||||||
}</cfoutput>--->
|
|
||||||
|
|
||||||
<cffunction name="isValidX"
|
<cffunction name="isValidX"
|
||||||
access="private"
|
access="private"
|
||||||
returntype="boolean"
|
returntype="boolean"
|
||||||
@@ -420,7 +351,7 @@
|
|||||||
access="public"
|
access="public"
|
||||||
returntype="any"
|
returntype="any"
|
||||||
output="false"
|
output="false"
|
||||||
hint="validate field of a structure, if exisits">
|
hint="Проверяет поле структуры, если оно существует">
|
||||||
|
|
||||||
<cfargument name="struct" type="struct" required=true/>
|
<cfargument name="struct" type="struct" required=true/>
|
||||||
<cfargument name="name" required=true/>
|
<cfargument name="name" required=true/>
|
||||||
|
|||||||
@@ -30,7 +30,6 @@
|
|||||||
<cfreturn representationOf(out) />
|
<cfreturn representationOf(out) />
|
||||||
</cffunction>
|
</cffunction>
|
||||||
|
|
||||||
<!--- хотя такая зависимость очень не нравится своим направлением, как бы задом наперед--->
|
|
||||||
<cffunction name="generateDefaultName">
|
<cffunction name="generateDefaultName">
|
||||||
<cfargument name="service_id" type="numeric"/>
|
<cfargument name="service_id" type="numeric"/>
|
||||||
<cfargument name="usr_id" type="numeric"/>
|
<cfargument name="usr_id" type="numeric"/>
|
||||||
|
|||||||
Reference in New Issue
Block a user