groups and reset
This commit is contained in:
parent
e71fccd27c
commit
0889832efc
@ -22,7 +22,7 @@ Auth.login = async function(data){
|
|||||||
|
|
||||||
return {user, token}
|
return {user, token}
|
||||||
}catch(error){
|
}catch(error){
|
||||||
throw error;
|
throw this.errors.login();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -54,7 +54,10 @@ async function addMember(client, group, user){
|
|||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
}catch(error){
|
}catch(error){
|
||||||
if(error = "TypeOrValueExistsError")return ;
|
// if(error = "TypeOrValueExistsError"){
|
||||||
|
// console.error('addMember error skipped', error)
|
||||||
|
// return ;
|
||||||
|
// }
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -100,6 +103,7 @@ Group.listDetail = async function(){
|
|||||||
|
|
||||||
await client.unbind();
|
await client.unbind();
|
||||||
|
|
||||||
|
|
||||||
return groups;
|
return groups;
|
||||||
}catch(error){
|
}catch(error){
|
||||||
throw error;
|
throw error;
|
||||||
@ -121,14 +125,24 @@ Group.get = async function(data){
|
|||||||
scope: 'sub',
|
scope: 'sub',
|
||||||
filter: `(&(objectClass=groupOfNames)(cn=${data.name}))`,
|
filter: `(&(objectClass=groupOfNames)(cn=${data.name}))`,
|
||||||
attributes: ['*', 'createTimestamp', 'modifyTimestamp'],
|
attributes: ['*', 'createTimestamp', 'modifyTimestamp'],
|
||||||
})).searchEntries;
|
})).searchEntries[0];
|
||||||
|
|
||||||
await client.unbind();
|
await client.unbind();
|
||||||
|
|
||||||
if(!Array.isArray(group.member)) group.member = [group.member];
|
if(!Array.isArray(group.member)) group.member = [group.member];
|
||||||
|
|
||||||
return group;
|
if(group){
|
||||||
|
let obj = Object.create(this);
|
||||||
|
Object.assign(obj, group);
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}else{
|
||||||
|
let error = new Error('GroupNotFound');
|
||||||
|
error.name = 'GroupNotFound';
|
||||||
|
error.message = `LDAP:${data.cn} does not exists`;
|
||||||
|
error.status = 404;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
}catch(error){
|
}catch(error){
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
@ -145,8 +159,55 @@ Group.add = async function(data){
|
|||||||
return this.get(data);
|
return this.get(data);
|
||||||
|
|
||||||
}catch(error){
|
}catch(error){
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Group.addMember = async function(user){
|
||||||
|
try{
|
||||||
|
await client.bind(conf.bindDN, conf.bindPassword);
|
||||||
|
|
||||||
|
await addMember(client, this, user);
|
||||||
|
|
||||||
|
await client.unbind();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
|
||||||
|
}catch(error){
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Group.removeMember = async function(user){
|
||||||
|
try{
|
||||||
|
await client.bind(conf.bindDN, conf.bindPassword);
|
||||||
|
|
||||||
|
await removeMember(client, this, user);
|
||||||
|
|
||||||
|
await client.unbind();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
|
||||||
|
}catch(error){
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Group.remove = async function(){
|
||||||
|
try{
|
||||||
|
await client.bind(conf.bindDN, conf.bindPassword);
|
||||||
|
|
||||||
|
await client.del(this.dn);
|
||||||
|
|
||||||
|
await client.unbind();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}catch(error){
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {Group};
|
module.exports = {Group};
|
||||||
|
@ -59,4 +59,13 @@ AuthToken.add = async function(data){
|
|||||||
return AuthToken.__proto__.add(data);
|
return AuthToken.__proto__.add(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = {Token, InviteToken, AuthToken}
|
var PasswordResetToken = Object.create(Token({
|
||||||
|
name: 'auth',
|
||||||
|
}));
|
||||||
|
|
||||||
|
PasswordResetToken.add = async function(data){
|
||||||
|
data.created_by = data.uid;
|
||||||
|
return PasswordResetToken.__proto__.add(data);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {Token, InviteToken, AuthToken, PasswordResetToken};
|
||||||
|
@ -4,7 +4,7 @@ const { Client, Attribute, Change } = require('ldapts');
|
|||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
|
|
||||||
const {Mail} = require('./email');
|
const {Mail} = require('./email');
|
||||||
const {Token, InviteToken} = require('./token');
|
const {Token, InviteToken, PasswordResetToken} = require('./token');
|
||||||
const conf = require('../app').conf.ldap;
|
const conf = require('../app').conf.ldap;
|
||||||
|
|
||||||
const client = new Client({
|
const client = new Client({
|
||||||
@ -93,21 +93,6 @@ async function deleteLdapUser(client, data){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function changeLdapPassword(client, data){
|
|
||||||
try{
|
|
||||||
await client.modify(`cn=${data.uid},${conf.userBase}`, [
|
|
||||||
new Change({
|
|
||||||
operation: 'replace',
|
|
||||||
modification: new Attribute({
|
|
||||||
type: 'userPassword',
|
|
||||||
values: ['{MD5}'+crypto.createHash('md5').update(data.userPassword, "binary").digest('base64')]
|
|
||||||
})}),
|
|
||||||
]);
|
|
||||||
}catch(error){
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const user_parse = function(data){
|
const user_parse = function(data){
|
||||||
if(data[conf.userNameAttribute]){
|
if(data[conf.userNameAttribute]){
|
||||||
data.username = data[conf.userNameAttribute]
|
data.username = data[conf.userNameAttribute]
|
||||||
@ -167,7 +152,7 @@ User.listDetail = async function(){
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
User.get = async function(data){
|
User.get = async function(data, value){
|
||||||
try{
|
try{
|
||||||
if(typeof data !== 'object'){
|
if(typeof data !== 'object'){
|
||||||
let uid = data;
|
let uid = data;
|
||||||
@ -177,7 +162,12 @@ User.get = async function(data){
|
|||||||
|
|
||||||
await client.bind(conf.bindDN, conf.bindPassword);
|
await client.bind(conf.bindDN, conf.bindPassword);
|
||||||
|
|
||||||
let filter = `(&${conf.userFilter}(${conf.userNameAttribute}=${data.uid}))`;
|
data.searchKey = data.searchKey || conf.userNameAttribute;
|
||||||
|
data.searchValue = data.searchValue || data.uid;
|
||||||
|
|
||||||
|
let filter = `(&${conf.userFilter}(${data.searchKey}=${data.searchValue}))`;
|
||||||
|
|
||||||
|
console.log('get filter', filter)
|
||||||
|
|
||||||
const res = await client.search(conf.userBase, {
|
const res = await client.search(conf.userBase, {
|
||||||
scope: 'sub',
|
scope: 'sub',
|
||||||
@ -197,7 +187,7 @@ User.get = async function(data){
|
|||||||
}else{
|
}else{
|
||||||
let error = new Error('UserNotFound');
|
let error = new Error('UserNotFound');
|
||||||
error.name = 'UserNotFound';
|
error.name = 'UserNotFound';
|
||||||
error.message = `LDAP:${data.uid} does not exists`;
|
error.message = `LDAP:${data.searchValue} does not exists`;
|
||||||
error.status = 404;
|
error.status = 404;
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
@ -289,11 +279,42 @@ User.verifyEmail = async function(data){
|
|||||||
link:`${data.url}/login/invite/${token.token}/${token.mail_token}`
|
link:`${data.url}/login/invite/${token.token}/${token.mail_token}`
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
return this;
|
||||||
}catch(error){
|
}catch(error){
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
User.passwordReset = async function(url, mail){
|
||||||
|
try{
|
||||||
|
|
||||||
|
let user = await User.get({
|
||||||
|
searchKey: 'mail',
|
||||||
|
searchValue: mail
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('user', user)
|
||||||
|
|
||||||
|
let token = await PasswordResetToken.add(user);
|
||||||
|
|
||||||
|
await Mail.sendTemplate(
|
||||||
|
user.mail,
|
||||||
|
'reset_link',
|
||||||
|
{
|
||||||
|
user: user,
|
||||||
|
link:`${url}/login/resetpassword/${token.token}`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}catch(error){
|
||||||
|
// if(error.name === 'UserNotFound') return false;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
User.remove = async function(data){
|
User.remove = async function(data){
|
||||||
try{
|
try{
|
||||||
|
|
||||||
@ -303,22 +324,34 @@ User.remove = async function(data){
|
|||||||
|
|
||||||
await client.unbind();
|
await client.unbind();
|
||||||
|
|
||||||
return true
|
return true;
|
||||||
|
|
||||||
}catch(error){
|
}catch(error){
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// User.setPassword = async function(data){
|
User.setPassword = async function(data){
|
||||||
// try{
|
try{
|
||||||
// await linuxUser.setPassword(this.username, data.password);
|
|
||||||
|
|
||||||
// return this;
|
await client.bind(conf.bindDN, conf.bindPassword);
|
||||||
// }catch(error){
|
|
||||||
// throw error;
|
await client.modify(this.dn, [
|
||||||
// }
|
new Change({
|
||||||
// };
|
operation: 'replace',
|
||||||
|
modification: new Attribute({
|
||||||
|
type: 'userPassword',
|
||||||
|
values: ['{MD5}'+crypto.createHash('md5').update(data.userPassword, "binary").digest('base64')]
|
||||||
|
})}),
|
||||||
|
]);
|
||||||
|
|
||||||
|
await client.unbind();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}catch(error){
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
User.invite = async function(){
|
User.invite = async function(){
|
||||||
try{
|
try{
|
||||||
|
867
nodejs/package-lock.json
generated
867
nodejs/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -19,6 +19,7 @@
|
|||||||
"ldapts": "^2.2.1",
|
"ldapts": "^2.2.1",
|
||||||
"moment": "^2.25.3",
|
"moment": "^2.25.3",
|
||||||
"mustache": "^4.0.1",
|
"mustache": "^4.0.1",
|
||||||
|
"nodemon": "^2.0.4",
|
||||||
"redis": "^2.8.0",
|
"redis": "^2.8.0",
|
||||||
"smtpc": "^0.1.2"
|
"smtpc": "^0.1.2"
|
||||||
},
|
},
|
||||||
|
@ -43,7 +43,8 @@ app.api = (function(app){
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function remove(url, callack){
|
function remove(url, callack, callack2){
|
||||||
|
if(!$.isFunction(callack)) callack = callack2;
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: 'delete',
|
type: 'delete',
|
||||||
url: baseURL+url,
|
url: baseURL+url,
|
||||||
@ -129,6 +130,7 @@ app.auth = (function(app) {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
getToken: getToken,
|
getToken: getToken,
|
||||||
|
setToken: setToken,
|
||||||
isLoggedIn: isLoggedIn,
|
isLoggedIn: isLoggedIn,
|
||||||
logIn: logIn,
|
logIn: logIn,
|
||||||
logOut: logOut,
|
logOut: logOut,
|
||||||
@ -222,6 +224,22 @@ app.host = (function(app){
|
|||||||
}
|
}
|
||||||
})(app);
|
})(app);
|
||||||
|
|
||||||
|
app.group = (function(app){
|
||||||
|
function list(callack){
|
||||||
|
app.api.get('group?detail=true', function(error, data){
|
||||||
|
callack(error, data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function remove(args, callack){
|
||||||
|
app.api.delete('group/'+args.cn, function(error, data){
|
||||||
|
callack(error, data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {list, remove}
|
||||||
|
})(app)
|
||||||
|
|
||||||
app.util = (function(app){
|
app.util = (function(app){
|
||||||
|
|
||||||
function getUrlParameter(name) {
|
function getUrlParameter(name) {
|
||||||
@ -231,21 +249,24 @@ app.util = (function(app){
|
|||||||
return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
|
return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
|
||||||
};
|
};
|
||||||
|
|
||||||
function actionMessage(message, options){
|
function actionMessage(message, $target, type){
|
||||||
options = options || {};
|
|
||||||
$target = options.$target || $('div.actionMessage');
|
|
||||||
message = message || '';
|
message = message || '';
|
||||||
|
$target = $target.closest('div.card').find('.actionMessage');
|
||||||
|
type = type || 'info';
|
||||||
|
|
||||||
if($target.html() === message) return;
|
if($target.html() === message) return;
|
||||||
|
|
||||||
if($target.html()){
|
if($target.html()){
|
||||||
$target.slideUp('fast', function(){
|
$target.slideUp('fast', function(){
|
||||||
$target.html('')
|
$target.html('')
|
||||||
if(message) actionMessage(message, options);
|
$target.removeClass (function (index, className) {
|
||||||
|
return (className.match (/(^|\s)bg-\S+/g) || []).join(' ');
|
||||||
|
});
|
||||||
|
if(message) actionMessage(message, $target, type);
|
||||||
})
|
})
|
||||||
return;
|
return;
|
||||||
}else{
|
}else{
|
||||||
if(options.type) $target.addClass('alert-' + options.type);
|
if(type) $target.addClass('bg-' + type);
|
||||||
$target.html(message).slideDown('fast');
|
$target.html(message).slideDown('fast');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -277,7 +298,10 @@ app.util = (function(app){
|
|||||||
$.holdReady( true );
|
$.holdReady( true );
|
||||||
if(!location.pathname.includes('/login')){
|
if(!location.pathname.includes('/login')){
|
||||||
app.auth.isLoggedIn(function(error, isLoggedIn){
|
app.auth.isLoggedIn(function(error, isLoggedIn){
|
||||||
|
console.log('here', error, isLoggedIn)
|
||||||
|
|
||||||
if(error || !isLoggedIn){
|
if(error || !isLoggedIn){
|
||||||
|
app.auth.logOut(function(){})
|
||||||
location.replace('/login/?redirect='+location.pathname);
|
location.replace('/login/?redirect='+location.pathname);
|
||||||
}else{
|
}else{
|
||||||
$.holdReady( false );
|
$.holdReady( false );
|
||||||
@ -296,9 +320,6 @@ $( document ).ready( function () {
|
|||||||
$( this ).closest( '.card' ).find( '.card-body' ).slideToggle( 'fast' );
|
$( this ).closest( '.card' ).find( '.card-body' ).slideToggle( 'fast' );
|
||||||
});
|
});
|
||||||
|
|
||||||
$( '.glyphicon-remove-circle' ).click( function () {
|
|
||||||
$( this ).closest( 'div.panel' ).slideUp( 'fast' );
|
|
||||||
});
|
|
||||||
|
|
||||||
$( '.glyphicon-refresh' ).each( function () {
|
$( '.glyphicon-refresh' ).each( function () {
|
||||||
$(this).click( function () {
|
$(this).click( function () {
|
||||||
@ -314,19 +335,21 @@ function formAJAX( btn, del ) {
|
|||||||
var formData = $form.find( '[name]' ).serializeObject(); // builds query formDataing
|
var formData = $form.find( '[name]' ).serializeObject(); // builds query formDataing
|
||||||
var method = $form.attr('method') || 'post';
|
var method = $form.attr('method') || 'post';
|
||||||
|
|
||||||
if( !$form.validate(
|
app.util.actionMessage(
|
||||||
{
|
'<div class="spinner-border" role="status"><span class="sr-only">Loading...</span></div>',
|
||||||
form: {
|
$form,
|
||||||
alertCount: true,
|
'info'
|
||||||
alertCountMessage: " errors found on this form!"
|
);
|
||||||
}
|
|
||||||
}) ) {
|
if( !$form.validate()) {
|
||||||
|
app.util.actionMessage('Please fix the form errors.', $form, 'danger')
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
app.api[method]($form.attr( 'action' ), formData, function(error, data){
|
app.api[method]($form.attr('action'), formData, function(error, data){
|
||||||
app.util.actionMessage( data.message ); //re-populate table
|
app.util.actionMessage(data.message, $form, error ? 'danger' : 'success'); //re-populate table
|
||||||
if(!error){
|
if(!error){
|
||||||
|
$form.trigger("reset");
|
||||||
eval($form.attr('evalAJAX')); //gets JS to run after completion
|
eval($form.attr('evalAJAX')); //gets JS to run after completion
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
const router = require('express').Router();
|
const router = require('express').Router();
|
||||||
const {User} = require('../models/user');
|
const {User} = require('../models/user');
|
||||||
const {Auth, AuthToken} = require('../models/auth');
|
const {Auth, AuthToken} = require('../models/auth');
|
||||||
|
const {PasswordResetToken} = require('../models/token');
|
||||||
|
|
||||||
|
|
||||||
router.post('/login', async function(req, res, next){
|
router.post('/login', async function(req, res, next){
|
||||||
@ -11,6 +12,7 @@ router.post('/login', async function(req, res, next){
|
|||||||
return res.json({
|
return res.json({
|
||||||
login: true,
|
login: true,
|
||||||
token: auth.token.token,
|
token: auth.token.token,
|
||||||
|
message:`${req.body.uid} logged in!`,
|
||||||
});
|
});
|
||||||
}catch(error){
|
}catch(error){
|
||||||
next(error);
|
next(error);
|
||||||
@ -29,6 +31,36 @@ router.all('/logout', async function(req, res, next){
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.post('/resetpassword', async function(req, res, next){
|
||||||
|
try{
|
||||||
|
let sent = await User.passwordReset(`${req.protocol}://${req.hostname}`, req.body.mail);
|
||||||
|
|
||||||
|
console.info('resetpassword for', req.body.mail, sent)
|
||||||
|
|
||||||
|
return res.json({
|
||||||
|
message: 'If the emaill address is in our system, you will receive a message.'
|
||||||
|
});
|
||||||
|
}catch(error){
|
||||||
|
next(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post('/resetpassword/:token', async function(req, res, next){
|
||||||
|
try{
|
||||||
|
let token = await PasswordResetToken.get(req.params.token);
|
||||||
|
|
||||||
|
if(token.is_valid && 86400000+Number(token.created_on) > (new Date).getTime()){
|
||||||
|
let user = await User.get(token.created_by);
|
||||||
|
await user.setPassword(req.body);
|
||||||
|
return res.json({
|
||||||
|
message: 'Password has been changed.'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}catch(error){
|
||||||
|
next(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
router.post('/invite/:token/:mailToken', async function(req, res, next) {
|
router.post('/invite/:token/:mailToken', async function(req, res, next) {
|
||||||
try{
|
try{
|
||||||
req.body.token = req.params.token;
|
req.body.token = req.params.token;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const router = require('express').Router();
|
const router = require('express').Router();
|
||||||
|
const {User} = require('../models/user_ldap');
|
||||||
const {Group} = require('../models/group_ldap');
|
const {Group} = require('../models/group_ldap');
|
||||||
|
|
||||||
router.get('/', async function(req, res, next){
|
router.get('/', async function(req, res, next){
|
||||||
@ -13,6 +14,18 @@ router.get('/', async function(req, res, next){
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.post('/', async function(req, res, next){
|
||||||
|
try{
|
||||||
|
req.body.owner = req.user.dn;
|
||||||
|
return res.json({
|
||||||
|
results: await Group.add(req.body),
|
||||||
|
message: `${req.body.name} was added!`
|
||||||
|
})
|
||||||
|
}catch(error){
|
||||||
|
next(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
router.get('/:name', async function(req, res, next){
|
router.get('/:name', async function(req, res, next){
|
||||||
try{
|
try{
|
||||||
return res.json({
|
return res.json({
|
||||||
@ -23,4 +36,43 @@ router.get('/:name', async function(req, res, next){
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.put('/:name/:uid', async function(req, res, next){
|
||||||
|
try{
|
||||||
|
var group = await Group.get(req.params.name);
|
||||||
|
var user = await User.get(req.params.uid);
|
||||||
|
return res.json({
|
||||||
|
results: group.addMember(user),
|
||||||
|
message: `Added user ${req.params.uid} to ${req.params.name} group.`
|
||||||
|
});
|
||||||
|
}catch(error){
|
||||||
|
next(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.delete('/:name/:uid', async function(req, res, next){
|
||||||
|
try{
|
||||||
|
var group = await Group.get(req.params.name);
|
||||||
|
var user = await User.get(req.params.uid);
|
||||||
|
return res.json({
|
||||||
|
results: group.removeMember(user),
|
||||||
|
message: `Removed user ${req.params.uid} from ${req.params.name} group.`
|
||||||
|
});
|
||||||
|
}catch(error){
|
||||||
|
next(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.delete('/:name', async function(req, res, next){
|
||||||
|
try{
|
||||||
|
var group = await Group.get(req.params.name);
|
||||||
|
return res.json({
|
||||||
|
removed: await group.remove(),
|
||||||
|
results: group,
|
||||||
|
message: `Group ${req.params.name} Deleted`
|
||||||
|
});
|
||||||
|
}catch(error){
|
||||||
|
next(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
var express = require('express');
|
var express = require('express');
|
||||||
var router = express.Router();
|
var router = express.Router();
|
||||||
const moment = require('moment');
|
const moment = require('moment');
|
||||||
const {InviteToken} = require('./../models/token');
|
const {InviteToken, PasswordResetToken} = require('./../models/token');
|
||||||
|
|
||||||
|
|
||||||
/* GET home page. */
|
/* GET home page. */
|
||||||
@ -16,6 +16,21 @@ router.get('/users', function(req, res, next) {
|
|||||||
res.render('users', { title: 'Express' });
|
res.render('users', { title: 'Express' });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.get('/groups', function(req, res, next) {
|
||||||
|
res.render('groups', { title: 'Express' });
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
router.get('/login/resetpassword/:token', async function(req, res, next){
|
||||||
|
let token = await PasswordResetToken.get(req.params.token);
|
||||||
|
|
||||||
|
if(token.is_valid && 86400000+Number(token.created_on) > (new Date).getTime()){
|
||||||
|
res.render('reset_password', {token:token});
|
||||||
|
}else{
|
||||||
|
next({message: 'token not found', status: 404});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
router.get('/login/invite/:token/:mailToken', async function(req, res, next){
|
router.get('/login/invite/:token/:mailToken', async function(req, res, next){
|
||||||
try{
|
try{
|
||||||
|
|
||||||
|
@ -52,10 +52,13 @@ router.put('/password', async function(req, res, next){
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
router.put('/password/:uid', async function(req, res, next){
|
router.put('/:uid/password', async function(req, res, next){
|
||||||
try{
|
try{
|
||||||
let user = await User.get(req.params.uid);
|
let user = await User.get(req.params.uid);
|
||||||
return res.json({results: await user.setPassword(req.body)});
|
return res.json({
|
||||||
|
results: await user.setPassword(req.body),
|
||||||
|
message: `User ${user.uid} password changed.`
|
||||||
|
});
|
||||||
}catch(error){
|
}catch(error){
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
|
25
nodejs/views/email_templates/reset_link.js
Normal file
25
nodejs/views/email_templates/reset_link.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
module.exports = {
|
||||||
|
subject: 'Password reset for Theta 42 account',
|
||||||
|
message: `
|
||||||
|
<h2> Theta 42 account</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Hello {{ user.givenName }},
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
You have asked to reset the password for user name <b>{{ user.uid }}</b> . Please
|
||||||
|
click the link below to complete this request. If this was done in errror,
|
||||||
|
please ignore this email.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
{{ link }}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
Thank you,<br />
|
||||||
|
Theta 42
|
||||||
|
</p>
|
||||||
|
`
|
||||||
|
};
|
135
nodejs/views/groups.ejs
Normal file
135
nodejs/views/groups.ejs
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
<%- include('top') %>
|
||||||
|
<script id="rowTemplate" type="text/html">
|
||||||
|
<p>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<i class="fad fa-users-class"></i>
|
||||||
|
Group: {{ cn }}
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p>
|
||||||
|
{{ description }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<ul class="list-group">
|
||||||
|
{{ #member }}
|
||||||
|
<li class="list-group-item">
|
||||||
|
<i class="fad fa-user"></i> {{ uid }}
|
||||||
|
<button type="button" action="group/{{groupCN}}/{{uid}}" method="delete" onclick="formAJAX(this)" evalAJAX="tableAJAX(data.message)" class="btn btn-sm btn-danger float-right">
|
||||||
|
<i class="fad fa-user-slash"></i>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
{{ /member }}
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
<i class="fad fa-user-plus"></i>
|
||||||
|
</button>
|
||||||
|
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
|
||||||
|
{{ #toAdd }}{{#.}}
|
||||||
|
<a class="dropdown-item" action="group/{{groupCN}}/{{uid}}" method="put" onclick="formAJAX(this)" evalAJAX="tableAJAX(data.message)">
|
||||||
|
<i class="fad fa-user"></i> {{uid}}
|
||||||
|
</a>
|
||||||
|
{{/.}}{{ /toAdd }}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="button" onclick="app.group.remove({cn: '{{cn}}'}, function(){tableAJAX('Group {{cn}} deleted.')})" class="btn btn-danger float-right">
|
||||||
|
<i class="fad fa-trash"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</p>
|
||||||
|
</script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
var userlist;
|
||||||
|
|
||||||
|
function getUserList(callback){
|
||||||
|
app.user.list(function(error, data){
|
||||||
|
userlist = data.results;
|
||||||
|
callback()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function tableAJAX(actionMessage){
|
||||||
|
var rowTemplate = $('#rowTemplate').html();
|
||||||
|
var $target = $('#tableAJAX');
|
||||||
|
|
||||||
|
$target.html('').hide();
|
||||||
|
app.util.actionMessage('Refreshing user list...', $target);
|
||||||
|
|
||||||
|
app.group.list(function(error, data){
|
||||||
|
$.each( data.results, function(key, value) {
|
||||||
|
|
||||||
|
// console.log(value.member)
|
||||||
|
|
||||||
|
value.toAdd = userlist.map(function(user){
|
||||||
|
if(!value.member.includes(user.dn)) return user;
|
||||||
|
})
|
||||||
|
value.member = value.member.map(function(user){
|
||||||
|
return {
|
||||||
|
dn: user,
|
||||||
|
uid: user.match(/cn=[a-zA-Z0-9\_\-\@\.]+/)[0].replace('cn=', '')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
value.groupCN = value.cn;
|
||||||
|
user_row = Mustache.render(rowTemplate, value);
|
||||||
|
$target.append(user_row);
|
||||||
|
});
|
||||||
|
|
||||||
|
$target.fadeIn('slow');
|
||||||
|
|
||||||
|
app.util.actionMessage(actionMessage || '', $target, 'info');
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).ready(function(){
|
||||||
|
getUserList(tableAJAX);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<div class="row" style="display:none">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<i class="fas fa-layer-plus"></i>
|
||||||
|
Add new group
|
||||||
|
</div>
|
||||||
|
<div class="card-header actionMessage" style="display:none"></div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form action="group/" method="post" onsubmit="formAJAX(this)" evalAJAX="tableAJAX('')">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label">Name</label>
|
||||||
|
<input type="text" class="form-control" name="name" placeholder="app_gitea_admin" validate=":3" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label">Description</label>
|
||||||
|
<textarea class="form-control" name="description" placeholder="Admin group for gitea app" validate=":3"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-outline-dark">Add</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-8">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<i class="fad fa-users-class"></i>
|
||||||
|
Group list
|
||||||
|
</div>
|
||||||
|
<div class="alert alert-warning actionMessage" style="display:none">
|
||||||
|
<!-- Message after AJAX action is preformed -->
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="" id="tableAJAX">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<%- include('bottom') %>
|
@ -9,34 +9,43 @@
|
|||||||
<i>Unix User ID:</i> <b>{{uidNumber}} </b><br />
|
<i>Unix User ID:</i> <b>{{uidNumber}} </b><br />
|
||||||
<i>Unix Group ID:</i> <b>{{gidNumber}} </b><br />
|
<i>Unix Group ID:</i> <b>{{gidNumber}} </b><br />
|
||||||
<i>LDAP DN:</i> <b>{{dn}} </b><br />
|
<i>LDAP DN:</i> <b>{{dn}} </b><br />
|
||||||
|
<i>SSH Public Key</i> <b>{{sshPublicKey}}</b><br />
|
||||||
<i>Joined</i> <b>{{createTimestamp}} </b><br />
|
<i>Joined</i> <b>{{createTimestamp}} </b><br />
|
||||||
<i>Joined</i> <b>{{modifyTimestamp}} </b><br />
|
<i>Edited</i> <b>{{modifyTimestamp}} </b><br />
|
||||||
<img id="profile_photo" >
|
<img id="profile_photo" >
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<script id="paswordResetTemplate" type="text/html">
|
||||||
|
<h3>
|
||||||
|
Reset Password for {{uid}}
|
||||||
|
</h3>
|
||||||
|
<form action="user/{{uid}}/password" method="put" onsubmit="formAJAX(this)">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label">Password</label>
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<span class="input-group-text" ><i class="fad fa-key"></i></span>
|
||||||
|
</div>
|
||||||
|
<input type="password" name="userPassword" class="form-control" placeholder="hunter123!" validate=":3" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label">Agian</label>
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<span class="input-group-text" ><i class="fad fa-key"></i></span>
|
||||||
|
</div>
|
||||||
|
<input type="password" name="password" class="form-control" placeholder="hunter123!" validate="eq:userPassword" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-outline-dark">Change</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
||||||
function hexToBase64(str) {
|
function hexToBase64(str) {
|
||||||
return btoa(String.fromCharCode.apply(null, str.replace(/\r|\n/g, "").replace(/([\da-fA-F]{2}) ?/g, "0x$1 ").replace(/ +$/, "").split(" ")));
|
return btoa(String.fromCharCode.apply(null, str.replace(/\r|\n/g, "").replace(/([\da-fA-F]{2}) ?/g, "0x$1 ").replace(/ +$/, "").split(" ")));
|
||||||
}
|
|
||||||
|
|
||||||
function tableAJAX(actionMessage){
|
|
||||||
var profileTemplate = $('#profileTemplate').html();
|
|
||||||
|
|
||||||
$('#tableAJAX').html('').hide();
|
|
||||||
app.util.actionMessage('Refreshing user list...')
|
|
||||||
var user;
|
|
||||||
app.auth.isLoggedIn(function(error, data){
|
|
||||||
// data.photo = unescape(encodeURIComponent(data.jpegPhoto));
|
|
||||||
data.createTimestamp = moment(data.createTimestamp, "YYYYMMDDHHmmssZ").fromNow();
|
|
||||||
data.modifyTimestamp = moment(data.modifyTimestamp, "YYYYMMDDHHmmssZ").fromNow();
|
|
||||||
|
|
||||||
user_row = Mustache.render(profileTemplate, data);
|
|
||||||
$('#tableAJAX').append(user_row);
|
|
||||||
user = data
|
|
||||||
$('#tableAJAX').fadeIn('slow');
|
|
||||||
app.util.actionMessage(actionMessage || '', {type: 'info'});
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getInvite(){
|
function getInvite(){
|
||||||
@ -46,7 +55,26 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
tableAJAX(); //populate the table
|
var profileTemplate = $('#profileTemplate').html();
|
||||||
|
var paswordResetTemplate = $('#paswordResetTemplate').html();
|
||||||
|
var $target = $('#tableAJAX');
|
||||||
|
|
||||||
|
$target.html('').hide();
|
||||||
|
app.auth.isLoggedIn(function(error, data){
|
||||||
|
if(error){
|
||||||
|
app.util.actionMessage(data.message || '', $target, error ? 'danger': null);
|
||||||
|
}else{
|
||||||
|
// data.photo = unescape(encodeURIComponent(data.jpegPhoto));
|
||||||
|
data.createTimestamp = moment(data.createTimestamp, "YYYYMMDDHHmmssZ").fromNow();
|
||||||
|
data.modifyTimestamp = moment(data.modifyTimestamp, "YYYYMMDDHHmmssZ").fromNow();
|
||||||
|
|
||||||
|
$target.html(Mustache.render(profileTemplate, data));
|
||||||
|
|
||||||
|
$('#passwordReset').html(Mustache.render(paswordResetTemplate, data))
|
||||||
|
|
||||||
|
$target.fadeIn('slow');
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<div class="row" style="display:none">
|
<div class="row" style="display:none">
|
||||||
@ -56,11 +84,10 @@
|
|||||||
<i class="fas fa-user-plus"></i>
|
<i class="fas fa-user-plus"></i>
|
||||||
Invite User
|
Invite User
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
|
|
||||||
<i class="far fa-arrows-v"></i>
|
<i class="far fa-arrows-v"></i>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-header actionMessage" style="display:none">
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<button onclick="getInvite(this)">New Invite Token</button>
|
<button onclick="getInvite(this)">New Invite Token</button>
|
||||||
@ -78,6 +105,8 @@
|
|||||||
<i class="fad fa-th-list"></i>
|
<i class="fad fa-th-list"></i>
|
||||||
Services
|
Services
|
||||||
</div>
|
</div>
|
||||||
|
<div class="card-header actionMessage" style="display:none">
|
||||||
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<ul class="list-group text-dark">
|
<ul class="list-group text-dark">
|
||||||
<a href="https://emby.718it.biz/" target="_blank" class="text-dark">
|
<a href="https://emby.718it.biz/" target="_blank" class="text-dark">
|
||||||
@ -107,14 +136,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
<div class="shadow-lg card card-default">
|
<div class="shadow-lg card card-default mb-8">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<i class="fad fa-id-card"></i>
|
<i class="fad fa-id-card"></i>
|
||||||
Profile
|
Profile
|
||||||
<div class="hover-effect float-right">
|
<div class="hover-effect float-right">
|
||||||
<i class="far fa-arrows-v"></i>
|
<i class="far fa-arrows-v"></i>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-header actionMessage" style="display:none">
|
||||||
|
</div>
|
||||||
<div class="card-body" style="padding-bottom:0">
|
<div class="card-body" style="padding-bottom:0">
|
||||||
<div class="alert alert-warning actionMessage" style="display:none">
|
<div class="alert alert-warning actionMessage" style="display:none">
|
||||||
<!-- Message after AJAX action is preformed -->
|
<!-- Message after AJAX action is preformed -->
|
||||||
@ -124,6 +155,22 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<br />
|
||||||
|
<div class="shadow-lg card">
|
||||||
|
<div class="card-header">
|
||||||
|
<i class="fad fa-undo-alt"></i>
|
||||||
|
Password Reset
|
||||||
|
<div class="float-right">
|
||||||
|
<i class="far fa-arrows-v"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-header actionMessage" style="display:none">
|
||||||
|
</div>
|
||||||
|
<div id="passwordReset" class="card-body">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<%- include('bottom') %>
|
<%- include('bottom') %>
|
||||||
|
@ -15,13 +15,12 @@
|
|||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
Add new user
|
Add new user
|
||||||
</div>
|
</div>
|
||||||
|
<div class="card-header actionMessage" style="display:none">
|
||||||
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<p>
|
<p>
|
||||||
Invited By: <b><%= invite.created_by %></b>, <%= invite.created_on %>
|
Invited By: <b><%= invite.created_by %></b>, <%= invite.created_on %>
|
||||||
</p>
|
</p>
|
||||||
<div class="alert alert-warning actionMessage" style="display:none">
|
|
||||||
<!-- Message after AJAX action is preformed -->
|
|
||||||
</div>
|
|
||||||
<%- include('user_form') %>
|
<%- include('user_form') %>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
Validate Email
|
Validate Email
|
||||||
</div>
|
</div>
|
||||||
|
<div class="card-header actionMessage" style="display:none">
|
||||||
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<p>
|
<p>
|
||||||
Invited By: <b><%= invite.created_by %></b>, <%= invite.created_on %>.
|
Invited By: <b><%= invite.created_by %></b>, <%= invite.created_on %>.
|
||||||
|
@ -8,26 +8,7 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
$( "form[action='login']" ).submit(function( event ) {
|
|
||||||
event.preventDefault();
|
|
||||||
$form = $(this);
|
|
||||||
app.util.actionMessage('')
|
|
||||||
|
|
||||||
if($form.attr('isValid') !== 'true'){
|
|
||||||
console.log('')
|
|
||||||
return app.util.actionMessage('Please fix the errors bellow!')
|
|
||||||
}
|
|
||||||
|
|
||||||
app.auth.logIn($form.serializeObject(), function(error, data){
|
|
||||||
if(data){
|
|
||||||
app.util.actionMessage('Login successful!');
|
|
||||||
window.location.href = app.util.getUrlParameter('redirect') || '/';
|
|
||||||
|
|
||||||
}else{
|
|
||||||
app.util.actionMessage('Login Failed, please try again');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -37,10 +18,10 @@
|
|||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
Password Log in
|
Password Log in
|
||||||
</div>
|
</div>
|
||||||
|
<div class="card-header actionMessage" style="display:none">
|
||||||
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="alert alert-warning actionMessage" style="display:none">
|
<form action="auth/login" onsubmit="formAJAX(this)" evalAJAX="app.auth.setToken(data.token);window.location.href = app.util.getUrlParameter('redirect') || '/';">
|
||||||
</div>
|
|
||||||
<form action="login" onsubmit="$(this).validate()">
|
|
||||||
<input type="hidden" name="redirect" value="<%= redirect %>">
|
<input type="hidden" name="redirect" value="<%= redirect %>">
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@ -71,21 +52,27 @@
|
|||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
Social Login
|
Social Login
|
||||||
</div>
|
</div>
|
||||||
|
<div class="card-header actionMessage" style="display:none">
|
||||||
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="alert alert-warning actionMessage" style="display:none">
|
<div class="alert alert-warning actionMessage" style="display:none">
|
||||||
</div>
|
</div>
|
||||||
<h3>Coming soon!</h3>
|
<h3>Coming soon!</h3>
|
||||||
<ul>
|
<p>
|
||||||
<li><i class="fab fa-google"></i> Login with google OATH</li>
|
<ul class="list-group">
|
||||||
<li><i class="fab fa-github"></i> Login with github OATH</li>
|
<li class="list-group-item"><i class="fab fa-google"></i> Login with google OATH</li>
|
||||||
<li><i class="fab fa-facebook"></i> Login with facebook OATH</li>
|
<li class="list-group-item"><i class="fab fa-github"></i> Login with github OATH</li>
|
||||||
</ul>
|
<li class="list-group-item"><i class="fab fa-facebook"></i> Login with facebook OATH</li>
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="shadow-lg card border-danger mb-3">
|
<div class="shadow-lg card mb-3">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
Password Reset
|
Password Reset
|
||||||
</div>
|
</div>
|
||||||
|
<div class="card-header actionMessage" style="display:none">
|
||||||
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<p>
|
<p>
|
||||||
Forgot your password? Or your user name? No problem! Just
|
Forgot your password? Or your user name? No problem! Just
|
||||||
@ -93,7 +80,7 @@
|
|||||||
we will email with the required information to get back up
|
we will email with the required information to get back up
|
||||||
and running!
|
and running!
|
||||||
</p>
|
</p>
|
||||||
<form action="reset_password" onsubmit="$(this).validate()">
|
<form action="auth/resetpassword" onsubmit="formAJAX(this)">
|
||||||
<input type="hidden" name="redirect" value="<%= redirect %>">
|
<input type="hidden" name="redirect" value="<%= redirect %>">
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
41
nodejs/views/reset_password.ejs
Normal file
41
nodejs/views/reset_password.ejs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<%- include('top') %>
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(document).ready(function(){
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<div class="row" style="display:none">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
Password reset
|
||||||
|
</div>
|
||||||
|
<div class="card-header actionMessage" style="display:none">
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form action="auth/resetpassword/<%= token.token%>" method="post" onsubmit="formAJAX(this)">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label">Password</label>
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<span class="input-group-text" ><i class="fad fa-key"></i></span>
|
||||||
|
</div>
|
||||||
|
<input type="password" name="userPassword" class="form-control" placeholder="hunter123!" validate=":3" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label">Agian</label>
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<span class="input-group-text" ><i class="fad fa-key"></i></span>
|
||||||
|
</div>
|
||||||
|
<input type="password" name="password" class="form-control" placeholder="hunter123!" validate="eq:userPassword" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-outline-dark">Change</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<%- include('bottom') %>
|
@ -11,6 +11,7 @@
|
|||||||
<!-- Scripts are placed here -->
|
<!-- Scripts are placed here -->
|
||||||
<script src="https://code.jquery.com/jquery-3.5.0.min.js"></script>
|
<script src="https://code.jquery.com/jquery-3.5.0.min.js"></script>
|
||||||
<!-- <script type="text/javascript" src='/static/js/jquery.min.js'></script> -->
|
<!-- <script type="text/javascript" src='/static/js/jquery.min.js'></script> -->
|
||||||
|
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"></script>
|
||||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
|
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
|
||||||
<!-- <script type="text/javascript" src='/static/js/bootstrap.min.js'></script> -->
|
<!-- <script type="text/javascript" src='/static/js/bootstrap.min.js'></script> -->
|
||||||
<script src="https://kit.fontawesome.com/4625ee80a2.js" crossorigin="anonymous"></script>
|
<script src="https://kit.fontawesome.com/4625ee80a2.js" crossorigin="anonymous"></script>
|
||||||
@ -30,7 +31,8 @@
|
|||||||
<h5 class="hover-effect my-0 mr-md-auto font-weight-normal">SSO Manager - Theta 42</h5>
|
<h5 class="hover-effect my-0 mr-md-auto font-weight-normal">SSO Manager - Theta 42</h5>
|
||||||
<nav class="my-2 my-md-0 mr-md-3">
|
<nav class="my-2 my-md-0 mr-md-3">
|
||||||
<a class="hover-effect text-dark p-2" href="/"><i class="fad fa-tachometer-alt-fastest"></i> Home</a>
|
<a class="hover-effect text-dark p-2" href="/"><i class="fad fa-tachometer-alt-fastest"></i> Home</a>
|
||||||
<a class="hover-effect text-dark p-2" href="/users"><i class="fad fa-users"></i> User Admin</a>
|
<a class="hover-effect text-dark p-2" href="/users"><i class="fad fa-users"></i> Users</a>
|
||||||
|
<a class="hover-effect text-dark p-2" href="/groups"><i class="fad fa-users-class"></i> Groups</a>
|
||||||
</nav>
|
</nav>
|
||||||
<a class="hover-effect btn btn-outline-primary" onclick="app.auth.logOut(e => window.location.href='/')"><i class="fas fa-sign-out"></i> Log Out</a>
|
<a class="hover-effect btn btn-outline-primary" onclick="app.auth.logOut(e => window.location.href='/')"><i class="fas fa-sign-out"></i> Log Out</a>
|
||||||
|
|
||||||
|
@ -28,5 +28,5 @@
|
|||||||
<label class="control-label">Again</label>
|
<label class="control-label">Again</label>
|
||||||
<input type="password" class="form-control" name="passwordMatch" placeholder="Retype password" validate="eq:userPassword"/>
|
<input type="password" class="form-control" name="passwordMatch" placeholder="Retype password" validate="eq:userPassword"/>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" onclick="formAJAX(this)" class="btn btn-default">Add</button>
|
<button type="button" onclick="formAJAX(this)" class="btn btn-outline-dark">Add</button>
|
||||||
</form>
|
</form>
|
||||||
|
@ -18,19 +18,21 @@
|
|||||||
|
|
||||||
function tableAJAX(actionMessage){
|
function tableAJAX(actionMessage){
|
||||||
var rowTemplate = $('#rowTemplate').html();
|
var rowTemplate = $('#rowTemplate').html();
|
||||||
|
var $target = $('#tableAJAX');
|
||||||
|
|
||||||
$('#tableAJAX').html('').hide();
|
$target.html('').hide();
|
||||||
app.util.actionMessage('Refreshing user list...')
|
app.util.actionMessage('Refreshing user list...', $target);
|
||||||
|
|
||||||
app.user.list(function(error, data){
|
app.user.list(function(error, data){
|
||||||
$.each( data.results, function(key, value) {
|
$.each( data.results, function(key, value) {
|
||||||
|
if(value.uidNumber<1500) return;
|
||||||
user_row = Mustache.render(rowTemplate, value);
|
user_row = Mustache.render(rowTemplate, value);
|
||||||
$('#tableAJAX').append(user_row);
|
$target.append(user_row);
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#tableAJAX').fadeIn('slow');
|
$target.fadeIn('slow');
|
||||||
|
|
||||||
app.util.actionMessage(actionMessage || '', {type: 'info'});
|
app.util.actionMessage(actionMessage || '', $target, 'info');
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -46,6 +48,7 @@
|
|||||||
<i class="fas fa-user-plus"></i>
|
<i class="fas fa-user-plus"></i>
|
||||||
Add new user
|
Add new user
|
||||||
</div>
|
</div>
|
||||||
|
<div class="card-header actionMessage" style="display:none"></div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<%- include('user_form') %>
|
<%- include('user_form') %>
|
||||||
</div>
|
</div>
|
||||||
@ -57,10 +60,8 @@
|
|||||||
<i class="fad fa-th-list"></i>
|
<i class="fad fa-th-list"></i>
|
||||||
User List
|
User List
|
||||||
</div>
|
</div>
|
||||||
|
<div class="card-header actionMessage" style="display:none"></div>
|
||||||
<div class="card-body" style="padding-bottom:0">
|
<div class="card-body" style="padding-bottom:0">
|
||||||
<div class="alert alert-warning actionMessage" style="display:none">
|
|
||||||
<!-- Message after AJAX action is preformed -->
|
|
||||||
</div>
|
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user