@opengis/fastify-table 2.6.1 → 2.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/README.md +86 -86
  2. package/dist/functions.js +20 -20
  3. package/dist/helper.d.ts +1 -20
  4. package/dist/helper.d.ts.map +1 -1
  5. package/dist/module/core/cls/constraint_action.json +9 -9
  6. package/dist/module/core/cls/constraint_matchtype.json +5 -5
  7. package/dist/module/core/cls/constraint_type_full.json +17 -17
  8. package/dist/module/core/cls/core.user_type.json +13 -13
  9. package/dist/module/core/pt/schemaItem.pt.hbs +17 -17
  10. package/dist/module/core/select/core.user_mentioned.sql +1 -1
  11. package/dist/script/adduser +14 -14
  12. package/dist/script/dump.js +48 -48
  13. package/dist/script/dump.ts +216 -216
  14. package/dist/script/migrate.ts +23 -23
  15. package/dist/server/helpers/core/badge.js +1 -1
  16. package/dist/server/helpers/list/descriptionList.js +8 -8
  17. package/dist/server/helpers/list/tableList.js +4 -4
  18. package/dist/server/helpers/list/utils/button.js +1 -1
  19. package/dist/server/helpers/list/utils/buttonDel.js +3 -3
  20. package/dist/server/helpers/list/utils/buttonEdit.js +3 -3
  21. package/dist/server/helpers/utils/button.js +1 -1
  22. package/dist/server/helpers/utils/buttonAdd.js +15 -15
  23. package/dist/server/helpers/utils/buttonDel.js +11 -11
  24. package/dist/server/helpers/utils/buttonEdit.js +3 -3
  25. package/dist/server/migrations/0.sql +99 -99
  26. package/dist/server/migrations/1_users.sql +145 -145
  27. package/dist/server/migrations/cls.sql +105 -105
  28. package/dist/server/migrations/context.sql +136 -136
  29. package/dist/server/migrations/dictionaries.sql +78 -78
  30. package/dist/server/migrations/oauth.sql +79 -79
  31. package/dist/server/migrations/properties.sql +115 -115
  32. package/dist/server/migrations/roles.sql +201 -200
  33. package/dist/server/migrations/template.sql +43 -43
  34. package/dist/server/plugins/access/funcs/getUserPermissions.js +7 -7
  35. package/dist/server/plugins/auth/funcs/authorizeUser.js +4 -4
  36. package/dist/server/plugins/auth/funcs/getQuery.js +20 -20
  37. package/dist/server/plugins/crud/funcs/dataUpdate.js +7 -7
  38. package/dist/server/plugins/crud/funcs/getAccess.js +14 -14
  39. package/dist/server/plugins/crud/funcs/utils/getInsertQuery.js +6 -6
  40. package/dist/server/plugins/crud/funcs/utils/logChanges.js +18 -18
  41. package/dist/server/plugins/grpc/utils/convertp.proto +143 -143
  42. package/dist/server/plugins/grpc/utils/htmlTemplate.js +10 -10
  43. package/dist/server/plugins/grpc/utils/office2pdf.proto +13 -13
  44. package/dist/server/plugins/metric/loggerSystem.js +1 -1
  45. package/dist/server/plugins/pg/funcs/autoIndex.js +5 -5
  46. package/dist/server/plugins/pg/funcs/getMeta.js +15 -15
  47. package/dist/server/plugins/pg/funcs/init.js +36 -36
  48. package/dist/server/plugins/sqlite/funcs/init.js +22 -22
  49. package/dist/server/plugins/table/funcs/getData.js +13 -13
  50. package/dist/server/plugins/table/funcs/getFilterSQL/util/getCustomQuery.js +1 -1
  51. package/dist/server/plugins/table/funcs/getSelect.js +1 -1
  52. package/dist/server/plugins/table/funcs/gisIRColumn.js +3 -3
  53. package/dist/server/plugins/usercls/index.js +2 -2
  54. package/dist/server/routes/access/controllers/access.group.js +6 -6
  55. package/dist/server/routes/access/controllers/access.group.post.js +3 -3
  56. package/dist/server/routes/access/controllers/access.interface.js +14 -14
  57. package/dist/server/routes/access/controllers/access.user.js +6 -6
  58. package/dist/server/routes/auth/controllers/2factor/providers/totp.js +5 -5
  59. package/dist/server/routes/auth/controllers/2factor/qrcode.js +1 -1
  60. package/dist/server/routes/auth/controllers/2factor/recovery.js +1 -1
  61. package/dist/server/routes/auth/controllers/2factor/verify.js +1 -1
  62. package/dist/server/routes/auth/controllers/core/getUserInfo.js +33 -33
  63. package/dist/server/routes/auth/controllers/core/passwordRecovery.js +1 -1
  64. package/dist/server/routes/auth/controllers/core/registration.js +2 -2
  65. package/dist/server/routes/auth/controllers/page/login2faTemplate.js +1 -1
  66. package/dist/server/routes/crud/functions/deleteTableRelation.js +9 -9
  67. package/dist/server/routes/crud/functions/updateTableRelation.js +9 -9
  68. package/dist/server/routes/file/controllers/resizeAll.js +7 -7
  69. package/dist/server/routes/grpc/controllers/file2geojson.js +13 -13
  70. package/dist/server/routes/menu/controllers/getMenu.js +9 -9
  71. package/dist/server/routes/notifications/controllers/readNotifications.js +4 -4
  72. package/dist/server/routes/notifications/controllers/userNotifications.js +3 -3
  73. package/dist/server/routes/table/controllers/card.js +1 -1
  74. package/dist/server/routes/table/controllers/filter.js +6 -6
  75. package/dist/server/routes/table/controllers/form.js +1 -1
  76. package/dist/server/routes/table/controllers/getFormByTable.js +6 -6
  77. package/dist/server/routes/table/controllers/suggest.js +10 -10
  78. package/dist/server/routes/table/controllers/tableData.js +2 -2
  79. package/dist/server/routes/table/controllers/tableInfo.js +10 -10
  80. package/dist/server/routes/table/functions/getData.js +13 -13
  81. package/dist/server/routes/widget/controllers/widget.get.js +33 -33
  82. package/dist/server/routes/widget/controllers/widget.set.js +4 -4
  83. package/dist/server/routes/widget/services/widget.entity.get.js +33 -33
  84. package/dist/server/routes/widget/services/widget.entity.set.js +4 -4
  85. package/dist/server/templates/page/2factor-recovery.html +101 -101
  86. package/dist/server/templates/page/2factor.html +140 -140
  87. package/dist/server/templates/page/login.html +90 -90
  88. package/dist/server/templates/pt/recovery-codes-email-template.hbs +12 -12
  89. package/dist/server/templates/pt/recovery-password-email-template.html +20 -20
  90. package/package.json +99 -99
  91. package/dist/module/core/select/core.user_mentioned.json +0 -3
