From a7f9e3846e649600cca8e3566e3bcf226411dd31 Mon Sep 17 00:00:00 2001 From: Bryan Ashby Date: Mon, 11 May 2015 16:39:28 -0600 Subject: [PATCH] * WIP on user groups * Minor changes to user credential prompt --- core/config.js | 1 + core/database.js | 5 +++ core/text_view.js | 6 ++- core/user.js | 56 ++++++++++++++-------------- core/user_group.js | 93 ++++++++++++++++++++++++++++++++++++++++++++++ mods/apply.js | 4 +- mods/menu.json | 3 +- mods/prompt.json | 14 ++++--- 8 files changed, 145 insertions(+), 37 deletions(-) create mode 100644 core/user_group.js diff --git a/core/config.js b/core/config.js index e74b7342..29ba1927 100644 --- a/core/config.js +++ b/core/config.js @@ -86,6 +86,7 @@ function getDefaultConfig() { passwordMax : 128, requireActivation : true, // require SysOp activation? invalidUsernames : [], + defaultGroups : [ 'users' ] }, defaults : { diff --git a/core/database.js b/core/database.js index dbf5e688..d363ac69 100644 --- a/core/database.js +++ b/core/database.js @@ -70,4 +70,9 @@ function createInitialValues() { 'INSERT OR IGNORE INTO user_group ' + 'VALUES(1, "users");' ); + + dbs.user.run( + 'INSERT OR IGNORE INTO user_group ' + + 'VALUES(2, "sysops");' + ); } \ No newline at end of file diff --git a/core/text_view.js b/core/text_view.js index 268bd90a..23c1418f 100644 --- a/core/text_view.js +++ b/core/text_view.js @@ -13,6 +13,10 @@ var _ = require('lodash'); exports.TextView = TextView; function TextView(options) { + if(options.dimens) { + options.dimens.height = 1; // force height of 1 for TextView's & sub classes + } + View.call(this, options); var self = this; @@ -36,8 +40,6 @@ function TextView(options) { this.textMaskChar = options.textMaskChar; } - this.dimens.height = 1; - this.drawText = function(s) { // diff --git a/core/user.js b/core/user.js index 2b8dd858..049cb6df 100644 --- a/core/user.js +++ b/core/user.js @@ -3,6 +3,7 @@ var userDb = require('./database.js').dbs.user; var Config = require('./config.js').config; +var userGroup = require('./user_group.js'); var crypto = require('crypto'); var assert = require('assert'); @@ -116,6 +117,15 @@ User.prototype.authenticate = function(username, password, cb) { cachedInfo.properties = allProps; } + callback(err); + }); + }, + function initGroups(callback) { + userGroup.getGroupsForUser(cachedInfo.userId, function groupsLoaded(err, groups) { + if(!err) { + cachedInfo.groups = groups; + } + callback(err); }); } @@ -125,6 +135,7 @@ User.prototype.authenticate = function(username, password, cb) { self.userId = cachedInfo.userId; self.username = cachedInfo.username; self.properties = cachedInfo.properties; + self.groups = cachedInfo.groups; self.authenticated = true; } @@ -164,6 +175,8 @@ User.prototype.create = function(options, cb) { // :TODO: set various defaults, e.g. default activation status, etc. self.properties.account_status = Config.users.requireActivation ? User.AccountStatus.inactive : User.AccountStatus.active; + // :TODO: Set default groups from Config.users.defaultGroups[] + async.series( [ function beginTransaction(callback) { @@ -203,6 +216,16 @@ User.prototype.create = function(options, cb) { } }); }, + function setInitialGroupMembership(callback) { + userGroup.getGroupsByName(Config.users.defaultGroups, function defaultGroups(err, groups) { + if(err) { + callback(err); + } else { + self.groups = groups; + callback(null); + } + }); + }, function saveAll(callback) { self.persist(false, function persisted(err) { callback(err); @@ -245,6 +268,11 @@ User.prototype.persist = function(useTransaction, cb) { persistProperties(self, function persisted(err) { callback(err); }); + }, + function saveGroups(callback) { + userGroup.addUserToGroups(self.userId, self.groups, function groupsSaved(err) { + callback(err); + }); } ], function complete(err) { @@ -452,34 +480,6 @@ function loadProperties(options, cb) { }); } -function loadGroups(userId, cb) { - // - // user_group - // group_id | group_name - // - // - // user_group_member - // group_id | user_id - // - // - var sql = ''; - - var groups = {}; // id:name - - userDb.each(sql, [ userId ], function dbRow(err, row) { - if(err) { - cb(err); - return; - } else { - //groups[row.group_id] - } - }, - function complete() { - cb(null, groups); - }); - -} - /*function getProperties(userId, propNames, cb) { var properties = {}; diff --git a/core/user_group.js b/core/user_group.js new file mode 100644 index 00000000..219fe613 --- /dev/null +++ b/core/user_group.js @@ -0,0 +1,93 @@ +/* jslint node: true */ +'use strict'; + +var userDb = require('./database.js').dbs.user; +var Config = require('./config.js').config; + +var async = require('async'); +var _ = require('lodash'); + +exports.getGroupsForUser = getGroupsForUser; +exports.getGroupsByName = getGroupsByName; +exports.addUserToGroup = addUserToGroup; +exports.addUserToGroups = addUserToGroups; +exports.removeUserFromGroup = removeUserFromGroup; + + +// +// user_group +// group_id | group_name +// +// +// user_group_member +// group_id | user_id +// +// + + +function getGroupsForUser(userId, cb) { + var sql = + 'SELECT g.group_id, g.group_name ' + + 'FROM user_group g, user_group_member gm ' + + 'WHERE g.group_id = gm.group_id AND gm.user_id = ?;'; + + var groups = {}; // id:name + + userDb.each(sql, [ userId ], function dbRow(err, row) { + if(err) { + cb(err); + return; + } else { + console.log(row); + //groups[row.group_id] + } + }, + function complete() { + cb(null, groups); + }); +} + +function getGroupsByName(groupNames, cb) { + var sql = + 'SELECT group_id, group_name ' + + 'FROM user_group ' + + 'WHERE group_name IN ("' + groupNames.join('","') + '");'; + + userDb.all(sql, function allRows(err, rows) { + if(err) { + cb(err); + return; + } else { + var groups = {}; + rows.forEach(function row(r) { + groups[r.group_id] = r.group_name; + }); + cb(null, groups); + } + }); +} + +function addUserToGroup(userId, groupId, cb) { + userDb.run( + 'REPLACE INTO user_group_member (group_id, user_id) ' + + 'VALUES(?, ?);', + [ groupId, userId ], + function complete(err) { + cb(err); + } + ); +} + +function addUserToGroups(userId, groups, cb) { + async.each(Object.keys(groups), function item(groupId, nextItem) { + addUserToGroup(userId, groupId, function added(err) { + nextItem(err); + }); + }, function complete(err) { + cb(err); + }); +} + +function removeUserFromGroup(userId, groupId, cb) { + +} diff --git a/mods/apply.js b/mods/apply.js index 4b4429b7..93dc7cd7 100644 --- a/mods/apply.js +++ b/mods/apply.js @@ -74,6 +74,7 @@ function submitApplication(callingMenu, formData, extraArgs) { menuViewController.switchFocus(viewIds[0]); } else { // Seems legit! + // :TODO: All of this should be a system API, not a mod var newUser = new user.User(); newUser.username = formData.value.username; @@ -87,10 +88,11 @@ function submitApplication(callingMenu, formData, extraArgs) { email_address : formData.value.email, web_address : formData.value.web, + // :TODO: This is set in User.create() -- proabbly don't need it here: account_status : Config.users.requireActivation ? user.User.AccountStatus.inactive : user.User.AccountStatus.active, // :TODO: Other defaults - // :TODO: should probably have a place to create defaults/etc. + // :TODO: should probably have a place to create defaults/etc. }; if('*' === Config.defaults.theme) { diff --git a/mods/menu.json b/mods/menu.json index 6c238dc8..e71031c7 100644 --- a/mods/menu.json +++ b/mods/menu.json @@ -56,7 +56,8 @@ "submit" : true, "focus" : true, // :TODO: need a good way to localize these ... Standard Orig->Lookup seems good. - "items" : [ "Login", "Apply", "Log Off" ] + "items" : [ "Login", "Apply", "Log Off" ], + "itemSpacing" : 1 } }, "submit" : { diff --git a/mods/prompt.json b/mods/prompt.json index e7de80cc..f9937e93 100644 --- a/mods/prompt.json +++ b/mods/prompt.json @@ -1,14 +1,18 @@ { "userCredentials" : { - "art" : "USERCRED", + "art" : "usercred", "mci" : { "ET1" : { - "argName" : "username" + "argName" : "username", + "width" : 15, + "maxLength" : "@config:users.usernameMax" }, "ET2" : { - "submit" : true, - "argName" : "password", - "password" : true + "submit" : true, + "argName" : "password", + "password" : true, + "width" : 15, + "maxLength" : "@config:users.passwordMax" } } },