Initial commit

This commit is contained in:
Brian McGonagill 2025-12-06 15:44:43 -06:00
commit 35745a89ec
44 changed files with 3342 additions and 0 deletions

View file

@ -0,0 +1,40 @@
<template name="login">
{{#if $not currentUser}}
<div id="signInForm">
<div class="container">
<h4>Login</h4>
<article>
<div class="card-content">
<div class="login grid">
<div>
<label for="email">Email *</label>
<input type="email" name="email" id="email" class="email" />
</div>
</div>
<div class="grid">
<div>
<label for="password">Password *</label>
<input type="password" name="password" id="password" class="password" />
</div>
</div>
<div class="grid">
{{#if $eq areFilled false}}
<div>
<span>You must fill all fields to login.</span>
</div>
{{/if}}
<div>
<a id="logmein" class="right btn logmein" role="button">Log In</a>
</div>
</div>
</div>
{{#if $eq canReg true}}
<div>
<a href="#" id="reg">Register</a>
</div>
{{/if}}
</article>
</div>
</div>
{{/if}}
</template>

View file

@ -0,0 +1,44 @@
import { FlowRouter } from 'meteor/ostrio:flow-router-extra';
import { SysConfig } from '../../../imports/api/systemConfig';
Template.login.onCreated(function() {
this.subscribe("SystemConfig");
});
Template.login.onRendered(function() {
});
Template.login.helpers({
areFilled: function() {
return Session.get("filledFields");
},
canReg: function() {
let conf = SysConfig.findOne();
if (typeof conf != 'undefined') {
return conf.allowReg;
} else {
return true;
}
}
});
Template.login.events({
'click #logmein' (event) {
event.preventDefault();
console.log("clicked login");
let email = $("#email").val();
let pass = $("#password").val();
if (email == null || email == "" || pass == "" || pass == null) {
Session.set("filledFields", false);
return;
} else {
Meteor.loginWithPassword(email, pass);
}
},
'click #reg' (event) {
event.preventDefault();
FlowRouter.go('/reg');
},
});

View file

@ -0,0 +1,65 @@
<template name="reg">
{{#if $not currentUser}}
{{#if $eq allowReg true}}
<div id="registrationForm">
<div>
<h4>Register</h4>
<article>
<div class="card-content">
<div class="grid">
<div>
<label for="name">Your Full Name *</label>
<input type="text" name="name" class="name" id="name" style="{{#if $eq misName true}}border: 2px solid red;{{/if}}" />
</div>
</div>
<div class="grid">
<div>
<label for="email">Email *</label>
<input type="email" name="email" id="email" class="email" />
</div>
</div>
{{#if $eq misEmail true}}
<div class="grid">
<div>
<p style="color: red;">This does not appear to be a proper email.</p>
</div>
</div>
{{/if}}
<div class="grid">
<div>
<label for="password">Password *</label>
<input type="password" name="password" id="password" class="password {{#if $eq misPass true}}red lighten-3{{/if}}" />
</div>
</div>
<div class="grid">
<div>
<label for="passwordConfirm">Confirm Password *</label>
<input type="password" name="passwordConfirm" id="passwordConfirm" class="passwordConfirm" style="{{#if $eq passMatch false}}border: 2px solid red !important;{{/if}}" />
</div>
</div>
{{#if $eq passMatch false}}
<div class="grid">
<div>
<p style="color: red;">Passwords do no match!</p>
</div>
</div>
{{/if}}
<div class="grid">
<div>
<a id="registerMe" class="btn right registerMe" role="button">Register</a>
</div>
</div>
</div>
<div class="card-action">
<a href="#" id="login">Sign In</a>
</div>
</article>
</div>
</div>
{{else}}
<h3>Registration Disabled</h3>
<p>The administrator of this system has disabled registration. If you believe you should be allowed to register to use this system, please contact the system administrator for assistance.</p>
{{/if}}
{{/if}}
{{> snackbar}}
</template>

View file

@ -0,0 +1,137 @@
import { Meteor } from 'meteor/meteor';
import { FlowRouter } from 'meteor/ostrio:flow-router-extra';
import { SysConfig } from '../../../imports/api/systemConfig';
Template.reg.onCreated(function() {
this.subscribe("SystemConfig");
});
Template.reg.onRendered(function() {
Session.set("canReg", false);
Session.set("missingReq", false);
Session.set("missingName", false);
Session.set("missingEmail", false);
Session.set("missingPassword", false);
Session.set("passMatch", true);
});
Template.reg.helpers({
canReg: function() {
return Session.get("canReg");
},
misName: function() {
return Session.get("missingName");
},
misEmail: function() {
return Session.get("missingEmail");
},
misPass: function() {
return Session.get("missingPassword");
},
misReq: function() {
return Session.get("missingReq");
},
passMatch: function() {
return Session.get("passMatch");
},
allowReg: async() => {
const conf = await SysConfig.findOneAsync();
try {
if (typeof conf != 'undefined') {
return conf.allowReg;
} else {
return true
}
} catch(error) {
console.log(" ERROR getting registration allowed info: " + error);
}
}
});
Template.reg.events({
'click #registerMe' (event) {
event.preventDefault();
if (Session.get("canreg") == false) {
// console.log("reg disabled.");
} else {
// console.log("Clicked");
let missingName = false;
let missingEmail = false;
let missingPassword = false;
let email = $("#email").val();
let password = $("#password").val();
let name = $("#name").val();
if (name == "" || name == null) {
missingName = true;
Session.set("missingName", true);
}
if (email == "" || email == null) {
missingEmail = true;
Session.set("missingEmail", true);
}
if (password == "" || password == null) {
missingPassword = true;
Session.set("missingPassword", true);
}
let userId;
if (missingName == true || missingEmail == true || missingPassword == true) {
Session.set("missingReq", true);
} else {
Session.set("missingReq", false);
Accounts.createUser({
email: email,
password: password,
profile: {
fullname: name,
}
});
let userId = Meteor.userId();
// console.log("User ID: " + userId);
const addRole = async() => {
let result = await Meteor.callAsync("addToRole", "user");
if (!result) {
console.log(" ERROR: ROLES - Error adding user to role: ");
} else {
// console.log("User should be added to role - teacher.");
FlowRouter.go('/dashboard');
}
}
addRole();
}
}
},
'keyup #passwordConfirm' (event) {
let pwd = $("#password").val();
let pwdconf = $("#passwordConfirm").val();
if (pwd == pwdconf) {
// console.log("passwords match");
Session.set("canreg", true);
} else {
// console.log("passwords don't match");
Session.set("canreg", false);
}
},
'change #email' (event) {
let email = $("#email").val();
var regex = /^([a-zA-Z0-9_.+-])+\@(([a-zA-Z0-9-])+\.)+([a-zA-Z0-9]{2,4})+$/;
let isEmail = regex.test(email);
if (isEmail == false) {
Session.set("missingEmail", true);
} else {
Session.set("missingEmail", false);
}
},
'click #login' (event) {
event.preventDefault();
FlowRouter.go('/login');
},
});

View file

@ -0,0 +1,45 @@
<template name="userInfoModal">
<div id="userInfoModal" class="modal modal-fixed-footer">
<div class="modal-content">
<h4>User Info for: {{userInfo.profile.fullname}}</h4>
<div>
<p class="flow-text">Password Reset</p>
</div>
<form class="row" style="gap: 1em;">
<div class="col s12 m6 l6 input-field outlined">
<input type="password" class="newPass" id="newPass" />
<label for="newPass">Enter New Password</label>
</div>
<div class="col s12 m6 l6 input-field outlined">
<input type="password" class="newPassConf {{#if $eq passMatch false}}red lighten-3{{/if}}" id="newPassConf" />
<label for="newPassConf">Enter New Password</label>
{{#if $eq passMatch false}}<p class="red-text">Passwords do not match!</p>{{/if}}
</div>
<div class="col s12 m6 l6 input-field outlined">
<select name="userRole" id="userRole" class="userRole {{#if $eq roleEmpty true}}red lighten-2 white-text{{/if}}">
<option value="{{userRole}}" selected>{{userRole}}</option>
<option value="admin">Admin</option>
<option value="systemadmin">System Admin</option>
<option value="user">User</option>
</select>
<label for="userRole">User Role</label>
{{#if $eq roleEmpty true}}
<p class="red-text">This field is required.</p>
{{/if}}
</div>
<div class="col s12 m6 l6 input-field outlined">
<input type="text" class="usersEmail" id="usersEmail" value="{{userInfo.emails.[0].address}}"/>
<label for="usersEmail">Email</label>
{{#if $eq emailEmpty true}}
<p class="red-text">This field is required.</p>
{{/if}}
</div>
</form>
</div>
<div class="modal-footer">
<a class="modal-close btn waves-effect waves-light filled orange white-text">Cancel</a>
<a id="saveChanges" class="btn waves-effect waves-light filled green white-text">Save Changes</a>
</div>
</div>
{{> snackbar}}
</template>

View file

@ -0,0 +1,145 @@
Template.userInfoModal.onCreated(function() {
this.subscribe("rolesAvailable");
});
Template.userInfoModal.onRendered(function() {
Session.set("passMatch", true);
Session.set("passErr", false);
Session.set("userEmailErr", false);
Session.set("userRoleErr", false);
});
Template.userInfoModal.helpers({
passMatch: function() {
return Session.get("passMatch");
},
emailEmpty: function() {
return Session.get("userEmailErr");
},
roleEmpty: function() {
return Session.get("userRoleErr");
},
userInfo: function() {
let usersId = Session.get("usersId");
if (usersId != "" && usersId != null) {
let usersInfo = Meteor.users.findOne({ _id: usersId });
// console.dir(usersInfo);
Session.set("usersInfo", usersInfo);
return usersInfo;
} else {
return;
}
},
userRole: function() {
let userRole = Roles.getRolesForUser( Session.get("usersId"));
Session.set("usersRole", userRole);
console.log(userRole);
return userRole;
},
rolesOptions: function() {
return Roles.find();
}
});
Template.userInfoModal.events({
"click #saveChanges" (event) {
event.preventDefault();
let usersId = Session.get("usersId");
let passwd = $("#newPass").val();
let usersEmail = $("#usersEmail").val();
let userRole = $("#userRole").val();
let userInfo = Session.get("usersInfo");
let currEmail = userInfo.emails[0].address;
let userDbRole = Session.get("usersRole");
let currRole = userDbRole[0];
let passMatch = Session.get("passMatch");
if (passMatch == false) {
Session.set("passErr", true);
return;
} else {
Session.set("passErr", false);
}
if (usersEmail == null || usersEmail == "") {
Session.set("userEmailErr", true);
return;
} else {
Session.set("userEmailErr", false);
}
if (userRole == null || userRole == "") {
Session.set("userRoleErr", true);
return;
} else {
Session.set("userRoleErr", false);
}
if (passMatch == true || passMatch == "NA") {
if (passwd != "" && passwd != null) {
// need to account for the admin changing passwords and userRole or Email
changePassword(usersId, passwd);
}
if (usersEmail != null && usersEmail != "" && usersEmail != currEmail) {
changeUserEmail(usersId, usersEmail);
}
if (userRole != null && userRole != "" && userRole != currRole) {
changeUserRole(usersId, userRole);
}
}
},
"click #closePass" (event) {;
},
"keyup #newPassConf" (event) {
let newPass = $("#newPass").val();
let newPassConf = $("#newPassConf").val();
if (newPassConf.length > 2 && (newPass != null || newPass != "")) {
if (newPass != newPassConf) {
Session.set("passMatch", false);
} else {
Session.set("passMatch", true);
}
}
}
});
changePassword = function(userId, passwd) {
console.log("would change password.");
Meteor.call('edit.userPass', userId, passwd, function(err, result) {
if (err) {
console.log(" ERROR changing user passwrod:" + err);
} else {
showSnackbar("Successfully Saved Changes!", "green");
console.log(" Password changed successfully!");
}
});
}
changeUserEmail = function(usersId, usersEmail) {
console.log("Would change user email");
Meteor.call('update.userEmail', usersId, usersEmail, function(err, result) {
if (err) {
console.log(" ERROR updating user email: " + err);
} else {
showSnackbar("Email updated successfully!", "green");
}
});
}
changeUserRole = function(userId, role) {
console.log("Would change user Role.");
Meteor.call('edit.userRole', userId, role, function(err, result) {
if (err) {
console.log(" ERROR updating user role: " + err);
} else {
showSnackbar("Role Successfully Updated!", "green");
}
});
}

View file

@ -0,0 +1,36 @@
<template name="userMgmt">
{{#if isInRole 'systemadmin'}}
<h3>User Management</h3>
<div class="row">
<div class="col s12 m12 l12">
<table class="striped highlight responsive-table">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Role</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{{#each userInfo}}
<tr>
<td>{{userName}}</td>
<td>{{userEmail}}</td>
<td>{{userRole}}</td>
<td>
<div class="input-field">
<i class="material-icons modal-trigger clickable deleteUser" data-target="modalDelete">delete</i>
<i class="material-icons clickable editUser modal-trigger" data-target="userInfoModal">edit</i>
</div>
</td>
</tr>
{{/each}}
</tbody>
</table>
</div>
</div>
{{/if}}
{{> deleteConfirmationModal}}
{{> userInfoModal}}
</template>

View file

@ -0,0 +1,41 @@
Template.userMgmt.onCreated(function() {
this.subscribe("userList");
});
Template.userMgmt.onRendered(function() {
});
Template.userMgmt.helpers({
userInfo: function() {
return Meteor.users.find({});
},
userName: function() {
return this.profile.fullname;
},
userEmail: function() {
return this.emails[0].address;
},
userRole: function() {
return Roles.getRolesForUser( this._id );
}
});
Template.userMgmt.events({
"click .editUser" (event) {
event.preventDefault();
let userId = this._id;
Session.set("usersId", userId);
},
"click .deleteUser" (event) {
event.preventDefault();
let userId = this._id;
console.log("Delete called on : " + userId);
Session.set("deleteId", userId);
Session.set("item", "User");
Session.set("view", "Users");
Session.set("method", "delete.userFromSys");
}
});