alchemymvc 1.2.8 → 1.3.0
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/behaviour/sluggable_behaviour.js +4 -2
- package/lib/app/conduit/loopback_conduit.js +2 -2
- package/lib/app/helper/router_helper.js +82 -17
- package/lib/app/helper_controller/controller.js +45 -30
- package/lib/app/helper_datasource/00-nosql_datasource.js +44 -10
- package/lib/app/helper_field/enum_field.js +4 -4
- package/lib/app/helper_field/schema_field.js +6 -6
- package/lib/app/helper_model/document.js +41 -10
- package/lib/app/helper_model/field_set.js +11 -0
- package/lib/app/helper_model/model.js +35 -10
- package/lib/bootstrap.js +1 -0
- package/lib/class/conduit.js +231 -244
- package/lib/class/datasource.js +6 -2
- package/lib/class/document.js +3 -3
- package/lib/class/field.js +13 -0
- package/lib/class/inode.js +27 -0
- package/lib/class/inode_file.js +204 -4
- package/lib/class/model.js +4 -4
- package/lib/class/path_definition.js +76 -120
- package/lib/class/path_param_definition.js +202 -0
- package/lib/class/route.js +176 -32
- package/lib/class/router.js +17 -3
- package/lib/class/schema.js +11 -11
- package/lib/class/schema_client.js +52 -19
- package/lib/class/sitemap.js +341 -0
- package/lib/core/base.js +6 -2
- package/lib/core/client_alchemy.js +76 -7
- package/lib/core/client_base.js +16 -10
- package/lib/core/middleware.js +56 -45
- package/lib/init/alchemy.js +12 -9
- package/lib/init/constants.js +11 -0
- package/lib/init/functions.js +134 -83
- package/package.json +5 -5
package/lib/class/conduit.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
const FILECACHE = alchemy.getCache('served_files'),
|
|
2
|
+
RX_TEXT = /svg|xml|javascript|text/i;
|
|
3
|
+
|
|
4
|
+
var libstream = alchemy.use('stream'),
|
|
3
5
|
libpath = alchemy.use('path'),
|
|
4
|
-
libmime = alchemy.use('mime'),
|
|
5
6
|
libua = alchemy.use('useragent'),
|
|
6
7
|
zlib = alchemy.use('zlib'),
|
|
7
8
|
BODY = Symbol('body'),
|
|
@@ -345,7 +346,7 @@ Conduit.setMethod(function setRequestFiles(files) {
|
|
|
345
346
|
*
|
|
346
347
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
347
348
|
* @since 1.2.0
|
|
348
|
-
* @version 1.
|
|
349
|
+
* @version 1.3.0
|
|
349
350
|
*
|
|
350
351
|
* @param {Conduit} conduit
|
|
351
352
|
* @param {Array} files
|
|
@@ -370,7 +371,7 @@ function _setRequestFiles(conduit, files, target) {
|
|
|
370
371
|
|
|
371
372
|
_setRequestFiles(conduit, entry, context);
|
|
372
373
|
} else {
|
|
373
|
-
target[key] = Classes.Alchemy.Inode.File.
|
|
374
|
+
target[key] = Classes.Alchemy.Inode.File.fromUntrusted(entry);
|
|
374
375
|
}
|
|
375
376
|
}
|
|
376
377
|
}
|
|
@@ -980,7 +981,7 @@ Conduit.setMethod(function getRouteByName(name) {
|
|
|
980
981
|
*
|
|
981
982
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
982
983
|
* @since 0.2.0
|
|
983
|
-
* @version 1.
|
|
984
|
+
* @version 1.3.0
|
|
984
985
|
*
|
|
985
986
|
* @param {Route} after_route Only check routes after this one
|
|
986
987
|
*
|
|
@@ -1009,7 +1010,7 @@ Conduit.setMethod(async function parseRoute(after_route) {
|
|
|
1009
1010
|
|
|
1010
1011
|
if (temp) {
|
|
1011
1012
|
this.route = temp.route;
|
|
1012
|
-
this.
|
|
1013
|
+
this.setRouteParameters(temp.parameters);
|
|
1013
1014
|
this.route_string_parameters = temp.original_parameters;
|
|
1014
1015
|
this.path_definition = temp.definition;
|
|
1015
1016
|
} else {
|
|
@@ -1048,11 +1049,11 @@ Conduit.setMethod(async function parseRoute(after_route) {
|
|
|
1048
1049
|
}
|
|
1049
1050
|
|
|
1050
1051
|
if (temp) {
|
|
1051
|
-
this.
|
|
1052
|
+
this.setRouteParameters(temp.parameters);
|
|
1052
1053
|
this.route_string_parameters = temp.original_parameters || {};
|
|
1053
1054
|
this.path_definition = temp.definition;
|
|
1054
1055
|
} else {
|
|
1055
|
-
this.
|
|
1056
|
+
this.setRouteParameters();
|
|
1056
1057
|
}
|
|
1057
1058
|
}
|
|
1058
1059
|
});
|
|
@@ -1287,20 +1288,46 @@ Conduit.setMethod(function postpone(options) {
|
|
|
1287
1288
|
/**
|
|
1288
1289
|
* Set the response url
|
|
1289
1290
|
*
|
|
1291
|
+
* @deprecated Use {@link #setResponseUrl} instead
|
|
1292
|
+
*
|
|
1290
1293
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
1291
1294
|
* @since 1.2.5
|
|
1292
|
-
* @version 1.
|
|
1295
|
+
* @version 1.3.0
|
|
1293
1296
|
*
|
|
1294
1297
|
* @param {String|RURL} url
|
|
1295
1298
|
*/
|
|
1296
1299
|
Conduit.setMethod(function overrideResponseUrl(url) {
|
|
1300
|
+
return this.setResponseUrl(url);
|
|
1301
|
+
});
|
|
1297
1302
|
|
|
1298
|
-
|
|
1299
|
-
|
|
1303
|
+
/**
|
|
1304
|
+
* Set the response url
|
|
1305
|
+
*
|
|
1306
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
1307
|
+
* @since 1.3.0
|
|
1308
|
+
* @version 1.3.0
|
|
1309
|
+
*
|
|
1310
|
+
* @param {String|RURL|Boolean} new_url
|
|
1311
|
+
*/
|
|
1312
|
+
Conduit.setMethod(function setResponseUrl(new_url) {
|
|
1313
|
+
|
|
1314
|
+
if (new_url == null) {
|
|
1315
|
+
return;
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
if (!new_url) {
|
|
1319
|
+
this.renderer.history = false;
|
|
1320
|
+
return;
|
|
1321
|
+
} else {
|
|
1322
|
+
this.renderer.history = true;
|
|
1300
1323
|
}
|
|
1301
1324
|
|
|
1302
|
-
|
|
1303
|
-
|
|
1325
|
+
if (typeof new_url != 'string') {
|
|
1326
|
+
new_url = String(new_url);
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
this.setHeader('x-history-url', new_url);
|
|
1330
|
+
this.expose('redirected_to', new_url);
|
|
1304
1331
|
});
|
|
1305
1332
|
|
|
1306
1333
|
/**
|
|
@@ -1583,9 +1610,9 @@ Conduit.setMethod(function notModified() {
|
|
|
1583
1610
|
/**
|
|
1584
1611
|
* Respond with text. Objects get JSON-dry encoded
|
|
1585
1612
|
*
|
|
1586
|
-
* @author Jelle De Loecker <jelle@
|
|
1613
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
1587
1614
|
* @since 0.2.0
|
|
1588
|
-
* @version 1.
|
|
1615
|
+
* @version 1.3.0
|
|
1589
1616
|
*
|
|
1590
1617
|
* @param {String|Object} message
|
|
1591
1618
|
*/
|
|
@@ -1659,7 +1686,7 @@ Conduit.setMethod(function end(message) {
|
|
|
1659
1686
|
|
|
1660
1687
|
// Compress the output if the client accepts it,
|
|
1661
1688
|
// but only if the file is at least 150 bytes
|
|
1662
|
-
if (alchemy.settings.compression && message.length > 150 && this.accepts('gzip')) {
|
|
1689
|
+
if (alchemy.settings.compression !== false && message.length > 150 && this.accepts('gzip')) {
|
|
1663
1690
|
|
|
1664
1691
|
// Set the decompressed content-length for use in progress bars
|
|
1665
1692
|
this.setHeader('x-decompressed-content-length', Buffer.byteLength(message));
|
|
@@ -1865,287 +1892,229 @@ function bufferToStream(buffer) {
|
|
|
1865
1892
|
}
|
|
1866
1893
|
|
|
1867
1894
|
/**
|
|
1868
|
-
* Send a file to the browser
|
|
1869
|
-
* Uses cache-control by default.
|
|
1895
|
+
* Send a file to the browser
|
|
1870
1896
|
*
|
|
1871
|
-
* @author Jelle De Loecker <jelle@
|
|
1897
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
1872
1898
|
* @since 0.2.0
|
|
1873
|
-
* @version 1.
|
|
1899
|
+
* @version 1.3.0
|
|
1874
1900
|
*
|
|
1875
1901
|
* @param {String} path The path on the server to send to the browser
|
|
1876
1902
|
* @param {Object} options Options, including headers
|
|
1877
1903
|
*/
|
|
1878
|
-
Conduit.
|
|
1904
|
+
Conduit.setTypedMethod([Types.String, Types.Object.optional()], function serveFile(path, options = {}) {
|
|
1879
1905
|
|
|
1880
|
-
|
|
1881
|
-
tasks = [],
|
|
1882
|
-
stats,
|
|
1883
|
-
isStream;
|
|
1884
|
-
|
|
1885
|
-
// Create an options object if it doesn't exist yet
|
|
1886
|
-
if (options == null) {
|
|
1887
|
-
options = {};
|
|
1888
|
-
}
|
|
1906
|
+
let file = FILECACHE.get(path);
|
|
1889
1907
|
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
options.onError = function onError(err) {
|
|
1893
|
-
that.notFound(err);
|
|
1894
|
-
};
|
|
1908
|
+
if (!file) {
|
|
1909
|
+
file = new Classes.Alchemy.Inode.File(path);
|
|
1895
1910
|
}
|
|
1896
1911
|
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
if (Buffer.isBuffer(path)) {
|
|
1901
|
-
path = bufferToStream(path);
|
|
1902
|
-
}
|
|
1912
|
+
return this.serveFile(file, options);
|
|
1913
|
+
});
|
|
1903
1914
|
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1915
|
+
/**
|
|
1916
|
+
* Send a file to the browser
|
|
1917
|
+
*
|
|
1918
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
1919
|
+
* @since 0.2.0
|
|
1920
|
+
* @version 1.3.0
|
|
1921
|
+
*
|
|
1922
|
+
* @param {Alchemy.Inode.File} file The file to serve
|
|
1923
|
+
* @param {Object} options Options, including headers
|
|
1924
|
+
*/
|
|
1925
|
+
Conduit.setTypedMethod([Types.Alchemy.Inode.File, Types.Object.optional()], async function serveFile(file, options = {}) {
|
|
1914
1926
|
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1927
|
+
if (file.path && !FILECACHE.has(file.path)) {
|
|
1928
|
+
FILECACHE.set(file.path, file);
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
if (alchemy.settings.cache && (!options.cache_time && options.cache_time !== false)) {
|
|
1932
|
+
let stats = await file.getStats();
|
|
1933
|
+
options.cache_time = stats.mtime;
|
|
1920
1934
|
}
|
|
1921
1935
|
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
if (!stats.path) {
|
|
1926
|
-
return options.onError(new Error('No file to serve'));
|
|
1927
|
-
}
|
|
1928
|
-
|
|
1929
|
-
// Make sure the stats object is in the cache
|
|
1930
|
-
if (fileCache[stats.path] == null) {
|
|
1931
|
-
fileCache[stats.path] = stats;
|
|
1932
|
-
}
|
|
1933
|
-
|
|
1934
|
-
// Get file stats if it isn't available yet
|
|
1935
|
-
if (stats.mtime == null) {
|
|
1936
|
-
tasks.push(function getFileStats(next) {
|
|
1937
|
-
|
|
1938
|
-
fs.stat(stats.path, function gotStats(err, fileStats) {
|
|
1939
|
-
|
|
1940
|
-
if (err) {
|
|
1941
|
-
stats.err = err;
|
|
1942
|
-
stats.mtime = new Date();
|
|
1943
|
-
} else {
|
|
1944
|
-
Object.assign(stats, fileStats);
|
|
1945
|
-
}
|
|
1946
|
-
|
|
1947
|
-
next();
|
|
1948
|
-
});
|
|
1949
|
-
});
|
|
1950
|
-
}
|
|
1951
|
-
|
|
1952
|
-
// Get the mimetype if it isn't available yet
|
|
1953
|
-
if (!options.mimetype && stats.mimetype == null) {
|
|
1954
|
-
tasks.push(function getMimetype(next) {
|
|
1955
|
-
|
|
1956
|
-
// Don't use libmime if it isn't loaded,
|
|
1957
|
-
// that could be the case on NW.js
|
|
1958
|
-
if (!libmime) {
|
|
1959
|
-
return next();
|
|
1960
|
-
}
|
|
1961
|
-
|
|
1962
|
-
// Lookup the mimetype by the extension alone
|
|
1963
|
-
stats.mimetype = libmime.getType(stats.path);
|
|
1964
|
-
|
|
1965
|
-
// Return the result if a valid mimetype was found
|
|
1966
|
-
if (stats.mimetype !== 'application/octet-stream') {
|
|
1967
|
-
return next();
|
|
1968
|
-
}
|
|
1936
|
+
if (!options.mimetype) {
|
|
1937
|
+
options.mimetype = await file.getMimetype();
|
|
1938
|
+
}
|
|
1969
1939
|
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1940
|
+
if (!options.filename) {
|
|
1941
|
+
options.filename = file.name;
|
|
1942
|
+
}
|
|
1943
|
+
|
|
1944
|
+
return this.serveFile(file.createReadStream(), options);
|
|
1945
|
+
});
|
|
1974
1946
|
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1947
|
+
/**
|
|
1948
|
+
* Send a buffer to the client
|
|
1949
|
+
*
|
|
1950
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
1951
|
+
* @since 1.3.0
|
|
1952
|
+
* @version 1.3.0
|
|
1953
|
+
*
|
|
1954
|
+
* @param {Stream} buffer The buffer to send
|
|
1955
|
+
* @param {Object} options Options, including headers
|
|
1956
|
+
*/
|
|
1957
|
+
Conduit.setTypedMethod([Buffer, Types.Object.optional()], function serveFile(buffer, options = {}) {
|
|
1958
|
+
return this.serveFile(bufferToStream(buffer), options);
|
|
1959
|
+
});
|
|
1979
1960
|
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1961
|
+
/**
|
|
1962
|
+
* Send a stream to the client
|
|
1963
|
+
*
|
|
1964
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
1965
|
+
* @since 1.3.0
|
|
1966
|
+
* @version 1.3.0
|
|
1967
|
+
*
|
|
1968
|
+
* @param {Stream} stream The stream to send
|
|
1969
|
+
* @param {Object} options Options, including headers
|
|
1970
|
+
*/
|
|
1971
|
+
Conduit.setTypedMethod([Types.Stream, Types.Object.optional()], function serveFile(stream, options = {}) {
|
|
1984
1972
|
|
|
1985
|
-
|
|
1986
|
-
if (!getMagic()) {
|
|
1987
|
-
return next();
|
|
1988
|
-
}
|
|
1973
|
+
let is_text = false;
|
|
1989
1974
|
|
|
1990
|
-
|
|
1991
|
-
|
|
1975
|
+
if (options.mimetype && RX_TEXT.test(options.mimetype)) {
|
|
1976
|
+
options.mimetype += '; charset=utf-8';
|
|
1977
|
+
is_text = true;
|
|
1978
|
+
}
|
|
1992
1979
|
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1980
|
+
if (alchemy.settings.cache === false) {
|
|
1981
|
+
options.cache_time = null;
|
|
1982
|
+
}
|
|
1996
1983
|
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
});
|
|
2000
|
-
}
|
|
1984
|
+
if (options.compress == null) {
|
|
1985
|
+
options.compress = is_text;
|
|
2001
1986
|
}
|
|
2002
1987
|
|
|
2003
|
-
|
|
1988
|
+
if (options.compress && (alchemy.settings.compression === false || !this.accepts('gzip'))) {
|
|
1989
|
+
options.compress = false;
|
|
1990
|
+
}
|
|
2004
1991
|
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
headers,
|
|
2009
|
-
isText,
|
|
2010
|
-
since,
|
|
2011
|
-
key;
|
|
1992
|
+
if (options.cache_time && !alchemy.settings.cache) {
|
|
1993
|
+
options.cache_time = false;
|
|
1994
|
+
}
|
|
2012
1995
|
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
1996
|
+
if (!options.onError) {
|
|
1997
|
+
options.onError = err => this.notFound(err);
|
|
1998
|
+
}
|
|
2016
1999
|
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
}
|
|
2000
|
+
return this._sendStream(stream, options);
|
|
2001
|
+
});
|
|
2020
2002
|
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2003
|
+
/**
|
|
2004
|
+
* Send a stream to the client
|
|
2005
|
+
*
|
|
2006
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
2007
|
+
* @since 1.3.0
|
|
2008
|
+
* @version 1.3.0
|
|
2009
|
+
*
|
|
2010
|
+
* @param {Stream} stream The stream to send
|
|
2011
|
+
* @param {Object} options Options, including headers
|
|
2012
|
+
*/
|
|
2013
|
+
Conduit.setMethod(function _sendStream(stream, options) {
|
|
2024
2014
|
|
|
2025
|
-
|
|
2026
|
-
|
|
2015
|
+
if (options.cache_time) {
|
|
2016
|
+
let modified_since = this.headers['if-modified-since'];
|
|
2027
2017
|
|
|
2028
|
-
|
|
2029
|
-
since = new Date(
|
|
2018
|
+
if (modified_since != null) {
|
|
2019
|
+
let since = new Date(modified_since);
|
|
2030
2020
|
|
|
2031
2021
|
// If the file's modifytime is smaller or equal to the since time,
|
|
2032
2022
|
// don't serve the contents!
|
|
2033
|
-
if (
|
|
2034
|
-
return
|
|
2035
|
-
}
|
|
2036
|
-
}
|
|
2037
|
-
|
|
2038
|
-
mimetype = stats.mimetype;
|
|
2039
|
-
|
|
2040
|
-
// If we get a general mimetype, and an alternative is provided, use that one
|
|
2041
|
-
if (!mimetype || mimetype === 'application/octet-stream') {
|
|
2042
|
-
if (options.mimetype != null) {
|
|
2043
|
-
mimetype = options.mimetype;
|
|
2023
|
+
if (options.cache_time <= since) {
|
|
2024
|
+
return this.notModified();
|
|
2044
2025
|
}
|
|
2045
2026
|
}
|
|
2046
2027
|
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
//
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
// Setting the disposition makes the browser download the file
|
|
2057
|
-
// This is on by default, but can be disabled
|
|
2058
|
-
if (options.disposition == 'inline') {
|
|
2059
|
-
disposition = 'inline';
|
|
2060
|
-
|
|
2061
|
-
if (options.filename) {
|
|
2062
|
-
disposition += '; filename=' + JSON.stringify(options.filename)
|
|
2063
|
-
}
|
|
2064
|
-
|
|
2065
|
-
that.setHeader('content-disposition', disposition);
|
|
2066
|
-
} else if (options.disposition !== false) {
|
|
2067
|
-
if (options.filename) {
|
|
2068
|
-
disposition = 'attachment; filename=' + JSON.stringify(options.filename);
|
|
2069
|
-
} else {
|
|
2070
|
-
disposition = 'attachment';
|
|
2071
|
-
}
|
|
2028
|
+
// Allow the browser to cache this for 60 minutes,
|
|
2029
|
+
// after which it has to revalidate the content
|
|
2030
|
+
// by seeing if it has been modified
|
|
2031
|
+
this.setHeader('cache-control', 'public, max-age=3600, must-revalidate');
|
|
2032
|
+
this.setHeader('last-modified', options.cache_time.toGMTString());
|
|
2033
|
+
} else {
|
|
2034
|
+
this.setHeader('cache-control', 'no-cache');
|
|
2035
|
+
}
|
|
2072
2036
|
|
|
2073
|
-
|
|
2074
|
-
|
|
2037
|
+
let disposition,
|
|
2038
|
+
key;
|
|
2075
2039
|
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
// by seeing if it has been modified
|
|
2080
|
-
that.setHeader('cache-control', 'public, max-age=3600, must-revalidate');
|
|
2081
|
-
that.setHeader('last-modified', stats.mtime.toGMTString());
|
|
2082
|
-
} else if (!alchemy.settings.cache) {
|
|
2083
|
-
that.setHeader('cache-control', 'no-cache');
|
|
2084
|
-
}
|
|
2040
|
+
if (options.mimetype) {
|
|
2041
|
+
this.setHeader('content-type', options.mimetype);
|
|
2042
|
+
}
|
|
2085
2043
|
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2044
|
+
// Setting the disposition makes the browser download the file
|
|
2045
|
+
// This is on by default, but can be disabled
|
|
2046
|
+
if (options.disposition == 'inline') {
|
|
2047
|
+
disposition = 'inline';
|
|
2089
2048
|
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
return that.end();
|
|
2049
|
+
if (options.filename) {
|
|
2050
|
+
disposition += '; filename=' + JSON.stringify(options.filename)
|
|
2093
2051
|
}
|
|
2094
2052
|
|
|
2095
|
-
|
|
2096
|
-
|
|
2053
|
+
this.setHeader('content-disposition', disposition);
|
|
2054
|
+
} else if (options.disposition !== false) {
|
|
2055
|
+
if (options.filename) {
|
|
2056
|
+
disposition = 'attachment; filename=' + JSON.stringify(options.filename);
|
|
2097
2057
|
} else {
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
// Listen for file errors
|
|
2101
|
-
outStream.on('error', options.onError);
|
|
2058
|
+
disposition = 'attachment';
|
|
2102
2059
|
}
|
|
2103
2060
|
|
|
2104
|
-
|
|
2105
|
-
|
|
2061
|
+
this.setHeader('content-disposition', disposition);
|
|
2062
|
+
}
|
|
2106
2063
|
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2064
|
+
// Set all the headers
|
|
2065
|
+
for (key in options.headers) {
|
|
2066
|
+
this.setHeader(key, options.headers[key]);
|
|
2067
|
+
}
|
|
2110
2068
|
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2069
|
+
// Don't send anything if it's a HEAD request
|
|
2070
|
+
if (this.method == 'head') {
|
|
2071
|
+
return this.end();
|
|
2072
|
+
}
|
|
2114
2073
|
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2074
|
+
const response = this.response;
|
|
2075
|
+
let out_stream = stream;
|
|
2076
|
+
|
|
2077
|
+
if (options.compress) {
|
|
2078
|
+
// Set the gzip header
|
|
2079
|
+
this.setHeader('content-encoding', 'gzip');
|
|
2080
|
+
this.setHeader('vary', 'accept-encoding');
|
|
2122
2081
|
|
|
2123
|
-
|
|
2082
|
+
// Create the gzip stream
|
|
2083
|
+
out_stream = out_stream.pipe(zlib.createGzip());
|
|
2084
|
+
}
|
|
2124
2085
|
|
|
2086
|
+
if (options.cleanup_stream) {
|
|
2087
|
+
const cleanup = function cleanupOriginalStream() {
|
|
2125
2088
|
// Remove all pipes
|
|
2126
|
-
|
|
2089
|
+
stream.unpipe();
|
|
2127
2090
|
|
|
2128
|
-
if (
|
|
2129
|
-
|
|
2130
|
-
} else if (
|
|
2131
|
-
|
|
2091
|
+
if (stream.destroy) {
|
|
2092
|
+
stream.destroy();
|
|
2093
|
+
} else if (stream.end) {
|
|
2094
|
+
stream.end();
|
|
2132
2095
|
}
|
|
2133
|
-
}
|
|
2096
|
+
};
|
|
2134
2097
|
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2098
|
+
response.on('end', cleanup);
|
|
2099
|
+
response.on('finish', cleanup);
|
|
2100
|
+
response.on('error', cleanup);
|
|
2101
|
+
response.on('close', cleanup);
|
|
2102
|
+
}
|
|
2139
2103
|
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2104
|
+
// Set the response headers
|
|
2105
|
+
for (key in this.response_headers) {
|
|
2106
|
+
response.setHeader(key, this.response_headers[key]);
|
|
2107
|
+
}
|
|
2143
2108
|
|
|
2144
|
-
|
|
2109
|
+
if (this.new_cookie_header.length) {
|
|
2110
|
+
response.setHeader('set-cookie', this.new_cookie_header);
|
|
2111
|
+
}
|
|
2145
2112
|
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2113
|
+
// If we got this far, the file has been found!
|
|
2114
|
+
response.statusCode = 200;
|
|
2115
|
+
|
|
2116
|
+
// Actually stream the contents to the client
|
|
2117
|
+
out_stream.pipe(response);
|
|
2149
2118
|
});
|
|
2150
2119
|
|
|
2151
2120
|
/**
|
|
@@ -2307,6 +2276,24 @@ Conduit.setMethod(function routeParam(name) {
|
|
|
2307
2276
|
return this.params[name];
|
|
2308
2277
|
});
|
|
2309
2278
|
|
|
2279
|
+
/**
|
|
2280
|
+
* Set route parameters
|
|
2281
|
+
*
|
|
2282
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
2283
|
+
* @since 1.3.0
|
|
2284
|
+
* @version 1.3.0
|
|
2285
|
+
*/
|
|
2286
|
+
Conduit.setMethod(function setRouteParameters(data) {
|
|
2287
|
+
|
|
2288
|
+
if (!this.params) {
|
|
2289
|
+
this.params = {};
|
|
2290
|
+
}
|
|
2291
|
+
|
|
2292
|
+
if (data) {
|
|
2293
|
+
Object.assign(this.params, data);
|
|
2294
|
+
}
|
|
2295
|
+
});
|
|
2296
|
+
|
|
2310
2297
|
/**
|
|
2311
2298
|
* Get/set a cookie
|
|
2312
2299
|
*
|
|
@@ -2370,7 +2357,7 @@ Conduit.setMethod(function cookie(name, value, options) {
|
|
|
2370
2357
|
*
|
|
2371
2358
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
2372
2359
|
* @since 0.2.0
|
|
2373
|
-
* @version 1.
|
|
2360
|
+
* @version 1.3.0
|
|
2374
2361
|
*
|
|
2375
2362
|
* @param {String} name
|
|
2376
2363
|
* @param {Mixed} value
|
|
@@ -2382,7 +2369,7 @@ Conduit.setMethod(function setHeader(name, value) {
|
|
|
2382
2369
|
}
|
|
2383
2370
|
|
|
2384
2371
|
if (this.websocket) {
|
|
2385
|
-
throw new Error("Can't set
|
|
2372
|
+
throw new Error("Can't set header `" + name + "` on a websocket connection");
|
|
2386
2373
|
}
|
|
2387
2374
|
|
|
2388
2375
|
this.response_headers[name] = value;
|
package/lib/class/datasource.js
CHANGED
|
@@ -165,7 +165,7 @@ Datasource.setMethod(function getSchema(schema) {
|
|
|
165
165
|
*
|
|
166
166
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
167
167
|
* @since 0.2.0
|
|
168
|
-
* @version 1.
|
|
168
|
+
* @version 1.3.0
|
|
169
169
|
*
|
|
170
170
|
* @param {Schema|Model} schema
|
|
171
171
|
* @param {Object} data
|
|
@@ -187,7 +187,11 @@ Datasource.setMethod(function toDatasource(schema, data, callback) {
|
|
|
187
187
|
}
|
|
188
188
|
|
|
189
189
|
if (!schema) {
|
|
190
|
-
|
|
190
|
+
|
|
191
|
+
if (alchemy.settings.debug) {
|
|
192
|
+
log.todo('Schema not found: not normalizing data', data);
|
|
193
|
+
}
|
|
194
|
+
|
|
191
195
|
pledge = Pledge.resolve(data);
|
|
192
196
|
pledge.done(callback);
|
|
193
197
|
return pledge;
|
package/lib/class/document.js
CHANGED
|
@@ -647,7 +647,7 @@ Document.setMethod(['populate', 'addAssociatedData'], function addAssociatedData
|
|
|
647
647
|
*
|
|
648
648
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
649
649
|
* @since 0.3.0
|
|
650
|
-
* @version
|
|
650
|
+
* @version 1.3.0
|
|
651
651
|
*
|
|
652
652
|
* @param {Object} options
|
|
653
653
|
*
|
|
@@ -663,7 +663,7 @@ Document.setMethod(function getDisplayFieldValue(options) {
|
|
|
663
663
|
options = {};
|
|
664
664
|
}
|
|
665
665
|
|
|
666
|
-
display_field = Array.cast(this.$model.
|
|
666
|
+
display_field = Array.cast(this.$model.display_field);
|
|
667
667
|
|
|
668
668
|
// If there are fields we prefer, check those first
|
|
669
669
|
if (options.prefer) {
|
|
@@ -674,7 +674,7 @@ Document.setMethod(function getDisplayFieldValue(options) {
|
|
|
674
674
|
result = this[display_field[i]];
|
|
675
675
|
|
|
676
676
|
if (result) {
|
|
677
|
-
result = alchemy.pickTranslation(
|
|
677
|
+
result = alchemy.pickTranslation(options.prefix, result).result;
|
|
678
678
|
|
|
679
679
|
if (result) {
|
|
680
680
|
return result;
|