mirror of
				https://github.com/NodeBB/NodeBB.git
				synced 2025-10-31 02:55:58 +01:00 
			
		
		
		
	feat: #7743 , meta/cachebuster, meta/configs
This commit is contained in:
		| @@ -1,48 +1,45 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| var async = require('async'); | ||||
| var fs = require('fs'); | ||||
| var path = require('path'); | ||||
| var mkdirp = require('mkdirp'); | ||||
| var winston = require('winston'); | ||||
| const fs = require('fs'); | ||||
| const path = require('path'); | ||||
| const mkdirp = require('mkdirp'); | ||||
| const winston = require('winston'); | ||||
| const util = require('util'); | ||||
| const mkdirpAsync = util.promisify(mkdirp); | ||||
| const writeFileAsync = util.promisify(fs.writeFile); | ||||
| const readFileAsync = util.promisify(fs.readFile); | ||||
|  | ||||
| var filePath = path.join(__dirname, '../../build/cache-buster'); | ||||
| const filePath = path.join(__dirname, '../../build/cache-buster'); | ||||
|  | ||||
| var cached; | ||||
| let cached; | ||||
|  | ||||
| // cache buster is an 11-character, lowercase, alphanumeric string | ||||
| function generate() { | ||||
| 	return (Math.random() * 1e18).toString(32).slice(0, 11); | ||||
| } | ||||
|  | ||||
| exports.write = function write(callback) { | ||||
| 	async.waterfall([ | ||||
| 		function (next) { | ||||
| 			mkdirp(path.dirname(filePath), next); | ||||
| 		}, | ||||
| 		function (data, next) { | ||||
| 			fs.writeFile(filePath, generate(), next); | ||||
| 		}, | ||||
| 	], callback); | ||||
| exports.write = async function write() { | ||||
| 	await mkdirpAsync(path.dirname(filePath)); | ||||
| 	await writeFileAsync(filePath, generate()); | ||||
| }; | ||||
|  | ||||
| exports.read = function read(callback) { | ||||
| exports.read = async function read() { | ||||
| 	if (cached) { | ||||
| 		return callback(null, cached); | ||||
| 		return cached; | ||||
| 	} | ||||
|  | ||||
| 	fs.readFile(filePath, 'utf8', function (err, buster) { | ||||
| 		if (err) { | ||||
| 			winston.warn('[cache-buster] could not read cache buster', err); | ||||
| 			return callback(null, generate()); | ||||
| 		} | ||||
|  | ||||
| 	try { | ||||
| 		const buster = await readFileAsync(filePath, 'utf8'); | ||||
| 		if (!buster || buster.length !== 11) { | ||||
| 			winston.warn('[cache-buster] cache buster string invalid: expected /[a-z0-9]{11}/, got `' + buster + '`'); | ||||
| 			return callback(null, generate()); | ||||
| 			return generate(); | ||||
| 		} | ||||
|  | ||||
| 		cached = buster; | ||||
| 		callback(null, cached); | ||||
| 	}); | ||||
| 		return cached; | ||||
| 	} catch (err) { | ||||
| 		winston.warn('[cache-buster] could not read cache buster', err); | ||||
| 		return generate(); | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| require('../promisify')(exports); | ||||
|   | ||||
| @@ -1,15 +1,15 @@ | ||||
|  | ||||
| 'use strict'; | ||||
|  | ||||
| var async = require('async'); | ||||
| var nconf = require('nconf'); | ||||
| var path = require('path'); | ||||
| var winston = require('winston'); | ||||
| const nconf = require('nconf'); | ||||
| const path = require('path'); | ||||
| const winston = require('winston'); | ||||
| const util = require('util'); | ||||
|  | ||||
| var db = require('../database'); | ||||
| var pubsub = require('../pubsub'); | ||||
| var Meta = require('../meta'); | ||||
| var cacheBuster = require('./cacheBuster'); | ||||
| const db = require('../database'); | ||||
| const pubsub = require('../pubsub'); | ||||
| const Meta = require('../meta'); | ||||
| const cacheBuster = require('./cacheBuster'); | ||||
| const defaults = require('../../install/data/defaults'); | ||||
|  | ||||
| var Configs = module.exports; | ||||
| @@ -48,152 +48,114 @@ function deserialize(config) { | ||||
|  | ||||
| Configs.deserialize = deserialize; | ||||
|  | ||||
| Configs.init = function (callback) { | ||||
| 	var config; | ||||
| 	async.waterfall([ | ||||
| 		function (next) { | ||||
| 			Configs.list(next); | ||||
| 		}, | ||||
| 		function (_config, next) { | ||||
| 			config = _config; | ||||
| 			cacheBuster.read(next); | ||||
| 		}, | ||||
| 		function (buster, next) { | ||||
| Configs.init = async function () { | ||||
| 	const config = await Configs.list(); | ||||
| 	const buster = await cacheBuster.read(); | ||||
| 	config['cache-buster'] = 'v=' + (buster || Date.now()); | ||||
| 	Meta.config = config; | ||||
| 			next(); | ||||
| 		}, | ||||
| 	], callback); | ||||
| }; | ||||
|  | ||||
| Configs.list = function (callback) { | ||||
| 	Configs.getFields([], callback); | ||||
| Configs.list = async function () { | ||||
| 	return await Configs.getFields([]); | ||||
| }; | ||||
|  | ||||
| Configs.get = function (field, callback) { | ||||
| 	Configs.getFields([field], function (err, values) { | ||||
| 		callback(err, values ? values[field] : null); | ||||
| 	}); | ||||
| Configs.get = async function (field) { | ||||
| 	const values = await Configs.getFields([field]); | ||||
| 	return (values.hasOwnProperty(field) && values[field] !== undefined) ? values[field] : null; | ||||
| }; | ||||
|  | ||||
| Configs.getFields = function (fields, callback) { | ||||
| 	async.waterfall([ | ||||
| 		function (next) { | ||||
| Configs.getFields = async function (fields) { | ||||
| 	let values; | ||||
| 	if (fields.length) { | ||||
| 				db.getObjectFields('config', fields, next); | ||||
| 		values = await db.getObjectFields('config', fields); | ||||
| 	} else { | ||||
| 				db.getObject('config', next); | ||||
| 		values = await db.getObject('config'); | ||||
| 	} | ||||
| 		}, | ||||
| 		function (values, next) { | ||||
| 			try { | ||||
|  | ||||
| 	values = Object.assign({}, defaults, values ? deserialize(values) : {}); | ||||
| 			} catch (err) { | ||||
| 				return next(err); | ||||
| 			} | ||||
|  | ||||
| 	if (!fields.length) { | ||||
| 		values.version = nconf.get('version'); | ||||
| 		values.registry = nconf.get('registry'); | ||||
| 	} | ||||
| 			next(null, values); | ||||
| 		}, | ||||
| 	], callback); | ||||
| 	return values; | ||||
| }; | ||||
|  | ||||
| Configs.set = function (field, value, callback) { | ||||
| 	callback = callback || function () {}; | ||||
| Configs.set = async function (field, value) { | ||||
| 	if (!field) { | ||||
| 		return callback(new Error('[[error:invalid-data]]')); | ||||
| 		throw new Error('[[error:invalid-data]]'); | ||||
| 	} | ||||
|  | ||||
| 	Configs.setMultiple({ | ||||
| 	await Configs.setMultiple({ | ||||
| 		[field]: value, | ||||
| 	}, callback); | ||||
| 	}); | ||||
| }; | ||||
|  | ||||
| // data comes from client-side | ||||
| Configs.setMultiple = function (data, callback) { | ||||
| Configs.setMultiple = async function (data) { | ||||
| 	data = deserialize(data); | ||||
|  | ||||
| 	async.waterfall([ | ||||
| 		function (next) { | ||||
| 			processConfig(data, next); | ||||
| 		}, | ||||
| 		function (next) { | ||||
| 			db.setObject('config', data, next); | ||||
| 		}, | ||||
| 		function (next) { | ||||
| 	await processConfig(data); | ||||
| 	await db.setObject('config', data); | ||||
| 	updateConfig(data); | ||||
| 			setImmediate(next); | ||||
| 		}, | ||||
| 	], callback); | ||||
| }; | ||||
|  | ||||
| Configs.setOnEmpty = function (values, callback) { | ||||
| 	async.waterfall([ | ||||
| 		function (next) { | ||||
| 			db.getObject('config', next); | ||||
| 		}, | ||||
| 		function (data, next) { | ||||
| 			var config = Object.assign({}, values, data ? deserialize(data) : {}); | ||||
| 			db.setObject('config', config, next); | ||||
| 		}, | ||||
| 	], callback); | ||||
| Configs.setOnEmpty = async function (values) { | ||||
| 	const data = await db.getObject('config'); | ||||
| 	const config = Object.assign({}, values, data ? deserialize(data) : {}); | ||||
| 	await db.setObject('config', config); | ||||
| }; | ||||
|  | ||||
| Configs.remove = function (field, callback) { | ||||
| 	db.deleteObjectField('config', field, callback); | ||||
| Configs.remove = async function (field) { | ||||
| 	await db.deleteObjectField('config', field); | ||||
| }; | ||||
|  | ||||
| function processConfig(data, callback) { | ||||
| 	async.parallel([ | ||||
| 		async.apply(saveRenderedCss, data), | ||||
| 		function (next) { | ||||
| async function processConfig(data) { | ||||
| 	await Promise.all([ | ||||
| 		saveRenderedCss(data), | ||||
| 		getLogoSize(data), | ||||
| 	]); | ||||
| } | ||||
|  | ||||
| function lessRender(string, callback) { | ||||
| 	var less = require('less'); | ||||
| 	less.render(string, { | ||||
| 		compress: true, | ||||
| 	}, callback); | ||||
| } | ||||
|  | ||||
| const lessRenderAsync = util.promisify(lessRender); | ||||
|  | ||||
| async function saveRenderedCss(data) { | ||||
| 	if (!data.customCSS) { | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	const lessObject = await lessRenderAsync(data.customCSS); | ||||
| 	data.renderedCustomCSS = lessObject.css; | ||||
| } | ||||
|  | ||||
| async function getLogoSize(data) { | ||||
| 	var image = require('../image'); | ||||
| 			if (data['brand:logo']) { | ||||
| 				image.size(path.join(nconf.get('upload_path'), 'system', 'site-logo-x50.png'), function (err, size) { | ||||
| 					if (err && err.code === 'ENOENT') { | ||||
| 	if (!data['brand:logo']) { | ||||
| 		return; | ||||
| 	} | ||||
| 	let size; | ||||
| 	try { | ||||
| 		size = await image.size(path.join(nconf.get('upload_path'), 'system', 'site-logo-x50.png')); | ||||
| 	} catch (err) { | ||||
| 		if (err.code === 'ENOENT') { | ||||
| 			// For whatever reason the x50 logo wasn't generated, gracefully error out | ||||
| 			winston.warn('[logo] The email-safe logo doesn\'t seem to have been created, please re-upload your site logo.'); | ||||
| 			size = { | ||||
| 				height: 0, | ||||
| 				width: 0, | ||||
| 			}; | ||||
| 					} else if (err) { | ||||
| 						return next(err); | ||||
| 		} else { | ||||
| 			throw err; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	data['brand:emailLogo'] = nconf.get('url') + path.join(nconf.get('upload_url'), 'system', 'site-logo-x50.png'); | ||||
| 	data['brand:emailLogo:height'] = size.height; | ||||
| 	data['brand:emailLogo:width'] = size.width; | ||||
| 					next(); | ||||
| 				}); | ||||
| 			} else { | ||||
| 				setImmediate(next); | ||||
| 			} | ||||
| 		}, | ||||
| 	], function (err) { | ||||
| 		callback(err); | ||||
| 	}); | ||||
| } | ||||
|  | ||||
| function saveRenderedCss(data, callback) { | ||||
| 	if (!data.customCSS) { | ||||
| 		return setImmediate(callback); | ||||
| 	} | ||||
|  | ||||
| 	var less = require('less'); | ||||
| 	async.waterfall([ | ||||
| 		function (next) { | ||||
| 			less.render(data.customCSS, { | ||||
| 				compress: true, | ||||
| 			}, next); | ||||
| 		}, | ||||
| 		function (lessObject, next) { | ||||
| 			data.renderedCustomCSS = lessObject.css; | ||||
| 			setImmediate(next); | ||||
| 		}, | ||||
| 	], callback); | ||||
| } | ||||
|  | ||||
| function updateConfig(config) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user