alchemymvc 1.3.16 → 1.3.18
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.
- package/lib/app/datasource/mongo_datasource.js +51 -29
- package/lib/app/element/time_ago.js +19 -36
- package/lib/app/helper/alchemy_helper.js +2 -2
- package/lib/app/helper/cron.js +1502 -0
- package/lib/app/helper_model/document.js +1 -0
- package/lib/app/model/alchemy_task_history_model.js +109 -0
- package/lib/app/model/alchemy_task_model.js +141 -18
- package/lib/bootstrap.js +3 -0
- package/lib/class/conduit.js +103 -33
- package/lib/class/model.js +24 -0
- package/lib/class/schema_client.js +8 -11
- package/lib/class/session.js +14 -3
- package/lib/class/task.js +297 -145
- package/lib/class/task_service.js +933 -0
- package/lib/core/base.js +23 -1
- package/lib/core/middleware.js +2 -2
- package/lib/init/alchemy.js +210 -28
- package/lib/init/requirements.js +0 -7
- package/package.json +2 -2
|
@@ -1277,6 +1277,7 @@ Document.setMethod(function hasChanged(name) {
|
|
|
1277
1277
|
|
|
1278
1278
|
for (key in this.$attributes.original_record) {
|
|
1279
1279
|
if (!Object.alike(this.$attributes.original_record[key], this[key])) {
|
|
1280
|
+
// @TODO: some special fields always end up being different
|
|
1280
1281
|
result = true;
|
|
1281
1282
|
break;
|
|
1282
1283
|
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Alchemy Task History model:
|
|
3
|
+
* keep track of all the tasks that have been run
|
|
4
|
+
*
|
|
5
|
+
* @constructor
|
|
6
|
+
*
|
|
7
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
8
|
+
* @since 0.5.0
|
|
9
|
+
* @version 0.5.0
|
|
10
|
+
*/
|
|
11
|
+
const AlchemyTaskHistory = Function.inherits('Alchemy.Model.App', 'AlchemyTaskHistory');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Constitute the class wide schema
|
|
15
|
+
*
|
|
16
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
17
|
+
* @since 0.5.0
|
|
18
|
+
* @version 1.3.17
|
|
19
|
+
*/
|
|
20
|
+
AlchemyTaskHistory.constitute(function addTaskFields() {
|
|
21
|
+
|
|
22
|
+
this.belongsTo('AlchemyTask', {
|
|
23
|
+
description : 'The original AlchemyTask document it belonged to',
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// The timestamp this was scheduled for
|
|
27
|
+
this.addField('scheduled_at', 'Date', {
|
|
28
|
+
description : 'The original date this was scheduled for',
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
this.addField('process_id', 'Integer', {
|
|
32
|
+
description : 'The process ID of the task',
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// The type of Task that is running
|
|
36
|
+
this.addField('type', 'Enum', {
|
|
37
|
+
values: Classes.Alchemy.Task.Task.getLiveDescendantsMap(),
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// The payload/settings of the task
|
|
41
|
+
this.addField('settings', 'Schema', {
|
|
42
|
+
description : 'The settings of the task at the time it ran',
|
|
43
|
+
schema: 'type'
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
this.addField('had_error', 'Boolean', {
|
|
47
|
+
description : 'Did this task run into an error?'
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
this.addField('error_message', 'String', {
|
|
51
|
+
description : 'The main error message'
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
this.addField('error_stack', 'Text', {
|
|
55
|
+
description : 'The error stack trace'
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
this.addField('is_running', 'Boolean', {
|
|
59
|
+
description : 'Is this task still running?',
|
|
60
|
+
default : false,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
this.addField('started_at', 'Datetime', {
|
|
64
|
+
description : 'The datetime this task actually started running',
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
this.addField('ended_at', 'Datetime', {
|
|
68
|
+
description : 'The datetime this task actually ended',
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
this.addIndex('type');
|
|
72
|
+
this.addIndex('is_running');
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Configure the default chimera fieldsets
|
|
77
|
+
*
|
|
78
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
79
|
+
* @since 1.3.17
|
|
80
|
+
* @version 1.3.17
|
|
81
|
+
*/
|
|
82
|
+
AlchemyTaskHistory.constitute(function chimeraConfig() {
|
|
83
|
+
|
|
84
|
+
if (!this.chimera) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Get the list group
|
|
89
|
+
let list = this.chimera.getActionFields('list');
|
|
90
|
+
|
|
91
|
+
list.addField('created');
|
|
92
|
+
list.addField('type');
|
|
93
|
+
list.addField('process_id');
|
|
94
|
+
list.addField('scheduled_at');
|
|
95
|
+
list.addField('started_at');
|
|
96
|
+
list.addField('ended_at');
|
|
97
|
+
list.addField('had_error');
|
|
98
|
+
|
|
99
|
+
// Get the edit group
|
|
100
|
+
let edit = this.chimera.getActionFields('edit');
|
|
101
|
+
|
|
102
|
+
edit.addField('type');
|
|
103
|
+
edit.addField('settings');
|
|
104
|
+
edit.addField('had_error');
|
|
105
|
+
edit.addField('error_message');
|
|
106
|
+
edit.addField('error_stack');
|
|
107
|
+
edit.addField('started_at');
|
|
108
|
+
edit.addField('ended_at');
|
|
109
|
+
});
|
|
@@ -1,34 +1,157 @@
|
|
|
1
|
-
var all_task_types = alchemy.getClassGroup('task');
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
|
-
* The Alchemy Task
|
|
2
|
+
* The Alchemy Task model:
|
|
3
|
+
*
|
|
5
4
|
*
|
|
6
5
|
* @constructor
|
|
7
6
|
*
|
|
8
|
-
* @author Jelle De Loecker <jelle@
|
|
9
|
-
* @since
|
|
10
|
-
* @version
|
|
7
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
8
|
+
* @since 1.3.17
|
|
9
|
+
* @version 1.3.17
|
|
10
|
+
*/
|
|
11
|
+
const AlchemyTask = Function.inherits('Alchemy.Model.App', 'AlchemyTask');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Constitute the class wide schema
|
|
15
|
+
*
|
|
16
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
17
|
+
* @since 1.3.17
|
|
18
|
+
* @version 1.3.17
|
|
11
19
|
*/
|
|
12
|
-
|
|
20
|
+
AlchemyTask.constitute(function addTaskFields() {
|
|
21
|
+
|
|
22
|
+
this.addField('title', 'String', {
|
|
23
|
+
description : 'The title of the task',
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
this.addField('type', 'Enum', {
|
|
27
|
+
values : Classes.Alchemy.Task.Task.getLiveDescendantsMap(),
|
|
28
|
+
description : 'The type of task to run',
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
this.addField('settings', 'Schema', {
|
|
32
|
+
description : 'The settings to use for running the task',
|
|
33
|
+
schema: 'type'
|
|
34
|
+
});
|
|
13
35
|
|
|
14
|
-
|
|
36
|
+
this.addField('enabled', 'Boolean', {
|
|
37
|
+
description : 'Is this task enabled?',
|
|
38
|
+
default : true,
|
|
39
|
+
});
|
|
15
40
|
|
|
16
|
-
|
|
41
|
+
this.addField('frequency', 'String', {
|
|
42
|
+
description : 'The frequency this task should run at (CRON syntax)',
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
this.addField('comment', 'Text', {
|
|
46
|
+
description : 'A comment about this task',
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
this.addField('schedule_type', 'Enum', {
|
|
50
|
+
values: {
|
|
51
|
+
user : 'User',
|
|
52
|
+
system_forced : 'System (forced)',
|
|
53
|
+
system_fallback : 'System (fallback)',
|
|
54
|
+
},
|
|
55
|
+
default: 'user',
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
this.addField('forced_schedule_checksum', 'String', {
|
|
59
|
+
description : 'Checksum of the cron syntax and settings, set only for tasks originating from forced schedules',
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
this.addIndex('forced_schedule_checksum', {
|
|
63
|
+
unique : true,
|
|
64
|
+
sparse : true,
|
|
65
|
+
});
|
|
17
66
|
});
|
|
18
67
|
|
|
19
68
|
/**
|
|
20
|
-
*
|
|
69
|
+
* Configure the default chimera fieldsets
|
|
21
70
|
*
|
|
22
|
-
* @author Jelle De Loecker
|
|
23
|
-
* @since
|
|
24
|
-
* @version
|
|
71
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
72
|
+
* @since 1.3.17
|
|
73
|
+
* @version 1.3.17
|
|
25
74
|
*/
|
|
26
|
-
AlchemyTask.constitute(function
|
|
75
|
+
AlchemyTask.constitute(function chimeraConfig() {
|
|
76
|
+
|
|
77
|
+
if (!this.chimera) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Get the list group
|
|
82
|
+
let list = this.chimera.getActionFields('list');
|
|
83
|
+
|
|
84
|
+
list.addField('title');
|
|
85
|
+
list.addField('type');
|
|
86
|
+
list.addField('enabled');
|
|
87
|
+
list.addField('frequency');
|
|
88
|
+
list.addField('schedule_type');
|
|
89
|
+
|
|
90
|
+
// Get the edit group
|
|
91
|
+
let edit = this.chimera.getActionFields('edit');
|
|
92
|
+
|
|
93
|
+
edit.addField('title');
|
|
94
|
+
edit.addField('frequency')
|
|
95
|
+
edit.addField('enabled');
|
|
96
|
+
edit.addField('type');
|
|
97
|
+
edit.addField('settings');
|
|
98
|
+
edit.addField('comment');
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Do something before saving the record
|
|
103
|
+
*
|
|
104
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
105
|
+
* @since 1.3.17
|
|
106
|
+
* @version 1.3.17
|
|
107
|
+
*
|
|
108
|
+
* @param {Document.AlchemyTask} doc
|
|
109
|
+
*/
|
|
110
|
+
AlchemyTask.setMethod(function beforeSave(doc) {
|
|
111
|
+
|
|
112
|
+
if (!doc.schedule_type) {
|
|
113
|
+
doc.schedule_type = 'user';
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (doc.enabled == null) {
|
|
117
|
+
doc.enabled = false;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (!doc.title) {
|
|
121
|
+
let title = '';
|
|
122
|
+
|
|
123
|
+
if (doc.schedule_type == 'system_forced') {
|
|
124
|
+
title += 'System forced: ';
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (doc.schedule_type == 'system_fallback') {
|
|
128
|
+
title += 'System fallback: ';
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
title += doc.type;
|
|
132
|
+
doc.title = title;
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Update the schedules after saving
|
|
138
|
+
*
|
|
139
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
140
|
+
* @since 1.3.17
|
|
141
|
+
* @version 1.3.17
|
|
142
|
+
*
|
|
143
|
+
* @param {Object} main
|
|
144
|
+
* @param {Object} info
|
|
145
|
+
*/
|
|
146
|
+
AlchemyTask.setMethod(function afterSave(main, info) {
|
|
27
147
|
|
|
28
|
-
|
|
29
|
-
|
|
148
|
+
if (!main.type) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
30
151
|
|
|
31
|
-
|
|
32
|
-
|
|
152
|
+
if (!alchemy.task_service.has_loaded) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
33
155
|
|
|
156
|
+
alchemy.task_service.rescheduleTasksOfType(main.type);
|
|
34
157
|
});
|
package/lib/bootstrap.js
CHANGED
|
@@ -312,6 +312,9 @@ Alchemy.setMethod(function start(options, callback) {
|
|
|
312
312
|
// Make sure Blast has executed everything that's still waiting
|
|
313
313
|
Blast.doLoaded();
|
|
314
314
|
|
|
315
|
+
// Call the `afterStart` method
|
|
316
|
+
this.ready(() => this.afterStart());
|
|
317
|
+
|
|
315
318
|
// Schedule the callback
|
|
316
319
|
return this.ready(callback);
|
|
317
320
|
});
|
package/lib/class/conduit.js
CHANGED
|
@@ -125,12 +125,23 @@ Conduit.setProperty(function scene() {
|
|
|
125
125
|
return this.getSession().getScene(this.scene_id);
|
|
126
126
|
});
|
|
127
127
|
|
|
128
|
+
/**
|
|
129
|
+
* The session cookie name to use
|
|
130
|
+
*
|
|
131
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
132
|
+
* @since 1.3.18
|
|
133
|
+
* @version 1.3.18
|
|
134
|
+
*/
|
|
135
|
+
Conduit.setProperty(function session_cookie_name() {
|
|
136
|
+
return alchemy.settings.session_key || 'alchemy_sid';
|
|
137
|
+
});
|
|
138
|
+
|
|
128
139
|
/**
|
|
129
140
|
* Enforce the scene_id
|
|
130
141
|
*
|
|
131
142
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
132
143
|
* @since 1.1.0
|
|
133
|
-
* @version 1.3.
|
|
144
|
+
* @version 1.3.18
|
|
134
145
|
*/
|
|
135
146
|
Conduit.enforceProperty(function scene_id(new_value, old_value) {
|
|
136
147
|
|
|
@@ -160,7 +171,10 @@ Conduit.enforceProperty(function scene_id(new_value, old_value) {
|
|
|
160
171
|
path: path,
|
|
161
172
|
|
|
162
173
|
// Cookie should not live for more than 15 seconds
|
|
163
|
-
maxAge: 1000 * 15
|
|
174
|
+
maxAge: 1000 * 15,
|
|
175
|
+
|
|
176
|
+
// It should be restricted to the same domain
|
|
177
|
+
domain: false,
|
|
164
178
|
});
|
|
165
179
|
}
|
|
166
180
|
}
|
|
@@ -259,12 +273,17 @@ Conduit.setProperty(function is_secure() {
|
|
|
259
273
|
*
|
|
260
274
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
261
275
|
* @since 1.1.0
|
|
262
|
-
* @version 1.
|
|
276
|
+
* @version 1.3.18
|
|
263
277
|
*
|
|
264
|
-
* @param {Object}
|
|
278
|
+
* @param {Object|String}
|
|
265
279
|
*/
|
|
266
280
|
Conduit.setMethod(function setRequestBody(body) {
|
|
267
281
|
|
|
282
|
+
if (typeof body == 'string') {
|
|
283
|
+
this.body = body;
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
|
|
268
287
|
if (!body) {
|
|
269
288
|
return;
|
|
270
289
|
}
|
|
@@ -490,22 +509,20 @@ Conduit.setMethod(function time() {
|
|
|
490
509
|
/**
|
|
491
510
|
* Parse the request, get information from the url
|
|
492
511
|
*
|
|
493
|
-
* @author Jelle De Loecker <jelle@
|
|
512
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
494
513
|
* @since 0.2.0
|
|
495
|
-
* @version 1.
|
|
514
|
+
* @version 1.3.18
|
|
496
515
|
*
|
|
497
516
|
* @param {IncomingMessage} req
|
|
498
517
|
* @param {ServerResponse} res
|
|
499
518
|
*/
|
|
500
519
|
Conduit.setMethod(async function parseRequest() {
|
|
501
520
|
|
|
502
|
-
var protocol,
|
|
503
|
-
section;
|
|
504
|
-
|
|
505
521
|
if (this.method == null && this.request && this.request.method) {
|
|
506
522
|
this.method = this.request.method.toLowerCase();
|
|
507
523
|
}
|
|
508
524
|
|
|
525
|
+
this.parseUrl();
|
|
509
526
|
this.parseShortcuts();
|
|
510
527
|
this.parseLanguages();
|
|
511
528
|
this.parsePrefix();
|
|
@@ -529,11 +546,25 @@ Conduit.setMethod(async function parseRequest() {
|
|
|
529
546
|
this.overrideResponseUrl(new_url);
|
|
530
547
|
}
|
|
531
548
|
|
|
549
|
+
this.parseUrl();
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
/**
|
|
553
|
+
* Parse the url if it hasn't been done already
|
|
554
|
+
*
|
|
555
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
556
|
+
* @since 1.3.18
|
|
557
|
+
* @version 1.3.18
|
|
558
|
+
*/
|
|
559
|
+
Conduit.setMethod(function parseUrl() {
|
|
560
|
+
|
|
532
561
|
// If the url has already been parsed, return early
|
|
533
562
|
if (this.url) {
|
|
534
|
-
return;
|
|
563
|
+
return false;
|
|
535
564
|
}
|
|
536
565
|
|
|
566
|
+
let protocol;
|
|
567
|
+
|
|
537
568
|
if (alchemy.settings.assume_https) {
|
|
538
569
|
protocol = 'https://';
|
|
539
570
|
} else if (this.headers['x-forwarded-proto']) {
|
|
@@ -555,7 +586,12 @@ Conduit.setMethod(async function parseRequest() {
|
|
|
555
586
|
// Set the host
|
|
556
587
|
this.url.hostname = this.headers.host;
|
|
557
588
|
|
|
558
|
-
|
|
589
|
+
// If no URL was set, use the first requests URL (without the path)
|
|
590
|
+
if (!alchemy.settings.url && this.headers.host) {
|
|
591
|
+
alchemy.setUrl(this.url);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
let path = this.original_path;
|
|
559
595
|
|
|
560
596
|
if (this.prefix) {
|
|
561
597
|
path = '/' + this.prefix + '/' + path;
|
|
@@ -569,9 +605,9 @@ Conduit.setMethod(async function parseRequest() {
|
|
|
569
605
|
/**
|
|
570
606
|
* Parse the headers for shortcuts
|
|
571
607
|
*
|
|
572
|
-
* @author Jelle De Loecker <jelle@
|
|
608
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
573
609
|
* @since 0.2.0
|
|
574
|
-
* @version
|
|
610
|
+
* @version 1.3.17
|
|
575
611
|
*/
|
|
576
612
|
Conduit.setMethod(function parseShortcuts() {
|
|
577
613
|
|
|
@@ -597,6 +633,10 @@ Conduit.setMethod(function parseShortcuts() {
|
|
|
597
633
|
this.ajax = headers['x-requested-with'] === 'XMLHttpRequest';
|
|
598
634
|
}
|
|
599
635
|
|
|
636
|
+
// Is this request coming from a webview?
|
|
637
|
+
if (this.in_webview == null) {
|
|
638
|
+
this.in_webview = headers['x-protoblast-webview'] === 'true';
|
|
639
|
+
}
|
|
600
640
|
});
|
|
601
641
|
|
|
602
642
|
/**
|
|
@@ -1161,6 +1201,8 @@ Conduit.setMethod(async function callMiddleware() {
|
|
|
1161
1201
|
middleDebug.mark('Preparing viewrender');
|
|
1162
1202
|
}
|
|
1163
1203
|
|
|
1204
|
+
// An action will be called,
|
|
1205
|
+
// so we can already prepare the viewrender now.
|
|
1164
1206
|
that.prepareViewRender();
|
|
1165
1207
|
|
|
1166
1208
|
if (middleDebug) {
|
|
@@ -1184,10 +1226,14 @@ Conduit.setMethod(async function callMiddleware() {
|
|
|
1184
1226
|
*
|
|
1185
1227
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
1186
1228
|
* @since 0.2.0
|
|
1187
|
-
* @version 1.
|
|
1229
|
+
* @version 1.3.17
|
|
1188
1230
|
*/
|
|
1189
1231
|
Conduit.setMethod(function prepareViewRender() {
|
|
1190
1232
|
|
|
1233
|
+
if (this.renderer.conduit) {
|
|
1234
|
+
return;
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1191
1237
|
// Add a link to this conduit
|
|
1192
1238
|
this.renderer.conduit = this;
|
|
1193
1239
|
this.renderer.server_var('conduit', this);
|
|
@@ -1410,7 +1456,7 @@ Conduit.setMethod(function setResponseUrl(new_url) {
|
|
|
1410
1456
|
*
|
|
1411
1457
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
1412
1458
|
* @since 0.2.0
|
|
1413
|
-
* @version 1.3.
|
|
1459
|
+
* @version 1.3.17
|
|
1414
1460
|
*
|
|
1415
1461
|
* @param {Number} status 3xx redirection codes. 302 (temporary redirect) by default
|
|
1416
1462
|
* @param {String|Object} options Options or url
|
|
@@ -1508,13 +1554,18 @@ Conduit.setMethod(function redirect(status, options) {
|
|
|
1508
1554
|
}
|
|
1509
1555
|
}
|
|
1510
1556
|
|
|
1511
|
-
if (
|
|
1512
|
-
this.setHeader('x-hawkejs-
|
|
1557
|
+
if (options?.popup) {
|
|
1558
|
+
this.setHeader('x-hawkejs-popup', options.popup);
|
|
1513
1559
|
|
|
1514
|
-
if (options
|
|
1515
|
-
this.setHeader('x-hawkejs-popup', options.
|
|
1560
|
+
if (options.popup_url) {
|
|
1561
|
+
this.setHeader('x-hawkejs-popup-url', options.popup_url);
|
|
1516
1562
|
}
|
|
1517
1563
|
|
|
1564
|
+
hard_refresh = true;
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
if (hard_refresh && this.headers['x-hawkejs-request']) {
|
|
1568
|
+
this.setHeader('x-hawkejs-navigate', url);
|
|
1518
1569
|
} else {
|
|
1519
1570
|
this.setHeader('Location', url);
|
|
1520
1571
|
}
|
|
@@ -1921,11 +1972,11 @@ Conduit.setMethod(function createScene() {
|
|
|
1921
1972
|
*
|
|
1922
1973
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
1923
1974
|
* @since 0.2.0
|
|
1924
|
-
* @version 1.
|
|
1975
|
+
* @version 1.3.17
|
|
1925
1976
|
*/
|
|
1926
1977
|
Conduit.setMethod(function render(template_name, options, callback) {
|
|
1927
1978
|
|
|
1928
|
-
|
|
1979
|
+
let that = this,
|
|
1929
1980
|
templates;
|
|
1930
1981
|
|
|
1931
1982
|
if (typeof options == 'function') {
|
|
@@ -1935,6 +1986,10 @@ Conduit.setMethod(function render(template_name, options, callback) {
|
|
|
1935
1986
|
options = {};
|
|
1936
1987
|
}
|
|
1937
1988
|
|
|
1989
|
+
// Make sure the viewrender is prepared
|
|
1990
|
+
// (Fallback)
|
|
1991
|
+
this.prepareViewRender();
|
|
1992
|
+
|
|
1938
1993
|
if (template_name) {
|
|
1939
1994
|
templates = [template_name];
|
|
1940
1995
|
}
|
|
@@ -2266,7 +2321,7 @@ Conduit.setMethod(function _sendStream(stream, options) {
|
|
|
2266
2321
|
*
|
|
2267
2322
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
2268
2323
|
* @since 0.2.0
|
|
2269
|
-
* @version 1.3.
|
|
2324
|
+
* @version 1.3.18
|
|
2270
2325
|
*
|
|
2271
2326
|
* @param {Boolean} create Create a session if none exist
|
|
2272
2327
|
*
|
|
@@ -2279,13 +2334,10 @@ Conduit.setMethod(function getSession(allow_create = true) {
|
|
|
2279
2334
|
return this.sessionData;
|
|
2280
2335
|
}
|
|
2281
2336
|
|
|
2282
|
-
let cookie_name,
|
|
2337
|
+
let cookie_name = this.session_cookie_name,
|
|
2283
2338
|
session_id,
|
|
2284
2339
|
session;
|
|
2285
2340
|
|
|
2286
|
-
// Set the name of the cookie (could change in the future)
|
|
2287
|
-
cookie_name = alchemy.settings.session_key || 'alchemy_sid';
|
|
2288
|
-
|
|
2289
2341
|
// Get the ID of the session
|
|
2290
2342
|
session_id = this.cookie(cookie_name);
|
|
2291
2343
|
|
|
@@ -2449,9 +2501,9 @@ Conduit.setMethod(function setRouteParameters(data) {
|
|
|
2449
2501
|
/**
|
|
2450
2502
|
* Get/set a cookie
|
|
2451
2503
|
*
|
|
2452
|
-
* @author Jelle De Loecker <jelle@
|
|
2504
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
2453
2505
|
* @since 0.2.0
|
|
2454
|
-
* @version
|
|
2506
|
+
* @version 1.3.18
|
|
2455
2507
|
*
|
|
2456
2508
|
* @param {String} name
|
|
2457
2509
|
* @param {Mixed} value
|
|
@@ -2459,10 +2511,6 @@ Conduit.setMethod(function setRouteParameters(data) {
|
|
|
2459
2511
|
*/
|
|
2460
2512
|
Conduit.setMethod(function cookie(name, value, options) {
|
|
2461
2513
|
|
|
2462
|
-
var header,
|
|
2463
|
-
arr,
|
|
2464
|
-
key;
|
|
2465
|
-
|
|
2466
2514
|
// Return if cookies are disabled
|
|
2467
2515
|
if (!alchemy.settings.cookies) {
|
|
2468
2516
|
return;
|
|
@@ -2493,12 +2541,34 @@ Conduit.setMethod(function cookie(name, value, options) {
|
|
|
2493
2541
|
// Store it in the new_cookies object, for quick access
|
|
2494
2542
|
this.new_cookies[name] = value;
|
|
2495
2543
|
|
|
2544
|
+
// If there is no domain set, see if it is required
|
|
2545
|
+
if ((options.domain === true || options.domain == null) && alchemy.settings.cookie_domain && this.url) {
|
|
2546
|
+
let wanted_domain = alchemy.settings.cookie_domain,
|
|
2547
|
+
actual_domain = this.url.hostname;
|
|
2548
|
+
|
|
2549
|
+
if (wanted_domain != actual_domain) {
|
|
2550
|
+
// You can only set a cookie on the current domain,
|
|
2551
|
+
// or a parent domain. But not on a child domain.
|
|
2552
|
+
if (wanted_domain.length < actual_domain.length && actual_domain.endsWith(wanted_domain)) {
|
|
2553
|
+
// It's allowed!
|
|
2554
|
+
} else {
|
|
2555
|
+
// When on a domain like "11ways.be" you
|
|
2556
|
+
// can not set a cookie for "www.11ways.be"
|
|
2557
|
+
wanted_domain = false;
|
|
2558
|
+
}
|
|
2559
|
+
}
|
|
2560
|
+
|
|
2561
|
+
if (wanted_domain) {
|
|
2562
|
+
options.domain = wanted_domain;
|
|
2563
|
+
}
|
|
2564
|
+
}
|
|
2565
|
+
|
|
2496
2566
|
if (this.websocket) {
|
|
2497
2567
|
return this.socket.emit('alchemy-set-cookie', {name: name, value: value, options: options});
|
|
2498
2568
|
}
|
|
2499
2569
|
|
|
2500
2570
|
// Create the basic header string
|
|
2501
|
-
header = String.encodeCookie(name, value, options);
|
|
2571
|
+
let header = String.encodeCookie(name, value, options);
|
|
2502
2572
|
|
|
2503
2573
|
// Add this to the cookieheader array
|
|
2504
2574
|
this.new_cookie_header.push(header);
|
package/lib/class/model.js
CHANGED
|
@@ -1246,6 +1246,30 @@ Model.setMethod(function nukeCache(associated, parent) {
|
|
|
1246
1246
|
}
|
|
1247
1247
|
});
|
|
1248
1248
|
|
|
1249
|
+
/**
|
|
1250
|
+
* Perform a MongoDB pipeline
|
|
1251
|
+
*
|
|
1252
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
1253
|
+
* @since 1.3.17
|
|
1254
|
+
* @version 1.3.17
|
|
1255
|
+
*
|
|
1256
|
+
* @param {Array} pipeline
|
|
1257
|
+
*
|
|
1258
|
+
* @return {Promise}
|
|
1259
|
+
*/
|
|
1260
|
+
Model.setMethod(async function executeMongoPipeline(pipeline) {
|
|
1261
|
+
|
|
1262
|
+
if (typeof this.datasource.collection != 'function') {
|
|
1263
|
+
throw new Error('The `' + this.model_name + '` model does not seem to use MongoDB, unable to perform pipeline');
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
let collection = await this.datasource.collection(this.table);
|
|
1267
|
+
let cursor = await collection.aggregate(pipeline);
|
|
1268
|
+
let result = await cursor.toArray();
|
|
1269
|
+
|
|
1270
|
+
return result;
|
|
1271
|
+
});
|
|
1272
|
+
|
|
1249
1273
|
/**
|
|
1250
1274
|
* Delete the given record id
|
|
1251
1275
|
*
|
|
@@ -892,7 +892,7 @@ Schema.setMethod(function getFieldNames() {
|
|
|
892
892
|
*
|
|
893
893
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
894
894
|
* @since 0.2.0
|
|
895
|
-
* @version 1.3.
|
|
895
|
+
* @version 1.3.17
|
|
896
896
|
*
|
|
897
897
|
* @param {String|FieldType} _field
|
|
898
898
|
* @param {Object} options
|
|
@@ -901,24 +901,19 @@ Schema.setMethod(function getFieldNames() {
|
|
|
901
901
|
*/
|
|
902
902
|
Schema.setMethod(function addIndex(_field, _options) {
|
|
903
903
|
|
|
904
|
-
var that = this,
|
|
905
|
-
datasource,
|
|
906
|
-
options,
|
|
907
|
-
order,
|
|
908
|
-
field,
|
|
909
|
-
path;
|
|
910
|
-
|
|
911
904
|
// `Schema` is the `Client.Schema` class in this scope
|
|
912
905
|
if (Blast.isNode && this.constructor == Schema) {
|
|
913
906
|
return;
|
|
914
907
|
}
|
|
915
908
|
|
|
916
|
-
field = this.getField(_field);
|
|
909
|
+
let field = this.getField(_field);
|
|
917
910
|
|
|
918
911
|
if (!field) {
|
|
919
912
|
throw new Error('Could not find field "' + _field + '"');
|
|
920
913
|
}
|
|
921
914
|
|
|
915
|
+
let options;
|
|
916
|
+
|
|
922
917
|
if (typeof _options === 'string') {
|
|
923
918
|
options = {};
|
|
924
919
|
options[_options] = true;
|
|
@@ -961,6 +956,8 @@ Schema.setMethod(function addIndex(_field, _options) {
|
|
|
961
956
|
this.has_alternates++;
|
|
962
957
|
}
|
|
963
958
|
|
|
959
|
+
const that = this;
|
|
960
|
+
|
|
964
961
|
that.getDatasource().done(function gotDs(err, datasource) {
|
|
965
962
|
|
|
966
963
|
if (err) {
|
|
@@ -977,7 +974,7 @@ Schema.setMethod(function addIndex(_field, _options) {
|
|
|
977
974
|
return alchemy.printLog('error', ['Unable to ensure index on this datasource', options.name], {err: new Error()});
|
|
978
975
|
}
|
|
979
976
|
|
|
980
|
-
path = field.path;
|
|
977
|
+
let path = field.path;
|
|
981
978
|
|
|
982
979
|
if (options.db_property) {
|
|
983
980
|
path += '.' + options.db_property;
|
|
@@ -990,7 +987,7 @@ Schema.setMethod(function addIndex(_field, _options) {
|
|
|
990
987
|
datasource.ensureIndex(that.model_class, that.indexes[options.name], function ensuredIndex(err, result) {
|
|
991
988
|
|
|
992
989
|
if (err) {
|
|
993
|
-
alchemy.printLog('error', ['Error ensuring index', options.name], {err: err});
|
|
990
|
+
alchemy.printLog('error', ['Error ensuring index', options.name, 'in model', that.model_name], {err: err});
|
|
994
991
|
}
|
|
995
992
|
});
|
|
996
993
|
});
|