rc1
This commit is contained in:
parent
f2309463a4
commit
4d51a4ac9e
@ -5,7 +5,8 @@ const {Auth} = require('../models/auth');
|
|||||||
async function auth(req, res, next){
|
async function auth(req, res, next){
|
||||||
try{
|
try{
|
||||||
let user = await Auth.checkToken({token: req.header('auth-token')});
|
let user = await Auth.checkToken({token: req.header('auth-token')});
|
||||||
if(user.username){
|
|
||||||
|
if(user.uid){
|
||||||
req.user = user;
|
req.user = user;
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
const {User} = require('./user');
|
const {User} = require('./user');
|
||||||
const {Token, AuthToken} = require('./token');
|
const {Token, AuthToken} = require('./token');
|
||||||
|
|
||||||
Auth = {}
|
var Auth = {}
|
||||||
Auth.errors = {}
|
Auth.errors = {}
|
||||||
|
|
||||||
Auth.errors.login = function(){
|
Auth.errors.login = function(){
|
||||||
let error = new Error('PamLoginFailed');
|
let error = new Error('LDAPLoginFailed');
|
||||||
error.name = 'PamLoginFailed';
|
error.name = 'LDAPLoginFailed';
|
||||||
error.message = `Invalid Credentials, login failed.`;
|
error.message = `Invalid Credentials, login failed.`;
|
||||||
error.status = 401;
|
error.status = 401;
|
||||||
|
|
||||||
|
32
nodejs/models/email.js
Normal file
32
nodejs/models/email.js
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const sgMail = require('@sendgrid/mail');
|
||||||
|
const mustache = require('mustache');
|
||||||
|
const conf = require('../app').conf;
|
||||||
|
|
||||||
|
sgMail.setApiKey(conf.SENDGRID_API_KEY);
|
||||||
|
|
||||||
|
var Mail = {};
|
||||||
|
|
||||||
|
Mail.send = async function(to, subject, message, from){
|
||||||
|
await sgMail.send({
|
||||||
|
to: to,
|
||||||
|
from: from || 'Theta 42 Accounts <accounts@no-reply.theta42.com>',
|
||||||
|
subject: subject,
|
||||||
|
text: message,
|
||||||
|
html: message,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Mail.sendTemplate = async function(to, template, context, from){
|
||||||
|
template = require(`../views/email_templates/${template}`);
|
||||||
|
await Mail.send(
|
||||||
|
to,
|
||||||
|
mustache.render(template.subject, context),
|
||||||
|
mustache.render(template.message, context),
|
||||||
|
from || (template.from && mustache.render(template.message, context))
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {Mail};
|
@ -4,7 +4,7 @@ const { Client, Attribute, Change } = require('ldapts');
|
|||||||
const conf = require('../app').conf.ldap;
|
const conf = require('../app').conf.ldap;
|
||||||
|
|
||||||
const client = new Client({
|
const client = new Client({
|
||||||
url: conf.url,
|
url: conf.url,
|
||||||
});
|
});
|
||||||
|
|
||||||
async function getGroups(client){
|
async function getGroups(client){
|
||||||
@ -25,21 +25,21 @@ async function getGroups(client){
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function addGroup(client, data){
|
async function addGroup(client, data){
|
||||||
try{
|
try{
|
||||||
|
|
||||||
await client.add(`cn=${data.name},${conf.groupBase}`, {
|
await client.add(`cn=${data.name},${conf.groupBase}`, {
|
||||||
cn: data.name,
|
cn: data.name,
|
||||||
member: data.owner,
|
member: data.owner,
|
||||||
description: data.description,
|
description: data.description,
|
||||||
owner: data.owner,
|
owner: data.owner,
|
||||||
objectclass: [ 'groupOfNames', 'top' ]
|
objectclass: [ 'groupOfNames', 'top' ]
|
||||||
});
|
});
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
|
|
||||||
}catch(error){
|
}catch(error){
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function addMember(client, group, user){
|
async function addMember(client, group, user){
|
||||||
@ -61,18 +61,18 @@ async function addMember(client, group, user){
|
|||||||
|
|
||||||
async function removeMember(client, group, user){
|
async function removeMember(client, group, user){
|
||||||
try{
|
try{
|
||||||
await client.modify(group.dn, [
|
await client.modify(group.dn, [
|
||||||
new Change({
|
new Change({
|
||||||
operation: 'delete',
|
operation: 'delete',
|
||||||
modification: new Attribute({
|
modification: new Attribute({
|
||||||
type: 'member',
|
type: 'member',
|
||||||
values: [user.dn]
|
values: [user.dn]
|
||||||
})}),
|
})}),
|
||||||
]);
|
]);
|
||||||
}catch(error){
|
}catch(error){
|
||||||
if(error = "TypeOrValueExistsError")return ;
|
if(error = "TypeOrValueExistsError")return ;
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -134,4 +134,19 @@ Group.get = async function(data){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Group.add = async function(data){
|
||||||
|
try{
|
||||||
|
await client.bind(conf.bindDN, conf.bindPassword);
|
||||||
|
|
||||||
|
await addGroup(client, data);
|
||||||
|
|
||||||
|
await client.unbind();
|
||||||
|
|
||||||
|
return this.get(data);
|
||||||
|
|
||||||
|
}catch(error){
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {Group};
|
module.exports = {Group};
|
||||||
|
@ -29,7 +29,9 @@ Token.check = async function(data){
|
|||||||
var InviteToken = Object.create(Token({
|
var InviteToken = Object.create(Token({
|
||||||
name: 'invite',
|
name: 'invite',
|
||||||
keyMap:{
|
keyMap:{
|
||||||
claimed_by: {default:"__NONE__", isRequired: false, type: 'string',}
|
claimed_by: {default:"__NONE__", isRequired: false, type: 'string',},
|
||||||
|
mail: {default:"__NONE__", isRequired: false, type: 'string',},
|
||||||
|
mail_token: {default: UUID, type: 'string', min: 36, max: 36},
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -53,7 +55,7 @@ var AuthToken = Object.create(Token({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
AuthToken.add = async function(data){
|
AuthToken.add = async function(data){
|
||||||
data.created_by = data.username;
|
data.created_by = data.uid;
|
||||||
return AuthToken.__proto__.add(data);
|
return AuthToken.__proto__.add(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
const { Client, Attribute, Change } = require('ldapts');
|
const { Client, Attribute, Change } = require('ldapts');
|
||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
|
|
||||||
|
const {Mail} = require('./email');
|
||||||
const {Token, InviteToken} = require('./token');
|
const {Token, InviteToken} = require('./token');
|
||||||
const conf = require('../app').conf.ldap;
|
const conf = require('../app').conf.ldap;
|
||||||
|
|
||||||
@ -47,7 +48,9 @@ async function addPosixAccount(client, data){
|
|||||||
uid: data.uid,
|
uid: data.uid,
|
||||||
uidNumber: data.uidNumber,
|
uidNumber: data.uidNumber,
|
||||||
gidNumber: data.gidNumber,
|
gidNumber: data.gidNumber,
|
||||||
|
givenName: data.givenName,
|
||||||
mail: data.mail,
|
mail: data.mail,
|
||||||
|
mobile: data.mobile,
|
||||||
loginShell: data.loginShell,
|
loginShell: data.loginShell,
|
||||||
homeDirectory: data.homeDirectory,
|
homeDirectory: data.homeDirectory,
|
||||||
userPassword: data.userPassword,
|
userPassword: data.userPassword,
|
||||||
@ -81,6 +84,14 @@ async function addLdapUser(client, data){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function deleteLdapUser(client, data){
|
||||||
|
try{
|
||||||
|
await client.del(`cn=${data.cn},${conf.groupBase}`);
|
||||||
|
await client.del(data.dn);
|
||||||
|
}catch(error){
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function changeLdapPassword(client, data){
|
async function changeLdapPassword(client, data){
|
||||||
try{
|
try{
|
||||||
@ -100,14 +111,8 @@ async function changeLdapPassword(client, data){
|
|||||||
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]
|
||||||
// delete data[conf.userNameAttribute];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if(data.uidNumber){
|
|
||||||
// data.uid = data.uidNumber;
|
|
||||||
// delete data.uidNumber;
|
|
||||||
// }
|
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,11 +120,6 @@ var User = {}
|
|||||||
|
|
||||||
User.backing = "LDAP";
|
User.backing = "LDAP";
|
||||||
|
|
||||||
User.keyMap = {
|
|
||||||
'username': {isRequired: true, type: 'string', min: 3, max: 500},
|
|
||||||
'password': {isRequired: true, type: 'string', min: 3, max: 500},
|
|
||||||
}
|
|
||||||
|
|
||||||
User.list = async function(){
|
User.list = async function(){
|
||||||
try{
|
try{
|
||||||
await client.bind(conf.bindDN, conf.bindPassword);
|
await client.bind(conf.bindDN, conf.bindPassword);
|
||||||
@ -170,14 +170,14 @@ User.listDetail = async function(){
|
|||||||
User.get = async function(data){
|
User.get = async function(data){
|
||||||
try{
|
try{
|
||||||
if(typeof data !== 'object'){
|
if(typeof data !== 'object'){
|
||||||
let username = data;
|
let uid = data;
|
||||||
data = {};
|
data = {};
|
||||||
data.username = username;
|
data.uid = uid;
|
||||||
}
|
}
|
||||||
|
|
||||||
await client.bind(conf.bindDN, conf.bindPassword);
|
await client.bind(conf.bindDN, conf.bindPassword);
|
||||||
|
|
||||||
let filter = `(&${conf.userFilter}(${conf.userNameAttribute}=${data.username}))`;
|
let filter = `(&${conf.userFilter}(${conf.userNameAttribute}=${data.uid}))`;
|
||||||
|
|
||||||
const res = await client.search(conf.userBase, {
|
const res = await client.search(conf.userBase, {
|
||||||
scope: 'sub',
|
scope: 'sub',
|
||||||
@ -225,7 +225,18 @@ User.add = async function(data) {
|
|||||||
|
|
||||||
await client.unbind();
|
await client.unbind();
|
||||||
|
|
||||||
return this.get(data.uid);
|
let user = await this.get(data.uid);
|
||||||
|
|
||||||
|
|
||||||
|
await Mail.sendTemplate(
|
||||||
|
user.mail,
|
||||||
|
'welcome',
|
||||||
|
{
|
||||||
|
user: user
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return user;
|
||||||
|
|
||||||
}catch(error){
|
}catch(error){
|
||||||
if(error.message.includes('exists')){
|
if(error.message.includes('exists')){
|
||||||
@ -244,7 +255,7 @@ User.addByInvite = async function(data){
|
|||||||
try{
|
try{
|
||||||
let token = await InviteToken.get(data.token);
|
let token = await InviteToken.get(data.token);
|
||||||
|
|
||||||
if(!token.is_valid){
|
if(!token.is_valid && data.mailToken !== token.mail_token){
|
||||||
let error = new Error('Token Invalid');
|
let error = new Error('Token Invalid');
|
||||||
error.name = 'Token Invalid';
|
error.name = 'Token Invalid';
|
||||||
error.message = `Token is not valid or as allready been used. ${data.token}`;
|
error.message = `Token is not valid or as allready been used. ${data.token}`;
|
||||||
@ -252,6 +263,8 @@ User.addByInvite = async function(data){
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data.mail = token.mail;
|
||||||
|
|
||||||
let user = await this.add(data);
|
let user = await this.add(data);
|
||||||
|
|
||||||
if(user){
|
if(user){
|
||||||
@ -265,13 +278,37 @@ User.addByInvite = async function(data){
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// User.remove = async function(data){
|
User.verifyEmail = async function(data){
|
||||||
// try{
|
try{
|
||||||
// return await linuxUser.removeUser(this.username);
|
let token = await InviteToken.get(data.token);
|
||||||
// }catch(error){
|
await token.update({mail: data.mail})
|
||||||
// throw error;
|
await Mail.sendTemplate(
|
||||||
// }
|
data.mail,
|
||||||
// };
|
'validate_link',
|
||||||
|
{
|
||||||
|
link:`${data.url}/login/invite/${token.token}/${token.mail_token}`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}catch(error){
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
User.remove = async function(data){
|
||||||
|
try{
|
||||||
|
|
||||||
|
await client.bind(conf.bindDN, conf.bindPassword);
|
||||||
|
|
||||||
|
await deleteLdapUser(client, this);
|
||||||
|
|
||||||
|
await client.unbind();
|
||||||
|
|
||||||
|
return true
|
||||||
|
|
||||||
|
}catch(error){
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// User.setPassword = async function(data){
|
// User.setPassword = async function(data){
|
||||||
// try{
|
// try{
|
||||||
|
10
nodejs/package-lock.json
generated
10
nodejs/package-lock.json
generated
@ -444,11 +444,21 @@
|
|||||||
"brace-expansion": "^1.1.7"
|
"brace-expansion": "^1.1.7"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"moment": {
|
||||||
|
"version": "2.25.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.25.3.tgz",
|
||||||
|
"integrity": "sha512-PuYv0PHxZvzc15Sp8ybUCoQ+xpyPWvjOuK72a5ovzp2LI32rJXOiIfyoFoYvG3s6EwwrdkMyWuRiEHSZRLJNdg=="
|
||||||
|
},
|
||||||
"ms": {
|
"ms": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||||
},
|
},
|
||||||
|
"mustache": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/mustache/-/mustache-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-yL5VE97+OXn4+Er3THSmTdCFCtx5hHWzrolvH+JObZnUYwuaG7XV+Ch4fR2cIrcYI0tFHxS7iyFYl14bW8y2sA=="
|
||||||
|
},
|
||||||
"negotiator": {
|
"negotiator": {
|
||||||
"version": "0.6.2",
|
"version": "0.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
"express": "~4.16.1",
|
"express": "~4.16.1",
|
||||||
"extend": "^3.0.2",
|
"extend": "^3.0.2",
|
||||||
"ldapts": "^2.2.1",
|
"ldapts": "^2.2.1",
|
||||||
|
"moment": "^2.25.3",
|
||||||
|
"mustache": "^4.0.1",
|
||||||
"redis": "^2.8.0",
|
"redis": "^2.8.0",
|
||||||
"smtpc": "^0.1.2"
|
"smtpc": "^0.1.2"
|
||||||
},
|
},
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
.hover-effect {
|
||||||
|
transition: all .5s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hover-effect:hover {
|
||||||
|
color: darkblue;
|
||||||
|
transition: all .5s ease;
|
||||||
|
background-color: inherit;
|
||||||
|
-ms-transform: scale(1.1);
|
||||||
|
-webkit-transform: scale(1.1);
|
||||||
|
transform: scale(1.1); /* Standard syntax */
|
||||||
|
}
|
@ -112,8 +112,9 @@ app.auth = (function(app) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function logOut(){
|
function logOut(callack){
|
||||||
localStorage.removeItem('APIToken');
|
localStorage.removeItem('APIToken');
|
||||||
|
callack();
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeUserFromInvite(args, callack){
|
function makeUserFromInvite(args, callack){
|
||||||
@ -150,13 +151,13 @@ app.user = (function(app){
|
|||||||
}
|
}
|
||||||
|
|
||||||
function remove(args, callack){
|
function remove(args, callack){
|
||||||
app.api.delete('user/'+ args.username, function(error, data){
|
app.api.delete('user/'+ args.uid, function(error, data){
|
||||||
callack(error, data);
|
callack(error, data);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function changePassword(args, callack){
|
function changePassword(args, callack){
|
||||||
app.api.put('users/'+ arg.username || '', args, function(error, data){
|
app.api.put('users/'+ arg.uid || '', args, function(error, data){
|
||||||
callack(error, data);
|
callack(error, data);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -313,8 +314,6 @@ 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';
|
||||||
|
|
||||||
console.log('formAJAX method', method)
|
|
||||||
|
|
||||||
if( !$form.validate(
|
if( !$form.validate(
|
||||||
{
|
{
|
||||||
form: {
|
form: {
|
||||||
@ -326,9 +325,9 @@ function formAJAX( btn, del ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
app.api[method]($form.attr( 'action' ), formData, function(error, data){
|
app.api[method]($form.attr( 'action' ), formData, function(error, data){
|
||||||
tableAJAX( data.message ); //re-populate table
|
app.util.actionMessage( data.message ); //re-populate table
|
||||||
if(!error){
|
if(!error){
|
||||||
eval( $form.attr( 'evalAJAX' ) ); //gets JS to run after completion
|
eval($form.attr('evalAJAX')); //gets JS to run after completion
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -20,8 +20,8 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$( '<b>' ).html( ' - ' + error_message ).appendTo( $input.siblings( 'label' ) );
|
$( '<b>' ).html( ' - ' + error_message ).appendTo( $input.parents('.form-group').children( 'label' ) );
|
||||||
$input.parent().addClass("has-error");
|
$input.addClass("is-invalid");
|
||||||
failedCount++;
|
failedCount++;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -35,8 +35,8 @@
|
|||||||
value = $input.val(), //link to input value
|
value = $input.val(), //link to input value
|
||||||
rule = attr[0];
|
rule = attr[0];
|
||||||
|
|
||||||
$input.siblings( 'label' ).children( 'b' ).remove(); //removes old error
|
$input.parents('.form-group').children( 'label' ).children( 'b' ).remove(); //removes old error
|
||||||
$input.parent().removeClass( "has-error" ); //removes has-error class
|
$input.removeClass( "is-invalid" ); //removes is-invalid class
|
||||||
|
|
||||||
//checks if field is required, and length
|
//checks if field is required, and length
|
||||||
if (isNaN(requirement) === false && requirement && value.length < requirement) {
|
if (isNaN(requirement) === false && requirement && value.length < requirement) {
|
||||||
|
@ -29,14 +29,15 @@ router.all('/logout', async function(req, res, next){
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post('/invite/:token', 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;
|
||||||
|
req.body.mailToken = req.params.mailToken;
|
||||||
let user = await User.addByInvite(req.body);
|
let user = await User.addByInvite(req.body);
|
||||||
let token = await AuthToken.add(user);
|
let token = await AuthToken.add(user);
|
||||||
|
|
||||||
return res.json({
|
return res.json({
|
||||||
user: user.username,
|
user: user.uid,
|
||||||
token: token.token
|
token: token.token
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -46,6 +47,21 @@ router.post('/invite/:token', async function(req, res, next) {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.post('/invite/:token', async function(req, res, next){
|
||||||
|
try{
|
||||||
|
let data = {
|
||||||
|
token: req.params.token,
|
||||||
|
url: `${req.protocol}://${req.hostname}`,
|
||||||
|
mail: req.body.mail,
|
||||||
|
}
|
||||||
|
|
||||||
|
await User.verifyEmail(data);
|
||||||
|
return res.send({message: 'sent'});
|
||||||
|
}catch(error){
|
||||||
|
next(error)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
var express = require('express');
|
var express = require('express');
|
||||||
var router = express.Router();
|
var router = express.Router();
|
||||||
|
const moment = require('moment');
|
||||||
const {InviteToken} = require('./../models/token');
|
const {InviteToken} = require('./../models/token');
|
||||||
|
|
||||||
|
|
||||||
/* GET home page. */
|
/* GET home page. */
|
||||||
router.get('/', async function(req, res, next) {
|
router.get('/', async function(req, res, next) {
|
||||||
res.render('home', { title: 'Express' });
|
res.render('home', { title: 'Express' });
|
||||||
@ -12,21 +16,38 @@ router.get('/users', function(req, res, next) {
|
|||||||
res.render('users', { title: 'Express' });
|
res.render('users', { title: 'Express' });
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get('/login/invite/:token', async function(req, res, next){
|
router.get('/login/invite/:token/:mailToken', async function(req, res, next){
|
||||||
try{
|
try{
|
||||||
console.log('token', req.params.token)
|
|
||||||
let token = await InviteToken.get(req.params.token);
|
let token = await InviteToken.get(req.params.token);
|
||||||
console.log('invite', token);
|
|
||||||
if(token.is_valid){
|
if(token.is_valid && token.mail !== '__NONE__' && token.mail_token === req.params.mailToken){
|
||||||
|
token.created_on = moment(token.created_on, 'x').fromNow();
|
||||||
res.render('invite', { title: 'Express', invite: token });
|
res.render('invite', { title: 'Express', invite: token });
|
||||||
}else{
|
}else{
|
||||||
next({status: 404});
|
next({message: 'token not found', status: 404});
|
||||||
}
|
}
|
||||||
}catch(error){
|
}catch(error){
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.get('/login/invite/:token', async function(req, res, next){
|
||||||
|
try{
|
||||||
|
let token = await InviteToken.get(req.params.token);
|
||||||
|
token.created_on = moment(token.created_on, 'x').fromNow();
|
||||||
|
|
||||||
|
if(token.is_valid){
|
||||||
|
res.render('invite_email', { title: 'Express', invite: token });
|
||||||
|
}else{
|
||||||
|
next({message: 'token not found', status: 404});
|
||||||
|
}
|
||||||
|
}catch(error){
|
||||||
|
next(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
/* GET home page. */
|
/* GET home page. */
|
||||||
router.get('/login', function(req, res, next) {
|
router.get('/login', function(req, res, next) {
|
||||||
res.render('login', {redirect: req.query.redirect});
|
res.render('login', {redirect: req.query.redirect});
|
||||||
|
@ -15,7 +15,7 @@ router.get('/', async function(req, res, next){
|
|||||||
|
|
||||||
router.post('/', async function(req, res, next){
|
router.post('/', async function(req, res, next){
|
||||||
try{
|
try{
|
||||||
req.body.created_by = req.user.username
|
req.body.created_by = req.user.uid
|
||||||
|
|
||||||
return res.json({results: await User.add(req.body)});
|
return res.json({results: await User.add(req.body)});
|
||||||
}catch(error){
|
}catch(error){
|
||||||
@ -23,11 +23,13 @@ router.post('/', async function(req, res, next){
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
router.delete('/:username', async function(req, res, next){
|
router.delete('/:uid', async function(req, res, next){
|
||||||
try{
|
try{
|
||||||
let user = await User.get(req.params.username);
|
let user = await User.get(req.params.uid);
|
||||||
|
|
||||||
return res.json({username: req.params.username, results: await user.remove()})
|
console.log('delete user', user);
|
||||||
|
|
||||||
|
return res.json({uid: req.params.uid, results: await user.remove()})
|
||||||
}catch(error){
|
}catch(error){
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
@ -36,7 +38,7 @@ router.delete('/:username', async function(req, res, next){
|
|||||||
router.get('/me', async function(req, res, next){
|
router.get('/me', async function(req, res, next){
|
||||||
try{
|
try{
|
||||||
|
|
||||||
return res.json(await User.get({username: req.user.username}));
|
return res.json(await User.get({uid: req.user.uid}));
|
||||||
}catch(error){
|
}catch(error){
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
@ -50,9 +52,9 @@ router.put('/password', async function(req, res, next){
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
router.put('/password/:username', async function(req, res, next){
|
router.put('/password/:uid', async function(req, res, next){
|
||||||
try{
|
try{
|
||||||
let user = await User.get(req.params.username);
|
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)});
|
||||||
}catch(error){
|
}catch(error){
|
||||||
next(error);
|
next(error);
|
||||||
@ -72,7 +74,7 @@ router.post('/invite', async function(req, res, next){
|
|||||||
router.post('/key', async function(req, res, next){
|
router.post('/key', async function(req, res, next){
|
||||||
try{
|
try{
|
||||||
let added = await User.addSSHkey({
|
let added = await User.addSSHkey({
|
||||||
username: req.user.username,
|
uid: req.user.uid,
|
||||||
key: req.body.key
|
key: req.body.key
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
|
|
||||||
// using Twilio SendGrid's v3 Node.js Library
|
|
||||||
// https://github.com/sendgrid/sendgrid-nodejs
|
|
||||||
const sgMail = require('@sendgrid/mail');
|
|
||||||
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
|
|
||||||
const msg = {
|
|
||||||
to: 'wmantly@gmail.com',
|
|
||||||
from: 'info@no-reply.theta42.com',
|
|
||||||
subject: 'Sending with Twilio SendGrid is Fun',
|
|
||||||
text: 'and easy to do anywhere, even with Node.js',
|
|
||||||
html: '<strong>and easy to do anywhere, even with Node.js</strong>',
|
|
||||||
};
|
|
||||||
sgMail.send(msg);
|
|
@ -1,8 +1,10 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
const {createClient} = require('redis');
|
const {createClient} = require('redis');
|
||||||
const {promisify} = require('util');
|
const {promisify} = require('util');
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
prefix: 'proxy_'
|
prefix: 'sso_'
|
||||||
}
|
}
|
||||||
|
|
||||||
function client() {
|
function client() {
|
||||||
|
0
nodejs/views/email_templates/untitled
Normal file
0
nodejs/views/email_templates/untitled
Normal file
24
nodejs/views/email_templates/validate_link.js
Normal file
24
nodejs/views/email_templates/validate_link.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
module.exports = {
|
||||||
|
subject: 'Validate email for Theta 42 account',
|
||||||
|
message: `
|
||||||
|
<h2> Theta 42 account</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Welcome,
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
We need to verify the provided email address in order to continue. Please
|
||||||
|
follow the link below to verify this email address:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
{{ link }}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
Thank you,<br />
|
||||||
|
Theta 42
|
||||||
|
</p>
|
||||||
|
`
|
||||||
|
};
|
34
nodejs/views/email_templates/welcome.js
Normal file
34
nodejs/views/email_templates/welcome.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
module.exports = {
|
||||||
|
subject: 'Welcome to Theta 42!',
|
||||||
|
message: `
|
||||||
|
<p>
|
||||||
|
Welcome {{user.givenName}},
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Your new Theta 42 Single sign-on account is ready to use. Here is some
|
||||||
|
information to get you started.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Your username is <b>{{user.uid}}</b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
You can manage your account at https://sso.theta42.com
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
You account is ready to be used now, test it by SSHing into the Theta 42
|
||||||
|
jump host \`ssh {{user.uid}}@718it.biz\`
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The SSO service is still in beta, so please report any bugs you may find!
|
||||||
|
You will be notified of new features and services as they become available.
|
||||||
|
</p>
|
||||||
|
Thank you,<br />
|
||||||
|
Theta 42
|
||||||
|
</p>
|
||||||
|
`
|
||||||
|
};
|
@ -11,8 +11,6 @@
|
|||||||
<i>LDAP DN:</i> <b>{{dn}} </b><br />
|
<i>LDAP DN:</i> <b>{{dn}} </b><br />
|
||||||
<i>Joined</i> <b>{{createTimestamp}} </b><br />
|
<i>Joined</i> <b>{{createTimestamp}} </b><br />
|
||||||
<i>Joined</i> <b>{{modifyTimestamp}} </b><br />
|
<i>Joined</i> <b>{{modifyTimestamp}} </b><br />
|
||||||
|
|
||||||
|
|
||||||
<img id="profile_photo" >
|
<img id="profile_photo" >
|
||||||
</script>
|
</script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
@ -43,7 +41,6 @@
|
|||||||
|
|
||||||
function getInvite(){
|
function getInvite(){
|
||||||
app.user.createInvite(function(error, data){
|
app.user.createInvite(function(error, data){
|
||||||
console.log(data)
|
|
||||||
$('#invite_token').html(location.origin+"/login/invite/"+data.token);
|
$('#invite_token').html(location.origin+"/login/invite/"+data.token);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -54,14 +51,15 @@
|
|||||||
</script>
|
</script>
|
||||||
<div class="row" style="display:none">
|
<div class="row" style="display:none">
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<div class="card mb-3 card-default">
|
<div class="shadow-lg card mb-3 card-default">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<span class="card-title">
|
<div class="float-right">
|
||||||
<div class="float-right">
|
|
||||||
<i class="far fa-arrows-v"></i>
|
<i class="far fa-arrows-v"></i>
|
||||||
</div>
|
|
||||||
Invite User
|
</div>
|
||||||
</span>
|
Invite User
|
||||||
|
|
||||||
</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>
|
||||||
@ -71,24 +69,47 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card mb-3 card-default">
|
<div class="shadow-lg card mb-3 card-default">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<i class="far fa-arrows-v"></i>
|
<i class="far fa-arrows-v"></i>
|
||||||
</div>
|
</div>
|
||||||
<i class="fas fa-user-plus"></i> Add new user
|
<i class="fas fa-user-plus"></i>
|
||||||
|
Services
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<%- include('user_form') %>
|
<ul class="list-group text-dark">
|
||||||
|
<a href="https://emby.718it.biz/" target="_blank" class="text-dark">
|
||||||
|
<li class="list-group-item text-dark">
|
||||||
|
<i class="fad fa-film"></i>
|
||||||
|
Emby
|
||||||
|
</li>
|
||||||
|
</a>
|
||||||
|
<a href="https://git.theta42.com" target="_blank" class="text-dark">
|
||||||
|
<li class="list-group-item text-dark">
|
||||||
|
<i class="fab fa-git"></i>
|
||||||
|
Git server
|
||||||
|
</li>
|
||||||
|
</a>
|
||||||
|
<a href="https://pve.admin.vm42.us" target="_blank" class="text-dark">
|
||||||
|
<li class="list-group-item text-dark">
|
||||||
|
<i class="fad fa-server"></i>
|
||||||
|
Promox (contact wmanlty for access)
|
||||||
|
</li>
|
||||||
|
</a>
|
||||||
|
<li class="list-group-item text-dark">
|
||||||
|
<i class="fad fa-terminal"></i>
|
||||||
|
ssh:718it.biz
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
<div class="card card-default">
|
<div class="shadow-lg card card-default">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
User List
|
User List
|
||||||
<div class="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>
|
||||||
|
@ -5,25 +5,20 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
$('form').attr('action', 'auth/invite/<%= invite.token %>').attr('evalAJAX', 'location.replace("/login");')
|
$('form').attr('action', 'auth/invite/<%= invite.token %>/<%= invite.mail_token %>').attr('evalAJAX', 'location.replace("/login");')
|
||||||
|
$('[name="mail"').val('<%= invite.mail %>').prop("disabled", true);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<div class="row" style="display:none">
|
<div class="row" style="display:none">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<div class="panel panel-default">
|
<div class="card">
|
||||||
<div class="panel-heading">
|
<div class="card-header">
|
||||||
<div class="panel-title">
|
Add new user
|
||||||
Add new user
|
|
||||||
<div class="pull-right">
|
|
||||||
<label class="glyphicon glyphicon-circle-arrow-down panel-toggle"></label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="card-body">
|
||||||
<h3>
|
<p>
|
||||||
Invited By: <b><%= invite.created_by %></b>, On <b><%= invite.created_on %></b>
|
Invited By: <b><%= invite.created_by %></b>, <%= invite.created_on %>
|
||||||
</h3>
|
</p>
|
||||||
<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 -->
|
||||||
</div>
|
</div>
|
||||||
|
48
nodejs/views/invite_email.ejs
Normal file
48
nodejs/views/invite_email.ejs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<%- include('top') %>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
|
||||||
|
var emailSent = function(){
|
||||||
|
$('#email_card .card-body').html("<h1>Thank you!</h1><p>Check your mail</p>")
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).ready(function(){
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div id="email_card" class="card-deck">
|
||||||
|
<div class="shadow-lg card mb-3">
|
||||||
|
<div class="card-header">
|
||||||
|
Validate Email
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p>
|
||||||
|
Invited By: <b><%= invite.created_by %></b>, <%= invite.created_on %>.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Please enter a valid email address. A link will be sent to
|
||||||
|
the supplied address to complete the registration process.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
The supplied email will also be used as the linked email for
|
||||||
|
the new user.
|
||||||
|
</p>
|
||||||
|
<form action="auth/invite/<%= invite.token %>" onsubmit="formAJAX(this)" evalAJAX="emailSent()">
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<span class="input-group-text" ><i class="fad fa-at"></i></span>
|
||||||
|
</div>
|
||||||
|
<input type="email" name="mail" class="form-control" placeholder="jsmith@gmail.com" required />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-outline-dark"><i class="fad fa-paper-plane"></i> Send It!</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<%- include('bottom') %>
|
@ -32,28 +32,84 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-4">
|
<div class="card-deck">
|
||||||
<div class="panel panel-default">
|
<div class="shadow-lg card mb-3">
|
||||||
<div class="panel-heading">
|
<div class="card-header">
|
||||||
<div class="panel-title">Log in</div>
|
Password Log in
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-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>
|
||||||
<form action="login" onsubmit="$(this).validate()">
|
<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">
|
||||||
<label class="control-label">User name</label>
|
<label class="control-label">User name</label>
|
||||||
<input type="text" name="uid" class="form-control" placeholder="User" validate="user:3" />
|
<div class="input-group mb-3">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<span class="input-group-text" ><i class="fad fa-user"></i></span>
|
||||||
|
</div>
|
||||||
|
<input type="text" name="uid" class="form-control" placeholder="jsmith" validate="user:3" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label">Password</label>
|
<label class="control-label">Password</label>
|
||||||
<input type="password" name="password" class="form-control" placeholder="Password" validate="password:5" />
|
<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=":3" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="btn btn-default" >Log in</button>
|
|
||||||
|
<button type="submit" class="btn btn-outline-dark"><i class="fad fa-sign-in"></i> Log in</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="shadow-lg card border-danger mb-3">
|
||||||
|
<div class="card-header">
|
||||||
|
Social Login
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="alert alert-warning actionMessage" style="display:none">
|
||||||
|
</div>
|
||||||
|
<h3>Coming soon!</h3>
|
||||||
|
<ul>
|
||||||
|
<li><i class="fab fa-google"></i> Login with google OATH</li>
|
||||||
|
<li><i class="fab fa-github"></i> Login with github OATH</li>
|
||||||
|
<li><i class="fab fa-facebook"></i> Login with facebook OATH</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="shadow-lg card border-danger mb-3">
|
||||||
|
<div class="card-header">
|
||||||
|
Password Reset
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p>
|
||||||
|
Forgot your password? Or your user name? No problem! Just
|
||||||
|
enter you email address below and if you are in our system,
|
||||||
|
we will email with the required information to get back up
|
||||||
|
and running!
|
||||||
|
</p>
|
||||||
|
<form action="reset_password" onsubmit="$(this).validate()">
|
||||||
|
<input type="hidden" name="redirect" value="<%= redirect %>">
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<span class="input-group-text" ><i class="fad fa-at"></i></span>
|
||||||
|
</div>
|
||||||
|
<input type="email" name="mail" class="form-control" placeholder="jsmith@gmail.com" required />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-outline-dark"><i class="fad fa-question"></i> Help me!</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<%- include('bottom') %>
|
<%- include('bottom') %>
|
||||||
|
@ -26,15 +26,15 @@
|
|||||||
<![endif]-->
|
<![endif]-->
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="d-flex flex-column flex-md-row align-items-center p-3 px-md-4 mb-3 bg-white border-bottom shadow-sm">
|
<header class="shadow d-flex flex-column flex-md-row align-items-center p-3 px-md-4 mb-3 bg-white border-bottom shadow-sm">
|
||||||
<h5 class="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="p-2 text-dark" href="/">Home</a>
|
<a class="hover-effect text-dark p-2" href="/"><i class="fad fa-tachometer-alt-fastest"></i> Home</a>
|
||||||
<a class="p-2 text-dark" 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> User Admin</a>
|
||||||
</nav>
|
</nav>
|
||||||
<a class="btn btn-outline-primary" onclick="app.auth.logOut()"><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>
|
||||||
|
|
||||||
</div>
|
</header>
|
||||||
|
|
||||||
<!-- Container -->
|
<!-- Container -->
|
||||||
<div class="container">
|
<div class="container">
|
@ -12,12 +12,12 @@
|
|||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label">Email</label>
|
<label class="control-label">Email</label>
|
||||||
<input type="text" class="form-control" name="mail" placeholder="jsmith@gmail.com" validate="email" />
|
<input type="text" class="form-control" name="mail" placeholder="jsmith@gmail.com" validate="email:3" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label">Mobile Phone</label>
|
<label class="control-label">Mobile Phone</label>
|
||||||
<input type="text" class="form-control" name="mobile" placeholder="jsmith@gmail.com" validate="email" />
|
<input type="text" class="form-control" name="mobile" placeholder="9175551234" validate=":9" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
@ -2,21 +2,13 @@
|
|||||||
<script id="rowTemplate" type="text/html">
|
<script id="rowTemplate" type="text/html">
|
||||||
<tr action="user/password/{{ username }}" method="put" evalAJAX="$form.trigger('reset')">
|
<tr action="user/password/{{ username }}" method="put" evalAJAX="$form.trigger('reset')">
|
||||||
<td>
|
<td>
|
||||||
{{ uid }}:{{ username }}
|
{{ uidNumber }}:{{ uid }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="hidden" name="username" value="{{ username }}" />
|
{{givenName}} {{sn}} {{mail}}
|
||||||
<div class="col-xs-10 form-group">
|
|
||||||
<label class="control-label"></label>
|
|
||||||
<input type="password" size="15" class="form-control" name="password" placeholder="New password" validate="password:5"/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button type="button btn-warn" onclick="formAJAX(this)" class="btn btn-sm btn-warn">
|
|
||||||
Change
|
|
||||||
</button>
|
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<button type="button" onclick="app.user.remove({username: '{{username}}'}, function(){tableAJAX('username {{username}} delete.')})" class="btn btn-sm btn-danger">
|
<button type="button" onclick="app.user.remove({uid: '{{uid}}'}, function(){tableAJAX('username {{uid}} delete.')})" class="btn btn-sm btn-danger">
|
||||||
Delete
|
Delete
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
@ -49,46 +41,22 @@
|
|||||||
</script>
|
</script>
|
||||||
<div class="row" style="display:none">
|
<div class="row" style="display:none">
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<div class="panel panel-default">
|
<div class="card">
|
||||||
<div class="panel-heading">
|
<div class="card-header">
|
||||||
<div class="panel-title">
|
Add new user
|
||||||
Add new user
|
|
||||||
<div class="pull-right">
|
|
||||||
<label class="glyphicon glyphicon-circle-arrow-down panel-toggle"></label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="card-body">
|
||||||
<form action="user/" evalAJAX="$form.trigger('reset')">
|
<%- include('user_form') %>
|
||||||
<input type="hidden" class="form-control" name="delete" value="false" />
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="control-label">User-name</label>
|
|
||||||
<input type="text" class="form-control" name="username" placeholder="Letter, numbers, -, _, . and @ only" validate="user:3" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="control-label">Password</label>
|
|
||||||
<input type="password" class="form-control" name="password" placeholder="Atleast 5 char. long" validate="password:5"/>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="control-label">Again</label>
|
|
||||||
<input type="password" class="form-control" name="passwordMatch" placeholder="Retype password" validate="eq:password"/>
|
|
||||||
</div>
|
|
||||||
<button type="button" onclick="formAJAX(this)" class="btn btn-default">Add</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
<div class="panel panel-default">
|
<div class="card">
|
||||||
<div class="panel-heading">
|
<div class="card-header">
|
||||||
<div class="panel-title">
|
User List
|
||||||
User List
|
|
||||||
<div class="pull-right">
|
|
||||||
<label class="glyphicon glyphicon-circle-arrow-down panel-toggle"></label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-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 -->
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user