feat: created_at/created_by — видно время и сервис, добавивший строку

- CREATE TABLE IF NOT EXISTS дополнена колонками:
    created_at TIMESTAMPTZ NOT NULL DEFAULT now()
    created_by TEXT NOT NULL DEFAULT ''
- ALTER TABLE ... ADD COLUMN IF NOT EXISTS досыпает колонки в уже существующую
  таблицу — данные при этом не теряются;
- INSERT пишет created_by из env SERVICE_NAME (задаётся в json_env манифеста),
  created_at ставит сама СУБД;
- список записей и UI показывают обе колонки.

Зачем: три приложения (flask / lucee / nodejs) пишут в ОДНУ таблицу — теперь
сразу видно, какое из них и когда добавило строку.
This commit is contained in:
Repinoid
2026-10-01 18:37:34 +03:00
parent 7d1be4e089
commit ffcd0c0344
2 changed files with 40 additions and 7 deletions
+27 -1
View File
@@ -63,16 +63,35 @@
<!--- 3. Сохраняем в application scope — доступно всем запросам этого приложения ---> <!--- 3. Сохраняем в application scope — доступно всем запросам этого приложения --->
<cfset application.tableName = tableName /> <cfset application.tableName = tableName />
<!--- 3a. Имя сервиса — для колонки created_by («кто добавил строку»).
Задаётся в json_env манифеста (flask / lucee / nodejs): три приложения
пишут в ОДНУ таблицу, и по этой метке видно, какое именно добавило. --->
<cfset var serviceName = createObject("java", "java.lang.System").getEnv().get("SERVICE_NAME") />
<cfif NOT isDefined("serviceName") OR NOT len(serviceName)>
<cfset serviceName = "lucee" />
</cfif>
<cfset application.serviceName = serviceName />
<!--- 4. Создаём таблицу если она ещё не существует ---> <!--- 4. Создаём таблицу если она ещё не существует --->
<!--- id: автоинкрементный первичный ключ ---> <!--- id: автоинкрементный первичный ключ --->
<!--- value: текстовое поле для CRUD-значений ---> <!--- value: текстовое поле для CRUD-значений --->
<!--- created_at / created_by: когда и какое приложение добавило строку --->
<cftry> <cftry>
<cfquery> <cfquery>
CREATE TABLE IF NOT EXISTS #tableName# ( CREATE TABLE IF NOT EXISTS #tableName# (
id SERIAL PRIMARY KEY, id SERIAL PRIMARY KEY,
value TEXT NOT NULL DEFAULT '' value TEXT NOT NULL DEFAULT '',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
created_by TEXT NOT NULL DEFAULT ''
) )
</cfquery> </cfquery>
<!--- Досыпаем колонки в таблицу, созданную прошлой версией: данные не теряются --->
<cfquery>
ALTER TABLE #tableName# ADD COLUMN IF NOT EXISTS created_at TIMESTAMPTZ NOT NULL DEFAULT now()
</cfquery>
<cfquery>
ALTER TABLE #tableName# ADD COLUMN IF NOT EXISTS created_by TEXT NOT NULL DEFAULT ''
</cfquery>
<!--- Игнорируем ошибки: нет прав, БД недоступна ---> <!--- Игнорируем ошибки: нет прав, БД недоступна --->
<cfcatch type="database"></cfcatch> <cfcatch type="database"></cfcatch>
</cftry> </cftry>
@@ -97,6 +116,13 @@
<cfset request.tableName = "check_point" /> <cfset request.tableName = "check_point" />
</cfif> </cfif>
<!--- Имя сервиса — из application в request (см. OnApplicationStart) --->
<cfif isDefined("application.serviceName")>
<cfset request.serviceName = application.serviceName />
<cfelse>
<cfset request.serviceName = "lucee" />
</cfif>
<cfreturn true /> <cfreturn true />
</cffunction> </cffunction>
+12 -5
View File
@@ -20,6 +20,8 @@
- URL.edit — ID записи для редактирования (GET) - URL.edit — ID записи для редактирования (GET)
---> --->
<cfset tableName = request.tableName /> <cfset tableName = request.tableName />
<!--- Имя сервиса — пишется в колонку created_by при добавлении строки --->
<cfset serviceName = request.serviceName />
<!--- ====== ОБРАБОТКА POST-ЗАПРОСОВ (create / update / delete) ====== ---> <!--- ====== ОБРАБОТКА POST-ЗАПРОСОВ (create / update / delete) ====== --->
@@ -30,8 +32,11 @@
<cfif FORM.action EQ "create"> <cfif FORM.action EQ "create">
<!--- cfqueryparam cfsqltype="cf_sql_varchar" — экранирует значение, защита от SQL-инъекций ---> <!--- cfqueryparam cfsqltype="cf_sql_varchar" — экранирует значение, защита от SQL-инъекций --->
<cfquery name="insertRow"> <cfquery name="insertRow">
INSERT INTO #tableName# (value) INSERT INTO #tableName# (value, created_by)
VALUES (<cfqueryparam value="#FORM.value#" cfsqltype="cf_sql_varchar" />) VALUES (
<cfqueryparam value="#FORM.value#" cfsqltype="cf_sql_varchar" />,
<cfqueryparam value="#serviceName#" cfsqltype="cf_sql_varchar" />
)
</cfquery> </cfquery>
</cfif> </cfif>
@@ -65,7 +70,7 @@
<cfif isDefined("URL.edit")> <cfif isDefined("URL.edit")>
<!--- Загружаем запись по ID из URL ---> <!--- Загружаем запись по ID из URL --->
<cfquery name="editQuery"> <cfquery name="editQuery">
SELECT id, value FROM #tableName# SELECT id, value, created_at, created_by FROM #tableName#
WHERE id = <cfqueryparam value="#URL.edit#" cfsqltype="cf_sql_integer" /> WHERE id = <cfqueryparam value="#URL.edit#" cfsqltype="cf_sql_integer" />
</cfquery> </cfquery>
<!--- Если запись найдена — заполняем editRow данными из запроса ---> <!--- Если запись найдена — заполняем editRow данными из запроса --->
@@ -77,7 +82,7 @@
<!--- ====== СПИСОК ВСЕХ ЗАПИСЕЙ ====== ---> <!--- ====== СПИСОК ВСЕХ ЗАПИСЕЙ ====== --->
<cfquery name="rows"> <cfquery name="rows">
SELECT id, value FROM #tableName# ORDER BY id SELECT id, value, created_at, created_by FROM #tableName# ORDER BY id
</cfquery> </cfquery>
<!DOCTYPE html> <!DOCTYPE html>
@@ -213,13 +218,15 @@
<div class="card-body" style="padding: 0;"> <div class="card-body" style="padding: 0;">
<table> <table>
<thead> <thead>
<tr><th>ID</th><th>VALUE</th><th style="text-align:center;"></th><th style="text-align:center;"></th></tr> <tr><th>ID</th><th>VALUE</th><th>ДОБАВЛЕНО</th><th>КЕМ</th><th style="text-align:center;"></th><th style="text-align:center;"></th></tr>
</thead> </thead>
<tbody> <tbody>
<cfoutput query="rows"> <cfoutput query="rows">
<tr> <tr>
<td>#id#</td> <td>#id#</td>
<td>#value#</td> <td>#value#</td>
<td>#dateFormat(created_at, 'dd.mm.yyyy')# #timeFormat(created_at, 'HH:mm:ss')#</td>
<td>#created_by#</td>
<td style="text-align:center;"> <td style="text-align:center;">
<a href="index.cfm?edit=#id#" class="btn btn-sm">✏️</a> <a href="index.cfm?edit=#id#" class="btn btn-sm">✏️</a>
</td> </td>