@@ -153,12 +153,12 @@ export default async function filterAPI(req, reply, iscalled) {
153
153
  fields?.find?.((item) => item?.name === el.name))
154
154
  .map(async (el) => {
155
155
  const data = await pg
156
- .queryCache(`select array[
157
- min(${el.name}),
158
- percentile_disc(0.25) within group (order by ${el.name}),
159
- percentile_disc(0.5) within group (order by ${el.name}),
160
- percentile_disc(0.75) within group (order by ${el.name}),
161
- max(${el.name})
156
+ .queryCache(`select array[
157
+ min(${el.name}),
158
+ percentile_disc(0.25) within group (order by ${el.name}),
159
+ percentile_disc(0.5) within group (order by ${el.name}),
160
+ percentile_disc(0.75) within group (order by ${el.name}),
161
+ max(${el.name})
162
162
  ] as range from ${table} where ${tableQuery || "1=1"}`, { table })
163
163
  .then((res) => {
164
164
  if (res.timeout) {
@@ -1,6 +1,6 @@
1
1
  import { NotFoundError } from "../../../../errors.js";
2
2
  import { applyHook, getTemplate, pgClients } from "../../../../utils.js";
3
- const q = `select property_key as key, property_json as json, property_int as int,
3
+ const q = `select property_key as key, property_json as json, property_int as int,
4
4
  property_text as text from admin.properties where 1=1`;
5
5
  async function getSettings({ pg }) {
6
6
  const rows = pg?.pk?.["admin.properties"]
@@ -9,12 +9,12 @@ import getTemplate from "../../../plugins/table/funcs/getTemplate.js";
9
9
  import getEditData from "../../crud/controllers/table.js";
10
10
  import formatSchema from "./utils/formatSchema.js";
11
11
  import { ForbiddenError, NotFoundError, UnauthorizedError, } from "../../../../errors.js";
12
- const q = `select
13
- property_key as key,
14
- property_json as json,
15
- property_int as int,
16
- property_text as text
17
- from admin.properties
12
+ const q = `select
13
+ property_key as key,
14
+ property_json as json,
15
+ property_int as int,
16
+ property_text as text
17
+ from admin.properties
18
18
  where 1=1`;
19
19
  export default async function getForm({ pg = pgClients.client, params, user = {}, query = {}, method, }, reply) {
20
20
  const time = Date.now();
@@ -47,13 +47,13 @@ export async function getTableColumnMeta({ table, template, column, selectName,
47
47
  : `id in ( with cc(id, text) as (${select}) select id from cc where (lower("text") ~ $1) )`;
48
48
  const counts = pg.queryCache
49
49
  ? await pg
50
- .queryCache(`SELECT json_object_agg( (
51
- SELECT
52
- nspname
53
- FROM
54
- pg_namespace
55
- WHERE
56
- oid = relnamespace
50
+ .queryCache(`SELECT json_object_agg( (
51
+ SELECT
52
+ nspname
53
+ FROM
54
+ pg_namespace
55
+ WHERE
56
+ oid = relnamespace
57
57
  ) || '.' || relname, reltuples::bigint) FROM pg_class WHERE relkind = 'r'`)
58
58
  .then((r) => r.rows[0].json_object_agg)
59
59
  : {};
@@ -345,11 +345,11 @@ export default async function suggest(req) {
345
345
  const whereQuery = where.filter(Boolean).join(" and ") || "true";
346
346
  args.push(Math.min(query.limit || meta.limit || limit, limit));
347
347
  let sqlSuggest = tableName && column
348
- ? `${meta.original}
349
- WHERE EXISTS ( SELECT 1 FROM ${tableName} o
348
+ ? `${meta.original}
349
+ WHERE EXISTS ( SELECT 1 FROM ${tableName} o
350
350
  WHERE ${pg.pgType[dataTypeID]?.includes("[]")
351
351
  ? `c.id = ANY(o."${column}")`
352
- : `o."${column}" IS NOT DISTINCT FROM c.id`} ) and ${whereQuery || "true"}
352
+ : `o."${column}" IS NOT DISTINCT FROM c.id`} ) and ${whereQuery || "true"}
353
353
  ${order} LIMIT $${args.length}::int`
354
354
  : `with c(id,text) as ( ${meta.original} where ${whereQuery} ${order}) select * from c LIMIT $${args.length}::int`;
355
355
  if (sqlSuggest.includes("{{parent}}")) {
@@ -3,8 +3,8 @@ import getData from "../functions/getData.js";
3
3
  export default async function tableData(req, reply, called) {
4
4
  const { user, params, headers, query, pg = pgClients.client } = req;
5
5
  // це можна від користувача
6
- const q = `select attr,
7
- (select rule_values from admin.account_grants where account_id in (select account_id from admin.account_users where user_uid=$2) and rule_id=r.rule_id limit 1)
6
+ const q = `select attr,
7
+ (select rule_values from admin.account_grants where account_id in (select account_id from admin.account_users where user_uid=$2) and rule_id=r.rule_id limit 1)
8
8
  from admin.rules r where (select route_id from admin.routes where $1 in (alias,table_name)) = any(routes)`;
9
9
  const { rows = [] } = pg?.pk?.["admin.rules"] && pg?.pk?.["admin.account_grants"] && user?.uid
10
10
  ? await pg.query(q, [params.table, user.uid])
@@ -59,21 +59,21 @@ export default async function tableInfo({ pg = pgClients.client, params, query =
59
59
  if (!metaInfoCols.length) {
60
60
  throw BadRequestError("invalid meta info: columns not found");
61
61
  }
62
- const q = `select ${pk ? `"${pk}" as id,` : ""}
63
- ${metaInfoCols.join(",")}
64
- from (select * from ${table} where ${sqlTable ? "true" : where.join(" and ") || "true"}) t
65
- ${sqlTable}
66
- ${cardSqlTable}
67
- where ${where.join(" and ") || "true"}
62
+ const q = `select ${pk ? `"${pk}" as id,` : ""}
63
+ ${metaInfoCols.join(",")}
64
+ from (select * from ${table} where ${sqlTable ? "true" : where.join(" and ") || "true"}) t
65
+ ${sqlTable}
66
+ ${cardSqlTable}
67
+ where ${where.join(" and ") || "true"}
68
68
  limit 1`.replace(/{{uid}}/g, uid);
69
69
  if (query.sql === "1") {
70
70
  return q;
71
71
  }
72
72
  const { rows } = await pg.query(q, [params.id]);
73
- const qCount = `select
74
- count(*)::int as total,
75
- count(*) FILTER(WHERE ${[interfaceQuery].filter((el) => el).join(" and ") || "true"})::int as filtered
76
- from ${table} t ${sqlTable}
73
+ const qCount = `select
74
+ count(*)::int as total,
75
+ count(*) FILTER(WHERE ${[interfaceQuery].filter((el) => el).join(" and ") || "true"})::int as filtered
76
+ from ${table} t ${sqlTable}
77
77
  where ${[loadTable.query].filter((el) => el).join(" and ") || "true"} `.replace(/{{uid}}/g, uid);
78
78
  const { total, filtered } = params.id
79
79
  ? rows.length
@@ -355,9 +355,9 @@ export default async function dataAPI({ pg = pgClients.client, params, table, id
355
355
  interfaceQuery1,
356
356
  ].filter(Boolean);
357
357
  const omitGeometry = !objectId && loadTable?.showGeometryMode === "card";
358
- const q1 = `select ${pk ? `"${pk}" as id,` : ""}
359
- ${objectId || query?.key ? "*" : columnsParam || sqlColumns || cols || "*"}
360
- ${metaCols}
358
+ const q1 = `select ${pk ? `"${pk}" as id,` : ""}
359
+ ${objectId || query?.key ? "*" : columnsParam || sqlColumns || cols || "*"}
360
+ ${metaCols}
361
361
  ${dbColumns.filter((el) => pg.pgType?.[el.dataTypeID] === "geometry")
362
362
  .length &&
363
363
  !columnsParam &&
@@ -366,14 +366,14 @@ export default async function dataAPI({ pg = pgClients.client, params, table, id
366
366
  .filter((el) => pg.pgType?.[el.dataTypeID] === "geometry")
367
367
  .map((el) => `st_asgeojson("${el.name.replace(/'/g, "''")}")::json as "${el.name.replace(/'/g, "''")}"`)
368
368
  .join(",")}`
369
- : ""}
369
+ : ""}
370
370
  from (select * ${sql
371
371
  ?.filter((el) => el.inline && !(isExport && el.export === false))
372
372
  .map((el) => `,(${el.sql})`)
373
- .join("") || ""} from ${viewSql ? `(${viewSql})` : table1} t ${sqlTable} ) t
374
-
375
- ${objectId ? cardSqlTable : ""}
376
- where ${where.join(" and ") || "true"}
373
+ .join("") || ""} from ${viewSql ? `(${viewSql})` : table1} t ${sqlTable} ) t
374
+
375
+ ${objectId ? cardSqlTable : ""}
376
+ where ${where.join(" and ") || "true"}
377
377
  ${order} limit $${idx.limit}::bigint offset $${idx.offset}::bigint`;
378
378
  if (q1.includes("{{uid}}")) {
379
379
  args.push(uid || "");
@@ -458,18 +458,18 @@ export default async function dataAPI({ pg = pgClients.client, params, table, id
458
458
  type: pg.pgType?.[el.dataTypeID],
459
459
  }))
460
460
  .filter((el) => ["numeric", "double precision"].includes(el.type) && aggColumns[el.name]);
461
- const qCount = `select
462
- count(*)::int as total,
463
- count(*) FILTER(WHERE ${filterWhere.join(" and ") || "true"})::int as filtered
461
+ const qCount = `select
462
+ count(*)::int as total,
463
+ count(*) FILTER(WHERE ${filterWhere.join(" and ") || "true"})::int as filtered
464
464
  ${aggregates.length
465
465
  ? `,${aggregates
466
466
  .map((el) => `${aggColumns[el.name]}(${el.name}) FILTER(WHERE ${filterWhere.join(" and ") || "true"}) as ${el.name}`)
467
467
  .join(",")}`
468
- : ""}
468
+ : ""}
469
469
  from (select * ${sql
470
470
  ?.filter((el) => el.inline)
471
471
  .map((el) => `,(${el.sql})`)
472
- .join("") || ""} from ${viewSql ? `(${viewSql})` : table1} t ${sqlTable})t
472
+ .join("") || ""} from ${viewSql ? `(${viewSql})` : table1} t ${sqlTable})t
473
473
  where ${[loadTable?.query, tokenData?.query, accessQuery, contextQuery]
474
474
  .filter(Boolean)
475
475
  .join(" and ") || "true"} `.replace(/'{{uid}}'/g, `$${idx1.uid}`);
@@ -39,49 +39,49 @@ export default async function widgetGet({ pg = pgClients.client, user = {}, para
39
39
  }
40
40
  const sqls = {
41
41
  comment: pg.pk["admin.users"]
42
- ? `select communication_id, entity_id, body, subject, c.cdate, c.uid,
43
- ${username} as username, u.login, u.avatar
44
- from crm.communications c
45
- left join admin.users u on u.uid=c.uid
42
+ ? `select communication_id, entity_id, body, subject, c.cdate, c.uid,
43
+ ${username} as username, u.login, u.avatar
44
+ from crm.communications c
45
+ left join admin.users u on u.uid=c.uid
46
46
  where entity_id=$1 order by cdate desc`
47
47
  : "select communication_id, entity_id, body, subject, cdate, uid from crm.communications where entity_id=$1 order by cdate desc",
48
- history: `SELECT change_id, entity_id, entity_type, change_type, change_date, a.change_user_id, a.uid, a.cdate, b.json_agg as changes,
49
- ${username} as username, u.login, u.avatar
50
- FROM log.table_changes a
51
- left join admin.users u on a.change_user_id = u.uid
52
- left join lateral(
53
- select json_agg(row_to_json(q)) from (
54
- select change_data_id, entity_key, value_new, value_old from log.table_changes_data
55
- where change_id=a.change_id
56
- )q
57
- )b on 1=1
58
- where a.change_type != 'INSERT' and b.json_agg is not null and (entity_id=$1 or entity_id in (
59
- select communication_id from crm.communications where entity_id=$1
60
- union all select checklist_id from crm.checklists where entity_id=$1
61
- union all select file_id from crm.files where entity_id=$1)
62
- )
48
+ history: `SELECT change_id, entity_id, entity_type, change_type, change_date, a.change_user_id, a.uid, a.cdate, b.json_agg as changes,
49
+ ${username} as username, u.login, u.avatar
50
+ FROM log.table_changes a
51
+ left join admin.users u on a.change_user_id = u.uid
52
+ left join lateral(
53
+ select json_agg(row_to_json(q)) from (
54
+ select change_data_id, entity_key, value_new, value_old from log.table_changes_data
55
+ where change_id=a.change_id
56
+ )q
57
+ )b on 1=1
58
+ where a.change_type != 'INSERT' and b.json_agg is not null and (entity_id=$1 or entity_id in (
59
+ select communication_id from crm.communications where entity_id=$1
60
+ union all select checklist_id from crm.checklists where entity_id=$1
61
+ union all select file_id from crm.files where entity_id=$1)
62
+ )
63
63
  order by cdate desc limit 100`,
64
64
  checklist: pg.pk["admin.users"]
65
- ? `SELECT checklist_id, entity_id, subject, is_done, done_date, c.uid, c.cdate, ${username} as username, u.login, u.avatar
66
- FROM crm.checklists c
67
- left join admin.users u on u.uid=c.uid
65
+ ? `SELECT checklist_id, entity_id, subject, is_done, done_date, c.uid, c.cdate, ${username} as username, u.login, u.avatar
66
+ FROM crm.checklists c
67
+ left join admin.users u on u.uid=c.uid
68
68
  where entity_id=$1 order by cdate desc`
69
69
  : "SELECT checklist_id, entity_id, subject, is_done, done_date, uid, cdate FROM crm.checklists where entity_id=$1 order by cdate desc",
70
70
  file: pg.pk["admin.users"]
71
- ? `SELECT file_id, entity_id, entity_type, file_path, uploaded_name, ext, size, c.uid, c.cdate, file_type, c.ismain,
72
- ${username} as username, u.login, isverified, u.avatar, u.uid as author, file_status
73
- FROM crm.files c
74
- left join admin.users u on u.uid=c.uid
71
+ ? `SELECT file_id, entity_id, entity_type, file_path, uploaded_name, ext, size, c.uid, c.cdate, file_type, c.ismain,
72
+ ${username} as username, u.login, isverified, u.avatar, u.uid as author, file_status
73
+ FROM crm.files c
74
+ left join admin.users u on u.uid=c.uid
75
75
  where entity_id=$1 and file_status<>3 order by cdate desc`
76
- : `SELECT file_id, entity_id, entity_type, file_path, uploaded_name, ext, size, uid, cdate, file_type, ismain,
76
+ : `SELECT file_id, entity_id, entity_type, file_path, uploaded_name, ext, size, uid, cdate, file_type, ismain,
77
77
  isverified, uid as author, file_status FROM crm.files c where entity_id=$1 and file_status<>3 order by cdate desc`,
78
78
  gallery: pg.pk["admin.users"]
79
- ? `SELECT file_id, entity_id, entity_type, file_path, uploaded_name, ext, size, c.uid, c.cdate, file_type, c.ismain,
80
- ${username} as username, u.login, u.avatar, isverified, u.avatar, c.uid as author, file_status
81
- FROM crm.files c
82
- left join admin.users u on u.uid=c.uid
79
+ ? `SELECT file_id, entity_id, entity_type, file_path, uploaded_name, ext, size, c.uid, c.cdate, file_type, c.ismain,
80
+ ${username} as username, u.login, u.avatar, isverified, u.avatar, c.uid as author, file_status
81
+ FROM crm.files c
82
+ left join admin.users u on u.uid=c.uid
83
83
  where entity_id=$1 and file_status<>3 and ext = any($2) order by cdate desc`
84
- : `SELECT file_id, entity_id, entity_type, file_path, uploaded_name, ext, size, c.uid, c.cdate, file_type, ismain,
84
+ : `SELECT file_id, entity_id, entity_type, file_path, uploaded_name, ext, size, c.uid, c.cdate, file_type, ismain,
85
85
  isverified, uid as author, file_status FROM crm.files c where entity_id=$1 and file_status<>3 and ext = any($2) order by cdate desc`,
86
86
  reaction: "SELECT count(*), reaction_type FROM crm.reactions c where entity_id=$1 group by reaction_type",
87
87
  };
@@ -127,7 +127,7 @@ export default async function widgetGet({ pg = pgClients.client, user = {}, para
127
127
  }
128
128
  const cdateColumn = columns.find((col) => ["cdate", "created_at"].includes(col.name))?.name;
129
129
  const editorDateColumn = columns.find((col) => ["editor_date", "updated_at"].includes(col.name))?.name;
130
- const q1 = `select ${username} as author, u.login ${cdateColumn ? `,a.${cdateColumn} as cdate` : ""} ${editorDateColumn ? `,a.${editorDateColumn} as editor_date` : ""} from ${tableName} a
130
+ const q1 = `select ${username} as author, u.login ${cdateColumn ? `,a.${cdateColumn} as cdate` : ""} ${editorDateColumn ? `,a.${editorDateColumn} as editor_date` : ""} from ${tableName} a
131
131
  left join admin.users u on a.${authorIdColumn}=u.uid where a.${pk}=$1 limit 1`;
132
132
  const data = pg.pk["admin.users"] && pk && tableName
133
133
  ? await pg
@@ -68,9 +68,9 @@ export default async function widgetSet(req, reply) {
68
68
  uid: user?.uid,
69
69
  });
70
70
  if (type === "gallery") {
71
- await pg.query(`update crm.files set ismain=true
72
- where entity_id=$1
73
- and file_id=$2
71
+ await pg.query(`update crm.files set ismain=true
72
+ where entity_id=$1
73
+ and file_id=$2
74
74
  and (select count(*) = 0 from crm.files where entity_id=$1 and ismain)`, [objectid, rows[0]?.file_id]);
75
75
  }
76
76
  return {
@@ -111,7 +111,7 @@ export default async function widgetSet(req, reply) {
111
111
  });
112
112
  // put w/ out file
113
113
  if (type === "gallery" && body?.ismain && id) {
114
- await pg.query(`update crm.files set ismain=false
114
+ await pg.query(`update crm.files set ismain=false
115
115
  where entity_id=$1 and file_id<>$2`, [objectid, id]);
116
116
  }
117
117
  return reply.status(200).send({
@@ -36,49 +36,49 @@ export default async function widgetEntityGet({ type, entityType, objectid, uid,
36
36
  }
37
37
  const sqls = {
38
38
  comment: pg.pk["admin.users"]
39
- ? `select communication_id, entity_id, body, subject, c.cdate, c.uid,
40
- ${username} as username, u.login, u.avatar
41
- from crm.communications c
42
- left join admin.users u on u.uid=c.uid
39
+ ? `select communication_id, entity_id, body, subject, c.cdate, c.uid,
40
+ ${username} as username, u.login, u.avatar
41
+ from crm.communications c
42
+ left join admin.users u on u.uid=c.uid
43
43
  where entity_id=$1 and entity_type=$2 order by cdate desc`
44
44
  : "select communication_id, entity_id, body, subject, cdate, uid from crm.communications where entity_id=$1 and entity_type=$2 order by cdate desc",
45
- history: `SELECT change_id, entity_id, entity_type, change_type, change_date, a.change_user_id, a.uid, a.cdate, b.json_agg as changes,
46
- ${username} as username, u.login, u.avatar
47
- FROM log.table_changes a
48
- left join admin.users u on a.change_user_id = u.uid
49
- left join lateral(
50
- select json_agg(row_to_json(q)) from (
51
- select change_data_id, entity_key, value_new, value_old from log.table_changes_data
52
- where change_id=a.change_id
53
- )q
54
- )b on 1=1
55
- where a.change_type != 'INSERT' and b.json_agg is not null and ((entity_id=$1 and entity_type=$2) or entity_id in (
56
- select communication_id from crm.communications where entity_id=$1 and entity_type=$2
57
- union all select checklist_id from crm.checklists where entity_id=$1 and entity_type=$2
58
- union all select file_id from crm.files where entity_id=$1 and entity_type=$2)
59
- )
45
+ history: `SELECT change_id, entity_id, entity_type, change_type, change_date, a.change_user_id, a.uid, a.cdate, b.json_agg as changes,
46
+ ${username} as username, u.login, u.avatar
47
+ FROM log.table_changes a
48
+ left join admin.users u on a.change_user_id = u.uid
49
+ left join lateral(
50
+ select json_agg(row_to_json(q)) from (
51
+ select change_data_id, entity_key, value_new, value_old from log.table_changes_data
52
+ where change_id=a.change_id
53
+ )q
54
+ )b on 1=1
55
+ where a.change_type != 'INSERT' and b.json_agg is not null and ((entity_id=$1 and entity_type=$2) or entity_id in (
56
+ select communication_id from crm.communications where entity_id=$1 and entity_type=$2
57
+ union all select checklist_id from crm.checklists where entity_id=$1 and entity_type=$2
58
+ union all select file_id from crm.files where entity_id=$1 and entity_type=$2)
59
+ )
60
60
  order by cdate desc limit 100`,
61
61
  checklist: pg.pk["admin.users"]
62
- ? `SELECT checklist_id, entity_id, subject, is_done, done_date, c.uid, c.cdate, ${username} as username, u.login, u.avatar
63
- FROM crm.checklists c
64
- left join admin.users u on u.uid=c.uid
62
+ ? `SELECT checklist_id, entity_id, subject, is_done, done_date, c.uid, c.cdate, ${username} as username, u.login, u.avatar
63
+ FROM crm.checklists c
64
+ left join admin.users u on u.uid=c.uid
65
65
  where entity_id=$1 and entity_type=$2 order by cdate desc`
66
66
  : "SELECT checklist_id, entity_id, subject, is_done, done_date, uid, cdate FROM crm.checklists where entity_id=$1 and entity_type=$2 order by cdate desc",
67
67
  file: pg.pk["admin.users"]
68
- ? `SELECT file_id, entity_id, entity_type, file_path, uploaded_name, ext, size, c.uid, c.cdate, file_type, c.ismain,
69
- ${username} as username, u.login, isverified, u.avatar, u.uid as author, file_status
70
- FROM crm.files c
71
- left join admin.users u on u.uid=c.uid
68
+ ? `SELECT file_id, entity_id, entity_type, file_path, uploaded_name, ext, size, c.uid, c.cdate, file_type, c.ismain,
69
+ ${username} as username, u.login, isverified, u.avatar, u.uid as author, file_status
70
+ FROM crm.files c
71
+ left join admin.users u on u.uid=c.uid
72
72
  where entity_id=$1 and entity_type=$2 and file_status<>3 order by cdate desc`
73
- : `SELECT file_id, entity_id, entity_type, file_path, uploaded_name, ext, size, uid, cdate, file_type, ismain,
73
+ : `SELECT file_id, entity_id, entity_type, file_path, uploaded_name, ext, size, uid, cdate, file_type, ismain,
74
74
  isverified, uid as author, file_status FROM crm.files c where entity_id=$1 and entity_type=$2 and file_status<>3 order by cdate desc`,
75
75
  gallery: pg.pk["admin.users"]
76
- ? `SELECT file_id, entity_id, entity_type, file_path, uploaded_name, ext, size, c.uid, c.cdate, file_type, c.ismain,
77
- ${username} as username, u.login, u.avatar, isverified, u.avatar, c.uid as author, file_status
78
- FROM crm.files c
79
- left join admin.users u on u.uid=c.uid
76
+ ? `SELECT file_id, entity_id, entity_type, file_path, uploaded_name, ext, size, c.uid, c.cdate, file_type, c.ismain,
77
+ ${username} as username, u.login, u.avatar, isverified, u.avatar, c.uid as author, file_status
78
+ FROM crm.files c
79
+ left join admin.users u on u.uid=c.uid
80
80
  where entity_id=$1 and entity_type=$2 and file_status<>3 and ext = any($3) order by cdate desc`
81
- : `SELECT file_id, entity_id, entity_type, file_path, uploaded_name, ext, size, c.uid, c.cdate, file_type, ismain,
81
+ : `SELECT file_id, entity_id, entity_type, file_path, uploaded_name, ext, size, c.uid, c.cdate, file_type, ismain,
82
82
  isverified, uid as author, file_status FROM crm.files c where entity_id=$1 and entity_type=$2 and file_status<>3 and ext = any($3) order by cdate desc`,
83
83
  reaction: "SELECT count(*), reaction_type FROM crm.reactions c where entity_id=$1 and entity_type=$2 group by reaction_type",
84
84
  };
@@ -117,7 +117,7 @@ export default async function widgetEntityGet({ type, entityType, objectid, uid,
117
117
  }
118
118
  const cdateColumn = columns.find((col) => ["cdate", "created_at"].includes(col.name))?.name;
119
119
  const editorDateColumn = columns.find((col) => ["editor_date", "updated_at"].includes(col.name))?.name;
120
- const q1 = `select ${username} as author, u.login ${cdateColumn ? `,a.${cdateColumn} as cdate` : ""} ${editorDateColumn ? `,a.${editorDateColumn} as editor_date` : ""} from ${entityType} a
120
+ const q1 = `select ${username} as author, u.login ${cdateColumn ? `,a.${cdateColumn} as cdate` : ""} ${editorDateColumn ? `,a.${editorDateColumn} as editor_date` : ""} from ${entityType} a
121
121
  left join admin.users u on a.${authorIdColumn}=u.uid where a.${pk}=$1 limit 1`;
122
122
  const data = pg.pk["admin.users"] && pk && entityType
123
123
  ? await pg
@@ -75,9 +75,9 @@ export default async function widgetEntitySet({ type, entityType, objectid, id,
75
75
  uid,
76
76
  }).then((r) => r.rows?.[0]);
77
77
  if (type === "gallery") {
78
- await pg.query(`update crm.files set ismain=true
79
- where entity_id=$1 and entity_type=$2
80
- and file_id=$3
78
+ await pg.query(`update crm.files set ismain=true
79
+ where entity_id=$1 and entity_type=$2
80
+ and file_id=$3
81
81
  and (select count(*) = 0 from crm.files where entity_id=$1 and entity_type=$2 and ismain)`, [objectid, entityType, row?.file_id]);
82
82
  }
83
83
  return {
@@ -119,7 +119,7 @@ export default async function widgetEntitySet({ type, entityType, objectid, id,
119
119
  });
120
120
  // put w/ out file
121
121
  if (type === "gallery" && body?.ismain && id) {
122
- await pg.query(`update crm.files set ismain=false
122
+ await pg.query(`update crm.files set ismain=false
123
123
  where entity_id=$1 and entity_type=$2 and file_id<>$3`, [objectid, entityType, id]);
124
124
  }
125
125
  return {
@@ -1,102 +1,102 @@
1
- <!DOCTYPE html>
2
- <html lang="en" dir="" class="relative min-h-full">
3
- <head>
4
- <!-- scripts -->
5
- <script src="https://cdn.tailwindcss.com"></script>
6
- </head>
7
- <body class="bg-white dark:bg-neutral-900">
8
- <main class="flex min-h-full">
9
-
10
- <!-- Content -->
11
- <div class="grow px-5">
12
- <div class="h-full min-h-screen sm:w-[448px] flex flex-col justify-center mx-auto space-y-5">
13
-
14
- {{#if codes}}
15
- <div><h1 class="text-xl sm:text-2xl font-semibold text-gray-800 dark:text-neutral-200">Your recovery codes:</h1></div>
16
- {{/if}}
17
- {{#if recovery}}
18
- <div>
19
- <a href="/2factor/recovery" class="py-2.5 px-3 w-full inline-flex justify-center items-center gap-x-2 text-sm font-semibold rounded-lg border border-transparent bg-blue-600 text-white hover:bg-blue-700 disabled:opacity-50 disabled:pointer-events-none dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-neutral-600">
20
- Send recovery code via E-mail
21
- </a>
22
- <h1 class="text-xl sm:text-2xl font-semibold text-gray-800 dark:text-neutral-200">Reset 2factor settings via recovery code:</h1>
23
- </div>
24
- {{/if}}
25
-
26
- <form action="/2factor/recovery" method="post">
27
- <div class="space-y-5">
28
- <div>
29
- <label for="hs-pro-dale" class="block mb-2 text-sm font-medium text-gray-800 dark:text-white">
30
- Code
31
- </label>
32
-
33
- {{#if query.recovery}}
34
- <input type="text" name="code" id="hs-pro-dale" class="py-2.5 px-3 block w-full border-gray-200 rounded-lg text-sm placeholder:text-gray-400 focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none dark:bg-transparent dark:border-neutral-700 dark:text-neutral-300 dark:placeholder:text-white/60 dark:focus:ring-neutral-600" placeholder="999999">
35
- {{^}}
36
-
37
- <input type="text" name="code" class="form-input hidden">
38
- <div class="space-y-5">
39
- <div class="my-3 flex gap-x-2" data-hs-pin-input>
40
- <input id="input-1" type="text" class="input-code block w-[38px] h-[38px] text-center border rounded-md focus:outline-blue-600" >
41
- <input id="input-2" type="text" class="input-code block w-[38px] h-[38px] text-center border rounded-md focus:outline-blue-600" >
42
- <input id="input-3" type="text" class="input-code block w-[38px] h-[38px] text-center border rounded-md focus:outline-blue-600" >
43
- <input id="input-4" type="text" class="input-code block w-[38px] h-[38px] text-center border rounded-md focus:outline-blue-600" >
44
- <input id="input-5" type="text" class="input-code block w-[38px] h-[38px] text-center border rounded-md focus:outline-blue-600" >
45
- <input id="input-6" type="text" class="input-code block w-[38px] h-[38px] text-center border rounded-md focus:outline-blue-600" >
46
- </div>
47
- </div>
48
- {{/if}}
49
- </div>
50
-
51
- <button type="submit" class="py-2.5 px-3 w-full inline-flex justify-center items-center gap-x-2 text-sm font-semibold rounded-lg border border-transparent bg-blue-600 text-white hover:bg-blue-700 disabled:opacity-50 disabled:pointer-events-none dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-neutral-600">
52
- Reset 2factor settings
53
- </button>
54
- </div>
55
- </form>
56
-
57
- </div>
58
- </div>
59
- <!-- End Content -->
60
- </main><script>
61
- const inputs = document.querySelectorAll(".input-code");
62
- const formInput = document.querySelector(".form-input");
63
-
64
- const inputTextToInput = (event) => {
65
- const input = event.target;
66
- const value = input.value;
67
-
68
- if (value.length > 1) {
69
- input.value = value.slice(-1);
70
- }
71
-
72
- const currentIndex = Array.from(inputs).indexOf(input);
73
- if (value && currentIndex < inputs.length - 1) {
74
- inputs[currentIndex + 1].focus();
75
- }
76
-
77
- const combinedValue = Array.from(inputs)
78
- .map((input) => input.value)
79
- .join("");
80
-
81
- formInput.value = combinedValue;
82
- };
83
-
84
- const handleBackspace = (event) => {
85
- const input = event.target;
86
-
87
- if (event.key === "Backspace" && input.value === "") {
88
- const currentIndex = Array.from(inputs).indexOf(input);
89
- if (currentIndex > 0) {
90
- inputs[currentIndex - 1].focus();
91
- }
92
- }
93
- };
94
-
95
- inputs.forEach((input) => {
96
- input.addEventListener("input", inputTextToInput);
97
- input.addEventListener("keydown", handleBackspace);
98
- });
99
- </script>
100
- </body>
101
-
1
+ <!DOCTYPE html>
2
+ <html lang="en" dir="" class="relative min-h-full">
3
+ <head>
4
+ <!-- scripts -->
5
+ <script src="https://cdn.tailwindcss.com"></script>
6
+ </head>
7
+ <body class="bg-white dark:bg-neutral-900">
8
+ <main class="flex min-h-full">
9
+
10
+ <!-- Content -->
11
+ <div class="grow px-5">
12
+ <div class="h-full min-h-screen sm:w-[448px] flex flex-col justify-center mx-auto space-y-5">
13
+
14
+ {{#if codes}}
15
+ <div><h1 class="text-xl sm:text-2xl font-semibold text-gray-800 dark:text-neutral-200">Your recovery codes:</h1></div>
16
+ {{/if}}
17
+ {{#if recovery}}
18
+ <div>
19
+ <a href="/2factor/recovery" class="py-2.5 px-3 w-full inline-flex justify-center items-center gap-x-2 text-sm font-semibold rounded-lg border border-transparent bg-blue-600 text-white hover:bg-blue-700 disabled:opacity-50 disabled:pointer-events-none dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-neutral-600">
20
+ Send recovery code via E-mail
21
+ </a>
22
+ <h1 class="text-xl sm:text-2xl font-semibold text-gray-800 dark:text-neutral-200">Reset 2factor settings via recovery code:</h1>
23
+ </div>
24
+ {{/if}}
25
+
26
+ <form action="/2factor/recovery" method="post">
27
+ <div class="space-y-5">
28
+ <div>
29
+ <label for="hs-pro-dale" class="block mb-2 text-sm font-medium text-gray-800 dark:text-white">
30
+ Code
31
+ </label>
32
+
33
+ {{#if query.recovery}}
34
+ <input type="text" name="code" id="hs-pro-dale" class="py-2.5 px-3 block w-full border-gray-200 rounded-lg text-sm placeholder:text-gray-400 focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none dark:bg-transparent dark:border-neutral-700 dark:text-neutral-300 dark:placeholder:text-white/60 dark:focus:ring-neutral-600" placeholder="999999">
35
+ {{^}}
36
+
37
+ <input type="text" name="code" class="form-input hidden">
38
+ <div class="space-y-5">
39
+ <div class="my-3 flex gap-x-2" data-hs-pin-input>
40
+ <input id="input-1" type="text" class="input-code block w-[38px] h-[38px] text-center border rounded-md focus:outline-blue-600" >
41
+ <input id="input-2" type="text" class="input-code block w-[38px] h-[38px] text-center border rounded-md focus:outline-blue-600" >
42
+ <input id="input-3" type="text" class="input-code block w-[38px] h-[38px] text-center border rounded-md focus:outline-blue-600" >
43
+ <input id="input-4" type="text" class="input-code block w-[38px] h-[38px] text-center border rounded-md focus:outline-blue-600" >
44
+ <input id="input-5" type="text" class="input-code block w-[38px] h-[38px] text-center border rounded-md focus:outline-blue-600" >
45
+ <input id="input-6" type="text" class="input-code block w-[38px] h-[38px] text-center border rounded-md focus:outline-blue-600" >
46
+ </div>
47
+ </div>
48
+ {{/if}}
49
+ </div>
50
+
51
+ <button type="submit" class="py-2.5 px-3 w-full inline-flex justify-center items-center gap-x-2 text-sm font-semibold rounded-lg border border-transparent bg-blue-600 text-white hover:bg-blue-700 disabled:opacity-50 disabled:pointer-events-none dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-neutral-600">
52
+ Reset 2factor settings
53
+ </button>
54
+ </div>
55
+ </form>
56
+
57
+ </div>
58
+ </div>
59
+ <!-- End Content -->
60
+ </main><script>
61
+ const inputs = document.querySelectorAll(".input-code");
62
+ const formInput = document.querySelector(".form-input");
63
+
64
+ const inputTextToInput = (event) => {
65
+ const input = event.target;
66
+ const value = input.value;
67
+
68
+ if (value.length > 1) {
69
+ input.value = value.slice(-1);
70
+ }
71
+
72
+ const currentIndex = Array.from(inputs).indexOf(input);
73
+ if (value && currentIndex < inputs.length - 1) {
74
+ inputs[currentIndex + 1].focus();
75
+ }
76
+
77
+ const combinedValue = Array.from(inputs)
78
+ .map((input) => input.value)
79
+ .join("");
80
+
81
+ formInput.value = combinedValue;
82
+ };
83
+
84
+ const handleBackspace = (event) => {
85
+ const input = event.target;
86
+
87
+ if (event.key === "Backspace" && input.value === "") {
88
+ const currentIndex = Array.from(inputs).indexOf(input);
89
+ if (currentIndex > 0) {
90
+ inputs[currentIndex - 1].focus();
91
+ }
92
+ }
93
+ };
94
+
95
+ inputs.forEach((input) => {
96
+ input.addEventListener("input", inputTextToInput);
97
+ input.addEventListener("keydown", handleBackspace);
98
+ });
99
+ </script>
100
+ </body>
101
+
102
102
  </html>