jsharmony-cms 1.5.3 → 1.5.7

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.
@@ -91,7 +91,7 @@ exports = module.exports = function(jsh, cms){
91
91
  complete_cb();
92
92
  },
93
93
  error: function(xhr, status, err){
94
- complete_cb(error);
94
+ complete_cb(err);
95
95
  }
96
96
  });
97
97
  }
@@ -82,7 +82,7 @@
82
82
  //"ACL": "public-read",
83
83
  //More parameters can be found at:
84
84
  //https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#putObject-property
85
- }
85
+ },
86
86
  },
87
87
 
88
88
  //Git deployment settings
@@ -101,6 +101,12 @@
101
101
  "onDeploy": true, //true (all), false (none), or array of items, ex: ["page","media"]
102
102
  "onDeploy_PostBuild": true, //true (all), false (none), or array of items, ex: ["page","media"]
103
103
  },
104
+ //Remote folders or files to ignore when deleting excess files on publish
105
+ //Use with FTP, FTPS, SFTP, S3, and Local File System deployments
106
+ "ignore_remote": [
107
+ "path/to/folder",
108
+ "path/to/file"
109
+ ]
104
110
  }
105
111
 
106
112
  //Template Variables
@@ -111,7 +111,7 @@ function jsHarmonyCMSConfig(){
111
111
  //"ACL": "public-read",
112
112
  //More parameters can be found at:
113
113
  //https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#putObject-property
114
- }
114
+ },
115
115
  },
116
116
 
117
117
  //Advanced options
@@ -21,7 +21,7 @@
21
21
  {"name":"site_id","control":"dropdown","caption":"Site","validate":["Required"],"readonly":true,
22
22
  "lov":{"sql":"select site_id code_val, site_name code_txt from {schema}.site where site_sts='ACTIVE' and site_id={schema}.my_current_site_id()"}},
