import './UserManagement.html'; import '/imports/util/selectize/selectize.js'; import Swal from 'sweetalert2'; let QUERY_LIMIT = 100; let QUERY_LIMIT_INCREMENT = 100; let PREFIX = "UserManagement"; Tracker.autorun(function() { Meteor.subscribe("users", Session.get(PREFIX + 'searchQuery')); Meteor.subscribe("roleAssignments"); Meteor.subscribe("roles"); }); Template.UserManagement.onCreated(function() { Session.set(PREFIX + "displayNewUser", false); Session.set(PREFIX + "queryLimit", QUERY_LIMIT); }); Template.UserManagement.onRendered(function() { $(".tableContainer").mCustomScrollbar({ scrollButtons: {enable:true}, theme: "light-thick", scrollbarPosition: "outside", scrollEasing: "linear" }); }); Template.UserManagement.helpers({ displayNewUser: function() { return Session.get(PREFIX + "displayNewUser"); }, users: function() { let skipCount = Session.get(PREFIX + 'skipCount') || 0; let query = Session.get(PREFIX + 'searchQuery'); let dbQuery = []; if(query) { _.each(_.keys(query), function(key) { if(_.isFunction(query[key])) dbQuery.push({[key]: query[key]}); //dbQuery[key] = query[key](); else if(_.isObject(query[key])) dbQuery.push({[key]: query[key]}); //dbQuery[key] = query[key]; //Will look something like: {$in: [xxx,xxx,xxx]} else if(_.isNumber(query[key])) dbQuery.push({[key]: query[key]}); //dbQuery[key] = query[key]; else { //dbQuery[key] = {$regex: query[key], $options: 'i'}; let searchValue = query[key]; let searches = searchValue && searchValue.length > 0 ? searchValue.split(/\s+/) : undefined; for(let search of searches) { dbQuery.push({[key]: {$regex: '\\b' + search, $options: 'i'}}); } } }) } if(!Session.get(PREFIX + "showHidden")) { //Ignore any hidden elements by showing those not hidden, or those without the hidden field. dbQuery.push({$or: [{hidden: false}, {hidden: {$exists:false}}]}); } dbQuery = dbQuery.length > 0 ? {$and: dbQuery} : {}; Session.set(PREFIX + 'userCount', Meteor.collections.Users.find(dbQuery).count()); //Always get a full count. return Meteor.collections.Users.find(dbQuery, {limit: Session.get(PREFIX + "queryLimit"), skip: skipCount, sort: {username: 1}}); }, disableLoadMore: function() { return Session.get(PREFIX + 'userCount') - (Session.get(PREFIX + 'skipCount') || 0) - Session.get(PREFIX + "queryLimit") <= 0; } }); Template.UserManagement.events({ 'click .loadMoreLink': function(event, template) { event.preventDefault(); Session.set(PREFIX + 'queryLimit', Session.get(PREFIX + "queryLimit") + QUERY_LIMIT_INCREMENT); }, 'click .newUserButton': function(event, template) { if(template.$('.newUserButton').hasClass('active')) { Session.set(PREFIX + 'displayNewUser', false); } else { Session.set(PREFIX + 'displayNewUser', true); Session.set(PREFIX + "editedUser", undefined); //Clear the edited user so that only one editor is open at a time. } template.$('.newUserButton').toggleClass('active'); } }); Template.User.onCreated(function() { this.edited = new ReactiveVar(); }); Template.User.events({ "click .userEdit": function(event, template) { //template.edited.set(this); Session.set(PREFIX + "editedUser", this._id); Session.set(PREFIX + 'displayNewUser', false); //Ensure the new measure editor is closed. template.parentTemplate().$('.newUserButton').removeClass('active'); }, "click .userRemove": function(event, template) { let _this = this; Swal({title: "Delete User", text: "Delete the user?", type: 'warning', showCancelButton: true, confirmButtonColor: '#419c2b', cancelButtonColor: '#d33', confirmButtonText: "Yes, delete it!"}).then((isConfirm) => { if(isConfirm) { Meteor.call('deleteUser', _this._id, function(error, result) { if(error) { sAlert.error(error); } else { sAlert.success("User removed."); } }); } }); //bootbox.confirm({ // message: "Delete the user?", // buttons: {confirm: {label: "Yes", className: 'btn-success'}, cancel: {label: "No", className: "btn-danger"}}, // callback: function(result) { // if(result) { // Meteor.call('deleteUser', _this._id, function(error, result) { // if(error) { // sAlert.error(error); // } // else { // sAlert.success("User removed."); // } // }); // } // } //}); } }); Template.User.helpers({ email: function() { return this.emails && this.emails.length > 0 ? this.emails[0].address : ""; }, editing: function() { let editedUser = Session.get(PREFIX + "editedUser"); return editedUser == this._id; }, roles: function() { let roles = Meteor.roleAssignment.find({"user._id": this._id}, {"sort": [["role._id", "asc"]]}).fetch(); let result = [] for(let next of roles) result.push(next.role._id) return result } }); Template.UserEditor.helpers({ email: function() { return this.emails && this.emails.length > 0 ? this.emails[0].address : ""; }, allRoles: function() { return Meteor.collections.UserRoles.find(); }, getRoleState: function(role) { let user = Template.parentData(1); //Debug code... // console.log("GetRoleState") // console.log(role._id) // console.log(user._id) // console.log(Meteor.roleAssignment.find({"user._id": user._id, "role._id": role._id}).count()) //console.log("Role: " + role._id + " === " + Roles.userIsInRole(user._id, [role._id])) // Note: Meteor.roleAssignment.countDocuments({...}) returns a Promise and not a count. Cannot use that here. return Roles.userIsInRole(user._id, [role._id]) ? "selected" : "" } }); Template.UserEditor.events({ "click .editorCancel": function(event, template) { Session.set(PREFIX + "editedUser", undefined); Session.set(PREFIX + 'displayNewUser', false); template.parentTemplate().$('.newUserButton').removeClass('active'); }, "click .editorApply": function(event, template) { let user = {}; let roles = []; user.username = template.$('input[name="username"]').val(); user.emails = [{address: template.$('input[name="email"]').val(), verified: true}]; //Assume it is verified since an administrator is adding it. let roleSpans = template.$('.role.selected'); for(let i = 0; i < roleSpans.length; i++) { roles.push($(roleSpans[i]).text()); } //user.roles = roles; if(Session.get(PREFIX + 'displayNewUser')) { Meteor.call('insertUser', user, roles, function(error, result) { if(error) { sAlert.error(error); } else { sAlert.success("User created."); Session.set(PREFIX + 'displayNewUser', false); template.parentTemplate().$('.newUserButton').removeClass('active'); } }); } else { user._id = this._id; Meteor.call("updateUser", user, roles, function(error, result) { if(error) sAlert.error(error); else { sAlert.success("User updated."); Session.set(PREFIX + "editedUser", undefined); template.parentTemplate().$('.newUserButton').removeClass('active'); } }); } }, "click .role": function(event, template) { $(event.target).toggleClass("selected"); } }); Template.UserSearch.events({ "keyup .searchInput": _.throttle(function(event, template) { let searchQuery = Session.get(PREFIX + 'searchQuery') || {}; let searchFields = Session.get(PREFIX + 'searchFields') || {}; let searchValue = template.$('.searchInput').val(); if(searchValue) { if(this.number) searchValue = parseFloat(searchValue); if(this.collection) { let ids = Meteor.collections[this.collection].find({[this.collectionQueryColumnName]: {$regex: searchValue, $options: 'i'}}, {fields: {[this.collectionResultColumnName]: 1}}).fetch(); //Convert the ids to an array of ids instead of an array of objects containing an id. for(let i = 0; i < ids.length; i++) {ids[i] = ids[i]._id;} searchQuery[this.columnName] = {$in: ids}; searchFields[this.columnName] = searchValue; } else { searchFields[this.columnName] = searchQuery[this.columnName] = searchValue; } } else { //Remove columns from the search query whose values are empty so we don't bother the database with them. delete searchQuery[this.columnName]; delete searchFields[this.columnName]; } Session.set(PREFIX + 'searchQuery', searchQuery); Session.set(PREFIX + 'skipCount', 0); //Reset the paging of the results. }, 500) }); Template.UserSearch.helpers({ searchValue: function() { let searchFields = Session.get(PREFIX + 'searchFields'); return (searchFields && searchFields[this.columnName]) ? searchFields[this.columnName] : ''; } });