backend-plus 2.5.0-betha.3 → 2.5.2-betha.10

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.
@@ -172,6 +172,10 @@ export type SequenceDefinition = {
172
172
  name:string
173
173
  firstValue:number
174
174
  prefix?:string /* Prefix for the generated value */
175
+ }
176
+ export type SequenceMadMaxDefinition = {
177
+ madMax: string[] // grouping of mad max sequences
178
+ firstValue?: number
175
179
  }
176
180
  export type ExportMetadataDefinition={ /* TODO: define */ }
177
181
  export type PostInputOptions='upperSpanish' | 'upperWithoutDiacritics' | 'parseDecimal'
@@ -218,11 +222,21 @@ export type FieldDefinition = EditableDbDefinition & {
218
222
  alwaysShow?:boolean /* show when appears in fixed fields */
219
223
  suggestingKeys?:string[]
220
224
  postInput?:PostInputOptions
221
- } & ({} | {
222
- sequence:SequenceDefinition
223
- nullable:true
224
- editable:false
225
- })
225
+ } & (
226
+ {
227
+ sequence?: undefined
228
+ nullable?: boolean
229
+ editable?: boolean
230
+ } | {
231
+ sequence: SequenceDefinition
232
+ nullable: true
233
+ editable: false
234
+ } | {
235
+ sequence: SequenceMadMaxDefinition
236
+ nullable: true
237
+ editable: boolean
238
+ }
239
+ );
226
240
  export type EditableDbDefinition = {
227
241
  editable?:boolean
228
242
  allow?:{
@@ -395,6 +409,7 @@ export interface AppConfigServer
395
409
  "kill-9": string // a way to kill from URL with a token
396
410
  bitacoraSchema: string
397
411
  bitacoraTableName: string
412
+ allowedHosts:string[] //API allowed hosts
398
413
  }
399
414
  export interface AppConfigDb
400
415
  {
@@ -414,7 +429,6 @@ export interface AppConfigLogin
414
429
  {
415
430
  schema: string // schema of the user table
416
431
  table: string // user table
417
- from: string // complete expression to get table or join where get the user
418
432
  userFieldname: string // fieldname in user table that stores the user name
419
433
  passFieldname: string // fieldname in user table that stores the password hash
420
434
  rolFieldname: string // fieldname in user table that stores the rol
@@ -20,6 +20,7 @@ MiniTools.globalOpts.serveErr.propertiesWhiteList=['message','detail','code','ta
20
20
  var crypto = require('crypto');
21
21
  var serveContent = require('serve-content');
22
22
  var pg = require('pg-promise-strict');
23
+ var pgTriggers = require('pg-triggers');
23
24
  var SessionFileStore = require('session-file-store');
24
25
  var memorystore = require('memorystore');
25
26
  var jsToHtml=require('js-to-html');
@@ -30,6 +31,7 @@ var locatePath = require('@upgraded/locate-path');
30
31
  var jsYaml = require('js-yaml');
31
32
  var nodemailer = require('nodemailer');
32
33
  var os = require('os');
34
+ const cors = require('cors');
33
35
 
34
36
  var likeAr = require('like-ar');
35
37
 
@@ -902,6 +904,18 @@ AppBackend.prototype.start = function start(opts){
902
904
  }).then(async function(){
903
905
  mainApp = express();
904
906
  //mainApp.use(cookieParser());
907
+ const whitelist = ['localhost'].concat(be.config.server.allowedHosts||[]); // Agrega aquí los orígenes de tus aplicaciones
908
+ const corsOptions = {
909
+ origin: function (origin, callback) {
910
+ if (whitelist.some((element)=>origin?.includes(element)) || !origin){
911
+ callback(null, true);
912
+ }else{
913
+ callback(new Error('Not allowed by CORS'));
914
+ }
915
+ },
916
+ credentials: true
917
+ };
918
+ mainApp.use(cors(corsOptions));
905
919
  mainApp.use(bodyParser.urlencoded({extended:true, limit: '50mb'}));
906
920
  mainApp.use(function(req,res,next){
907
921
  if((req.headers['content-type']||'').match(/^multipart\/form-data/)){
@@ -2640,7 +2654,16 @@ AppBackend.prototype.dumpFkConstraint = function dumpFkConstraint(fk, tableDef,
2640
2654
  return {consName, clause, sourceFieldList};
2641
2655
  }
2642
2656
 
2657
+ AppBackend.prototype.isGeneratedSequence = function isGeneratedSequence(sequence, not){
2658
+ return sequence && ((!sequence.name && !sequence.madMax) == !not)
2659
+ }
2660
+
2661
+ AppBackend.prototype.isSequenceNonGenerated = function isSequenceNonGenerated(sequence){
2662
+ return this.isGeneratedSequence(sequence, true);
2663
+ }
2664
+
2643
2665
  AppBackend.prototype.dumpDbTableFields = function dumpDbTableFields(tableDef, opts = {}, complements = null){
2666
+ var be = this;
2644
2667
  var db = this.db;
2645
2668
  var fields=[];
2646
2669
  tableDef.fields.forEach(function(fieldDef){
@@ -2654,7 +2677,7 @@ AppBackend.prototype.dumpDbTableFields = function dumpDbTableFields(tableDef, op
2654
2677
  ' '+(fieldDef.dataLength?(fieldType=='text'?'varchar':fieldType)+'('+fieldDef.dataLength+')':fieldType)+
2655
2678
  (fieldDef.defaultValue!=null?' default '+db.quoteLiteral(fieldDef.defaultValue):'')+
2656
2679
  (fieldDef.defaultDbValue!=null?' default '+fieldDef.defaultDbValue:'')+
2657
- (fieldDef.sequence && !fieldDef.sequence.name?' generated always as identity':'')+
2680
+ (be.isGeneratedSequence(fieldDef.sequence)?' generated always as identity':'')+
2658
2681
  (fieldDef.generatedAs!=null?` generated always as (${fieldDef.generatedAs}) stored`:'')
2659
2682
  );
2660
2683
  if(complements){
@@ -2761,7 +2784,7 @@ AppBackend.prototype.dumpDbSchemaPartial = async function dumpDbSchemaPartial(pa
2761
2784
  lines.push('create table '+cualQuoteTableName+' (');
2762
2785
  var fields = be.dumpDbTableFields(tableDef, opts,
2763
2786
  function complements(fieldDef){
2764
- if(fieldDef.sequence && !fieldDef.sequence.name){
2787
+ if(be.isGeneratedSequence(fieldDef.sequence)){
2765
2788
  tablesWithStrictSequence[tableName]={}
2766
2789
  }
2767
2790
  if(fieldDef.typeName==='text' && !fieldDef.allowEmptyText){
@@ -2785,7 +2808,7 @@ AppBackend.prototype.dumpDbSchemaPartial = async function dumpDbSchemaPartial(pa
2785
2808
  ' alter column '+db.quoteIdent(fieldDef.name)+' set not null;'
2786
2809
  );
2787
2810
  }
2788
- if(fieldDef.sequence && fieldDef.sequence.name){
2811
+ if(be.isSequenceNonGenerated(fieldDef.sequence)){
2789
2812
  fieldsForSequences.push(fieldDef);
2790
2813
  }
2791
2814
  }
@@ -2888,19 +2911,26 @@ AppBackend.prototype.dumpDbSchemaPartial = async function dumpDbSchemaPartial(pa
2888
2911
  });
2889
2912
  lines.push(tableDef.sql.postCreateSqls);
2890
2913
  lines.push('');
2891
- fieldsForSequences.forEach(function(fieldDef) {
2914
+ await Promise.all(fieldsForSequences.map(async function(fieldDef) {
2892
2915
  var sequence = fieldDef.sequence;
2893
- lines.push("CREATE SEQUENCE "+db.quoteIdent(sequence.name)+" START "+db.quoteInteger(sequence.firstValue||1)+";");
2894
- lines.push(
2895
- "ALTER TABLE "+cualQuoteTableName+
2896
- " ALTER COLUMN "+db.quoteIdent(fieldDef.name)+
2897
- (sequence.prefix==null
2898
- ?" SET DEFAULT nextval("+db.quoteLiteral(sequence.name)+"::regclass);"
2899
- :" SET DEFAULT ("+db.quoteLiteral(sequence.prefix)+" || nextval("+db.quoteLiteral(sequence.name)+"::regclass)::text);"
2900
- )
2901
- );
2902
- lines.push('GRANT USAGE, SELECT ON SEQUENCE '+db.quoteIdent(sequence.name)+' TO '+user+';');
2903
- });
2916
+ if (sequence.name) {
2917
+ if (sequence.madMax) throw new Error('a sequence with madMax cannot have name');
2918
+ lines.push("CREATE SEQUENCE "+db.quoteIdent(sequence.name)+" START "+db.quoteInteger(sequence.firstValue||1)+";");
2919
+ lines.push(
2920
+ "ALTER TABLE "+cualQuoteTableName+
2921
+ " ALTER COLUMN "+db.quoteIdent(fieldDef.name)+
2922
+ (sequence.prefix==null
2923
+ ?" SET DEFAULT nextval("+db.quoteLiteral(sequence.name)+"::regclass);"
2924
+ :" SET DEFAULT ("+db.quoteLiteral(sequence.prefix)+" || nextval("+db.quoteLiteral(sequence.name)+"::regclass)::text);"
2925
+ )
2926
+ );
2927
+ lines.push('GRANT USAGE, SELECT ON SEQUENCE '+db.quoteIdent(sequence.name)+' TO '+user+';');
2928
+ } else if (sequence.madMax) {
2929
+ lines.push(await pgTriggers.dumpMaxIdTrigger(tableDef.sql.tableName, fieldDef.name, {grouping: sequence.madMax.grouping, firstValue: sequence.firstValue}));
2930
+ } else {
2931
+ throw new Error('a sequence without madMax nor name');
2932
+ }
2933
+ }));
2904
2934
  lines.push('');
2905
2935
  if(tableDef.sql.policies.enabled){
2906
2936
  policyLines.push(`ALTER TABLE ${cualQuoteTableName} ENABLE ROW LEVEL SECURITY;`);
@@ -2937,7 +2967,7 @@ AppBackend.prototype.dumpDbSchemaPartial = async function dumpDbSchemaPartial(pa
2937
2967
  }
2938
2968
  lines.push(`
2939
2969
  create or replace function set_app_user(p_user text) returns text
2940
- secirotu definer volatile language plpgsql
2970
+ security definer volatile language plpgsql
2941
2971
  as
2942
2972
  $body$
2943
2973
  declare
@@ -2953,8 +2983,11 @@ begin
2953
2983
  else
2954
2984
  select ${be.config.login.infoFieldList.map(fieldName => db.quoteIdent(fieldName)).join(', ')}
2955
2985
  into ${be.config.login.infoFieldList.map(fieldName => db.quoteIdent('v_'+fieldName)).join(', ')}
2956
- from usuarios u left join personas p using (idper)
2957
- where u."usuario" = p_user;
2986
+
2987
+ from ${(be.config.login.from ?? (
2988
+ (be.config.login.schema?be.db.quoteIdent(be.config.login.schema)+'.':'')+
2989
+ be.db.quoteIdent(be.config.login.table)))}
2990
+ where ${db.quoteIdent(be.config.login.userFieldName)} = p_user;
2958
2991
  ${be.config.login.infoFieldList.map(fieldName => `
2959
2992
  perform set_config('backend_plus._${fieldName}', v_${fieldName}, false);`).join('')}
2960
2993
 
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.5.0-betha.3",
4
+ "version": "2.5.2-betha.10",
5
5
  "author": "Codenautas <codenautas@googlegroups.com>",
6
6
  "license": "MIT",
7
7
  "repository": "codenautas/backend-plus",
@@ -35,12 +35,13 @@
35
35
  "best-globals": "^2.0.1",
36
36
  "big.js": "^7.0.1",
37
37
  "body-parser": "^2.2.0",
38
- "cast-error": "^0.1.1",
38
+ "cast-error": "^0.1.2",
39
39
  "castellano": "^0.1.4",
40
40
  "connect-pg-simple": "^10.0.0",
41
41
  "cookie-parser": "^1.4.7",
42
- "dialog-promise": "^0.10.1",
43
- "discrepances": "^0.2.8",
42
+ "cors": "^2.8.5",
43
+ "dialog-promise": "^0.10.2",
44
+ "discrepances": "^0.2.9",
44
45
  "express": "^5.1.0",
45
46
  "express-session": "^1.18.1",
46
47
  "express-useragent": "^1.0.15",
@@ -50,14 +51,15 @@
50
51
  "json4all": "^1.4.0",
51
52
  "lazy-some": "^0.1.0",
52
53
  "like-ar": "^0.5.1",
53
- "login-plus": "^1.7.2",
54
+ "login-plus": "^1.7.3",
54
55
  "memorystore": "^1.6.7",
55
- "mini-tools": "^1.13.2",
56
+ "mini-tools": "^1.13.3",
56
57
  "moment": "^2.30.1",
57
58
  "multiparty": "^4.2.3",
58
59
  "nodemailer": "^7.0.3",
59
60
  "numeral": "^2.0.6",
60
- "pg-promise-strict": "^1.4.2",
61
+ "pg-promise-strict": "^1.4.3",
62
+ "pg-triggers": "0.4.3",
61
63
  "pikaday": "^1.8.2",
62
64
  "pug": "^3.0.3",
63
65
  "read-yaml-promise": "^1.0.2",
@@ -76,13 +78,13 @@
76
78
  "devDependencies": {
77
79
  "@types/big.js": "^6.2.2",
78
80
  "@types/expect.js": "~0.3.32",
79
- "@types/express": "^5.0.2",
81
+ "@types/express": "^5.0.3",
80
82
  "@types/express-useragent": "^1.0.5",
81
83
  "@types/fs-extra": "^11.0.4",
82
84
  "@types/js-yaml": "^4.0.9",
83
85
  "@types/mocha": "^10.0.10",
84
86
  "@types/multiparty": "~4.2.1",
85
- "@types/node": "^22.15.29",
87
+ "@types/node": "^24.0.3",
86
88
  "@types/nodemailer": "^6.4.17",
87
89
  "@types/numeral": "~2.0.5",
88
90
  "@types/session-file-store": "^1.2.5",
@@ -97,10 +99,10 @@
97
99
  "karma-ie-launcher": "^1.0.0",
98
100
  "karma-mocha": "^2.0.1",
99
101
  "kill-9": "~0.4.3",
100
- "mocha": "^11.5.0",
102
+ "mocha": "^11.7.0",
101
103
  "nyc": "^17.1.0",
102
- "puppeteer": "^24.9.0",
103
- "sinon": "^20.0.0",
104
+ "puppeteer": "^24.10.2",
105
+ "sinon": "^21.0.0",
104
106
  "supertest": "^7.1.1",
105
107
  "types.d.ts": "~0.6.22",
106
108
  "typescript": "^5.8.3",