backend-plus 2.0.0-rc.13 → 2.0.0-rc.15

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.
@@ -161,5 +161,9 @@ a.disabled
161
161
  font-size 80%
162
162
  text-align right
163
163
  color #777
164
+ > .json-container
165
+ position sticky
166
+ top 5%
167
+ bottom 5%
164
168
 
165
169
 
@@ -12,9 +12,7 @@ export type LangId = 'en'|'es'|'etc...';
12
12
 
13
13
  export type Server=net.Server;
14
14
 
15
- export interface CoreFunctionParameters{
16
- [key:string]: any
17
- }
15
+ export type CoreFunctionParameters<T extends Record<string, any>> = T;
18
16
 
19
17
  export type MarkdownDoc = 'markdown documentation with `` can content newlines. The identation of the first line is deleted in all others'|'etc...';
20
18
 
@@ -365,6 +363,129 @@ export interface Caches {
365
363
  procedures:Record<string, {timestamp:number, result:any}>
366
364
  }
367
365
 
366
+ export interface AppConfigBin { // executables in SO
367
+ "zip-password-parameter-flag": string // parameter to pass the password to the zipper
368
+ "zip-password-prefix": string // password prefix
369
+ "zip-fixed-parameters":string // fixed parameters to pass to zipper
370
+ }
371
+
372
+ export interface AppConfig {
373
+ package: {
374
+ version: string
375
+ }
376
+ server: {
377
+ "base-url": string // rool path in the url
378
+ port: number // port of the API services
379
+ "session-store": string // strategies to store session info
380
+ "ip-replacer": string // ip that can be not showed or deduced in logs
381
+ "silent-startup": boolean // less logs when startup
382
+ "kill-9": string // a way to kill from URL with a token
383
+ bitacoraSchema: string
384
+ bitacoraTableName: string
385
+ }
386
+ db: {
387
+ motor: 'postgresql'
388
+ database: string
389
+ user: string
390
+ password: string
391
+ schema: string
392
+ search_path: string
393
+ tablespace: string // for creation scripts
394
+ "min-version": string // min version of the motor needed
395
+ nodb: boolean // if there is no database needed in the app
396
+ no_login: boolean // if no login is needed. Used only for all public sites
397
+ "downloadable-backup-path": string // OS path of the encrypted downloadable backup
398
+ }
399
+ login: {
400
+ schema: string // schema of the user table
401
+ table: string // user table
402
+ userFieldname: string // fieldname in user table that stores the user name
403
+ passFieldname: string // fieldname in user table that stores the password hash
404
+ rolFieldname: string // fieldname in user table that stores the rol
405
+ unloggedLandPage: string // land page when there is no user logged when the backend has public services
406
+ noLoggedUrlPath: string // path of non logged users when the backend has no public services
407
+ "preserve-case": boolean // preserve the case of the user name
408
+ activeClausule: string // SQL expression over the user table to check if a user is active
409
+ lockedClausule: string // SQL expression over the user table to check if a user is locked
410
+ disableChangePassword: boolean // disallow password change
411
+ skipBitacora: boolean // don't register logins
412
+ keepAlive: number // secs to keep alive a session if only keep alive request where received
413
+ plus: {
414
+ userFieldName:string
415
+ store:{
416
+ module: string
417
+ }
418
+ }
419
+ forget: { // forget password configurations:
420
+ urlPath: string // url sent by mail. default: `/new-pass`
421
+ urlPathOk: string // confirmation page
422
+ mailFields: string[] // fields for the forget pass mail
423
+
424
+ }
425
+ "double-dragon": boolean // app user must match db user
426
+ }
427
+ install: {
428
+ "table-data-dir": string // SO path to the .tab files in the db creation script
429
+ dump: { // configuration of --dump-db, the db creation script
430
+ "drop-his": boolean // include drop schema his in the db creation script
431
+ db: {
432
+ owner: string
433
+ extensions: string[] // extensions to be installed (gist, pg_trgm, pgcrypto)
434
+ enances: 'file' // if the enances must be dumped in a separate file
435
+ // from here info to set the owner and replace owner and user used in devel when script creation
436
+ "owner4special-scripts": string
437
+ "user4special-scripts": string
438
+ "apply-generic-user-replaces": string
439
+ }
440
+ "admin-can-create-tables": boolean // for apps that allows the user to create tables
441
+ "skip-content": boolean // don't create data from "table-data-dir"
442
+ folders: string //
443
+ scripts: {
444
+ prepare: string // SO path to the prepare scripts that will be run before the functions creations and inserts
445
+ "post-adapt": string // SO path to the post-adapt scripts that will be run after data inserts (of .tab tables)
446
+ }
447
+ }
448
+ }
449
+ "client-setup": { // front-end config
450
+ title:string // title of the app (common sufix of the title bar)
451
+ }
452
+ log: {
453
+ "serve-content": never
454
+ req: {
455
+ "keep-alive": boolean
456
+ }
457
+ db: {
458
+ "last-error": boolean // store last db error in a log file
459
+ devel: boolean //
460
+ "on-demand": string // if log db level can be changed on the fly
461
+ until: string | Date // full log until...
462
+ results: boolean // if query results must be included in full db logs
463
+ }
464
+ session: boolean // if all session activity must be logged
465
+ }
466
+ devel: {
467
+ delay: number // msec avg random delay in API responses (to emulate slow nets)
468
+ "cache-content": boolean // if the cache header must be sent to the client (when no devel config the default is true)
469
+ forceShowAsEditable: boolean // force "editable" behavior in grids
470
+ }
471
+ mailer: { // config to send mails
472
+ conn: string // connection string
473
+ "mail-info": {} // static mail config
474
+ supervise: {
475
+ to: string // email addres of the supervisor
476
+ event: {
477
+ }
478
+ }
479
+ }
480
+ bin: AppConfigBin
481
+ data: {
482
+ transformers: {
483
+ text: string // define the inputTransformers for text comming from the fron-end via the API
484
+ }
485
+ }
486
+ skipUnknownFieldsAtImport: boolean // if unknown fields must be skipped by default in import
487
+ }
488
+
368
489
  export class AppBackend{
369
490
  procedures:ProcedureDef[]
370
491
  procedure:{ [key:string]:ProcedureDef }
@@ -372,7 +493,7 @@ export class AppBackend{
372
493
  getTableDefinition: TableDefinitionsGetters
373
494
  tableStructures: TableDefinitions
374
495
  db: MotorDb
375
- config: any
496
+ config: AppConfig
376
497
  rootPath: string
377
498
  caches:Caches
378
499
  fieldDomain:{[k:string]:Partial<FieldDefinition>}
@@ -461,7 +461,13 @@ AppBackend.prototype.setStaticConfig = function setStaticConfig(defConfigYamlStr
461
461
  }
462
462
 
463
463
  AppBackend.prototype.configList = function configList(){
464
- var list=[this.staticConfig];
464
+ var list=[
465
+ {
466
+ package:{
467
+ version: packagejson.version
468
+ }
469
+ },
470
+ this.staticConfig];
465
471
  if(!this.staticConfig["client-setup"]?.title && fs.existsSync(this.rootPath+'/def-config.yaml')){
466
472
  console.log('DEPRECATED!!!!!!')
467
473
  console.error('ERROR el def-config hay que ponerlo dentro de staticConfig');
@@ -1929,6 +1935,9 @@ AppBackend.prototype.addUnloggedServices = function addUnloggedServices(mainApp,
1929
1935
  // http://localhost:3033/img/login-logo-icon.png
1930
1936
  mainApp.get(Path.posix.join(baseUrl,'/img/login-logo-icon.png'), async function(req,res,next){
1931
1937
  var buscar = [
1938
+ 'unlogged/img/login-logo-icon.svg',
1939
+ 'dist/unlogged/img/login-logo-icon.svg',
1940
+ 'dist/client/unlogged/img/login-logo-icon.svg',
1932
1941
  'unlogged/img/login-logo-icon.png',
1933
1942
  'dist/unlogged/img/login-logo-icon.png',
1934
1943
  'dist/client/unlogged/img/login-logo-icon.png',
@@ -2878,8 +2887,14 @@ AppBackend.prototype.dumpDbSchemaPartial = async function dumpDbSchemaPartial(pa
2878
2887
  if (err.code != 'ENOENT') throw err;
2879
2888
  try {
2880
2889
  var allTableContent = await fs.readFile('install/local-dump.psql','utf-8');
2881
- var startIndex = allTableContent.search(/\n-- Data for Name: /);
2882
- var lastIndex = allTableContent.search(/\nSELECT pg_catalog.setval/);
2890
+ var startIndex = allTableContent.indexOf('-- Data for Name: ');
2891
+ console.log('startIndex', startIndex);
2892
+ var lastUseful = allTableContent.lastIndexOf('\nSELECT pg_catalog.setval')
2893
+ console.log('lastUseful', lastUseful);
2894
+ if (lastUseful == -1) lastUseful = allTableContent.lastIndexOf('\n\\.\n');
2895
+ console.log('lastUseful', lastUseful);
2896
+ var lastIndex = allTableContent.indexOf('\n--', lastUseful);
2897
+ console.log('lastIndex', lastIndex);
2883
2898
  allTableData = allTableContent.slice(startIndex, lastIndex);
2884
2899
  } catch(err) {
2885
2900
  if (err.code != 'ENOENT') throw err;
@@ -3003,27 +3018,33 @@ AppBackend.prototype.dumpDbSchemaPartial = async function dumpDbSchemaPartial(pa
3003
3018
  }
3004
3019
  let installFolders = be.config.install.dump.folders ?? ['install']
3005
3020
  let texts = await Promise.all(
3006
- ['prepare.sql','pre-adapt.sql','adapt.sql']
3007
- .concat(be.config.install.dump.scripts['prepare'])
3008
- .concat(be.config.install.dump.scripts['post-adapt'])
3009
- .map(async function(fileName){
3010
- if (!fileName) return '';
3021
+ [
3022
+ ['prepare.sql'],
3023
+ ['pre-adapt.sql'].concat(be.config.install.dump.scripts['pre-adapt']),
3024
+ ['adapt.sql'],
3025
+ be.config.install.dump.scripts['prepare'] ?? [],
3026
+ be.config.install.dump.scripts['post-adapt'] ?? []
3027
+ ]
3028
+ .map(async function(fileNames){
3029
+ if (!fileNames) return '';
3011
3030
  var i = 0;
3012
- var content;
3013
- do {
3014
- var folder = installFolders[i];
3015
- try{
3016
- content = await fs.readFile(be.rootPath+'/'+folder+'/'+fileName, {encoding:'UTF8'});
3017
- } catch (err) {
3018
- if(err.code!='ENOENT') throw err;
3019
- }
3020
- i++;
3021
- } while (i < installFolders.length && !content);
3022
- if (!content) {
3023
- return '-- no '+fileName+'\n';
3024
- } else {
3025
- return '-- '+folder+'/'+fileName+'\n'+content;
3026
- };
3031
+ return (await Promise.all(fileNames.map(async fileName => {
3032
+ var content;
3033
+ do {
3034
+ var folder = installFolders[i];
3035
+ try{
3036
+ content = await fs.readFile(be.rootPath+'/'+folder+'/'+fileName, {encoding:'UTF8'});
3037
+ } catch (err) {
3038
+ if(err.code!='ENOENT') throw err;
3039
+ }
3040
+ i++;
3041
+ } while (i < installFolders.length && !content);
3042
+ if (!content) {
3043
+ return '-- no '+fileName+'\n';
3044
+ } else {
3045
+ return '-- '+folder+'/'+fileName+'\n'+content;
3046
+ };
3047
+ }))).join('\n')
3027
3048
  })
3028
3049
  );
3029
3050
 
@@ -3053,7 +3074,7 @@ AppBackend.prototype.dumpDbSchemaPartial = async function dumpDbSchemaPartial(pa
3053
3074
  '\n-- common'+
3054
3075
  common+'\n'+
3055
3076
  (complete? '\n\n--prepare.sql\n'+ texts[0]+'\n\n' :'' )+
3056
- (complete? texts.slice(3,3+prepareList.length).join('\n\n')+'\n\n' : '' )+
3077
+ (complete? texts[3] + '\n\n' : '' )+
3057
3078
  '\n-- functions\n' + functionLines.join('\n')+
3058
3079
  '\n-- lines \n' + lines.join('\n')+
3059
3080
  (complete? ('\n\n-- pre-ADAPTs\n'+texts[1]+'\n\n') : '' )+
@@ -3063,7 +3084,7 @@ AppBackend.prototype.dumpDbSchemaPartial = async function dumpDbSchemaPartial(pa
3063
3084
  '\n-- FKs\n' + fkLines.join('\n')+
3064
3085
  '\n-- index\n' + indexLines.join('\n')+
3065
3086
  '\n-- policies\n' + policyLines.join('\n')+
3066
- (complete? texts.slice(3+prepareList.length).join('\n\n')+'\n\n' : '' )+
3087
+ (complete? texts[4] + '\n\n' : '' )+
3067
3088
  (complete? (be.config.install.dump.enances==='inline'?enancePart:'') :'')
3068
3089
  ).replace(/\uFEFF/g /*inner BOM replacing*/,'\n\n').replace(
3069
3090
  new RegExp(escapeRegExp(db.quoteIdent(be.config.install.dump.db["owner4special-scripts"])),'g'),
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "backend-plus",
3
3
  "description": "Backend for the anti Pareto rule",
4
- "version": "2.0.0-rc.13",
4
+ "version": "2.0.0-rc.15",
5
5
  "author": "Codenautas <codenautas@googlegroups.com>",
6
6
  "license": "MIT",
7
7
  "repository": "codenautas/backend-plus",
@@ -30,16 +30,16 @@
30
30
  ],
31
31
  "dependencies": {
32
32
  "@upgraded/locate-path": "^6.0.0-alfa.1",
33
- "ajax-best-promise": "^0.4.0",
33
+ "ajax-best-promise": "^0.4.2",
34
34
  "backend-skins": "^0.1.15",
35
35
  "best-globals": "^1.1.4",
36
36
  "big.js": "^6.2.1",
37
37
  "body-parser": "^1.20.2",
38
38
  "cast-error": "^0.1.1",
39
- "castellano": "^0.1.3",
39
+ "castellano": "^0.1.4",
40
40
  "connect-pg-simple": "^9.0.1",
41
41
  "cookie-parser": "^1.4.6",
42
- "dialog-promise": "^0.9.15",
42
+ "dialog-promise": "^0.10.0",
43
43
  "discrepances": "^0.2.8",
44
44
  "express": "^4.19.2",
45
45
  "express-session": "^1.18.0",
@@ -49,7 +49,7 @@
49
49
  "js-yaml": "^4.1.0",
50
50
  "json4all": "^1.3.0-beta.1",
51
51
  "lazy-some": "^0.1.0",
52
- "like-ar": "^0.4.0",
52
+ "like-ar": "^0.4.1",
53
53
  "login-plus": "^1.7.1",
54
54
  "memorystore": "^1.6.7",
55
55
  "mini-tools": "^1.12.1",
@@ -63,7 +63,7 @@
63
63
  "read-yaml-promise": "^1.0.2",
64
64
  "regexplicit": "^0.1.3",
65
65
  "require-bro": "^0.3.1",
66
- "self-explain": "^0.10.22",
66
+ "self-explain": "^0.11.0",
67
67
  "serve-content": "^0.3.19",
68
68
  "session-file-store": "^1.5.0",
69
69
  "sql-tools": "^0.1.2",
@@ -82,8 +82,8 @@
82
82
  "@types/js-yaml": "^4.0.9",
83
83
  "@types/mocha": "^10.0.6",
84
84
  "@types/multiparty": "~0.0.36",
85
- "@types/node": "^20.12.6",
86
- "@types/nodemailer": "^6.4.14",
85
+ "@types/node": "^20.12.12",
86
+ "@types/nodemailer": "^6.4.15",
87
87
  "@types/numeral": "~2.0.5",
88
88
  "@types/session-file-store": "^1.2.5",
89
89
  "@types/stack-trace": "~0.0.33",
@@ -99,11 +99,11 @@
99
99
  "kill-9": "~0.4.3",
100
100
  "mocha": "^10.4.0",
101
101
  "nyc": "^15.1.0",
102
- "puppeteer": "^22.6.3",
103
- "sinon": "^17.0.1",
104
- "supertest": "^6.3.4",
102
+ "puppeteer": "^22.9.0",
103
+ "sinon": "^18.0.0",
104
+ "supertest": "^7.0.0",
105
105
  "types.d.ts": "~0.6.21",
106
- "typescript": "^5.4.4",
106
+ "typescript": "^5.4.5",
107
107
  "why-is-node-running": "^2.2.2"
108
108
  },
109
109
  "engines": {
@@ -495,13 +495,27 @@ function agregar_json_default_ubicaciones(div, o, a){
495
495
  var table = div2.laTabla;
496
496
  var row = table.insertRow(-1);
497
497
  var cellName = row.insertCell(-1);
498
- cellName.className='attr-name';
499
- cellName.textContent = a;
498
+ agregar_class_textInDiv(cellName, 'attr-name', a)
500
499
  var cell = row.insertCell(-1);
501
500
  cell.colSpan=99;
502
501
  return {title:cellName, data:cell, skip:o[a] == null}
503
502
  }
504
503
 
504
+ /**
505
+ *
506
+ * @param {HTMLTableDataElement} td
507
+ * @param {string|number} text
508
+ * @param {string} className
509
+ */
510
+ function agregar_class_textInDiv(td, className, text){
511
+ var div = document.createElement('div');
512
+ td.className = className;
513
+ div.className = 'json-container';
514
+ div.textContent = text;
515
+ td.innerHTML = '';
516
+ td.appendChild(div);
517
+ }
518
+
505
519
  /**
506
520
  *
507
521
  * @param {HTMLElement} div
@@ -524,9 +538,7 @@ function agregar_json(div, o, ubicaciones=agregar_json_default_ubicaciones){
524
538
  if(o[a]!=null){
525
539
  var row = table.insertRow(-1);
526
540
  var cellName = row.insertCell(-1);
527
- cellName.className='row-num';
528
- // @ts-ignore numero y texto
529
- cellName.textContent = isNaN(a)?a:Number(a)+1;
541
+ agregar_class_textInDiv(cellName, 'row-num', isNaN(a)?a:Number(a)+1);
530
542
  agregar_json(row, o[a], function(div, _o, a){
531
543
  // @ts-ignore sé que es Row
532
544
  /** @type {HTMLTableRowElement} */
@@ -554,11 +566,9 @@ function agregar_json(div, o, ubicaciones=agregar_json_default_ubicaciones){
554
566
  if(!cells.skip){
555
567
  if(cells.title){
556
568
  if(o instanceof Array && !isNaN(a)){
557
- cells.title.className='row-num';
558
- cells.title.textContent = Number(a) + 1;
569
+ agregar_class_textInDiv(cells.title, 'row-num', Number(a) + 1);
559
570
  }else{
560
- cells.title.className='attr-name';
561
- cells.title.textContent = a;
571
+ agregar_class_textInDiv(cells.title, 'attr-name', a);
562
572
  }
563
573
  }
564
574
  agregar_json(cells.data, o[a]);
@@ -566,13 +576,16 @@ function agregar_json(div, o, ubicaciones=agregar_json_default_ubicaciones){
566
576
  }
567
577
  }
568
578
  }else{
569
- div.className='plain-content';
579
+ var textContent;
570
580
  if(typeof o == "boolean"){
571
- div.textContent = o?'Sí':'No'
581
+ textContent = o ? 'Sí' : 'No'
572
582
  }else if(o && o instanceof Date && o.isRealDate){
573
- div.textContent = o.toDmy();
583
+ textContent = o.toDmy();
574
584
  }else{
575
- div.textContent = o.toLocaleString();
585
+ textContent = o.toLocaleString();
586
+ }
587
+ if (textContent) {
588
+ agregar_class_textInDiv(div, 'plain-content', textContent)
576
589
  }
577
590
  }
578
591
  }