23
23
  {"name":"deployment_target_id","control":"dropdown","caption":"Deployment Target","validate":["Required"],
24
- "lov":{"parent":"site_id" ,"sql2":"select site_id code_parent, deployment_target_id code_val, deployment_target_name code_txt from {schema}.v_my_deployment_target where deployment_target_can_publish = 1 and deployment_target_sts='ACTIVE' and site_id={schema}.my_current_site_id() order by site_id,deployment_target_name"}},
24
+ "lov":{"parent":"site_id" ,"sql2":"select site_id code_parent, deployment_target_id code_val, deployment_target_name code_txt from {schema}.v_my_deployment_target where ((deployment_target_can_publish = 1) or (deployment_target_can_publish_release = 1)) and deployment_target_sts='ACTIVE' and site_id={schema}.my_current_site_id() order by site_id,deployment_target_name"}},
25
25
  {"control":"html","value":[
26
26
  "<% if(jsh.globalparams.isWebmaster){ %>",
27
27
  "<a href='#' onclick='<%=jsh._instance%>.XExt.popupForm(\"{namespace}Site_Tabs\",\"update\",{site_id:<%=jsh._instance%>.globalparams.site_id}); return false;'>Configure Deployment Targets</a>",
@@ -11,7 +11,10 @@
11
11
  {"control":"subform","caption":"Preview / Editor","target":"Site_Deployment_Target_Role_Editor","bindings":{"deployment_target_id":"deployment_target_id","deployment_target_role_type":"'EDITOR'"},
12
12
  "controlstyle":"display:inline-block; margin-right:15px;"
13
13
  },
14
- {"control":"subform","caption":"Publish","target":"Site_Deployment_Target_Role_Publish","bindings":{"deployment_target_id":"deployment_target_id","deployment_target_role_type":"'PUBLISH'"},
14
+ {"control":"subform","caption":"Publish (Any Branch)","target":"Site_Deployment_Target_Role_Publish","bindings":{"deployment_target_id":"deployment_target_id","deployment_target_role_type":"'PUBLISH'"},
15
+ "controlstyle":"display:inline-block;"
16
+ },
17
+ {"control":"subform","caption":"Publish Release","target":"Site_Deployment_Target_Role_Publish_Release","bindings":{"deployment_target_id":"deployment_target_id","deployment_target_role_type":"'PUBLISH_RELEASE'"},
15
18
  "controlstyle":"display:inline-block;"
16
19
  },
17
20
  ]
@@ -23,4 +23,7 @@
23
23
  "Site_Deployment_Target_Role_Publish": {
24
24
  "inherits": "Site_Deployment_Target_Role_Base"
25
25
  },
26
+ "Site_Deployment_Target_Role_Publish_Release": {
27
+ "inherits": "Site_Deployment_Target_Role_Base"
28
+ },
26
29
  }
@@ -546,6 +546,19 @@ module.exports = exports = function(module, funcs){
546
546
 
547
547
  branchData.page_mapping = {};
548
548
 
549
+ //Sort folders first, then by path length
550
+ branchItems = (branchItems||[]).sort(function(a,b){
551
+ a = a || {};
552
+ b = b || {};
553
+ if(!(a.page_is_folder) && (b.page_is_folder)) return 1;
554
+ if((a.page_is_folder) && !(b.page_is_folder)) return -1;
555
+ var apath = (a.page_path||'').toString();
556
+ var bpath = (b.page_path||'').toString();
557
+ if(apath.length > bpath.length) return 1;
558
+ if(apath.length < bpath.length) return -1;
559
+ return 0;
560
+ });
561
+
549
562
  _.each(branchItems, function(item){
550
563
  //Create mapping
551
564
  branchData.page_mapping[item.page_key] = item;
@@ -680,6 +693,19 @@ module.exports = exports = function(module, funcs){
680
693
 
681
694
  branchData.media_mapping = {};
682
695
 
696
+ //Sort folders first, then by path length
697
+ branchItems = (branchItems||[]).sort(function(a,b){
698
+ a = a || {};
699
+ b = b || {};
700
+ if(!(a.media_is_folder) && (b.media_is_folder)) return 1;
701
+ if((a.media_is_folder) && !(b.media_is_folder)) return -1;
702
+ var apath = (a.media_path||'').toString();
703
+ var bpath = (b.media_path||'').toString();
704
+ if(apath.length > bpath.length) return 1;
705
+ if(apath.length < bpath.length) return -1;
706
+ return 0;
707
+ });
708
+
683
709
  async.waterfall([
684
710
  function(cb){
685
711
  //Get all media from current database
@@ -514,7 +514,10 @@ module.exports = exports = function(module, funcs){
514
514
  var cms = module;
515
515
  var git_path = cms.Config.git.bin_path || 'git';
516
516
  return funcs.shellExec(git_path, repo_path, params, function(err, rslt, stderr){
517
- if(err) return cb(new Error('Git Error: ' + err.toString() + ' ' + (stderr||'')), rslt);
517
+ if(err){
518
+ if(err && (err.code == 'ENOENT')) err = new Error('Git executable not found using command: "'+git_path+'". Please install git, or set the git.bin_path config parameter');
519
+ return cb(new Error('Git Error: ' + err.toString() + ' ' + (stderr||'')), rslt);
520
+ }
518
521
  return cb(err, rslt);
519
522
  }, exec_options);
520
523
  }
@@ -1801,7 +1804,7 @@ module.exports = exports = function(module, funcs){
1801
1804
  appsrv.ExecRecordset('deployment', sql, sql_ptypes, sql_params, function (err, rslt) {
1802
1805
  if (err != null) { err.sql = sql; return cb(err); }
1803
1806
  if(!rslt || !rslt.length || !rslt[0]){ return cb(new Error('Error loading deployment media')); }
1804
- async.eachSeries(rslt[0], function(media, item_cb){
1807
+ async.eachLimit(rslt[0], 10, function(media, item_cb){
1805
1808
  var srcpath = funcs.getMediaFilename(media.media_file_id, media.media_ext);
1806
1809
  var media_fpath = '';
1807
1810
  async.waterfall([
@@ -1833,7 +1836,7 @@ module.exports = exports = function(module, funcs){
1833
1836
  },
1834
1837
  //Export thumbnails
1835
1838
  function(generate_cb){
1836
- async.eachOfSeries(branchData.site_config.media_thumbnails, function(thumbnail_config, thumbnail_id, thumbnail_cb){
1839
+ async.eachOf(branchData.site_config.media_thumbnails, function(thumbnail_config, thumbnail_id, thumbnail_cb){
1837
1840
  if(!thumbnail_config || !thumbnail_config.export) return thumbnail_cb();
1838
1841
  if(!_.includes(['.jpg','.jpeg','.tif','.tiff','.png','.gif','.svg'], media.media_ext)) return thumbnail_cb();
1839
1842
 
@@ -2011,27 +2014,16 @@ module.exports = exports = function(module, funcs){
2011
2014
 
2012
2015
  exports.deploy_ignore_remote = function(publish_params, fpath){
2013
2016
  if(fpath=='.git') return true;
2014
- return false;
2015
- /*
2016
2017
  if(!publish_params || !publish_params.ignore_remote) return false;
2017
- var origpath = fpath;
2018
2018
  fpath = HelperFS.convertWindowsToPosix(fpath);
2019
- while(fpath){
2020
- for(var i=0;i<publish_params.ignore_remote.length;i++){
2021
- var ignore_expr = publish_params.ignore_remote[i];
2022
- if(!ignore_expr) continue;
2023
- if(ignore_expr.regex){
2024
- }
2025
- else {
2026
- if(ignore_expr == fpath) return true;
2027
- }
2028
- }
2029
- fpath = path.dirname(fpath);
2030
- if(fpath=='.') fpath = '';
2031
- if(fpath=='..') fpath = '';
2019
+ for(var i=0;i<publish_params.ignore_remote.length;i++){
2020
+ var ignore_expr = publish_params.ignore_remote[i];
2021
+ if(!ignore_expr) continue;
2022
+ var ignore_path = HelperFS.convertWindowsToPosix(ignore_expr.toString());
2023
+ if(ignore_path == fpath) return true;
2024
+ if(fpath.indexOf(ignore_path+'/')==0) return true;
2032
2025
  }
2033
- return true;
2034
- */
2026
+ return false;
2035
2027
  }
2036
2028
 
2037
2029
  exports.deploy_fs = function(deployment, publish_path, deploy_path, site_files, cb){
@@ -2578,6 +2570,7 @@ module.exports = exports = function(module, funcs){
2578
2570
  if(bucket_prefix){
2579
2571
  if(!bucket_prefix || (bucket_prefix[bucket_prefix.length-1]!='/')) bucket_prefix += '/';
2580
2572
  }
2573
+ var S3_THREADS = 10;
2581
2574
 
2582
2575
  var s3_files = {};
2583
2576
  var s3_upload = [];
@@ -2613,7 +2606,9 @@ module.exports = exports = function(module, funcs){
2613
2606
  if(site_md5 != s3_md5) s3_upload.push(fname);
2614
2607
  }
2615
2608
  else {
2616
- s3_delete.push(fname);
2609
+ if(!funcs.deploy_ignore_remote(deployment.publish_params, fname)){
2610
+ s3_delete.push(fname);
2611
+ }
2617
2612
  }
2618
2613
  }
2619
2614
  for(var fname in site_files){
@@ -2625,7 +2620,7 @@ module.exports = exports = function(module, funcs){
2625
2620
 
2626
2621
  //Upload new files to S3
2627
2622
  function(s3_cb){
2628
- async.eachSeries(s3_upload, function(page_path, page_cb){
2623
+ async.eachLimit(s3_upload, S3_THREADS, function(page_path, page_cb){
2629
2624
  var page_bpath = bucket_prefix + page_path;
2630
2625
  var page_fpath = path.join(publish_path, page_path);
2631
2626
  var fstream = fs.createReadStream(page_fpath);
@@ -2635,7 +2630,6 @@ module.exports = exports = function(module, funcs){
2635
2630
  Bucket: bucket,
2636
2631
  Key: page_bpath,
2637
2632
  Body: fstream,
2638
- ACL: 'public-read'
2639
2633
  };
2640
2634
  var contentType = HelperFS.getMimeType(page_bpath);
2641
2635
  if(contentType) uploadParams.ContentType = contentType;
@@ -2648,7 +2642,7 @@ module.exports = exports = function(module, funcs){
2648
2642
 
2649
2643
  //Delete removed files from S3
2650
2644
  function(s3_cb){
2651
- async.eachSeries(s3_delete, function(page_path, page_cb){
2645
+ async.eachLimit(s3_delete, S3_THREADS, function(page_path, page_cb){
2652
2646
  var page_bpath = bucket_prefix + page_path;
2653
2647
  funcs.deploy_log_info(deployment_id, 'Deleting: '+page_path);
2654
2648
  funcs.deploy_log_change(deployment_id, 'Deleting file: '+page_path);
@@ -199,6 +199,28 @@
199
199
  "\")",
200
200
  ]
201
201
  },
202
+ "{schema}.can_publish":{
203
+ "params": ["BRANCH_ID","DEPLOYMENT_TARGET_ID"],
204
+ "sql": [
205
+ "(case when exists(",
206
+ " select * from {schema}.v_my_deployment_target where deployment_target_id=%%%DEPLOYMENT_TARGET_ID%%% and (",
207
+ " (deployment_target_can_publish=1) or",
208
+ " (deployment_target_can_publish_release=1 and exists(select branch_child.branch_id from {schema}.branch branch_child where branch_child.branch_id=%%%BRANCH_ID%%% and branch_child.branch_type='PUBLIC'))",
209
+ " )",
210
+ ") then 1 else 0 end)"
211
+ ]
212
+ },
213
+ "{schema}.could_have_published":{
214
+ "params": ["BRANCH_ID","DEPLOYMENT_TARGET_ID"],
215
+ "sql": [
216
+ "(case when exists(",
217
+ " select * from {schema}.v_my_deployment_target where deployment_target_id=%%%DEPLOYMENT_TARGET_ID%%% and (",
218
+ " (deployment_target_can_publish=1) or",
219
+ " (deployment_target_can_publish_release=1 and exists(select branch_child.branch_id from {schema}.branch branch_child inner join {schema}.branch branch_parent on branch_parent.branch_id = branch_child.branch_parent_id where branch_child.branch_id=%%%BRANCH_ID%%% and branch_parent.branch_type='PUBLIC'))",
220
+ " )",
221
+ ") then 1 else 0 end)"
222
+ ]
223
+ },
202
224
  "{schema}.insert_token": {
203
225
  "params": ["sys_user_token_hash","sys_user_token_ext","sys_user_token_keys"],
204
226
  "sql": [
@@ -4,7 +4,8 @@
4
4
  "caption": "Deployment Target Role Type",
5
5
  "init_data": [
6
6
  { "code_val": "PUBLISH", "code_txt": "Publish", "code_seq": 1 },
7
- { "code_val": "EDITOR", "code_txt": "Preview / Editor", "code_seq": 2 }
7
+ { "code_val": "PUBLISH_RELEASE", "code_txt": "Publish Release", "code_seq": 2 },
8
+ { "code_val": "EDITOR", "code_txt": "Preview / Editor", "code_seq": 3 }
8
9
  ]
9
10
  },
10
11
 
@@ -153,6 +154,16 @@
153
154
  " when exists(select * from deployment_target_role dtr inner join {schema}.sys_user_site r on r.sys_user_site_access = dtr.sys_role_name and r.sys_user_id = jsharmony.my_sys_user_id() and r.site_id = deployment_target.site_id and dtr.deployment_target_role_type='PUBLISH' and dtr.deployment_target_id = deployment_target.deployment_target_id) then 1",
154
155
  " else 0 end"
155
156
  ]
157
+ },
158
+ {
159
+ "name":"deployment_target_can_publish_release", "type": "int",
160
+ "sqlselect": [
161
+ "case ",
162
+ " when {schema}.my_user_is_publisher(deployment_target.site_id) = 0 then 0",
163
+ " when exists(select * from deployment_target_role dtr inner join jsharmony.sys_user_role r on r.sys_role_name = dtr.sys_role_name and r.sys_user_id = jsharmony.my_sys_user_id() and dtr.deployment_target_role_type='PUBLISH_RELEASE' and dtr.deployment_target_id = deployment_target.deployment_target_id) then 1",
164
+ " when exists(select * from deployment_target_role dtr inner join {schema}.sys_user_site r on r.sys_user_site_access = dtr.sys_role_name and r.sys_user_id = jsharmony.my_sys_user_id() and r.site_id = deployment_target.site_id and dtr.deployment_target_role_type='PUBLISH_RELEASE' and dtr.deployment_target_id = deployment_target.deployment_target_id) then 1",
165
+ " else 0 end"
166
+ ]
156
167
  }
157
168
  ]
158
169
  }
@@ -181,7 +192,7 @@
181
192
  "deployment_etstmp",
182
193
  "deployment_euser",
183
194
  "deployment_mtstmp",
184
- "deployment_muser"
195
+ "deployment_muser",
185
196
  ]
186
197
  },
187
198
  "v_my_deployment_target": {
@@ -191,14 +202,14 @@
191
202
  "join_type": "inner",
192
203
  "join_columns": {
193
204
  "deployment.deployment_target_id": "v_my_deployment_target.deployment_target_id",
194
- "deployment_target_can_publish": "1"
205
+ "{schema}.could_have_published(deployment.branch_id, deployment.deployment_target_id)": "1"
195
206
  }
196
207
  }
197
208
  },
198
209
  "triggers": [
199
210
  {"on": ["insert"], "exec": [
200
211
  //Verify access
201
- "errorif(not exists(select 1 from {schema}.v_my_deployment_target where v_my_deployment_target.deployment_target_id=inserted(deployment_target_id) and deployment_target_can_publish=1),'No access to publish to this deployment target.');",
212
+ "errorif($ifnull({schema}.can_publish(inserted(branch_id), inserted(deployment_target_id)),0)<>1,'No access to publish to this deployment target.');",
202
213
  //Verify non-duplicate tag name
203
214
  "errorif(exists(select 1 from {schema}.deployment inner join {schema}.branch on {schema}.branch.branch_id={schema}.deployment.branch_id where deployment_tag=inserted(deployment_tag) and site_id=inserted(site_id)),'Deployment Tag must be unique for the site.');",
204
215
  "errorif(exists(select 1 from {schema}.deployment inner join {schema}.deployment_target on {schema}.deployment_target.deployment_target_id={schema}.deployment.deployment_target_id where deployment_tag=inserted(deployment_tag) and site_id=(select site_id from deployment_target where deployment_target_id=inserted(deployment_target_id))),'Deployment Tag must be unique for the site.');",
@@ -218,7 +229,7 @@
218
229
  },
219
230
  {"on": ["update"], "exec": [
220
231
  //Verify access
221
- "errorif(not exists(select 1 from {schema}.v_my_deployment_target where v_my_deployment_target.deployment_target_id=(select deployment_target_id from {schema}.deployment where deployment_id = deleted(deployment_id)) and deployment_target_can_publish=1),'No access to cancel to this deployment.');",
232
+ "errorif($ifnull({schema}.could_have_published((select branch_id from {schema}.deployment where deployment_id = deleted(deployment_id)), (select deployment_target_id from {schema}.deployment where deployment_id = deleted(deployment_id))),0)<>1,'No access to cancel this deployment.');",
222
233
  "update {schema}.deployment set deployment_sts = 'CANCEL' where deployment_id = deleted(deployment_id)"
223
234
  ]
224
235
  }
@@ -0,0 +1,3 @@
1
+ jsharmony.version_increment('jsHarmonyCMS',1,5,7,0);
2
+ update {schema}.code_deployment_target_role_type set code_seq=3 where code_val='EDITOR';
3
+ insert into {schema}.code_deployment_target_role_type(code_val, code_txt, code_seq) values ('PUBLISH_RELEASE','Publish Release',2);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jsharmony-cms",
3
- "version": "1.5.3",
3
+ "version": "1.5.7",
4
4
  "description": "jsHarmony CMS",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -30,7 +30,7 @@
30
30
  "diff2html": "3.4.1",
31
31
  "ejs": "2.7.4",
32
32
  "js-beautify": "^1.11.0",
33
- "jsharmony": "^1.4.0",
33
+ "jsharmony": "^1.5.2",
34
34
  "jsharmony-factory": "^1.2.0",
35
35
  "lodash": "^4.17.19",
36
36
  "node-forge": "^0.10.0",