Merge branch '0.0.9-alpha' of github.com:NuSkooler/enigma-bbs into user-interruptions
This commit is contained in:
commit
d9238ee6a5
Binary file not shown.
|
@ -127,14 +127,16 @@
|
||||||
mainMenuSystemStats: {
|
mainMenuSystemStats: {
|
||||||
mci: {
|
mci: {
|
||||||
BN1: { width: 17 }
|
BN1: { width: 17 }
|
||||||
VL2: { width: 17 }
|
VN2: { width: 17 }
|
||||||
OS3: { width: 33 }
|
OS3: { width: 33 }
|
||||||
SC4: { width: 33 }
|
SC4: { width: 33 }
|
||||||
DT5: { width: 33 }
|
|
||||||
CT6: { width: 33 }
|
|
||||||
AN7: { width: 6 }
|
AN7: { width: 6 }
|
||||||
ND8: { width: 6 }
|
ND8: { width: 6 }
|
||||||
TC9: { width: 6 }
|
TC9: { width: 6 }
|
||||||
|
TT11: { width: 6 }
|
||||||
|
PT12: { width: 6 }
|
||||||
|
TP13: { width: 6 }
|
||||||
|
NV14: { width: 17 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
28
core/bbs.js
28
core/bbs.js
|
@ -11,6 +11,8 @@ const logger = require('./logger.js');
|
||||||
const database = require('./database.js');
|
const database = require('./database.js');
|
||||||
const resolvePath = require('./misc_util.js').resolvePath;
|
const resolvePath = require('./misc_util.js').resolvePath;
|
||||||
const UserProps = require('./user_property.js');
|
const UserProps = require('./user_property.js');
|
||||||
|
const SysProps = require('./system_property.js');
|
||||||
|
const SysLogKeys = require('./system_log.js');
|
||||||
|
|
||||||
// deps
|
// deps
|
||||||
const async = require('async');
|
const async = require('async');
|
||||||
|
@ -19,6 +21,7 @@ const _ = require('lodash');
|
||||||
const mkdirs = require('fs-extra').mkdirs;
|
const mkdirs = require('fs-extra').mkdirs;
|
||||||
const fs = require('graceful-fs');
|
const fs = require('graceful-fs');
|
||||||
const paths = require('path');
|
const paths = require('path');
|
||||||
|
const moment = require('moment');
|
||||||
|
|
||||||
// our main entry point
|
// our main entry point
|
||||||
exports.main = main;
|
exports.main = main;
|
||||||
|
@ -246,13 +249,13 @@ function initialize(cb) {
|
||||||
|
|
||||||
if(err) {
|
if(err) {
|
||||||
propLoadOpts.names.concat('username').forEach(v => {
|
propLoadOpts.names.concat('username').forEach(v => {
|
||||||
StatLog.setNonPeristentSystemStat(`sysop_${v}`, 'N/A');
|
StatLog.setNonPersistentSystemStat(`sysop_${v}`, 'N/A');
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
opProps.username = opUserName;
|
opProps.username = opUserName;
|
||||||
|
|
||||||
_.each(opProps, (v, k) => {
|
_.each(opProps, (v, k) => {
|
||||||
StatLog.setNonPeristentSystemStat(`sysop_${k}`, v);
|
StatLog.setNonPersistentSystemStat(`sysop_${k}`, v);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,17 +263,24 @@ function initialize(cb) {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
function initFileAreaStats(callback) {
|
function initCallsToday(callback) {
|
||||||
const getAreaStats = require('./file_base_area.js').getAreaStats;
|
const StatLog = require('./stat_log.js');
|
||||||
getAreaStats( (err, stats) => {
|
const filter = {
|
||||||
if(!err) {
|
logName : SysLogKeys.UserLoginHistory,
|
||||||
const StatLog = require('./stat_log.js');
|
resultType : 'count',
|
||||||
StatLog.setNonPeristentSystemStat('file_base_area_stats', stats);
|
date : moment(),
|
||||||
}
|
};
|
||||||
|
|
||||||
|
StatLog.findSystemLogEntries(filter, (err, callsToday) => {
|
||||||
|
if(!err) {
|
||||||
|
StatLog.setNonPersistentSystemStat(SysProps.LoginsToday, callsToday);
|
||||||
|
}
|
||||||
return callback(null);
|
return callback(null);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
function initMessageStats(callback) {
|
||||||
|
return require('./message_area.js').startup(callback);
|
||||||
|
},
|
||||||
function initMCI(callback) {
|
function initMCI(callback) {
|
||||||
return require('./predefined_mci.js').init(callback);
|
return require('./predefined_mci.js').init(callback);
|
||||||
},
|
},
|
||||||
|
|
|
@ -969,7 +969,7 @@ function getDefaultConfig() {
|
||||||
|
|
||||||
statLog : {
|
statLog : {
|
||||||
systemEvents : {
|
systemEvents : {
|
||||||
loginHistoryMax: -1 // forever
|
loginHistoryMax: -1, // set to -1 for forever
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -73,7 +73,7 @@ function getISOTimestampString(ts) {
|
||||||
}
|
}
|
||||||
ts = moment(ts);
|
ts = moment(ts);
|
||||||
}
|
}
|
||||||
return ts.utc().format('YYYY-MM-DDTHH:mm:ss.SSS[Z]');
|
return ts.format('YYYY-MM-DDTHH:mm:ss.SSSZ');
|
||||||
}
|
}
|
||||||
|
|
||||||
function sanatizeString(s) {
|
function sanatizeString(s) {
|
||||||
|
@ -189,14 +189,6 @@ const DB_INIT_TABLE = {
|
||||||
);`
|
);`
|
||||||
);
|
);
|
||||||
|
|
||||||
dbs.user.run(
|
|
||||||
`CREATE TABLE IF NOT EXISTS user_login_history (
|
|
||||||
user_id INTEGER NOT NULL,
|
|
||||||
user_name VARCHAR NOT NULL,
|
|
||||||
timestamp DATETIME NOT NULL
|
|
||||||
);`
|
|
||||||
);
|
|
||||||
|
|
||||||
return cb(null);
|
return cb(null);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,8 @@ const Log = require('./logger.js').log;
|
||||||
const getConnectionByUserId = require('./client_connections.js').getConnectionByUserId;
|
const getConnectionByUserId = require('./client_connections.js').getConnectionByUserId;
|
||||||
const webServerPackageName = require('./servers/content/web.js').moduleInfo.packageName;
|
const webServerPackageName = require('./servers/content/web.js').moduleInfo.packageName;
|
||||||
const Events = require('./events.js');
|
const Events = require('./events.js');
|
||||||
|
const UserProps = require('./user_property.js');
|
||||||
|
const SysProps = require('./system_menu_method.js');
|
||||||
|
|
||||||
// deps
|
// deps
|
||||||
const hashids = require('hashids');
|
const hashids = require('hashids');
|
||||||
|
@ -470,10 +472,11 @@ class FileAreaWebAccess {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
function updateStats(user, callback) {
|
function updateStats(user, callback) {
|
||||||
StatLog.incrementUserStat(user, 'dl_total_count', 1);
|
StatLog.incrementUserStat(user, UserProps.FileDlTotalCount, 1);
|
||||||
StatLog.incrementUserStat(user, 'dl_total_bytes', dlBytes);
|
StatLog.incrementUserStat(user, UserProps.FileDlTotalBytes, dlBytes);
|
||||||
StatLog.incrementSystemStat('dl_total_count', 1);
|
|
||||||
StatLog.incrementSystemStat('dl_total_bytes', dlBytes);
|
StatLog.incrementSystemStat(SysProps.FileDlTotalCount, 1);
|
||||||
|
StatLog.incrementSystemStat(SysProps.FileDlTotalBytes, dlBytes);
|
||||||
|
|
||||||
return callback(null, user);
|
return callback(null, user);
|
||||||
},
|
},
|
||||||
|
|
|
@ -15,6 +15,7 @@ const stringFormat = require('./string_format.js');
|
||||||
const wordWrapText = require('./word_wrap.js').wordWrapText;
|
const wordWrapText = require('./word_wrap.js').wordWrapText;
|
||||||
const StatLog = require('./stat_log.js');
|
const StatLog = require('./stat_log.js');
|
||||||
const UserProps = require('./user_property.js');
|
const UserProps = require('./user_property.js');
|
||||||
|
const SysProps = require('./system_property.js');
|
||||||
|
|
||||||
// deps
|
// deps
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
|
@ -56,7 +57,25 @@ const WellKnownAreaTags = exports.WellKnownAreaTags = {
|
||||||
};
|
};
|
||||||
|
|
||||||
function startup(cb) {
|
function startup(cb) {
|
||||||
return cleanUpTempSessionItems(cb);
|
async.series(
|
||||||
|
[
|
||||||
|
(callback) => {
|
||||||
|
return cleanUpTempSessionItems(callback);
|
||||||
|
},
|
||||||
|
(callback) => {
|
||||||
|
getAreaStats( (err, stats) => {
|
||||||
|
if(!err) {
|
||||||
|
StatLog.setNonPersistentSystemStat(SysProps.FileBaseAreaStats, stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
return callback(null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
],
|
||||||
|
err => {
|
||||||
|
return cb(err);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isInternalArea(areaTag) {
|
function isInternalArea(areaTag) {
|
||||||
|
@ -1012,7 +1031,7 @@ function getAreaStats(cb) {
|
||||||
function updateAreaStatsScheduledEvent(args, cb) {
|
function updateAreaStatsScheduledEvent(args, cb) {
|
||||||
getAreaStats( (err, stats) => {
|
getAreaStats( (err, stats) => {
|
||||||
if(!err) {
|
if(!err) {
|
||||||
StatLog.setNonPeristentSystemStat('file_base_area_stats', stats);
|
StatLog.setNonPersistentSystemStat(SysProps.FileBaseAreaStats, stats);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cb(err);
|
return cb(err);
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
const MenuModule = require('./menu_module.js').MenuModule;
|
const MenuModule = require('./menu_module.js').MenuModule;
|
||||||
const { getSortedAvailableFileAreas } = require('./file_base_area.js');
|
const { getSortedAvailableFileAreas } = require('./file_base_area.js');
|
||||||
const StatLog = require('./stat_log.js');
|
const StatLog = require('./stat_log.js');
|
||||||
|
const SysProps = require('./system_property.js');
|
||||||
|
|
||||||
// deps
|
// deps
|
||||||
const async = require('async');
|
const async = require('async');
|
||||||
|
@ -52,7 +53,7 @@ exports.getModule = class FileAreaSelectModule extends MenuModule {
|
||||||
async.waterfall(
|
async.waterfall(
|
||||||
[
|
[
|
||||||
function mergeAreaStats(callback) {
|
function mergeAreaStats(callback) {
|
||||||
const areaStats = StatLog.getSystemStat('file_base_area_stats') || { areas : {} };
|
const areaStats = StatLog.getSystemStat(SysProps.FileBaseAreaStats) || { areas : {} };
|
||||||
|
|
||||||
// we could use 'sort' alone, but area/conf sorting has some special properties; user can still override
|
// we could use 'sort' alone, but area/conf sorting has some special properties; user can still override
|
||||||
const availAreas = getSortedAvailableFileAreas(self.client);
|
const availAreas = getSortedAvailableFileAreas(self.client);
|
||||||
|
|
|
@ -11,6 +11,8 @@ const StatLog = require('./stat_log.js');
|
||||||
const FileEntry = require('./file_entry.js');
|
const FileEntry = require('./file_entry.js');
|
||||||
const Log = require('./logger.js').log;
|
const Log = require('./logger.js').log;
|
||||||
const Events = require('./events.js');
|
const Events = require('./events.js');
|
||||||
|
const UserProps = require('./user_property.js');
|
||||||
|
const SysProps = require('./system_property.js');
|
||||||
|
|
||||||
// deps
|
// deps
|
||||||
const async = require('async');
|
const async = require('async');
|
||||||
|
@ -479,10 +481,11 @@ exports.getModule = class TransferFileModule extends MenuModule {
|
||||||
});
|
});
|
||||||
}, () => {
|
}, () => {
|
||||||
// All stats/meta currently updated via fire & forget - if this is ever a issue, we can wait for callbacks
|
// All stats/meta currently updated via fire & forget - if this is ever a issue, we can wait for callbacks
|
||||||
StatLog.incrementUserStat(this.client.user, 'dl_total_count', downloadCount);
|
StatLog.incrementUserStat(this.client.user, UserProps.FileDlTotalCount, downloadCount);
|
||||||
StatLog.incrementUserStat(this.client.user, 'dl_total_bytes', downloadBytes);
|
StatLog.incrementUserStat(this.client.user, UserProps.FileDlTotalBytes, downloadBytes);
|
||||||
StatLog.incrementSystemStat('dl_total_count', downloadCount);
|
|
||||||
StatLog.incrementSystemStat('dl_total_bytes', downloadBytes);
|
StatLog.incrementSystemStat(SysProps.FileDlTotalCount, downloadCount);
|
||||||
|
StatLog.incrementSystemStat(SysProps.FileDlTotalBytes, downloadBytes);
|
||||||
|
|
||||||
fileIds.forEach(fileId => {
|
fileIds.forEach(fileId => {
|
||||||
FileEntry.incrementAndPersistMetaValue(fileId, 'dl_count', 1);
|
FileEntry.incrementAndPersistMetaValue(fileId, 'dl_count', 1);
|
||||||
|
@ -509,10 +512,11 @@ exports.getModule = class TransferFileModule extends MenuModule {
|
||||||
return next(null);
|
return next(null);
|
||||||
});
|
});
|
||||||
}, () => {
|
}, () => {
|
||||||
StatLog.incrementUserStat(this.client.user, 'ul_total_count', uploadCount);
|
StatLog.incrementUserStat(this.client.user, UserProps.FileUlTotalCount, uploadCount);
|
||||||
StatLog.incrementUserStat(this.client.user, 'ul_total_bytes', uploadBytes);
|
StatLog.incrementUserStat(this.client.user, UserProps.FileUlTotalBytes, uploadBytes);
|
||||||
StatLog.incrementSystemStat('ul_total_count', uploadCount);
|
|
||||||
StatLog.incrementSystemStat('ul_total_bytes', uploadBytes);
|
StatLog.incrementSystemStat(SysProps.FileUlTotalCount, uploadCount);
|
||||||
|
StatLog.incrementSystemStat(SysProps.FileUlTotalBytes, uploadBytes);
|
||||||
|
|
||||||
return cb(null);
|
return cb(null);
|
||||||
});
|
});
|
||||||
|
|
|
@ -25,6 +25,7 @@ const Config = require('./config.js').get;
|
||||||
const { getAddressedToInfo } = require('./mail_util.js');
|
const { getAddressedToInfo } = require('./mail_util.js');
|
||||||
const Events = require('./events.js');
|
const Events = require('./events.js');
|
||||||
const UserProps = require('./user_property.js');
|
const UserProps = require('./user_property.js');
|
||||||
|
const SysProps = require('./system_property.js');
|
||||||
|
|
||||||
// deps
|
// deps
|
||||||
const async = require('async');
|
const async = require('async');
|
||||||
|
@ -470,7 +471,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateUserStats(cb) {
|
updateUserAndSystemStats(cb) {
|
||||||
if(Message.isPrivateAreaTag(this.message.areaTag)) {
|
if(Message.isPrivateAreaTag(this.message.areaTag)) {
|
||||||
Events.emit(Events.getSystemEvents().UserSendMail, { user : this.client.user });
|
Events.emit(Events.getSystemEvents().UserSendMail, { user : this.client.user });
|
||||||
if(cb) {
|
if(cb) {
|
||||||
|
@ -480,6 +481,9 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul
|
||||||
}
|
}
|
||||||
|
|
||||||
Events.emit(Events.getSystemEvents().UserPostMessage, { user : this.client.user, areaTag : this.message.areaTag });
|
Events.emit(Events.getSystemEvents().UserPostMessage, { user : this.client.user, areaTag : this.message.areaTag });
|
||||||
|
|
||||||
|
StatLog.incrementNonPersistentSystemStat(SysProps.MessageTotalCount, 1);
|
||||||
|
StatLog.incrementNonPersistentSystemStat(SysProps.MessagesToday, 1);
|
||||||
return StatLog.incrementUserStat(this.client.user, UserProps.MessagePostCount, 1, cb);
|
return StatLog.incrementUserStat(this.client.user, UserProps.MessagePostCount, 1, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ const User = require('./user.js');
|
||||||
const sysDb = require('./database.js').dbs.system;
|
const sysDb = require('./database.js').dbs.system;
|
||||||
const { Errors } = require('./enig_error.js');
|
const { Errors } = require('./enig_error.js');
|
||||||
const UserProps = require('./user_property.js');
|
const UserProps = require('./user_property.js');
|
||||||
|
const SysLogKeys = require('./system_log.js');
|
||||||
|
|
||||||
// deps
|
// deps
|
||||||
const moment = require('moment');
|
const moment = require('moment');
|
||||||
|
@ -91,7 +92,7 @@ exports.getModule = class LastCallersModule extends MenuModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
StatLog.getSystemLogEntries(
|
StatLog.getSystemLogEntries(
|
||||||
'user_login_history',
|
SysLogKeys.UserLoginHistory,
|
||||||
StatLog.Order.TimestampDesc,
|
StatLog.Order.TimestampDesc,
|
||||||
200, // max items to fetch - we need more than max displayed for filtering/etc.
|
200, // max items to fetch - we need more than max displayed for filtering/etc.
|
||||||
(err, loginHistory) => {
|
(err, loginHistory) => {
|
||||||
|
|
|
@ -239,7 +239,10 @@ module.exports = class Message {
|
||||||
filter.toUserName
|
filter.toUserName
|
||||||
filter.fromUserName
|
filter.fromUserName
|
||||||
filter.replyToMesageId
|
filter.replyToMesageId
|
||||||
filter.newerThanTimestamp
|
|
||||||
|
filter.newerThanTimestamp - may not be used with |date|
|
||||||
|
filter.date - moment object - may not be used with |newerThanTimestamp|
|
||||||
|
|
||||||
filter.newerThanMessageId
|
filter.newerThanMessageId
|
||||||
filter.areaTag - note if you want by conf, send in all areas for a conf
|
filter.areaTag - note if you want by conf, send in all areas for a conf
|
||||||
*filter.metaTuples - {category, name, value}
|
*filter.metaTuples - {category, name, value}
|
||||||
|
@ -356,7 +359,10 @@ module.exports = class Message {
|
||||||
});
|
});
|
||||||
|
|
||||||
if(_.isString(filter.newerThanTimestamp) && filter.newerThanTimestamp.length > 0) {
|
if(_.isString(filter.newerThanTimestamp) && filter.newerThanTimestamp.length > 0) {
|
||||||
|
// :TODO: should be using "localtime" here?
|
||||||
appendWhereClause(`DATETIME(m.modified_timestamp) > DATETIME("${filter.newerThanTimestamp}", "+1 seconds")`);
|
appendWhereClause(`DATETIME(m.modified_timestamp) > DATETIME("${filter.newerThanTimestamp}", "+1 seconds")`);
|
||||||
|
} else if(moment.isMoment(filter.date)) {
|
||||||
|
appendWhereClause(`DATE(m.modified_timestamp, "localtime") = DATE("${filter.date.format('YYYY-MM-DD')}")`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_.isNumber(filter.newerThanMessageId)) {
|
if(_.isNumber(filter.newerThanMessageId)) {
|
||||||
|
|
|
@ -9,12 +9,17 @@ const Log = require('./logger.js').log;
|
||||||
const msgNetRecord = require('./msg_network.js').recordMessage;
|
const msgNetRecord = require('./msg_network.js').recordMessage;
|
||||||
const sortAreasOrConfs = require('./conf_area_util.js').sortAreasOrConfs;
|
const sortAreasOrConfs = require('./conf_area_util.js').sortAreasOrConfs;
|
||||||
const UserProps = require('./user_property.js');
|
const UserProps = require('./user_property.js');
|
||||||
|
const StatLog = require('./stat_log.js');
|
||||||
|
const SysProps = require('./system_property.js');
|
||||||
|
|
||||||
// deps
|
// deps
|
||||||
const async = require('async');
|
const async = require('async');
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
const moment = require('moment');
|
||||||
|
|
||||||
|
exports.startup = startup;
|
||||||
|
exports.shutdown = shutdown;
|
||||||
exports.getAvailableMessageConferences = getAvailableMessageConferences;
|
exports.getAvailableMessageConferences = getAvailableMessageConferences;
|
||||||
exports.getSortedAvailMessageConferences = getSortedAvailMessageConferences;
|
exports.getSortedAvailMessageConferences = getSortedAvailMessageConferences;
|
||||||
exports.getAvailableMessageAreasByConfTag = getAvailableMessageAreasByConfTag;
|
exports.getAvailableMessageAreasByConfTag = getAvailableMessageAreasByConfTag;
|
||||||
|
@ -35,6 +40,37 @@ exports.updateMessageAreaLastReadId = updateMessageAreaLastReadId;
|
||||||
exports.persistMessage = persistMessage;
|
exports.persistMessage = persistMessage;
|
||||||
exports.trimMessageAreasScheduledEvent = trimMessageAreasScheduledEvent;
|
exports.trimMessageAreasScheduledEvent = trimMessageAreasScheduledEvent;
|
||||||
|
|
||||||
|
function startup(cb) {
|
||||||
|
// by default, private messages are NOT included
|
||||||
|
async.series(
|
||||||
|
[
|
||||||
|
(callback) => {
|
||||||
|
Message.findMessages( { resultType : 'count' }, (err, count) => {
|
||||||
|
if(count) {
|
||||||
|
StatLog.setNonPersistentSystemStat(SysProps.MessageTotalCount, count);
|
||||||
|
}
|
||||||
|
return callback(err);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
(callback) => {
|
||||||
|
Message.findMessages( { resultType : 'count', date : moment() }, (err, count) => {
|
||||||
|
if(count) {
|
||||||
|
StatLog.setNonPersistentSystemStat(SysProps.MessagesToday, count);
|
||||||
|
}
|
||||||
|
return callback(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
],
|
||||||
|
err => {
|
||||||
|
return cb(err);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function shutdown(cb) {
|
||||||
|
return cb(null);
|
||||||
|
}
|
||||||
|
|
||||||
function getAvailableMessageConferences(client, options) {
|
function getAvailableMessageConferences(client, options) {
|
||||||
options = options || { includeSystemInternal : false };
|
options = options || { includeSystemInternal : false };
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ exports.getModule = class AreaPostFSEModule extends FullScreenEditorModule {
|
||||||
return persistMessage(msg, callback);
|
return persistMessage(msg, callback);
|
||||||
},
|
},
|
||||||
function updateStats(callback) {
|
function updateStats(callback) {
|
||||||
self.updateUserStats(callback);
|
self.updateUserAndSystemStats(callback);
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
function complete(err) {
|
function complete(err) {
|
||||||
|
|
|
@ -14,6 +14,8 @@ const FileBaseFilters = require('./file_base_filter.js');
|
||||||
const { formatByteSize } = require('./string_util.js');
|
const { formatByteSize } = require('./string_util.js');
|
||||||
const ANSI = require('./ansi_term.js');
|
const ANSI = require('./ansi_term.js');
|
||||||
const UserProps = require('./user_property.js');
|
const UserProps = require('./user_property.js');
|
||||||
|
const SysProps = require('./system_property.js');
|
||||||
|
const SysLogKeys = require('./system_log.js');
|
||||||
|
|
||||||
// deps
|
// deps
|
||||||
const packageJson = require('../package.json');
|
const packageJson = require('../package.json');
|
||||||
|
@ -29,12 +31,12 @@ function init(cb) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function setNextRandomRumor(cb) {
|
function setNextRandomRumor(cb) {
|
||||||
StatLog.getSystemLogEntries('system_rumorz', StatLog.Order.Random, 1, (err, entry) => {
|
StatLog.getSystemLogEntries(SysLogKeys.UserAddedRumorz, StatLog.Order.Random, 1, (err, entry) => {
|
||||||
if(entry) {
|
if(entry) {
|
||||||
entry = entry[0];
|
entry = entry[0];
|
||||||
}
|
}
|
||||||
const randRumor = entry && entry.log_value ? entry.log_value : '';
|
const randRumor = entry && entry.log_value ? entry.log_value : '';
|
||||||
StatLog.setNonPeristentSystemStat('random_rumor', randRumor);
|
StatLog.setNonPersistentSystemStat(SysProps.NextRandomRumor, randRumor);
|
||||||
if(cb) {
|
if(cb) {
|
||||||
return cb(null);
|
return cb(null);
|
||||||
}
|
}
|
||||||
|
@ -67,12 +69,12 @@ const PREDEFINED_MCI_GENERATORS = {
|
||||||
VN : function version() { return packageJson.version; },
|
VN : function version() { return packageJson.version; },
|
||||||
|
|
||||||
// +op info
|
// +op info
|
||||||
SN : function opUserName() { return StatLog.getSystemStat('sysop_username'); },
|
SN : function opUserName() { return StatLog.getSystemStat(SysProps.SysOpUsername); },
|
||||||
SR : function opRealName() { return StatLog.getSystemStat('sysop_real_name'); },
|
SR : function opRealName() { return StatLog.getSystemStat(SysProps.SysOpRealName); },
|
||||||
SL : function opLocation() { return StatLog.getSystemStat('sysop_location'); },
|
SL : function opLocation() { return StatLog.getSystemStat(SysProps.SysOpLocation); },
|
||||||
SA : function opAffils() { return StatLog.getSystemStat('sysop_affiliation'); },
|
SA : function opAffils() { return StatLog.getSystemStat(SysProps.SysOpAffiliations); },
|
||||||
SS : function opSex() { return StatLog.getSystemStat('sysop_sex'); },
|
SS : function opSex() { return StatLog.getSystemStat(SysProps.SysOpSex); },
|
||||||
SE : function opEmail() { return StatLog.getSystemStat('sysop_email_address'); },
|
SE : function opEmail() { return StatLog.getSystemStat(SysProps.SysOpEmailAddress); },
|
||||||
// :TODO: op age, web, ?????
|
// :TODO: op age, web, ?????
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -153,13 +155,14 @@ const PREDEFINED_MCI_GENERATORS = {
|
||||||
//
|
//
|
||||||
// Date/Time
|
// Date/Time
|
||||||
//
|
//
|
||||||
// :TODO: change to CD for 'Current Date'
|
|
||||||
DT : function date(client) { return moment().format(client.currentTheme.helpers.getDateFormat()); },
|
DT : function date(client) { return moment().format(client.currentTheme.helpers.getDateFormat()); },
|
||||||
CT : function time(client) { return moment().format(client.currentTheme.helpers.getTimeFormat()) ;},
|
CT : function time(client) { return moment().format(client.currentTheme.helpers.getTimeFormat()) ;},
|
||||||
|
|
||||||
//
|
//
|
||||||
// OS/System Info
|
// OS/System Info
|
||||||
//
|
//
|
||||||
|
// https://github.com/nodejs/node-v0.x-archive/issues/25769
|
||||||
|
//
|
||||||
OS : function operatingSystem() {
|
OS : function operatingSystem() {
|
||||||
return {
|
return {
|
||||||
linux : 'Linux',
|
linux : 'Linux',
|
||||||
|
@ -167,6 +170,9 @@ const PREDEFINED_MCI_GENERATORS = {
|
||||||
win32 : 'Windows',
|
win32 : 'Windows',
|
||||||
sunos : 'SunOS',
|
sunos : 'SunOS',
|
||||||
freebsd : 'FreeBSD',
|
freebsd : 'FreeBSD',
|
||||||
|
android : 'Android',
|
||||||
|
openbsd : 'OpenBSD',
|
||||||
|
aix : 'IBM AIX',
|
||||||
}[os.platform()] || os.type();
|
}[os.platform()] || os.type();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -189,7 +195,10 @@ const PREDEFINED_MCI_GENERATORS = {
|
||||||
|
|
||||||
AN : function activeNodes() { return clientConnections.getActiveConnections().length.toString(); },
|
AN : function activeNodes() { return clientConnections.getActiveConnections().length.toString(); },
|
||||||
|
|
||||||
TC : function totalCalls() { return StatLog.getSystemStat('login_count').toLocaleString(); },
|
TC : function totalCalls() { return StatLog.getSystemStat(SysProps.LoginCount).toLocaleString(); },
|
||||||
|
TT : function totalCallsToday() {
|
||||||
|
return StatLog.getSystemStat(SysProps.LoginsToday).toLocaleString();
|
||||||
|
},
|
||||||
|
|
||||||
RR : function randomRumor() {
|
RR : function randomRumor() {
|
||||||
// start the process of picking another random one
|
// start the process of picking another random one
|
||||||
|
@ -203,34 +212,35 @@ const PREDEFINED_MCI_GENERATORS = {
|
||||||
//
|
//
|
||||||
// :TODO: DD - Today's # of downloads (iNiQUiTY)
|
// :TODO: DD - Today's # of downloads (iNiQUiTY)
|
||||||
//
|
//
|
||||||
SD : function systemNumDownloads() { return sysStatAsString('dl_total_count', 0); },
|
SD : function systemNumDownloads() { return sysStatAsString(SysProps.FileDlTotalCount, 0); },
|
||||||
SO : function systemByteDownload() {
|
SO : function systemByteDownload() {
|
||||||
const byteSize = StatLog.getSystemStatNum('dl_total_bytes');
|
const byteSize = StatLog.getSystemStatNum(SysProps.FileDlTotalBytes);
|
||||||
return formatByteSize(byteSize, true); // true=withAbbr
|
return formatByteSize(byteSize, true); // true=withAbbr
|
||||||
},
|
},
|
||||||
SU : function systemNumUploads() { return sysStatAsString('ul_total_count', 0); },
|
SU : function systemNumUploads() { return sysStatAsString(SysProps.FileUlTotalCount, 0); },
|
||||||
SP : function systemByteUpload() {
|
SP : function systemByteUpload() {
|
||||||
const byteSize = StatLog.getSystemStatNum('ul_total_bytes');
|
const byteSize = StatLog.getSystemStatNum(SysProps.FileUlTotalBytes);
|
||||||
return formatByteSize(byteSize, true); // true=withAbbr
|
return formatByteSize(byteSize, true); // true=withAbbr
|
||||||
},
|
},
|
||||||
TF : function totalFilesOnSystem() {
|
TF : function totalFilesOnSystem() {
|
||||||
const areaStats = StatLog.getSystemStat('file_base_area_stats');
|
const areaStats = StatLog.getSystemStat(SysProps.FileBaseAreaStats);
|
||||||
return _.get(areaStats, 'totalFiles', 0).toLocaleString();
|
return _.get(areaStats, 'totalFiles', 0).toLocaleString();
|
||||||
},
|
},
|
||||||
TB : function totalBytesOnSystem() {
|
TB : function totalBytesOnSystem() {
|
||||||
const areaStats = StatLog.getSystemStat('file_base_area_stats');
|
const areaStats = StatLog.getSystemStat(SysProps.FileBaseAreaStats);
|
||||||
const totalBytes = parseInt(_.get(areaStats, 'totalBytes', 0));
|
const totalBytes = parseInt(_.get(areaStats, 'totalBytes', 0));
|
||||||
return formatByteSize(totalBytes, true); // true=withAbbr
|
return formatByteSize(totalBytes, true); // true=withAbbr
|
||||||
},
|
},
|
||||||
|
PT : function messagesPostedToday() { // Obv/2
|
||||||
|
return sysStatAsString(SysProps.MessagesToday, 0);
|
||||||
|
},
|
||||||
|
TP : function totalMessagesOnSystem() { // Obv/2
|
||||||
|
return sysStatAsString(SysProps.MessageTotalCount, 0);
|
||||||
|
},
|
||||||
|
|
||||||
// :TODO: PT - Messages posted *today* (Obv/2)
|
|
||||||
// -> Include FTN/etc.
|
|
||||||
// :TODO: NT - New users today (Obv/2)
|
// :TODO: NT - New users today (Obv/2)
|
||||||
// :TODO: CT - Calls *today* (Obv/2)
|
|
||||||
// :TODO: FT - Files uploaded/added *today* (Obv/2)
|
// :TODO: FT - Files uploaded/added *today* (Obv/2)
|
||||||
// :TODO: DD - Files downloaded *today* (iNiQUiTY)
|
// :TODO: DD - Files downloaded *today* (iNiQUiTY)
|
||||||
// :TODO: TP - total message/posts on the system (Obv/2)
|
|
||||||
// -> Include FTN/etc.
|
|
||||||
// :TODO: LC - name of last caller to system (Obv/2)
|
// :TODO: LC - name of last caller to system (Obv/2)
|
||||||
// :TODO: TZ - Average *system* post/call ratio (iNiQUiTY)
|
// :TODO: TZ - Average *system* post/call ratio (iNiQUiTY)
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ const theme = require('./theme.js');
|
||||||
const resetScreen = require('./ansi_term.js').resetScreen;
|
const resetScreen = require('./ansi_term.js').resetScreen;
|
||||||
const StatLog = require('./stat_log.js');
|
const StatLog = require('./stat_log.js');
|
||||||
const renderStringLength = require('./string_util.js').renderStringLength;
|
const renderStringLength = require('./string_util.js').renderStringLength;
|
||||||
|
const SystemLogKeys = require('./system_log.js');
|
||||||
|
|
||||||
// deps
|
// deps
|
||||||
const async = require('async');
|
const async = require('async');
|
||||||
|
@ -20,8 +21,6 @@ exports.moduleInfo = {
|
||||||
packageName : 'codes.l33t.enigma.rumorz',
|
packageName : 'codes.l33t.enigma.rumorz',
|
||||||
};
|
};
|
||||||
|
|
||||||
const STATLOG_KEY_RUMORZ = 'system_rumorz';
|
|
||||||
|
|
||||||
const FormIds = {
|
const FormIds = {
|
||||||
View : 0,
|
View : 0,
|
||||||
Add : 1,
|
Add : 1,
|
||||||
|
@ -52,10 +51,16 @@ exports.getModule = class RumorzModule extends MenuModule {
|
||||||
if(_.isString(formData.value.rumor) && renderStringLength(formData.value.rumor) > 0) {
|
if(_.isString(formData.value.rumor) && renderStringLength(formData.value.rumor) > 0) {
|
||||||
const rumor = formData.value.rumor.trim(); // remove any trailing ws
|
const rumor = formData.value.rumor.trim(); // remove any trailing ws
|
||||||
|
|
||||||
StatLog.appendSystemLogEntry(STATLOG_KEY_RUMORZ, rumor, StatLog.KeepDays.Forever, StatLog.KeepType.Forever, () => {
|
StatLog.appendSystemLogEntry(
|
||||||
this.clearAddForm();
|
SystemLogKeys.UserAddedRumorz,
|
||||||
return this.displayViewScreen(true, cb); // true=cls
|
rumor,
|
||||||
});
|
StatLog.KeepDays.Forever,
|
||||||
|
StatLog.KeepType.Forever,
|
||||||
|
() => {
|
||||||
|
this.clearAddForm();
|
||||||
|
return this.displayViewScreen(true, cb); // true=cls
|
||||||
|
}
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
// empty message - treat as if cancel was hit
|
// empty message - treat as if cancel was hit
|
||||||
return this.displayViewScreen(true, cb); // true=cls
|
return this.displayViewScreen(true, cb); // true=cls
|
||||||
|
@ -149,7 +154,7 @@ exports.getModule = class RumorzModule extends MenuModule {
|
||||||
function fetchEntries(callback) {
|
function fetchEntries(callback) {
|
||||||
const entriesView = self.viewControllers.view.getView(MciCodeIds.ViewForm.Entries);
|
const entriesView = self.viewControllers.view.getView(MciCodeIds.ViewForm.Entries);
|
||||||
|
|
||||||
StatLog.getSystemLogEntries(STATLOG_KEY_RUMORZ, StatLog.Order.Timestamp, (err, entries) => {
|
StatLog.getSystemLogEntries(SystemLogKeys.UserAddedRumorz, StatLog.Order.Timestamp, (err, entries) => {
|
||||||
return callback(err, entriesView, entries);
|
return callback(err, entriesView, entries);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -158,7 +163,7 @@ exports.getModule = class RumorzModule extends MenuModule {
|
||||||
return {
|
return {
|
||||||
text : e.log_value, // standard
|
text : e.log_value, // standard
|
||||||
rumor : e.log_value,
|
rumor : e.log_value,
|
||||||
}
|
};
|
||||||
}));
|
}));
|
||||||
|
|
||||||
entriesView.redraw();
|
entriesView.redraw();
|
||||||
|
|
|
@ -21,6 +21,8 @@ const copyFileWithCollisionHandling = require('../file_util.js').copyFileWit
|
||||||
const getAreaStorageDirectoryByTag = require('../file_base_area.js').getAreaStorageDirectoryByTag;
|
const getAreaStorageDirectoryByTag = require('../file_base_area.js').getAreaStorageDirectoryByTag;
|
||||||
const isValidStorageTag = require('../file_base_area.js').isValidStorageTag;
|
const isValidStorageTag = require('../file_base_area.js').isValidStorageTag;
|
||||||
const User = require('../user.js');
|
const User = require('../user.js');
|
||||||
|
const StatLog = require('../stat_log.js');
|
||||||
|
const SysProps = require('../system_property.js');
|
||||||
|
|
||||||
// deps
|
// deps
|
||||||
const moment = require('moment');
|
const moment = require('moment');
|
||||||
|
@ -1261,12 +1263,12 @@ function FTNMessageScanTossModule() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// we do this after such that error cases can be preseved above
|
// we do this after such that error cases can be preserved above
|
||||||
if(lookupName !== message.toUserName) {
|
if(lookupName !== message.toUserName) {
|
||||||
message.toUserName = localUserName;
|
message.toUserName = localUserName;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the meta information - used elsehwere for retrieval
|
// set the meta information - used elsewhere for retrieval
|
||||||
message.meta.System[Message.SystemMetaNames.LocalToUserID] = localToUserId;
|
message.meta.System[Message.SystemMetaNames.LocalToUserID] = localToUserId;
|
||||||
return callback(null);
|
return callback(null);
|
||||||
});
|
});
|
||||||
|
@ -1277,6 +1279,10 @@ function FTNMessageScanTossModule() {
|
||||||
|
|
||||||
// save to disc
|
// save to disc
|
||||||
message.persist(err => {
|
message.persist(err => {
|
||||||
|
if(!message.isPrivate()) {
|
||||||
|
StatLog.incrementNonPersistentSystemStat(SysProps.MessageTotalCount, 1);
|
||||||
|
StatLog.incrementNonPersistentSystemStat(SysProps.MessagesToday, 1);
|
||||||
|
}
|
||||||
return callback(err);
|
return callback(err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
133
core/stat_log.js
133
core/stat_log.js
|
@ -5,9 +5,11 @@ const sysDb = require('./database.js').dbs.system;
|
||||||
const {
|
const {
|
||||||
getISOTimestampString
|
getISOTimestampString
|
||||||
} = require('./database.js');
|
} = require('./database.js');
|
||||||
|
const Errors = require('./enig_error.js');
|
||||||
|
|
||||||
// deps
|
// deps
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
|
const moment = require('moment');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
System Event Log & Stats
|
System Event Log & Stats
|
||||||
|
@ -70,11 +72,23 @@ class StatLog {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// :TODO: fix spelling :)
|
setNonPersistentSystemStat(statName, statValue) {
|
||||||
setNonPeristentSystemStat(statName, statValue) {
|
|
||||||
this.systemStats[statName] = statValue;
|
this.systemStats[statName] = statValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
incrementNonPersistentSystemStat(statName, incrementBy) {
|
||||||
|
incrementBy = incrementBy || 1;
|
||||||
|
|
||||||
|
let newValue = parseInt(this.systemStats[statName]);
|
||||||
|
if(!isNaN(newValue)) {
|
||||||
|
newValue += incrementBy;
|
||||||
|
} else {
|
||||||
|
newValue = incrementBy;
|
||||||
|
}
|
||||||
|
this.setNonPersistentSystemStat(statName, newValue);
|
||||||
|
return newValue;
|
||||||
|
}
|
||||||
|
|
||||||
setSystemStat(statName, statValue, cb) {
|
setSystemStat(statName, statValue, cb) {
|
||||||
// live stats
|
// live stats
|
||||||
this.systemStats[statName] = statValue;
|
this.systemStats[statName] = statValue;
|
||||||
|
@ -100,19 +114,7 @@ class StatLog {
|
||||||
}
|
}
|
||||||
|
|
||||||
incrementSystemStat(statName, incrementBy, cb) {
|
incrementSystemStat(statName, incrementBy, cb) {
|
||||||
incrementBy = incrementBy || 1;
|
const newValue = this.incrementNonPersistentSystemStat(statName, incrementBy);
|
||||||
|
|
||||||
let newValue = parseInt(this.systemStats[statName]);
|
|
||||||
if(newValue) {
|
|
||||||
if(!_.isNumber(newValue)) {
|
|
||||||
return cb(new Error(`Value for ${statName} is not a number!`));
|
|
||||||
}
|
|
||||||
|
|
||||||
newValue += incrementBy;
|
|
||||||
} else {
|
|
||||||
newValue = incrementBy;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.setSystemStat(statName, newValue, cb);
|
return this.setSystemStat(statName, newValue, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,26 +219,78 @@ class StatLog {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getSystemLogEntries(logName, order, limit, cb) {
|
/*
|
||||||
let sql =
|
Find System Log entries by |filter|:
|
||||||
`SELECT timestamp, log_value
|
|
||||||
FROM system_event_log
|
|
||||||
WHERE log_name = ?`;
|
|
||||||
|
|
||||||
switch(order) {
|
filter.logName (required)
|
||||||
case 'timestamp' :
|
filter.resultType = (obj) | count
|
||||||
case 'timestamp_asc' :
|
where obj contains timestamp and log_value
|
||||||
sql += ' ORDER BY timestamp ASC';
|
filter.limit
|
||||||
break;
|
filter.date - exact date to filter against
|
||||||
|
filter.order = (timestamp) | timestamp_asc | timestamp_desc | random
|
||||||
case 'timestamp_desc' :
|
*/
|
||||||
sql += ' ORDER BY timestamp DESC';
|
findSystemLogEntries(filter, cb) {
|
||||||
break;
|
filter = filter || {};
|
||||||
|
if(!_.isString(filter.logName)) {
|
||||||
case 'random' :
|
return cb(Errors.MissingParam('filter.logName is required'));
|
||||||
sql += ' ORDER BY RANDOM()';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
filter.resultType = filter.resultType || 'obj';
|
||||||
|
filter.order = filter.order || 'timestamp';
|
||||||
|
|
||||||
|
let sql;
|
||||||
|
if('count' === filter.resultType) {
|
||||||
|
sql =
|
||||||
|
`SELECT COUNT() AS count
|
||||||
|
FROM system_event_log`;
|
||||||
|
} else {
|
||||||
|
sql =
|
||||||
|
`SELECT timestamp, log_value
|
||||||
|
FROM system_event_log`;
|
||||||
|
}
|
||||||
|
|
||||||
|
sql += ' WHERE log_name = ?';
|
||||||
|
|
||||||
|
if(filter.date) {
|
||||||
|
filter.date = moment(filter.date);
|
||||||
|
sql += ` AND DATE(timestamp, "localtime") = DATE("${filter.date.format('YYYY-MM-DD')}")`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if('count' !== filter.resultType) {
|
||||||
|
switch(filter.order) {
|
||||||
|
case 'timestamp' :
|
||||||
|
case 'timestamp_asc' :
|
||||||
|
sql += ' ORDER BY timestamp ASC';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'timestamp_desc' :
|
||||||
|
sql += ' ORDER BY timestamp DESC';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'random' :
|
||||||
|
sql += ' ORDER BY RANDOM()';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_.isNumber(filter.limit) && 0 !== filter.limit) {
|
||||||
|
sql += ` LIMIT ${filter.limit}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
sql += ';';
|
||||||
|
|
||||||
|
if('count' === filter.resultType) {
|
||||||
|
sysDb.get(sql, [ filter.logName ], (err, row) => {
|
||||||
|
return cb(err, row ? row.count : 0);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
sysDb.all(sql, [ filter.logName ], (err, rows) => {
|
||||||
|
return cb(err, rows);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getSystemLogEntries(logName, order, limit, cb) {
|
||||||
if(!cb && _.isFunction(limit)) {
|
if(!cb && _.isFunction(limit)) {
|
||||||
cb = limit;
|
cb = limit;
|
||||||
limit = 0;
|
limit = 0;
|
||||||
|
@ -244,15 +298,12 @@ class StatLog {
|
||||||
limit = limit || 0;
|
limit = limit || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(0 !== limit) {
|
const filter = {
|
||||||
sql += ` LIMIT ${limit}`;
|
logName,
|
||||||
}
|
order,
|
||||||
|
limit,
|
||||||
sql += ';';
|
};
|
||||||
|
return this.findSystemLogEntries(filter, cb);
|
||||||
sysDb.all(sql, [ logName ], (err, rows) => {
|
|
||||||
return cb(err, rows);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
appendUserLogEntry(user, logName, logValue, keepDays, cb) {
|
appendUserLogEntry(user, logName, logValue, keepDays, cb) {
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
/* jslint node: true */
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
//
|
||||||
|
// Common SYSTEM/global log keys
|
||||||
|
//
|
||||||
|
module.exports = {
|
||||||
|
UserAddedRumorz : 'system_rumorz',
|
||||||
|
UserLoginHistory : 'user_login_history',
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
/* jslint node: true */
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
//
|
||||||
|
// Common SYSTEM/global properties/stats used throughout the system.
|
||||||
|
//
|
||||||
|
// This IS NOT a full list. Custom modules & the like can create
|
||||||
|
// their own!
|
||||||
|
//
|
||||||
|
module.exports = {
|
||||||
|
LoginCount : 'login_count',
|
||||||
|
LoginsToday : 'logins_today', // non-persistent
|
||||||
|
|
||||||
|
FileBaseAreaStats : 'file_base_area_stats', // object - see file_base_area.js::getAreaStats
|
||||||
|
FileUlTotalCount : 'ul_total_count',
|
||||||
|
FileUlTotalBytes : 'ul_total_bytes',
|
||||||
|
FileDlTotalCount : 'dl_total_count',
|
||||||
|
FileDlTotalBytes : 'dl_total_bytes',
|
||||||
|
|
||||||
|
MessageTotalCount : 'message_post_total_count', // total non-private messages on the system; non-persistent
|
||||||
|
MessagesToday : 'message_post_today', // non-private messages posted/imported today; non-persistent
|
||||||
|
|
||||||
|
// begin +op non-persistent...
|
||||||
|
SysOpUsername : 'sysop_username',
|
||||||
|
SysOpRealName : 'sysop_real_name',
|
||||||
|
SysOpLocation : 'sysop_location',
|
||||||
|
SysOpAffiliations : 'sysop_affiliation',
|
||||||
|
SysOpSex : 'sysop_sex',
|
||||||
|
SysOpEmailAddress : 'sysop_email_address',
|
||||||
|
// end +op non-persistent
|
||||||
|
|
||||||
|
NextRandomRumor : 'random_rumor',
|
||||||
|
};
|
|
@ -473,7 +473,9 @@ module.exports = class User {
|
||||||
return this.removeProperty(name, next);
|
return this.removeProperty(name, next);
|
||||||
},
|
},
|
||||||
err => {
|
err => {
|
||||||
return cb(err);
|
if(cb) {
|
||||||
|
return cb(err);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,8 @@ const {
|
||||||
ErrorReasons
|
ErrorReasons
|
||||||
} = require('./enig_error.js');
|
} = require('./enig_error.js');
|
||||||
const UserProps = require('./user_property.js');
|
const UserProps = require('./user_property.js');
|
||||||
|
const SysProps = require('./system_property.js');
|
||||||
|
const SystemLogKeys = require('./system_log.js');
|
||||||
|
|
||||||
// deps
|
// deps
|
||||||
const async = require('async');
|
const async = require('async');
|
||||||
|
@ -86,7 +88,8 @@ function userLogin(client, username, password, cb) {
|
||||||
return callback(null);
|
return callback(null);
|
||||||
},
|
},
|
||||||
function updateSystemLoginCount(callback) {
|
function updateSystemLoginCount(callback) {
|
||||||
return StatLog.incrementSystemStat('login_count', 1, callback); // :TODO: create system_property.js
|
StatLog.incrementNonPersistentSystemStat(SysProps.LoginsToday, 1);
|
||||||
|
return StatLog.incrementSystemStat(SysProps.LoginCount, 1, callback);
|
||||||
},
|
},
|
||||||
function recordLastLogin(callback) {
|
function recordLastLogin(callback) {
|
||||||
return StatLog.setUserStat(user, UserProps.LastLoginTs, StatLog.now, callback);
|
return StatLog.setUserStat(user, UserProps.LastLoginTs, StatLog.now, callback);
|
||||||
|
@ -102,7 +105,7 @@ function userLogin(client, username, password, cb) {
|
||||||
});
|
});
|
||||||
|
|
||||||
return StatLog.appendSystemLogEntry(
|
return StatLog.appendSystemLogEntry(
|
||||||
'user_login_history',
|
SystemLogKeys.UserLoginHistory,
|
||||||
historyItem,
|
historyItem,
|
||||||
loginHistoryMax,
|
loginHistoryMax,
|
||||||
StatLog.KeepType.Max,
|
StatLog.KeepType.Max,
|
||||||
|
|
|
@ -65,12 +65,15 @@ for a full listing. Many codes attempt to pay homage to Oblivion/2, iNiQUiTY, et
|
||||||
| `SC` | System CPU model |
|
| `SC` | System CPU model |
|
||||||
| `NV` | System underlying Node.js version |
|
| `NV` | System underlying Node.js version |
|
||||||
| `AN` | Current active node count |
|
| `AN` | Current active node count |
|
||||||
| `TC` | Total login/calls to system |
|
| `TC` | Total login/calls to the system *ever* |
|
||||||
|
| `TT` | Total login/calls to the system *today* |
|
||||||
| `RR` | Displays a random rumor |
|
| `RR` | Displays a random rumor |
|
||||||
| `SD` | Total downloads, system wide |
|
| `SD` | Total downloads, system wide |
|
||||||
| `SO` | Total downloaded amount, system wide (formatted to appropriate bytes/megs/etc.) |
|
| `SO` | Total downloaded amount, system wide (formatted to appropriate bytes/megs/etc.) |
|
||||||
| `SU` | Total uploads, system wide |
|
| `SU` | Total uploads, system wide |
|
||||||
| `SP` | Total uploaded amount, system wide (formatted to appropriate bytes/megs/etc.) |
|
| `SP` | Total uploaded amount, system wide (formatted to appropriate bytes/megs/etc.) |
|
||||||
|
| `TP` | Total messages posted/imported to the system *currently* |
|
||||||
|
| `PT` | Total messages posted/imported to the system *today* |
|
||||||
|
|
||||||
Some additional special case codes also exist:
|
Some additional special case codes also exist:
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,10 @@ layout: page
|
||||||
title: ACS
|
title: ACS
|
||||||
---
|
---
|
||||||
## File Base ACS
|
## File Base ACS
|
||||||
[ACS Codes](/docs/configuration/acs.md) may be used to control acess to File Base areas by specifying an `acs` string in a file area's definition. If no `acs` is supplied in a file area definition, the following defaults apply to an area:
|
[ACS Codes](/docs/configuration/acs.md) may be used to control access to File Base areas by specifying an `acs` string in a file area's definition. If no `acs` is supplied in a file area definition, the following defaults apply to an area:
|
||||||
* `read` (list, download, etc.): `GM[users]`
|
* `read` : `GM[users]`: List/view the area and it's contents.
|
||||||
* `write` (upload): `GM[sysops]`
|
* `write` : `GM[sysops]`: Upload.
|
||||||
|
* `download` : `GM[users]`: Download.
|
||||||
|
|
||||||
To override read and/or write ACS, supply a valid `acs` member.
|
To override read and/or write ACS, supply a valid `acs` member.
|
||||||
|
|
||||||
|
@ -18,8 +19,13 @@ areas: {
|
||||||
desc: Oldschool PC/DOS
|
desc: Oldschool PC/DOS
|
||||||
storageTags: [ "retro_pc", "retro_pc_bbs" ]
|
storageTags: [ "retro_pc", "retro_pc_bbs" ]
|
||||||
acs: {
|
acs: {
|
||||||
write: GM[users]
|
// only users of the "l33t" group or those who have
|
||||||
|
// uploaded 10+ files can download from here...
|
||||||
|
download: GM[l33t]|UP10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
[Access Condition System (ACS)](/docs/configuration/acs.md)
|
||||||
|
|
|
@ -2,18 +2,21 @@
|
||||||
layout: page
|
layout: page
|
||||||
title: About File Areas
|
title: About File Areas
|
||||||
---
|
---
|
||||||
## A Different Approach
|
## About File Areas
|
||||||
ENiGMA½ has strayed away from the old familure setup here and instead takes a more modern approach:
|
|
||||||
* [Gazelle](https://whatcd.github.io/Gazelle/) inspired system for searching & browsing files
|
|
||||||
* No File Conferences (just areas!)
|
|
||||||
* File Areas are still around but should generally be used less. Instead, files can have one or more tags. Think things like `dos.retro`, `pc.warez`, `games`, etc.
|
|
||||||
* Temporary web (http:// or https://) download links in additional to standard X/Y/Z protocol support
|
|
||||||
* Users can star rate files & search/filter by ratings
|
|
||||||
* Concept of user defined filters
|
|
||||||
|
|
||||||
## Other bells and whistles
|
### A Different Approach
|
||||||
* A given area can span one to many physical storage locations
|
ENiGMA½ has strayed away from the old familiar setup here and instead takes a more modern approach:
|
||||||
* Upload processor can extract and use `FILE_ID.DIZ`/`DESC.SDI`, for standard descriptions as well as `README.TXT`, `*.NFO`, and so on for longer descriptions
|
* [Gazelle](https://whatcd.github.io/Gazelle/) inspired system for searching & browsing files.
|
||||||
* Upload processor also attempts release year estimation by scanning prementioned description file(s)
|
* No conferences (just areas!)
|
||||||
* Fast indexed Full Text Search (FTS)
|
* File areas are still around but should *generally* be used less. Instead, files can have one or more tags. Think things like `dos.retro`, `pc.warez`, `games`, etc.
|
||||||
* Duplicates validated by SHA-256
|
|
||||||
|
### Other bells and whistles
|
||||||
|
* Temporary web (http:// or https://) download links in additional to standard X/Y/Z protocol support. Batch downloads of many files can be downloaded as a single ZIP archive.
|
||||||
|
* Users can rate files & search/filter by ratings.
|
||||||
|
* Users can also create and save their own filters for later use such as "Latest Artscene Releases" or "C64 SIDs".
|
||||||
|
* A given area can span one to many physical storage locations.
|
||||||
|
* Upload processor can extract and use `FILE_ID.DIZ`/`DESC.SDI`, for standard descriptions as well as `README.TXT`, `*.NFO`, and so on for longer descriptions. The processor also attempts release year estimation by scanning aforementioned description file(s).
|
||||||
|
* Fast indexed [Full Text Search (FTS)](https://sqlite.org/fts3.html) across descriptions and filenames.
|
||||||
|
* Duplicates are checked for by cryptographically secure [SHA-256](https://en.wikipedia.org/wiki/SHA-2) hashes.
|
||||||
|
* Support for many archive and file formats. External utilities can easily be added to the configuration to extend for additional formats.
|
||||||
|
* Much, much more!
|
||||||
|
|
|
@ -2,7 +2,24 @@
|
||||||
layout: page
|
layout: page
|
||||||
title: Uploads
|
title: Uploads
|
||||||
---
|
---
|
||||||
|
## Uploads
|
||||||
|
The default ACS for file areas areas in ENiGMA½ is to allow read (viewing of the area), and downloads for users while only permitting SysOps to write (upload). See [File Base ACS](acs.md) for more information.
|
||||||
|
|
||||||
Note that `storageTags` may contain *1:n* storage tag references.
|
To allow uploads to a particular area, change the ACS level for `write`. For example:
|
||||||
|
```hjson
|
||||||
|
uploads: {
|
||||||
|
name: Uploads
|
||||||
|
desc: User Uploads
|
||||||
|
storageTags: [
|
||||||
|
"uploads"
|
||||||
|
]
|
||||||
|
acs: {
|
||||||
|
write: GM[users]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
````
|
||||||
|
|
||||||
|
:information_source: Remember that uploads in a particular area are stored **using the first storage tag defined in that area.**
|
||||||
|
|
||||||
|
:information_source: Any ACS checks are allowed. See [ACS](/docs/acs.md)
|
||||||
|
|
||||||
**Uploads in a particular area are stored in the first storage tag defined in an area.**
|
|
||||||
|
|
Loading…
Reference in New Issue