Commit 9b0bffa7 authored by Rosanny Sihombing's avatar Rosanny Sihombing
Browse files

Merge branch 'testing' into devel

parents 91e7f42e 961ab112
Showing with 14366 additions and 2591 deletions
+14366 -2591
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "m4lab-user-account",
"version": "0.0.1",
"description": "Example for PassportJS SAML strategy",
"description": "M4_LAB User Account",
"author": {
"name": "Rosanny Sihombing",
"email": "rosanny.sihombing@hft-stuttgart.de",
......@@ -9,39 +9,65 @@
},
"keywords": [
"m4_lab",
"saml",
"sso"
"account"
],
"repository": {
"type": "git",
"url": "https://transfer.gitlab.com/tbd.git"
"url": "https://transfer.hft-stuttgart.de/gitlab/m4lab_tv1/user-account.git"
},
"scripts": {
"start": "nodemon app.js",
"test": ""
"start": "nodemon app.ts",
"build": "tsc -build",
"clean": "tsc -build --clean",
"test": "jest"
},
"dependencies": {
"async": "^3.1.0",
"axios": "^0.21.1",
"bcryptjs": "^2.4.3",
"body-parser": "^1.19.0",
"compression": "^1.7.4",
"cookie-parser": "1.4.3",
"crypto": "^1.0.1",
"errorhandler": "1.4.3",
"dotenv": "^9.0.2",
"express": "^4.17.1",
"express-fileupload": "^1.1.6",
"express-flash": "0.0.2",
"express-flash-2": "^1.0.1",
"express-session": "^1.17.0",
"form-data": "^3.0.0",
"fs": "0.0.1-security",
"i18n": "^0.8.5",
"helmet": "^4.6.0",
"jest": "^26.5.0",
"method-override": "^3.0.0",
"morgan": "^1.9.1",
"mysql": "^2.17.1",
"mysql2": "^2.2.5",
"nodemailer": "^6.3.1",
"nodemon": "^2.0.1",
"nodemailer-ntlm-auth": "^1.0.1",
"passport": "0.3.2",
"passport-saml": "^1.2.0",
"pug": "^2.0.4"
"passport-saml": "^2.1.0",
"pug": "^3.0.2"
},
"devDependencies": {
"@types/async": "^3.2.6",
"@types/bcryptjs": "^2.4.2",
"@types/compression": "^1.7.0",
"@types/cookie-parser": "^1.4.2",
"@types/express": "^4.17.11",
"@types/express-fileupload": "^1.1.6",
"@types/express-flash-2": "^1.0.6",
"@types/express-session": "^1.17.0",
"@types/jest": "^26.0.23",
"@types/method-override": "^0.0.31",
"@types/morgan": "^1.9.2",
"@types/mysql": "^2.15.18",
"@types/node": "^15.0.2",
"@types/nodemailer": "^6.4.1",
"@types/passport": "^1.0.6",
"@types/passport-strategy": "^0.2.35",
"@types/xml2js": "^0.4.8",
"nodemon": "^2.0.1",
"ts-node": "^9.1.1",
"typescript": "^4.2.4"
},
"devDependencies": {},
"engines": {
"node": ">= 4.0.0"
},
......
public/default/logo.png

84.7 KB

......@@ -70,8 +70,8 @@ function head(){
alertbutton.innerHTML = "×";
alertdiv.innerHTML="<strong>Disclaimer</strong> This website is under construction and in prototype-phase. It is not for public use."
prependChild(alertdiv, alertbutton);
alertdiv.classList.add('alert','alert-danger', 'alert-dismissible', 'fade','show');
alertdiv.style = "text-align:center;";
alertdiv.classList.add('alert','alert-danger', 'alert-dismissible', 'fade','show', 'text-center');
//alertdiv.style = "text-align:center;";
navheader.appendChild(alertdiv);
let navbar = document.createElement('nav');
navbar.classList.add("navbar", "navbar-default");
......
/* German initialisation for the jQuery UI date picker plugin. */
/* Written by Milian Wolff (mail@milianw.de). */
( function( factory ) {
if ( typeof define === "function" && define.amd ) {
// AMD. Register as an anonymous module.
define( [ "../widgets/datepicker" ], factory );
} else {
// Browser globals
factory( jQuery.datepicker );
}
}( function( datepicker ) {
datepicker.regional.de = {
closeText: "Schließen",
prevText: "&#x3C;Zurück",
nextText: "Vor&#x3E;",
currentText: "Heute",
monthNames: [ "Januar","Februar","März","April","Mai","Juni",
"Juli","August","September","Oktober","November","Dezember" ],
monthNamesShort: [ "Jan","Feb","Mär","Apr","Mai","Jun",
"Jul","Aug","Sep","Okt","Nov","Dez" ],
dayNames: [ "Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag" ],
dayNamesShort: [ "So","Mo","Di","Mi","Do","Fr","Sa" ],
dayNamesMin: [ "So","Mo","Di","Mi","Do","Fr","Sa" ],
weekHeader: "KW",
dateFormat: "dd.mm.yy",
firstDay: 1,
isRTL: false,
showMonthAfterYear: false,
yearSuffix: "" };
datepicker.setDefaults( datepicker.regional.de );
return datepicker.regional.de;
} ) );
\ No newline at end of file
const methods = require('./methods')
const async = require('async')
const helpers = require('./helpers')
const pictSizeLimit = 1000000 // 1 MB
module.exports = function (app) {
// ======== APP ROUTES - PROJECT ====================
var lang = 'DE'
app.get('/mailinglists', function (req, res) {
async.waterfall([
function(done) {
methods.getAllMailinglists(function(mailinglistOverview, err) {
if (!err) {
done(err, mailinglistOverview)
}
})
},
// create JSON object of mailinglists for front-end
function(mailinglistOverview, done) {
var allMailingLists = [] // JSON object
for (let i = 0; i < mailinglistOverview.length; i++) {
// add data to JSON object
allMailingLists.push({
id: mailinglistOverview[i].id,
name: mailinglistOverview[i].name,
src: mailinglistOverview[i].src,
projectstatus: mailinglistOverview[i].projectstatus,
project_title: mailinglistOverview[i].project_title,
keywords: mailinglistOverview[i].keywords
});
}
res.render(lang+'/project/mailinglists', {
isUserAuthenticated: req.isAuthenticated(),
user: req.user,
mailinglists: allMailingLists
});
}
])
});
app.get('/project_', function (req, res) {
async.waterfall([
// get all projects from projectdb
function(done) {
methods.getAllProjects(function(projectsOverview, err) {
if (!err) {
done(err, projectsOverview)
}
})
},
// create JSON object for front-end
function(projectsOverview, done) {
var activeProjects = []
var nonActiveProjects = []
for (var i = 0; i < projectsOverview.length; i++) {
var project = {
id: projectsOverview[i].id,
logo: projectsOverview[i].logo,
akronym: projectsOverview[i].pname,
title: projectsOverview[i].title,
summary: projectsOverview[i].onelinesummary,
category: projectsOverview[i].category,
cp: projectsOverview[i].contact_email,
gitlab: projectsOverview[i].gitlab
}
if (projectsOverview[i].projectstatus == 0) {
nonActiveProjects.push(project)
}
else if (projectsOverview[i].projectstatus == 1) {
activeProjects.push(project)
}
}
// render the page
if (req.isAuthenticated()) {
res.render(lang+'/project/projects', {
isUserAuthenticated: true,
nonActive: nonActiveProjects,
active: activeProjects
});
}
else {
res.render(lang+'/project/projects', {
isUserAuthenticated: false,
nonActive: nonActiveProjects,
active: activeProjects
});
}
}
])
})
app.get('/project', function (req, res) {
res.render(lang+'/project/project-simplified', {
isUserAuthenticated: req.isAuthenticated(),
user: req.user
});
})
app.get('/addprojectoverview', function (req, res) {
if (req.isAuthenticated()) {
res.render(lang+'/project/addProjectOverview')
}
else {
res.redirect('/login')
}
})
app.post('/addprojectoverview__', function (req, res) {
if (req.isAuthenticated()) {
var wiki = 0
if (req.body.wiki)
wiki = 1
var projectTerm = req.body.termForm + " - " + req.body.termTo
var projectOverviewData = {
pname: req.body.pname,
title: req.body.title,
onelinesummary: req.body.summary,
category: req.body.category,
logo: req.body.logo,
gitlab: req.body.gitlabURL,
wiki: wiki,
overview: req.body.overview,
question: req.body.question,
approach: req.body.approach,
result: req.body.result,
keywords: req.body.keywords,
announcement: req.body.announcement,
term: projectTerm,
further_details: req.body.furtherDetails,
website: req.body.website,
src: req.body.src,
caption: req.body.caption,
contact_lastname: req.body.contactName,
contact_email: req.body.contactEmail,
leader_lastname: req.body.leaderName,
leader_email: req.body.leaderEmail
}
methods.addProjectOverview(projectOverviewData, function(err){
if (err) {
//req.flash('error', "Failed")
req.flash('error', "Fehlgeschlagen")
res.redirect('/addProjectOverview');
}
else {
req.flash('success', 'Your project has been created.')
res.redirect('/project');
}
})
}
})
app.post('/addprojectoverview', function (req, res) {
if (req.isAuthenticated()) {
var wiki = 0
if (req.body.wiki)
wiki = 1
var projectLogo = req.files.logo
var projectPicture = req.files.src
var projectLogoPath, projectPicturePath
if (projectLogo) {
// raise error if size limit is exceeded
if (projectLogo.size === pictSizeLimit) {
req.flash('error', 'Projektlogo exceeds 1 MB');
res.redirect('/addprojectoverview');
}
else {
// TEST PATH FOR DEVELOPMENT (LOCALHOST)
projectLogoPath = './folder-in-server-to-save-projektlogo/'+req.body.pname+'/'+projectLogo.name
// PATH FOR TEST/LIVE SERVER
// var projectLogoPath = to-be-defined
}
}
if (projectPicture) {
// raise error if size limit is exceeded
if (projectPicture.size === pictSizeLimit) {
req.flash('error', 'Projektbild exceeds 1 MB');
res.redirect('/addprojectoverview');
}
else {
// TEST PATH FOR DEVELOPMENT (LOCALHOST)
projectPicturePath = './folder-in-server-to-save-projektbild/'+req.body.pname+'/'+projectPicture.name
// PATH FOR TEST/LIVE SERVER
// var projectPicturePath = to-be-defined
}
}
var projectTerm = req.body.termForm + " - " + req.body.termTo
var projectOverviewData = {
pname: req.body.pname,
title: req.body.title,
onelinesummary: req.body.summary,
category: req.body.category,
logo: projectLogoPath,
gitlab: req.body.gitlabURL,
wiki: wiki,
overview: req.body.overview,
question: req.body.question,
approach: req.body.approach,
result: req.body.result,
keywords: req.body.keywords,
announcement: req.body.announcement,
term: projectTerm,
further_details: req.body.furtherDetails,
website: req.body.website,
src: projectPicturePath,
caption: req.body.caption,
contact_lastname: req.body.contactName,
contact_email: req.body.contactEmail,
leader_lastname: req.body.leaderName,
leader_email: req.body.leaderEmail
}
// save pictures
if (projectLogo) {
projectLogo.mv(projectLogoPath, function(err) {
if (err) {
console.error(err)
res.status(500).render(lang+'/500', {
error: err
})
}
});
}
if (projectPicture) {
projectPicture.mv(projectPicturePath, function(err) {
if (err) {
console.error(err)
res.status(500).render(lang+'/500', {
error: err
})
}
});
}
/* RS: Temporary solution while Project DB is still in early phase.
When User DB and Project DB are integrated and quite stabil, this operation should be done in 1 transaction.
*/
var userId // todo: make this global variable?
async.waterfall([
// get userId by email from userdb
function(done) {
methods.getUserIdByEmail(req.user.email, function(id, err) {
if (!err) {
userId = id
done(err)
}
})
},
// add project overview
function(done) {
methods.addProjectOverview(projectOverviewData, function(data, err){
if (err) {
res.status(500).render(lang+'/500', {
error: err
})
}
else {
done(err, data.insertId)
}
})
},
// assign the created overview to logged-in user
function(projectOverviewId, done) {
var userProjectRoleData = {
project_id: projectOverviewId,
user_id: userId,
role_id: 3 // OVERVIEW_CREATOR
}
methods.addUserProjectRole(userProjectRoleData, function(userProjects, err) {
if (err) {
//req.flash('error', "Failed")
req.flash('error', "Fehlgeschlagen")
res.redirect('/addProjectOverview');
}
else {
req.flash('success', 'Your project has been created.')
res.redirect('/project');
}
})
}
])
}
})
app.get('/updateprojectoverview', function (req, res) {
// only their own project
})
app.post('/updateprojectoverview', function (req, res) {
// only their own project
})
app.get('/projectoverview', function(req, res){
async.waterfall([
function(done) {
methods.getProjectOverviewById(req.query.projectID, function(projectOverview, err) {
if (!err) {
done(err, projectOverview)
}
})
},
function(projectOverview,done){
methods.getProjectImagesById(req.query.projectID, function(projectImages, err) {
if (!err) {
done(err, projectImages, projectOverview)
}
})
},
// render projectOverview page
function(projectImages, projectOverview, done) {
console.log(projectImages);
partnerWebsites = helpers.stringToArray(projectOverview[0].partner_website);
partnerNames = helpers.stringToArray(projectOverview[0].partner_name);
awardSites = helpers.stringToArray(projectOverview[0].award_website);
awardNames = helpers.stringToArray(projectOverview[0].award_name);
sponsorWebsites = helpers.stringToArray(projectOverview[0].sponsor_website);
sponsorImgs = helpers.stringToArray(projectOverview[0].sponsor_img);
sponsorNames = helpers.stringToArray(projectOverview[0].sponsor_name);
res.render(lang+'/project/projectOverview', {
isUserAuthenticated: req.isAuthenticated(),
user: req.user,
projectOV: projectOverview,
projectImgs: projectImages,
partnerWS: partnerWebsites,
partnerN: partnerNames,
awardWS: awardSites,
awardN: awardNames,
sponsorWS: sponsorWebsites,
sponsorIMG: sponsorImgs,
sponsorN: sponsorNames
});
}
])
})
app.get('/videoconferences', function(req, res){
res.render(lang+'/project/videoconferences', {
isUserAuthenticated: req.isAuthenticated(),
user: req.user,
});
})
app.get('/landingpage', function(req, res){
res.render(lang+'/project/landingpage', {
isUserAuthenticated: req.isAuthenticated(),
user: req.user,
});
})
};
\ No newline at end of file
import fs from 'fs'
import async from 'async'
import bcrypt from 'bcryptjs'
import * as passportSaml from 'passport-saml'
import dbconn from '../config/dbconn'
import methods from '../functions/methods'
import gitlab from '../functions/gitlab'
import constants from '../config/const'
import mailer from '../config/mailer'
import portalUser from '../classes/user'
import projectInformation from '../classes/website'
import projectRepo from '../classes/repo'
const SamlStrategy = passportSaml.Strategy
const saltRounds = 10;
const salt = 64; // salt length
const logoDir = 'public/upload/'
const defaultLogo:any = 'public/default/logo.png'
export = function (app:any, config:any, passport:any, lang:string) {
// =========== PASSPORT =======
passport.serializeUser(function (user:any, done:any) {
done(null, user);
});
passport.deserializeUser(function (user:any, done:any) {
done(null, user);
});
var samlStrategy = new SamlStrategy({
// URL that goes from the Identity Provider -> Service Provider
callbackUrl: config.passport.saml.path,
// Base address to call logout requests
logoutUrl: config.passport.saml.logoutUrl,
entryPoint: config.passport.saml.entryPoint,
issuer: config.passport.saml.issuer,
identifierFormat: undefined,
// Service Provider private key
decryptionPvk: fs.readFileSync(__dirname + '/cert/key.pem', 'utf8'),
// Service Provider Certificate
privateKey: fs.readFileSync(__dirname + '/cert/key.pem', 'utf8'),
// Identity Provider's public key
cert: fs.readFileSync(__dirname + '/cert/cert_idp.pem', 'utf8'),
validateInResponseTo: false,
disableRequestedAuthnContext: true
},
function (profile:any, done:any) {
return done(null, {
id: profile.nameID,
idFormat: profile.nameIDFormat,
email: profile.email,
firstName: profile.givenName,
lastName: profile.sn
});
});
passport.use(samlStrategy);
// ============= SAML ==============
app.post(config.passport.saml.path,
passport.authenticate(config.passport.strategy,
{
failureRedirect: '/account/',
failureFlash: true
}),
function (req:any, res:any) {
res.redirect('/account/');
}
);
// to generate Service Provider's XML metadata
app.get('/saml/metadata',
function(req:any, res:any) {
res.type('application/xml');
var spMetadata = samlStrategy.generateServiceProviderMetadata(fs.readFileSync(__dirname + '/cert/cert.pem', 'utf8'));
res.status(200).send(spMetadata);
}
);
// ======== APP ROUTES - ACCOUNT ====================
async function getLoggedInUserData(email:string) {
let user = await methods.getUserByEmail(email)
if (!user) {
console.log('no user found')
return null
} else {
let loggedInUser = new portalUser(
user.id, email, user.salutation, user.title, user.firstname, user.lastname, user.industry, user.organisation, user.speciality, user.m4lab_idp, user.verificationStatus
)
let userGitlabId = await methods.getGitlabId(loggedInUser.id)
if (userGitlabId) {
loggedInUser.setGitlabUserId(userGitlabId)
}
return loggedInUser
}
}
app.get('/', async function (req:any, res:any) {
if ( !req.isAuthenticated() ) {
res.redirect('/login')
} else {
let loggedInUser = await getLoggedInUserData(req.user.email)
if (!loggedInUser) {
console.error("user data is not found")
res.status(500).render(lang+'/500', { error: "Your data is not found. Please try again." })
} else {
res.render(lang+'/account/home', {
user: loggedInUser
});
}
}
});
app.get('/login',
passport.authenticate(config.passport.strategy, {
successRedirect: '/',
failureRedirect: '/login'
})
)
app.get('/logout', function (req:any, res:any) {
if (req.user == null) {
return res.redirect('/');
}
req.user.nameID = req.user.id;
req.user.nameIDFormat = req.user.idFormat;
return samlStrategy.logout(req, function(err:any, uri:any) {
req.logout();
if ( req.session ) {
req.session.destroy((err:any) => {
if(err) {
return console.log(err);
}
});
}
return res.redirect(uri);
});
});
app.get('/profile', async function (req:any, res:any) {
if ( !req.isAuthenticated() ) {
res.redirect('/login')
} else {
let loggedInUser = await getLoggedInUserData(req.user.email)
if (!loggedInUser) { // null user
res.redirect('/account/')
} else {
if(loggedInUser.getVerificationStatus() != 1) {
res.redirect('/account/')
} else {
res.render(lang+'/account/profile', {
user: loggedInUser
})
}
}
}
})
app.get('/services', async function(req:any, res:any){
if( !req.isAuthenticated() ) {
res.redirect('/login')
} else {
let loggedInUser = await getLoggedInUserData(req.user.email)
if (!loggedInUser) { // null user
res.redirect('/account/')
} else {
if(loggedInUser.getVerificationStatus() != 1) { // unverified users
res.redirect('/account/')
} else {
let gitlabReposArr = []
let gitlabPagesArr = []
if(loggedInUser.getGitlabUserId()) { // for users who have activated their gitlab account
let userProjects = await gitlab.getUserProjects(loggedInUser.getGitlabUserId()!)
if (!userProjects) {
console.error("something went wrong")
res.status(500).render(lang+'/500', { error: "something went wrong" })
}
let project:any
for (project in userProjects) {
if (userProjects[project].tag_list.includes('website')) {
let page = {
projectInformation: new projectInformation(loggedInUser.getGitlabUserId()!, userProjects[project].name, userProjects[project].description,
userProjects[project].id, userProjects[project].avatar_url, userProjects[project].path_with_namespace),
pipelineStatus: await gitlab.getProjectPipelineLatestStatus(userProjects[project].id)
}
gitlabPagesArr.push(page)
} else {
let repo = new projectRepo(loggedInUser.getGitlabUserId()!, userProjects[project].name, userProjects[project].description,
userProjects[project].id, userProjects[project].avatar_url, userProjects[project].path_with_namespace)
gitlabReposArr.push(repo)
}
}
res.render(lang+'/account/services', {
user: loggedInUser,
gitlabRepos: gitlabReposArr,
gitlabPages: gitlabPagesArr
})
} else { // for users who have not activated their gitlab account yet
let gitlabUser = await gitlab.getUserByEmail(loggedInUser.getEmail())
if (!gitlabUser) {
res.render(lang+'/account/services', {
user: loggedInUser,
gitlabRepos: null,
gitlabPages: null
})
} else {
let gitlabActivationData = {
user_id: loggedInUser.getId(),
gitlab_userId: gitlabUser.id}
methods.addGitlabUser(gitlabActivationData, function(err:any){
if(err) {
res.status(500).render(lang+'/500', { error: err })
} else {
res.redirect('/account/services')
}
})
}
}
}
}
}
})
app.get('/security', async function (req:any, res:any) {
if ( !req.isAuthenticated() ) {
res.redirect('/login')
} else {
let loggedInUser = await getLoggedInUserData(req.user.email)
if (!loggedInUser) { // null user
res.redirect('/account/')
} else {
if(loggedInUser.getVerificationStatus() == 1 && loggedInUser.getIdpStatus() == 1) {
res.render(lang+'/account/security', {
user: loggedInUser
})
} else {
res.redirect('/account/')
}
}
}
})
app.post('/updateProfile', async function (req:any, res:any) {
if ( !req.isAuthenticated() ) {
res.redirect('/login')
} else {
let loggedInUser = await getLoggedInUserData(req.user.email)
if (!loggedInUser) { // null user
res.redirect('/account/')
} else {
let userData = {
salutation: req.body.inputSalutation,
title: req.body.inputTitle,
firstname: req.body.inputFirstname,
lastname: req.body.inputLastname,
email: req.body.inputEmail,
organisation: req.body.inputOrganisation,
industry: req.body.inputIndustry,
speciality: req.body.inputSpeciality,
}
let result = await methods.updateUserById(loggedInUser.getId(), userData)
if (!result) {
res.flash('error', "Failed")
} else {
loggedInUser.updateProfile(userData.salutation, userData.title, userData.firstname, userData.lastname, userData.email,
userData.organisation, userData.industry, userData.speciality)
res.flash('success', 'Ihr Benutzerprofil wurde aktualisiert!')
}
res.redirect('/account/profile')
}
}
});
app.post('/changePwd', async function (req:any, res:any) {
if( !req.isAuthenticated() ) {
res.redirect('/login')
} else {
let loggedInUser = await getLoggedInUserData(req.user.email)
if (!loggedInUser) { // null user
res.redirect('/account/')
} else {
let currPwd = req.body.inputCurrPwd
let newPwd = req.body.inputNewPwd
let retypePwd = req.body.inputConfirm
dbconn.user.query('SELECT password FROM credential WHERE user_id='+loggedInUser.getId(), function (err:any, rows:any) {
if (err) {
console.error(err)
res.status(500).render(lang+'/500', { error: err })
}
let userPwd = rows[0].password
// check if the password is correct
bcrypt.compare(currPwd, userPwd, function(err, isMatch) {
if (err) {
console.error(err)
res.status(500).render(lang+'/500', { error: err })
} else if (!isMatch) {
res.flash('error', "Das Passwort ist leider falsch. Bitte überprüfen Sie Ihre Eingabe.")
res.redirect('/account/security')
} else {
if ( newPwd != retypePwd ) {
res.flash('error', 'Passwörter stimmen nicht überein. Bitte stellen Sie sicher, dass Sie das Passwort beide Male genau gleich eingeben.')
res.redirect('/account/security')
} else {
// update password
bcrypt.genSalt(saltRounds, function(err, salt) {
bcrypt.hash(newPwd, salt, async function(err, hash) {
var credentialData = {
password: hash,
user_id: loggedInUser!.getId()
}
let result = await methods.updateCredential(credentialData)
if (!result) {
console.log('Failed to reset password')
res.flash('error', "Datenbankfehler: Passwort kann nicht geändert werden.")
} else {
res.flash('success', "Passwort aktualisiert!")
// send notifiaction email
mailer.options.to = loggedInUser!.getEmail()
mailer.options.subject = constants.updatePasswordMailSubject
mailer.options.html = constants.updatePasswordMailContent+'<div>'+constants.mailSignature+'</div>'
mailer.transporter.sendMail(mailer.options, function(err:any) {
if (err) { console.log(err) }
})
}
res.redirect('/account/security')
});
});
}
}
})
})
}
}
});
app.get('/resendVerificationEmail', async function(req:any, res:any){
if (!req.isAuthenticated) {
res.redirect('/login')
} else {
let loggedInUser = await getLoggedInUserData(req.user.email)
if (!loggedInUser) {
res.redirect('/login')
} else {
let token = await methods.getVerificationTokenByUserId(loggedInUser.id)
if (!token) {
res.send(false)
} else {
// send email
var emailSubject = "Bitte bestätigen Sie Ihr M4_LAB Benutzerkonto"
var emailContent = '<div>Lieber Nutzer,<br/><br/>' +
'<p>vielen Dank für Ihre Anmeldung am Transferportal der HFT Stuttgart. <br/>' +
'Um Ihre Anmeldung zu bestätigen, klicken Sie bitte diesen Link: ' + config.app.host + '/verifyAccount?token=' + token +
'<br/><br/>' +
'Ohne Bestätigung Ihres Kontos müssen wir Ihr Konto leider nach 7 Tagen löschen.</p><br/>' + constants.mailSignature +
'</div>';
mailer.options.to = loggedInUser.email;
mailer.options.subject = emailSubject;
mailer.options.html = emailContent;
mailer.transport.sendMail(mailer.options, function(err:any) {
if (err) {
console.log('cannot send email')
throw err
}
})
res.send(true)
}
}
}
})
// ============= NEW GITLAB PAGES ===========================
app.get('/newInformation', async function(req:any, res:any){
if ( !req.isAuthenticated() ) {
res.redirect('/login')
} else {
let loggedInUser = await getLoggedInUserData(req.user.email)
if (!loggedInUser) {
res.redirect('/login')
} else {
let gitlabUser = await gitlab.getUserByEmail(loggedInUser.getEmail())
if (!gitlabUser) { // no user found
res.redirect('/account/services')
} else {
res.render(lang+'/account/newInformation', {
user: loggedInUser,
gitlabUsername: gitlabUser.username
})
}
}
}
})
app.post('/newInformation', async function(req:any, res:any) {
if( !req.isAuthenticated() ) {
res.redirect('/login')
} else {
let loggedInUser = await getLoggedInUserData(req.user.email)
if (!loggedInUser) {
res.redirect('/login')
} else {
if (!req.body.name && !req.body.description) {
res.flash('error', 'Bitte geben Sie die benötigten Daten ein')
res.redirect('/account/newInformation')
} else {
let projectName = req.body.name.toLowerCase().replace(/\s/g, '-')
let projectDesc = req.body.description
let projectTemplate = req.body.template
let newInformation = new projectInformation(loggedInUser.getGitlabUserId()!, projectName, projectDesc)
let newLogoFile = defaultLogo
if (req.files) { newLogoFile = req.files.logo }
async.waterfall([
function(callback:any){ // upload logo
if (!req.files) {
callback(null, newLogoFile)
} else {
newLogoFile.mv(logoDir + newLogoFile.name, function(err:any) {
newLogoFile = logoDir+newLogoFile.name
callback(err, newLogoFile)
})
}
},
async function(newLogoFile:any){ // create a new GitLab Page
let newPages = await gitlab.createNewPages(newInformation, newLogoFile, projectTemplate)
if (newPages.status) {
if(newPages.data.message.name == "has already been taken") {
res.flash("error", "Der Projektname '"+newInformation.getName()+"' ist bereits vergeben, bitte wählen Sie einen anderen Namen.")
} else {
res.flash("error", "Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut. ")
}
res.redirect('/account/newInformation')
} else {
res.flash("success", "Ihre Webseite wurde erstellt, aber noch nicht veröffentlicht. Um Ihre Webseite endgültig zu veröffentlichen, "+
"schließen Sie die Einrichtung gemäß unten stehender Anleitung ab.")
res.redirect('/account/updateInformation?id='+newPages.id)
}
}
], function (err) {
if(err) console.log(err)
// remove logo
if (req.files) {
fs.unlink(newLogoFile, (err) => {
if(err) console.log(err)
})
}
})
}
}
}
})
app.get('/updateInformation', async function(req:any, res:any){
if( !req.isAuthenticated() ) {
res.redirect('/login')
} else {
let loggedInUser = await getLoggedInUserData(req.user.email)
if (!loggedInUser) {
res.redirect('/login')
} else {
if(!req.query.id) {
res.redirect('/account/services')
} else {
let project = await gitlab.getProjectById(req.query.id)
if (!project) {
console.log(" ========= Error or no project found")
res.redirect('/account/services')
} else if (!project.owner) {
console.log(" ========= Project cannot be accessed, since it does not have an owner")
res.redirect('/account/services')
} else if (project.owner.id != loggedInUser.getGitlabUserId()) {
console.log(" ========= Access denied: Not your project")
res.redirect('/account/services')
} else {
let curInformation = new projectInformation(loggedInUser.getGitlabUserId()!, project.name, project.description,
req.query.id, project.avatar_url, project.path_with_namespace)
res.render(lang+'/account/updateInformation', {
user: loggedInUser,
information: curInformation
})
}
}
}
}
})
// update a website
app.post('/updateInformation', async function(req:any, res:any){
if( !req.isAuthenticated() ) {
res.redirect('/login')
} else {
let loggedInUser = await getLoggedInUserData(req.user.email)
if (!loggedInUser) {
res.redirect('/login')
} else {
if (!req.body.name && !req.body.description) {
res.flash('error', 'Bitte geben Sie die benötigten Daten ein')
res.redirect('/account/updateInformation')
} else {
let projectName = req.body.name.toLowerCase().replace(/\s/g, '-')
let projectDesc = req.body.description
let updatedInformation = new projectInformation(loggedInUser.getGitlabUserId()!, projectName, projectDesc, req.query.id)
let newLogoFile:any
async.waterfall([
function(callback:any){ // upload logo
if(!req.files) {
callback(null, newLogoFile)
} else {
newLogoFile = req.files.logo
newLogoFile.mv(logoDir + newLogoFile.name, function(err:any) {
newLogoFile = logoDir + newLogoFile.name
callback(err, newLogoFile)
})
}
},
async function(newLogoFile:any){ // update gitlab page
let updatedPages = await gitlab.updateProject(updatedInformation, newLogoFile)
if (updatedPages.status) {
if(updatedPages.data.message.name == "has already been taken") {
res.flash("error", "Der Projektname '"+projectName+"' ist bereits vergeben, bitte wählen Sie einen anderen Namen.")
} else {
res.flash("error", "Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut. ")
}
} else {
updatedInformation.setLogo(updatedPages.avatar_url)
updatedInformation.setPath(updatedPages.path)
res.flash("success", "Ihre Website wurde aktualisiert")
}
res.redirect('/account/updateInformation?id='+updatedInformation.getId())
}
], function (err) {
if(err) console.log(err)
if(newLogoFile){ // remove logo
fs.unlink(newLogoFile, (err) => {
if(err) console.log(err)
})
}
})
}
}
}
})
app.delete('/deleteProject', async function(req:any, res:any){
if( !req.isAuthenticated() ) {
res.redirect('/login')
} else {
let loggedInUser = await getLoggedInUserData(req.user.email)
if (!loggedInUser) {
res.redirect('/login')
} else {
let projectId = req.body.id
if (projectId) {
// check if the owner is valid
let project = await gitlab.getProjectById(projectId)
if (!project) {
console.log(" ========= Error or no project found")
} else if (!project.owner) {
console.log(" ========= Project cannot be accessed, since it does not have an owner")
} else if (project.owner.id != loggedInUser.getGitlabUserId()) {
console.log(" ========= Access denied: Not your project")
} else {
let isDeleted = await gitlab.deleteProjectById(projectId)
if (!isDeleted) {
res.flash("error", "Project cannot be deleted. Please try again.")
}
}
}
res.redirect('/account/services')
}
}
})
}
\ No newline at end of file
// ==== USER ACOOUNT API ====
var dbconn = require('./dbconn')
module.exports = function (app) {
//console.log(dbconn);
//var con = dbconn.connection
app.get('/api/v1/profile', function (req, res) {
if (req.isAuthenticated()) {
// read data based on email
dbconn.user.query('SELECT * FROM user WHERE email="'+req.user.email+'"', function (err, rows, fields) {
if (err) throw err
res.send(rows[0])
})
} else {
res.send('authentication required');
}
});
}
\ No newline at end of file
const mysql = require('mysql')
var env = process.env.NODE_ENV || 'development';
const config = require('../config/config')[env]
// ==== USER ACOOUNT DB CONNECTION ====
var userConnection = mysql.createConnection({
host: config.database.host,
user: config.database.user,
password: config.database.password,
port: config.database.port,
database: config.database.dbUser,
multipleStatements: true
})
userConnection.connect(function(err) {
if (err) throw err;
})
userConnection.query('USE '+config.database.dbUser)
// user db connection test
userConnection.query('SELECT 1 + 5 AS solution', function (err, rows, fields) {
if (err) throw err
console.log('Solution = ', rows[0].solution)
})
//userConnection.end()
// ALTERNATIVE approach: close db connection manually after every query
/*
var dbconn = function dbconn(query, values, next) {
var connection = mysql.createConnection({
host: config.database.host,
user: config.database.user,
password: config.database.password,
port: config.database.port,
database: config.database.db
})
connection.connect(function(err) {
if (err) throw err;
})
connection.query(query, values, function(err) {
connection.end(); // close the connection
if (err) {
throw err;
}
// Execute the callback
next.apply(this, arguments);
});
}
*/
// ==== PROJECT DB CONNECTION ====
var projectConnection = mysql.createConnection({
host: config.database.host_project,
user: config.database.user,
password: config.database.password,
port: config.database.port,
database: config.database.dbProject
})
projectConnection.connect(function(err) {
if (err) throw err;
})
projectConnection.query('USE '+config.database.dbProject)
// projectdb connection test
projectConnection.query('SELECT 10 + 5 AS project', function (err, rows, fields) {
if (err) throw err
console.log('Project = ', rows[0].project)
})
//projectConnection.end()
var connection = {
user: userConnection,
project: projectConnection
}
module.exports = connection
\ No newline at end of file
const nodemailer = require('nodemailer')
var env = process.env.NODE_ENV || 'development';
const config = require('../config/config')[env]
var smtpTransport = nodemailer.createTransport({
host: config.mailer.host,
secureConnection: config.mailer.secureConnection,
port: config.mailer.port,
auth: {
user: config.mailer.authUser,
pass: config.mailer.authPass
},
tls: {
ciphers: config.mailer.tlsCiphers
}
});
var mailOptions = {
to: "",
from: config.mailer.from,
subject: "",
text: ""
};
var mailer = {
transport: smtpTransport,
options: mailOptions
}
module.exports = mailer
\ No newline at end of file
const dbconn = require('./dbconn');
var methods = {
// test method
currentDate: function() {
console.log('Current Date is: ' + new Date().toISOString().slice(0, 10));
},
// ===================== user db =====================
registerNewUser: function(data, callback) {
dbconn.user.beginTransaction(function(err) { // START TRANSACTION
if (err) {
throw err
}
// insert profile
dbconn.user.query('INSERT INTO user SET ?', data.profile, function (err, results, fields) {
if (err) {
return dbconn.user.rollback(function() {
throw err
});
}
var newUserId = results.insertId
// set password
var credentialData = {
user_id: newUserId,
password: data.password
}
dbconn.user.query('INSERT INTO credential SET ?', credentialData, function (err, results, fields) {
if (err) {
return dbconn.user.rollback(function() {
throw err
});
}
// set default user-project-role
var projectRoleData = {
project_id: 1, //M4_LAB
role_id: 2, // USER
user_id: newUserId
}
dbconn.user.query('INSERT INTO user_project_role SET ?', projectRoleData, function (err, results, fields) {
if (err) {
return dbconn.user.rollback(function() {
throw err
});
}
// MLAB-129: INSERT verification token
let verificationData = {
user_id: newUserId,
token: data.verificationToken
}
dbconn.user.query('INSERT INTO verification SET ?', verificationData, function (err, results, fields) {
if (err) {
return dbconn.user.rollback(function() {
throw err
});
}
// COMMIT
dbconn.user.commit(function(err) {
if (err) {
return dbconn.user.rollback(function() {
throw err
})
}
})
})
})
});
});
callback(err)
})
},
getUserByEmail: function(email, callback) {
dbconn.user.query('SELECT verificationStatus, salutation, title, firstname, lastname, industry, organisation, speciality FROM user WHERE email = "' +email+'"', function (err, rows, fields) {
if (err) {
throw err;
}
else {
if ( rows.length > 0) {
user = rows[0];
}
}
callback(user, err);
});
},
checkUserEmail: function(email, callback) {
let user;
dbconn.user.query('SELECT id, email FROM user WHERE email = "' +email+'"', function (err, rows, fields) {
if (err) {
throw err;
}
else {
if ( rows.length > 0) {
user = rows[0];
}
}
callback(err, user);
});
},
getUserByToken: function(token, callback) {
var user;
dbconn.user.query('SELECT t1.user_id, t2.email FROM userdb.credential AS t1 INNER JOIN userdb.user AS t2 ON t1.user_id = t2.id AND t1.resetPasswordToken = "'
+token+'" and resetPasswordExpires > '+Date.now(), function (err, rows, fields) {
if (err) {
throw err;
}
else {
if ( rows.length > 0) {
user = rows[0]
console.log(user)
}
}
callback(err, user);
}
);
},
updateUserById: function(userData, callback) {
dbconn.user.query('UPDATE user SET ? WHERE id = ' +userData.id, userData, function (err, rows, fields) {
if (err) throw err
callback(err)
})
},
updateCredential: function(data, callback) {
dbconn.user.query('UPDATE credential SET ? WHERE user_id = ' +data.user_id, data, function (err, rows, fields) {
if (err) throw err
callback(err)
})
},
getUserIdByEmail: function(email, callback) {
let userId
dbconn.user.query('SELECT id FROM user WHERE email = "' +email+'"', function (err, rows, fields) {
if (err) {
throw err;
}
else {
if ( rows.length > 0) {
userId = rows[0].id;
}
}
callback(userId, err);
});
},
getUserProjectRole: function(userId, callback) {
dbconn.user.query('SELECT project_id, role_id FROM user_project_role WHERE user_id = "' +userId+'"', function (err, rows, fields) {
if (err) throw err;
callback(rows, err);
});
},
addUserProjectRole: function(data, callback) {
dbconn.user.query('INSERT INTO user_project_role SET ?', data, function (err, results, fields){
if (err) throw err;
callback(err);
})
},
// MLAB-129
getVerificationTokenByUserId: function(userId, callback) {
let token
dbconn.user.query('SELECT token FROM verification WHERE user_id = "' +userId+'"', function (err, rows, fields) {
if (err) {
throw err
}
else {
if (rows.length > 0) {
token = rows[0].token
}
}
callback(token, err)
})
},
getUserIdByVerificationToken: function(token, callback) {
let userId
dbconn.user.query('SELECT user_id FROM verification WHERE token = "' +token+'"', function (err, rows, fields) {
if (err) {
throw err
}
else if(rows[0]) {
userId = rows[0].user_id
}
callback(userId, err)
})
},
verifyUserAccount: function(userData, callback) {
dbconn.user.beginTransaction(function(err) { // START TRANSACTION
if (err) { throw err }
// update user status
dbconn.user.query('UPDATE user SET ? WHERE id =' +userData.id, userData, function (err, rows, fields) {
if (err) {
return dbconn.user.rollback(function() { throw err })
}
// delete verification token
dbconn.user.query('DELETE FROM verification WHERE user_id = '+userData.id, function (err, rows, fields) {
if (err) {
return dbconn.user.rollback(function() { throw err })
}
// COMMIT
dbconn.user.commit(function(err) {
if (err) {
return dbconn.user.rollback(function() { throw err })
}
})
})
})
callback(err)
})
},
// ======================= project db =======================
getAllProjects: function(callback) {
dbconn.project.query('CALL getAllprojects', function (err, rows, fields){
if (err) throw err;
callback(rows[0], err);
})
},
getAllMailinglists: function(callback) {
dbconn.project.query('CALL getAllLists', function (err, rows, fields){
if (err) throw err;
callback(rows[0], err);
})
},
getProjectOverviewById: function(projectId, callback) {
dbconn.project.query('CALL GetProjectInformationByProjectID(' + projectId+ ')', function (err, rows, fields){
if (err) throw err;
callback(rows[0], err);
})
},
getProjectImagesById: function(projectId, callback) {
dbconn.project.query('CALL getImagesByProjectID(' + projectId+ ')', function (err, rows, fields){
if (err) throw err;
callback(rows[0], err);
})
},
addProjectOverview: function(data, callback) {
dbconn.project.query('INSERT INTO project_overview SET ?', data, function (err, results, fields){
if (err) {
console.error(err);
}
callback(results, err);
})
}
};
module.exports = methods;
\ No newline at end of file
import async from 'async'
import bcrypt from 'bcryptjs'
import methods from '../functions/methods'
import mailer from '../config/mailer'
import constants from '../config/const'
const saltRounds:number = 10
const salt:number = 64
export = function (app:any, config:any, lang:string) {
// ================== NEW USERS REGISTRATION ======================
app.get('/registration', function(req:any, res:any) {
res.render(lang+'/account/registration')
})
app.post('/registration', function(req:any, res:any) {
// user data
let curDate:Date = new Date()
let userData:any = {
salutation: req.body.inputSalutation,
title: req.body.inputTitle,
firstname: req.body.inputFirstname,
lastname: req.body.inputLastname,
email: req.body.inputEmail,
organisation: req.body.inputOrganisation,
industry: req.body.inputIndustry,
speciality: req.body.inputSpeciality,
createdDate: curDate.toISOString().slice(0,10)
}
let userEmail:any = userData.email
let pos:number = userEmail.indexOf('@')
let emailLength:number = userEmail.length
let emailDomain:any = userEmail.slice(pos, emailLength);
if ( emailDomain.toLowerCase() == "@hft-stuttgart.de") {
res.flash('error', "Fehlgeschlagen: HFT-Account")
res.redirect('/account/registration')
} else {
async.waterfall([
function(done:any) {
// generate token
let token:string = '';
let randomChars:string = 'abcdefghijklmnopqrstuvwxyz0123456789';
for ( let i = 0; i<40; i++ ) {
token += randomChars.charAt(Math.floor(Math.random() * randomChars.length));
}
// encrypt password
bcrypt.genSalt(saltRounds, function(err, salt) {
bcrypt.hash(req.body.inputPassword, salt, function(err:any, hash:any) {
let newAccount:any = {
profile: userData,
password: hash,
verificationToken: token
}
done(err, newAccount)
});
});
},
// save data
function(newAccount:any, err:any) {
methods.registerNewUser(newAccount, function(err:any){
if (err) {
res.flash('error', "Fehlgeschlagen")
}
else {
// send email
let emailSubject = "Bitte bestätigen Sie Ihr M4_LAB Benutzerkonto"
let emailContent = '<div>Lieber Nutzer,<br/><br/>' +
'<p>vielen Dank für Ihre Anmeldung am Transferportal der HFT Stuttgart. <br/>' +
'Um Ihre Anmeldung zu bestätigen, klicken Sie bitte <a href='+config.app.host+'/verifyAccount?token='+newAccount.verificationToken+'>diesen Link</a> ' +
'<br/><br/>' +
'Ohne Bestätigung Ihres Kontos müssen wir Ihr Konto leider nach 7 Tagen löschen.</p><br/>' + constants.mailSignature +
'</div>';
mailer.options.to = req.body.inputEmail;
mailer.options.subject = emailSubject;
mailer.options.html = emailContent;
mailer.transporter.sendMail(mailer.options, function(err:any) {
if (err) {
console.error('Cannot send email. [Error] '+err)
throw err
}
})
// user feedback
res.flash('success', 'Vielen Dank für Ihre Registrierung!'+'\r\n\r\n'+
'Wir haben Ihnen eine E-Mail an Ihre verwendete Adresse gesendet. Diese enthält einen Link zur Bestätigung Ihres Accounts.'+'\r\n'+
'Wenn Sie die Mail nicht in ihrem Postfach vorfinden, prüfen Sie bitte auch Ihren Spam-Ordner.')
}
res.redirect('/account/registration')
})
}
])
}
})
// to check whether or not an account is already exist
app.get('/email/:email', async function(req:any, res:any) {
let user = await methods.checkUserEmail(req.params.email)
if (!user) {
console.log('No user found: '+req.params.email)
res.send(true)
} else {
console.log('User found: '+req.params.email)
res.send(false)
}
})
// =================== USERS VERIFICATION =========================
app.get("/verifyAccount", async function(req:any, res:any){
let userId:number = await methods.getUserIdByVerificationToken(req.query.token)
if (!userId) {
// no user found
res.render(lang+'/account/verification', {
status: null
})
} else {
// a user found, verify the account
let userData:any = {
id: userId,
verificationStatus: 1
}
methods.verifyUserAccount(userData, async function(err:any){
if (err) {
console.log("Error: "+err)
res.render(lang+'/account/verification', {
status: false
});
} else {
// send welcome email after successful account verification
let userEmail:string = await methods.getUserEmailById(userId)
if (!userEmail) {
res.render(lang+'/account/verification', {
status: false
})
} else {
// send email
let emailSubject = "Herzlich willkommen";
let emailContent = '<div>Lieber Nutzer,<br/><br/>' +
'<p>herzlich willkommen beim Transferportal der HFT Stuttgart!<br/>' +
'Sie können nun alle Dienste des Portals nutzen.<p/><br/>' + constants.mailSignature;
mailer.options.to = userEmail;
mailer.options.subject = emailSubject;
mailer.options.html = emailContent;
mailer.transporter.sendMail(mailer.options, function(err:any) {
if (err) {
console.log('cannot send email');
throw err;
}
})
res.render(lang+'/account/verification', {
status: true
})
}
}
})
}
})
// ==================== FORGOT PASSWORD ===========================
app.get('/forgotPwd', function (req:any, res:any) {
res.render(lang+'/account/forgotPwd', {
user: req.user
})
})
app.post('/forgotPwd', function(req:any, res:any) {
let emailAddress = req.body.inputEmail
async.waterfall([
async function(done:any) {
let user = await methods.checkUserEmail(emailAddress)
if (!user) {
console.log('No user found: '+emailAddress)
} else {
// generate token
let token:string = '';
let randomChars:string = 'abcdefghijklmnopqrstuvwxyz0123456789';
for ( let i = 0; i<40; i++ ) {
token += randomChars.charAt(Math.floor(Math.random() * randomChars.length));
}
let emailSubject = "Ihre Passwort-Anfrage an das Transferportal der HFT Stuttgart";
let emailContent = '<div>Lieber Nutzer,<br/><br/>' +
'<p>wir haben Ihre Anfrage zur Erneuerung Ihres Passwortes erhalten. Falls Sie diese Anfrage nicht gesendet haben, ignorieren Sie bitte diese E-Mail.<br/><br/>' +
'Sie können Ihr Passwort mit dem Klick auf diesen Link ändern: '+config.app.host+'/reset/' + token + '<br/>' +
'Dieser Link ist aus Sicherheitsgründen nur für 1 Stunde gültig.<br/></p>' + constants.mailSignature + '</div>'
let credentialData = {
user_id: user.id,
resetPasswordToken: token,
resetPasswordExpires: Date.now() + 3600000 // 1 hour
}
let result = await methods.updateCredential(credentialData)
if (!result) {
console.log('failed to update credential')
} else {
// send email
mailer.options.to = emailAddress
mailer.options.subject = emailSubject
mailer.options.html = emailContent
mailer.transporter.sendMail(mailer.options, function(err:any) {
if (err) { console.error(err) }
})
}
}
done(null)
}
], function(err:any) {
if (err) {
res.flash('error', 'Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut.')
}
else {
res.flash('success', 'Wenn Ihre E-Mail-Adresse registriert ist, wurde eine E-Mail mit dem weiteren Vorgehen an ' + emailAddress + ' versendet.')
}
res.redirect('/account/forgotPwd')
})
})
// reset
app.get('/reset/:token', async function(req:any, res:any) {
let user = await methods.getUserByToken(req.params.token)
if (!user) {
res.flash('error', 'Der Schlüssel zum zurücksetzen des Passworts ist ungültig oder abgelaufen.')
res.redirect('/account/forgotPwd')
} else {
res.render(lang+'/account/reset')
}
})
app.post('/reset/:token', async function(req:any, res:any) {
let newPwd = req.body.inputNewPwd
let user = await methods.getUserByToken(req.params.token)
if (!user) {
res.flash('error', "User not found.")
res.redirect('/login')
} else {
// encrypt password
bcrypt.genSalt(saltRounds, function(err, salt) {
bcrypt.hash(newPwd, salt, async function(err:any, hash) {
let credentialData = {
password: hash,
user_id: user.user_id,
resetPasswordToken: null,
resetPasswordExpires: null
}
// update password
let result = await methods.updateCredential(credentialData)
if (!result) {
console.log('Failed to reset password')
res.flash('error', "Datenbankfehler: Passwort kann nicht geändert werden.")
} else {
res.flash('success', "Passwort aktualisiert!")
// send notification email
mailer.options.to = user.email
mailer.options.subject = constants.updatePasswordMailSubject
mailer.options.html = constants.updatePasswordMailContent+'<div>'+constants.mailSignature+'</div>'
mailer.transporter.sendMail(mailer.options, function(err:any) {
if (err) { console.log(err) }
})
}
res.redirect('/login')
});
});
}
})
// ======================= CONTACT FORM ===========================
app.get('/contact', function (req:any, res:any) {
res.render(lang+'/account/contact', {
user: req.user
})
})
app.post('/contact', function(req:any, res:any, next:any) {
//methods.currentDate();
let emailAddress = req.body.inputEmail;
let supportAddress = "support-transfer@hft-stuttgart.de";
let inputName = req.body.name;
let inputContent = req.body.message;
let emailSubject = "Ihre Anfrage an das Transferportal";
let emailContent = "<div>Es wurde eine Anfrage an das Transferportal gestellt: <br/><br/>NAME: " + inputName + "<br/>NACHRICHT: "+ inputContent+"</div>";
async.waterfall([
function(done:any) {
// send email
mailer.options.to = supportAddress;
mailer.options.cc = emailAddress;
mailer.options.subject = emailSubject;
mailer.options.html = emailContent;
mailer.transporter.sendMail(mailer.options, function(err:any) {
done(err, 'done');
});
}
], function(err:any) {
if (err) {
console.error(err)
res.flash('error', 'Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut.');
}
else {
res.flash('success', 'Vielen Dank für Ihre Anfrage. Wir melden uns baldmöglichst bei Ihnen. Eine Kopie Ihrer Anfrage wurde an ' + emailAddress + ' versandt.');
}
res.redirect('/account/contact')
})
})
}
\ No newline at end of file
const fs = require('fs')
const SamlStrategy = require('passport-saml').Strategy
const dbconn = require('./dbconn')
const methods = require('./methods')
// pwd encryption
const bcrypt = require('bcryptjs');
const saltRounds = 10;
const salt = 64; // salt length
// forgot pwd
const async = require('async')
const crypto = require('crypto')
const mailer = require('./mailer')
module.exports = function (app, config, passport, i18n) {
// =========== PASSPORT =======
passport.serializeUser(function (user, done) {
done(null, user);
});
passport.deserializeUser(function (user, done) {
done(null, user);
});
var samlStrategy = new SamlStrategy({
// URL that goes from the Identity Provider -> Service Provider
callbackUrl: config.passport.saml.path,
// Base address to call logout requests
logoutUrl: config.passport.saml.logoutUrl,
entryPoint: config.passport.saml.entryPoint,
issuer: config.passport.saml.issuer,
identifierFormat: null,
// Service Provider private key
decryptionPvk: fs.readFileSync(__dirname + '/cert/key.pem', 'utf8'),
// Service Provider Certificate
privateCert: fs.readFileSync(__dirname + '/cert/key.pem', 'utf8'),
// Identity Provider's public key
cert: fs.readFileSync(__dirname + '/cert/cert_idp.pem', 'utf8'),
validateInResponseTo: false,
disableRequestedAuthnContext: true
},
function (profile, done) {
return done(null, {
id: profile.nameID,
idFormat: profile.nameIDFormat,
email: profile.email,
firstName: profile.givenName,
lastName: profile.sn
});
});
passport.use(samlStrategy);
// ============= SAML ==============
app.post(config.passport.saml.path,
passport.authenticate(config.passport.strategy,
{
failureRedirect: '/account/',
failureFlash: true
}),
function (req, res) {
res.redirect('/account/');
}
);
// to generate Service Provider's XML metadata
app.get('/saml/metadata',
function(req, res) {
res.type('application/xml');
var spMetadata = samlStrategy.generateServiceProviderMetadata(fs.readFileSync(__dirname + '/cert/cert.pem', 'utf8'));
res.status(200).send(spMetadata);
}
);
// ================ test i18n ==================
i18n.setLocale('de');
app.get('/de', function(req, res) {
var greeting = i18n.__('Hello World')
res.send(greeting)
});
var lang = 'DE'
// ======== APP ROUTES - ACCOUNT ====================
var updatePasswordMailSubject = "Ihr Passwort für das Transferportal wurde gespeichert."
var mailSignature = "Mit den besten Grüßen,\ndas Transferportal-Team der HFT Stuttgart\n\n"+
"Transferportal der Hochschule für Technik Stuttgart\n"+
"Schellingstr. 24\n"+
"70174 Stuttgart\n"+
"m4lab@hft-stuttgart.de\n"+
"https://transfer.hft-stuttgart.de"
var updatePasswordMailContent = "Lieber Nutzer,\n\n"+"Ihr Passwort wurde erfolgreich geändert.\n\n"+mailSignature
app.get('/', function (req, res) {
if (req.isAuthenticated()) {
methods.getUserByEmail(req.user.email, function(data, err){
if (!err) {
res.render(lang+'/account/home', {
user: data
});
}
})
} else {
res.redirect('/login'); // localhost
}
});
app.get('/login',
passport.authenticate(config.passport.strategy,
{
successRedirect: '/',
failureRedirect: '/login'
})
);
app.get('/logout', function (req, res) {
if (req.user == null) {
return res.redirect('/');
}
req.user.nameID = req.user.id;
req.user.nameIDFormat = req.user.idFormat;
return samlStrategy.logout(req, function(err, uri) {
req.logout();
if ( req.session ) {
req.session.destroy((err) => {
if(err) {
return console.log(err);
}
});
}
return res.redirect(uri);
});
});
app.get('/profile', function (req, res) {
if (req.isAuthenticated()) {
methods.getUserByEmail(req.user.email, function(data, err){
if (!err) {
if (data.verificationStatus == 1) {
console.log(data)
res.render(lang+'/account/profile', {
user: data,
email: req.user.email
})
}
else {
res.render(lang+'/account/home', {
user: data
});
}
}
})
} else {
res.redirect('/login');
}
});
app.get('/services', function (req, res) {
if (req.isAuthenticated()) {
methods.getUserByEmail(req.user.email, function(data, err){
if (!err) {
if (data.verificationStatus == 1) {
async.waterfall([
// get userId by email from userdb
function(done) {
methods.getUserIdByEmail(req.user.email, function(userId, err) {
if (!err) {
done(err, userId)
}
})
},
// get user-project-role from userdb
function(userId, done) {
methods.getUserProjectRole(userId, function(userProjects, err) {
if (!err) {
done(err, userProjects)
}
})
},
// get all projects from projectdb
function(userProjects, done) {
methods.getAllProjects(function(projectsOverview, err) {
if (!err) {
done(err, userProjects, projectsOverview)
}
})
},
// create JSON object of projects and user status for front-end
function(userProjects, projectsOverview, done) {
var allProjects = [] // JSON object
var userProjectId = [] // array of user's project_id
for (var i = 0; i < userProjects.length; i++) {
userProjectId.push(userProjects[i].project_id)
}
for (var i = 0; i < projectsOverview.length; i++) {
// check if projectId is exist in userProjectId[]
var status = false
if (userProjectId.indexOf(projectsOverview[i].id) > -1) {
status = true
}
// add data to JSON object
allProjects.push({
id: projectsOverview[i].id,
title: projectsOverview[i].title,
summary: projectsOverview[i].onelinesummary,
cp: projectsOverview[i].contact_email,
userStatus: status
});
}
// render the page
res.render(lang+'/account/services', {
user: data,
project: allProjects
});
}
])
}
else {
res.render(lang+'/account/home', {
user: data
});
}
}
})
} else {
res.redirect('/login');
}
});
app.get('/security', function (req, res) {
if (req.isAuthenticated()) {
methods.getUserByEmail(req.user.email, function(data, err){
if (!err) {
if (data.verificationStatus == 1) {
console.log(data)
res.render(lang+'/account/security', {
user: data
})
}
else {
res.render(lang+'/account/home', {
user: data
});
}
}
})
} else {
res.redirect('/login');
}
});
app.post('/updateProfile', function (req, res) {
var userData = {
salutation: req.body.inputSalutation,
title: req.body.inputTitle,
firstname: req.body.inputFirstname,
lastname: req.body.inputLastname,
email: req.body.inputEmail,
organisation: req.body.inputOrganisation,
industry: req.body.inputIndustry,
speciality: req.body.inputSpeciality,
}
if (req.isAuthenticated()) {
if (userData.email) {
dbconn.user.query('UPDATE user SET ? WHERE email = "' +userData.email+'"', userData, function (err, rows, fields) {
//if (err) throw err;
if (err) {
req.flash('error', "Failed");
}
else {
//req.flash('success', 'Profile updated!');
req.flash('success', 'Ihr Benutzerprofil wurde aktualisiert!');
}
res.redirect('/account/profile');
})
}
} else {
res.redirect('/login');
}
});
app.post('/changePwd', function (req, res) {
if (req.isAuthenticated()) {
var currPwd = req.body.inputCurrPwd
var newPwd = req.body.inputNewPwd
var retypePwd = req.body.inputConfirm
methods.getUserIdByEmail(req.user.email, function(userId, err) {
if (!err) {
// Load hashed passwd from DB
dbconn.user.query('SELECT password FROM credential WHERE user_id='+userId, function (err, rows, fields) {
if (err) {
console.error(err)
res.status(500).render(lang+'/500', {
error: err
})
}
var userPwd = rows[0].password
// check if the password is correct
bcrypt.compare(currPwd, userPwd, function(err, isMatch) {
if (err) {
console.error(err)
res.status(500).render(lang+'/500', {
error: err
})
}
else if (!isMatch) {
//req.flash('error', "Sorry, your password was incorrect. Please double-check your password.")
req.flash('error', "Das Passwort ist leider falsch. Bitte überprüfen Sie Ihre Eingabe.")
//res.redirect('/security')
res.redirect('/account/security')
}
else {
if ( newPwd != retypePwd ) {
//req.flash('error', "Passwords do no match. Please make sure you re-type your new password correctly.")
req.flash('error', 'Passwörter stimmen nicht überein. Bitte stellen Sie sicher, dass Sie das Passwort beide Male genau gleich eingeben.')
res.redirect('/account/security')
}
else {
// update password
bcrypt.genSalt(saltRounds, function(err, salt) {
bcrypt.hash(newPwd, salt, function(err, hash) {
var credentialData = {
password: hash,
user_id: userId
}
methods.updateCredential(credentialData, function(err){
if (err) {
//req.flash('error', "Database error: Password cannot be modified.")
req.flash('error', "Datenbankfehler: Passwort kann nicht geändert werden.")
throw err
}
else {
//req.flash('success', "Pasword updated!")
req.flash('success', "Passwort aktualisiert!")
mailer.options.to = req.user.email
//mailOptions.subject = "Your M4_LAB Password has been updated."
mailer.options.subject = updatePasswordMailSubject
mailer.options.text = updatePasswordMailContent
mailer.transport.sendMail(mailer.options, function(err) {
if (err) {
console.log(err)
}
});
}
res.redirect('/account/security')
})
});
});
}
}
})
})
}
})
}
else {
res.redirect('/login');
}
});
app.get('/forgotPwd', function (req, res) {
res.render(lang+'/account/forgotPwd', {
user: req.user
});
});
// =========== MLAB-129 ========
app.get("/verifyAccount", function(req, res){
methods.getUserIdByVerificationToken(req.query.token, function(userId, err){
console.log(err)
console.log(userId)
if (userId) {
let userData = {
id: userId,
verificationStatus: 1
}
methods.verifyUserAccount(userData, function(err){
if (err) {
res.send("Failed to verify your account. Please try again. https://transfer.hft-stuttgart.de")
// todo: create a page for this. copy the template from error page.
}
else {
res.send("email verified.\n\nhttps://transfer.hft-stuttgart.de")
// todo: create a page for this. copy the template from error page.
}
})
}
else {
res.send("Your account is not found.\n\nhttps://transfer.hft-stuttgart.de")
// todo: create a page for this. copy the template from error page.
}
})
})
app.get("/resendVerificationEmail", function(req, res){
if (req.isAuthenticated()) {
var emailAddress = req.user.email
methods.getUserIdByEmail(req.user.email, function(userId, err) {
if (!err) {
// get token
methods.getVerificationTokenByUserId(userId, function(token, err){
if (!err) {
if (token) {
// send email
var emailSubject = "Verify Your M4_LAB Account"; // todo: translate to DE
var emailContent = "Lieber Nutzer,\n\n"+
"vielen Dank für Ihre Anmeldung am Transferportal der HFT Stuttgart. "+
"\nUm Ihre Anmeldung zu bestätigen, klicken Sie bitte diesen Link: "+config.app.host+"/verifyAccount?token="+token+
"\n\nOhne Bestätigung Ihres Kontos müssen wir Ihr Konto leider nach 7 Tagen löschen.\n\n"+mailSignature
mailer.options.to = emailAddress;
mailer.options.subject = emailSubject;
mailer.options.text = emailContent;
mailer.transport.sendMail(mailer.options, function(err) {
if (err) {
console.log('cannot send email')
throw err
}
})
res.send(true)
}
else {
res.send(false)
}
}
else {
console.log(err)
}
})
}
})
}
})
// ===================
app.post('/forgotPwd', function(req, res, next) {
//methods.currentDate();
var emailAddress = req.body.inputEmail;
/* var emailContent = "Hi there,\n\n"+
"we've received a request to reset your password. However, this email address is not on our database of registered users.\n\n"+
"Thanks,\nM4_LAB Team";
var emailSubject = "Account Access Attempted"; */
async.waterfall([
function(done) {
crypto.randomBytes(20, function(err, buf) {
var token = buf.toString('hex');
done(err, token);
});
},
function(token, done) {
methods.checkUserEmail(emailAddress, function(err, user){
if (user) {
console.log("email: user found");
//var emailSubject = "M4_LAB Password Reset";
var emailSubject = "Ihre Passwort-Anfrage an das Transferportal der HFT Stuttgart";
/* var emailContent = "Hi User,\n\n"+
"we've received a request to reset your password. If you didn't make the request, just ignore this email.\n\n"+
"Otherwise, you can reset your password using this link: http://m4lab.hft-stuttgart.de/account/reset/" + token + "\n" +
"This password reset is only valid for 1 hour.\n\n"+
"Thanks,\nM4_LAB Team" */
var emailContent = "Lieber Nutzer,\n\n"+
"wir haben Ihre Anfrage zur Erneuerung Ihres Passwortes erhalten. Falls Sie diese Anfrage nicht gesendet haben, ignorieren Sie bitte diese E-Mail.\n\n"+
"Sie können Ihr Passwort mit dem Klick auf diesen Link ändern: http://m4lab.hft-stuttgart.de/account/reset/" + token + "\n" + // test server
//"Sie können Ihr Passwort mit dem Klick auf diesen Link ändern: http://localhost:9989/reset/" + token + "\n" + // localhost
"Dieser Link ist aus Sicherheitsgründen nur für 1 Stunde gültig.\n\n"+mailSignature
var credentialData = {
user_id: user.id,
resetPasswordToken: token,
resetPasswordExpires: Date.now() + 3600000 // 1 hour
}
methods.updateCredential(credentialData, function(err) {
done(err, token, user);
});
// send email
mailer.options.to = emailAddress;
mailer.options.subject = emailSubject;
mailer.options.text = emailContent;
mailer.transport.sendMail(mailer.options, function(err) {
done(err, 'done');
});
}
else {
//done(err, null, null);
done(err, 'no user found');
}
});
}
], function(err) {
if (err) {
//req.flash('error', 'An error occured. Please try again.');
req.flash('error', 'Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut.');
}
else {
//req.flash('success', 'If your email is registered, an e-mail has been sent to ' + emailAddress + ' with further instructions.');
req.flash('success', 'Wenn Ihre E-Mail-Adresse registriert ist, wurde eine E-Mail mit dem weiteren Vorgehen an ' + emailAddress + ' versendet.');
}
//res.redirect('/forgotPwd'); // deployment
res.redirect('/account/forgotPwd'); // localhost
});
});
app.get('/reset/:token', function(req, res) {
methods.getUserByToken(req.params.token, function(err, user){
if (!user) {
//req.flash('error', 'Password reset token is invalid or has expired.');
req.flash('error', 'Der Schlüssel zum zurücksetzen des Passworts ist ungültig oder abgelaufen.');
//res.redirect('/forgotPwd'); // deployment
res.redirect('/account/forgotPwd'); // deployment
}
else {
res.render(lang+'/account/reset');
}
});
});
app.post('/reset/:token', function(req, res) {
var newPwd = req.body.inputNewPwd
methods.getUserByToken(req.params.token, function(err, user){
if (user) {
// encrypt password
bcrypt.genSalt(saltRounds, function(err, salt) {
bcrypt.hash(newPwd, salt, function(err, hash) {
var credentialData = {
password: hash,
user_id: user.user_id
}
// update password
methods.updateCredential(credentialData, function(err){
if (err) {
//req.flash('error', "Database error: Password cannot be modified.")
req.flash('error', "Datenbankfehler: Passwort kann nicht geändert werden.")
throw err
}
else {
//req.flash('success', "Your pasword has been updated.")
req.flash('success', "Passwort aktualisiert!")
// send notifiaction email
mailer.options.to = user.email
mailer.options.subject = updatePasswordMailSubject
mailer.options.text = updatePasswordMailContent
mailer.transport.sendMail(mailer.options, function(err) {
if (err) {
console.log(err)
}
});
// redirect to login page
res.redirect('/login')
}
})
});
});
}
else {
req.flash('error', "User not found.")
res.redirect('/login')
}
});
});
app.get('/registration', function(req, res) {
res.render(lang+'/account/registration')
})
app.post('/registration', function(req, res) {
// user data
var curDate = new Date()
var userData = {
salutation: req.body.inputSalutation,
title: req.body.inputTitle,
firstname: req.body.inputFirstname,
lastname: req.body.inputLastname,
email: req.body.inputEmail,
organisation: req.body.inputOrganisation,
industry: req.body.inputIndustry,
speciality: req.body.inputSpeciality,
createdDate: curDate.toISOString().slice(0,10)
}
async.waterfall([
// token
function(done) {
crypto.randomBytes(20, function(err, buf) {
var token = buf.toString('hex');
done(err, token);
});
},
// encrypt password
function(token, done) {
bcrypt.genSalt(saltRounds, function(err, salt) {
bcrypt.hash(req.body.inputPassword, salt, function(err, hash) {
var newAccount = {
profile: userData,
password: hash,
verificationToken: token
}
done(err, newAccount)
});
});
},
// save data
function(newAccount, err) {
methods.registerNewUser(newAccount, function(err){
if (err) {
//req.flash('error', "Failed")
req.flash('error', "Fehlgeschlagen")
}
else {
//req.flash('success', 'Your account has been created. Please log in.')
req.flash('success', 'Ihr Benutzerkonto wurde angelegt. Bitte melden Sie sich an.')
}
res.redirect('/account/registration');
})
}
])
})
app.get('/email/:email', function(req, res) {
methods.checkUserEmail(req.params.email, function(err, user){
if (!err) {
if (user) {
res.send(false)
}
else {
res.send(true)
}
}
})
})
app.get('/contact', function (req, res) {
res.render(lang+'/account/contact', {
user: req.user
});
});
app.post('/contact', function(req, res, next) {
//methods.currentDate();
let emailAddress = req.body.inputEmail;
let supportAddress = "support-transfer@hft-stuttgart.de";
let inputName = req.body.name;
let inputContent = req.body.message;
let emailContent = "Es wurde eine Anfrage an das Transferportal gestellt: \n\n NAME: " + inputName + "\n NACHRICHT:\n "+ inputContent;
let emailSubject = "Ihre Anfrage an das Transferportal";
async.waterfall([
function(done) {
// send email
mailer.options.to = supportAddress;
mailer.options.cc = emailAddress;
mailer.options.subject = emailSubject;
mailer.options.text = emailContent;
mailer.transport.sendMail(mailer.options, function(err) {
done(err, 'done');
});
}
], function(err) {
if (err) {
req.flash('error', 'Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut.');
}
else {
req.flash('success', 'Vielen Dank für Ihre Anfrage. Wir melden uns baldmöglichst bei Ihnen. Eine Kopie Ihrer Anfrage wurde an ' + emailAddress + ' versandt.');
}
//res.redirect('/forgotPwd'); // deployment
res.redirect('/account/contact'); // localhost
});
});
};
\ No newline at end of file
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"rootDir": "./",
"outDir": "./built",
"esModuleInterop": true,
"strict": true,
"allowJs": true
}
}
\ No newline at end of file
......@@ -4,7 +4,7 @@ html(lang="de")
title= "404 - Page not found"
meta(charset="UTF-8")
meta(name="viewport", content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no")
link(rel="stylesheet", type="text/css", href="https://transfer.hft-stuttgart.de/css/bootstrap/bootstrap.css")
link(rel="stylesheet", type="text/css", href="/css/bootstrap.min.css")
style.
.container {
height: 400px;
......@@ -21,8 +21,8 @@ html(lang="de")
body
div(class="container")
div(class="center", align="center")
a(href="https://m4lab.hft-stuttgart.de")
img(src="https://transfer.hft-stuttgart.de/images/demo/m4lab_logo.jpg", class="img-responsive center-block", width="185", height="192")
a(href="/")
img(src="/images/demo/m4lab_logo.jpg", class="img-responsive center-block", width="185", height="192")
br
br
p(class="h5") 404. The requested URL was not found.
......
......@@ -4,7 +4,7 @@ html(lang="de")
title= "500 - Internal Server Error"
meta(charset="UTF-8")
meta(name="viewport", content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no")
link(rel="stylesheet", type="text/css", href="https://transfer.hft-stuttgart.de/css/bootstrap/bootstrap.css")
link(rel="stylesheet", type="text/css", href="/css/bootstrap.min.css")
style.
.container {
height: 400px;
......@@ -21,8 +21,8 @@ html(lang="de")
body
div(class="container")
div(class="center", align="center")
a(href="https://m4lab.hft-stuttgart.de")
img(src="https://transfer.hft-stuttgart.de/images/demo/m4lab_logo.jpg", class="img-responsive center-block", width="185", height="192")
a(href="/")
img(src="/images/demo/m4lab_logo.jpg", class="img-responsive center-block", width="185", height="192")
br
br
p(class="h5") 500. Unexpected Error :(
......
......@@ -4,48 +4,23 @@ html(lang="de")
title= "Kontakt"
meta(charset="UTF-8")
meta(name="viewport", content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no")
link(rel="stylesheet", type="text/css", href="https://transfer.hft-stuttgart.de/css/bootstrap/bootstrap.css")
link(rel="stylesheet", type="text/css", href="/css/bootstrap.min.css")
link(rel="stylesheet", type="text/css", href="/fonts/ionicons.min.css")
link(rel="stylesheet", type="text/css", href="/css/m4lab.css")
link(rel="stylesheet", type="text/css", href="/css/m4lab-mobile.css")
link(rel="stylesheet", type="text/css", href="/css/Contact-Form-Clean.css")
link(rel="stylesheet", type="text/css", href="/css/Testimonials.css")
link(rel="stylesheet", type="text/css", href="https://transfer.hft-stuttgart.de/css/custom/login.css")
link(rel="stylesheet", href="https://use.fontawesome.com/releases/v5.8.2/css/all.css", integrity="sha384-oS3vJWv+0UjzBfQzYUhtDYW+Pj2yciDJxpsK1OYPAYjqT085Qq/1cq5FLXAZQ7Ay", crossorigin="anonymous")
style.
.collapse {
display: none;
}
.collapse.in {
display: block;
}
.collapsing {
position: relative;
height: 0;
overflow: hidden;
-webkit-transition-timing-function: ease;
-o-transition-timing-function: ease;
transition-timing-function: ease;
-webkit-transition-duration: .35s;
-o-transition-duration: .35s;
transition-duration: .35s;
-webkit-transition-property: height,visibility;
-o-transition-property: height,visibility;
transition-property: height,visibility;
}
body
div(class="container")
div(class="row")
div(class="col-md-12" style="margin-bottom: 40px;")
div(class="col-md-12 margin_bottom_40")
img(class="mx-auto" src="/img/Kontakt.jpg" width="100%")
div(class="contact-clean" style="background-color: rgb(234,234,234);")
if successes
for success in successes
div.alert.alert-success.alert-dismissible #{ success }
a(class="close", href="#", data-dismiss="alert", aria-label="close") &times;
if errors
for error, i in errors
div.alert.alert-danger.alert-dismissible.fade.show #{ error }
a(class="close", href="#", data-dismiss="alert", aria-label="close") &times;
div(class="contact-clean background_eaeaea")
if flash.success
div.alert.alert-success.alert-dismissible #{flash.success}
a(class="close", href="#", data-dismiss="alert", aria-label="close") &times;
if flash.error
div.alert.alert-danger.alert-dismissible.fade.show #{flash.error}
a(class="close", href="#", data-dismiss="alert", aria-label="close") &times;
form(method="POST")
h2(class="text_center") Kontaktieren Sie uns
div(class="form-group")
......@@ -55,18 +30,18 @@ html(lang="de")
div(class="form-group")
textarea#message(class="form-control" name="message" placeholder="Nachricht" rows="14")
div(class="form-group")
input#submitBtn(class="btn btn-primary" type="submit" style="background-color: #8a348b;" value="SENDEN")
div(class="contact-clean" style="background-color: rgb(234,234,234);padding: 80px;padding-top: 0px;")
form(method="POST")
p(style="margin-top: 25px;") <strong>Hochschule für Technik Stuttgart</strong><br/>Institut für Angewandte Forschung<br/>Innovative Hochschule - Projekt M4_LAB<br/>Schellingstr. 24<br/>70174 Stuttgart<br/>Deutschland<br/><br/><a href="mailto:support-transfer@hft-stuttgart.de">support-transfer@hft-stuttgart.de</a><br/><br/><a href="https://www.hft-stuttgart.de/">www.hft-stuttgart.de</a> / <a href="https://www.hft-stuttgart.de/M4LAB">www.hft-stuttgart.de/M4LAB</a><br/>
div(style="background-color: rgba(138,52,139,0.45);")
input#submitBtn(class="btn btn-primary" type="submit" value="SENDEN")
div(class="contact-clean contact_footer")
form
p(class="m_top_25") <strong>Hochschule für Technik Stuttgart</strong><br/>Institut für Angewandte Forschung<br/>Innovative Hochschule - Projekt M4_LAB<br/>Schellingstr. 24<br/>70174 Stuttgart<br/>Deutschland<br/><br/><a href="mailto:support-transfer@hft-stuttgart.de">support-transfer@hft-stuttgart.de</a><br/><br/><a href="https://www.hft-stuttgart.de/">www.hft-stuttgart.de</a> / <a href="https://www.hft-stuttgart.de/M4LAB">www.hft-stuttgart.de/M4LAB</a><br/>
div(class="background_8a348b")
div(class="container")
div(class="row")
div(class="col-md-4 col-lg-2")
div(class="col-md-4 col-lg-8")
div(style="background-color: #feffff;margin: 0px;padding: 60px;padding-top: 20px;padding-bottom: 20px;")
img(class="d-flex d-lg-flex justify-content-center justify-content-lg-center align-items-lg-start mx-auto" src="/img/Logo_TV1.png" width="100px" style="padding-bottom: 35px;")
h2(class="text-center" style="color: #8a348b;") <strong>Transferportal</strong>
div(class="contact_foot_message")
img(class="d-flex d-lg-flex justify-content-center justify-content-lg-center align-items-lg-start mx-auto p_bottom_35" src="/img/Logo_TV1.png" width="100px")
h2(class="text-center color_8a348b") <strong>Transferportal</strong>
p(class="text-center") Das Transferportal entsteht in einem Teilprojekt der Innovativen <a href="https://www.hft-stuttgart.de">Hochschule für Technik Stuttgart</a>. Im <a href="https://www.hft-stuttgart.de/forschung/innovative-hochschule-m4-lab">Innovationslabor M4_LAB</a> wird das Transferportal als eine Webpräsenz entwickelt, welches Wissen, Lösungen und Dienste für HFT-Mitglieder, externe Partner und die allgemeine Öffentlichkeit bereitstellt.<br/><br/>Es ergänzt die Informationen der allgemeinen HFT-Webseite durch konkrete Ergebnisse aus Forschung und Entwicklung, verfügbar in verschiedenster Form wie beispielsweise Daten, Dokumentationen und Software-Code.<br/><br/>Zudem stellt es Kollaborationsmittel für Projektpartner und später auch Partizipationsmöglichkeiten für die breite Öffentlichkeit bereit.
div(class="col-md-4 col-lg-2")
......@@ -78,3 +53,4 @@ html(lang="de")
script(src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous")
// M4_LAB
script(src="/js/headfoot.js")
script(src="/js/mobile.js")
......@@ -4,44 +4,23 @@ html(lang="de")
title= "Forgot Password"
meta(charset="UTF-8")
meta(name="viewport", content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no")
link(rel="stylesheet", type="text/css", href="https://transfer.hft-stuttgart.de/css/bootstrap/bootstrap.css")
link(rel="stylesheet", type="text/css", href="https://transfer.hft-stuttgart.de/css/custom/login.css")
link(rel="stylesheet", type="text/css", href="/css/bootstrap.min.css")
link(rel="stylesheet", type="text/css", href="/css/m4lab.css")
link(rel="stylesheet", type="text/css", href="/css/m4lab-mobile.css")
link(rel="stylesheet", type="text/css", href="/css/custom/login.css")
link(rel="stylesheet", href="https://use.fontawesome.com/releases/v5.8.2/css/all.css", integrity="sha384-oS3vJWv+0UjzBfQzYUhtDYW+Pj2yciDJxpsK1OYPAYjqT085Qq/1cq5FLXAZQ7Ay", crossorigin="anonymous")
style.
.collapse {
display: none;
}
.collapse.in {
display: block;
}
.collapsing {
position: relative;
height: 0;
overflow: hidden;
-webkit-transition-timing-function: ease;
-o-transition-timing-function: ease;
transition-timing-function: ease;
-webkit-transition-duration: .35s;
-o-transition-duration: .35s;
transition-duration: .35s;
-webkit-transition-property: height,visibility;
-o-transition-property: height,visibility;
transition-property: height,visibility;
}
body
div(class="container-fluid")
div(class="row")
div(class="col-md-6 offset-md-3")
if successes
for success in successes
div.alert.alert-success.alert-dismissible #{ success }
a(class="close", href="#", data-dismiss="alert", aria-label="close") &times;
if errors
for error, i in errors
div.alert.alert-danger.alert-dismissible.fade.show #{ error }
a(class="close", href="#", data-dismiss="alert", aria-label="close") &times;
if flash.success
div.alert.alert-success.alert-dismissible #{flash.success}
a(class="close", href="#", data-dismiss="alert", aria-label="close") &times;
if flash.error
div.alert.alert-danger.alert-dismissible.fade.show #{flash.error}
a(class="close", href="#", data-dismiss="alert", aria-label="close") &times;
form#forgotForm(class="form-signin", method="POST")
img(src="https://transfer.hft-stuttgart.de/images/demo/m4lab_logo.jpg", class="img-responsive center-block", width="185", height="192")
img(src="https://transfer.hft-stuttgart.de/img/M4_LAB_LOGO.png", class="img-responsive center-block", width="185", height="192")
div(class="form-row")
input#inputEmail(name="inputEmail", type="email", class="form-control", placeholder="E-Mail-Adresse" required)
br
......@@ -54,3 +33,4 @@ html(lang="de")
script(src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous")
// M4_LAB
script(src="/js/headfoot.js")
script(src="/js/mobile.js")
......@@ -4,7 +4,9 @@ html(lang="de")
title= "User Account"
meta(charset="UTF-8")
meta(name="viewport", content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no")
link(rel="stylesheet", type="text/css", href="https://transfer.hft-stuttgart.de/css/bootstrap/bootstrap.css")
link(rel="stylesheet", type="text/css", href="/css/bootstrap.min.css")
link(rel="stylesheet", type="text/css", href="/css/m4lab.css")
link(rel="stylesheet", type="text/css", href="/css/m4lab-mobile.css")
link(rel="stylesheet", href="https://use.fontawesome.com/releases/v5.8.2/css/all.css", integrity="sha384-oS3vJWv+0UjzBfQzYUhtDYW+Pj2yciDJxpsK1OYPAYjqT085Qq/1cq5FLXAZQ7Ay", crossorigin="anonymous")
body
div(class="container")
......@@ -15,7 +17,7 @@ html(lang="de")
| Wir haben Ihnen eine E-Mail an Ihre verwendete Adresse gesendet. Diese enthält einen Link zur Bestätigung Ihres Accounts.
| Wenn Sie die Mail nicht in ihrem Postfach vorfinden, prüfen Sie bitte auch Ihren Spam-Ordner.
| <br >Falls Sie keine E-Mail von uns erhalten haben, können Sie <a href="javascript:void(0);" onclick="verify();">diese hier</a> erneut anfordern.
div(class="spinner-border text-secondary", role="status", style="display: none")
div(class="spinner-border text-secondary display_none", role="status")
else
div(class="row min-vh-100 flex-column flex-md-row")
aside(class="col-12 col-md-3 p-0 flex-shrink-1")
......@@ -24,21 +26,22 @@ html(lang="de")
ul(class="flex-md-column flex-row navbar-nav w-100 justify-content-between")
li(class="nav-item")
a(class="nav-link pl-0 text-nowrap" href="#")
span(class="font-weight-bold" style="color:black;") #{user.firstname} #{user.lastname}
span(class="font-weight-bold color_black") #{user.firstName} #{user.lastName}
li(class="nav-item")
a(class="nav-link pl-0" href="/profile")
a(class="nav-link pl-0" href="/account/profile")
i(class="fa fa-user fa-fw")
span(class="d-none d-md-inline") Benutzerprofil
if user.is_m4lab_idp
li(class="nav-item")
a(class="nav-link pl-0" href="/account/security")
i(class="fa fa-lock fa-fw")
span(class="d-none d-md-inline") Sicherheitseinstellungen
li(class="nav-item")
a(class="nav-link pl-0" href="/security")
i(class="fa fa-lock fa-fw")
span(class="d-none d-md-inline") Sicherheitseinstellungen
li(class="nav-item")
a(class="nav-link pl-0" href="/services")
a(class="nav-link pl-0" href="/account/services")
i(class="fa fa-tasks fa-fw")
span(class="d-none d-md-inline") Projekte und Dienste
li(class="nav-item")
a(class="nav-link pl-0" href="/logout" style="color:red;")
a(class="nav-link pl-0 color_red" href="/logout")
i(class="fa fa-sign-out-alt fa-fw")
span(class="d-none d-md-inline") Logout
main(class="col bg-faded py-3 flex-grow-1")
......@@ -52,19 +55,15 @@ html(lang="de")
// Bootstrap
script(src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous")
// M4_LAB
script(src="https://m4lab.hft-stuttgart.de/js/headfoot.js")
script(src="/js/headfoot.js")
script(src="/js/mobile.js")
script.
// call verifyAccount
function verify() {
$(".spinner-border").show()
$.get( "/resendVerificationEmail", function( data ) {
console.log(data)
if (data) {
alert( "Email sent!" )
}
else {
alert("Please contact support-transfer@hft-stuttgart.de to verify your account.")
}
if (data) { alert( "Email sent!" ) }
else { alert("Please contact support-transfer@hft-stuttgart.de to verify your account.") }
})
.fail(function() {
alert( "Something went wrong. Please try again." ) // todo: to DE
......
doctype html
html(lang="de")
head
title= "Setup a new website"
meta(charset="UTF-8")
meta(name="viewport", content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no")
link(rel="stylesheet", type="text/css", href="/css/bootstrap.min.css")
link(rel="stylesheet", type="text/css", href="/css/m4lab.css")
link(rel="stylesheet", type="text/css", href="/css/m4lab-mobile.css")
link(rel="stylesheet", href="https://use.fontawesome.com/releases/v5.8.2/css/all.css", integrity="sha384-oS3vJWv+0UjzBfQzYUhtDYW+Pj2yciDJxpsK1OYPAYjqT085Qq/1cq5FLXAZQ7Ay", crossorigin="anonymous")
body
div(class="container")
div(class="row min-vh-100 flex-column flex-md-row")
aside(class="col-12 col-md-3 p-0 flex-shrink-1")
nav(class="navbar navbar-expand flex-md-column flex-row align-items-start py-2")
div(class="collapse navbar-collapse")
ul(class="flex-md-column flex-row navbar-nav w-100 justify-content-between")
li(class="nav-item")
a(class="nav-link pl-0 text-nowrap" href="/account/")
span(class="font-weight-bold" style="color:black;") #{user.firstName} #{user.lastName}
li(class="nav-item")
a(class="nav-link pl-0" href="/account/profile")
i(class="fa fa-user fa-fw")
span(class="d-none d-md-inline") Benutzerprofil
if user.is_m4lab_idp
li(class="nav-item")
a(class="nav-link pl-0" href="/account/security")
i(class="fa fa-lock fa-fw")
span(class="d-none d-md-inline") Sicherheitseinstellungen
li(class="nav-item")
a(class="nav-link pl-0" href="/account/services")
i(class="fa fa-tasks fa-fw" style="color:black;")
span(class="d-none d-md-inline" style="color:black;") Projekte und Dienste
li(class="nav-item")
a(class="nav-link pl-0" href="/logout" style="color:red;")
i(class="fa fa-sign-out-alt fa-fw")
span(class="d-none d-md-inline") Logout
main(class="col bg-faded py-3 flex-grow-1")
nav(aria-label="breadcrumb")
ol(class="breadcrumb")
li(class="breadcrumb-item")
a(href="/account/") Konto
li(class="breadcrumb-item")
a(href="/account/services") Projekte und Dienste
li(class="breadcrumb-item active" aria-current="page") Neue Projektinformation
if flash.success
div.alert.alert-success.alert-dismissible #{flash.success}
a(class="close", href="#", data-dismiss="alert", aria-label="close") &times;
if flash.error
div.alert.alert-danger.alert-dismissible.fade.show #{flash.error}
a(class="close", href="#", data-dismiss="alert", aria-label="close") &times;
h3(class="pb-2") Neue Projektinformation
div(class="mx-4")
h4(class="pb-1") Schritt 1: Setup
p Bitte füllen Sie alle Felder aus
form(method="POST", encType="multipart/form-data")
div(class='form-group row')
label(for="template", class="col-sm-2") Template
div(class="col-sm-8")
select#templateSelector(name="template", class="form-control")
option(value="generic") generic
option(value="simple_raw") simple_raw
option(value="simple_thesis") simple_thesis
| <span id="templateExample" class="font-italic font-weight-light"><small>See the demo: <a href="https://transfer.hft-stuttgart.de/pages/athanasios.koukofikis/mygeneric/home/" target="_blank">generic</a>, <a href="https://transfer.hft-stuttgart.de/pages/athanasios.koukofikis/myraw/home/" target="_blank">simple_raw</a>, <a href="https://transfer.hft-stuttgart.de/pages/athanasios.koukofikis/mythesis/home/" target="_blank">simple_thesis</a></small></span>
div(class='form-group row')
label(for="name", class="col-sm-2") Name
div(class="col-sm-8")
input#name(name="name", type="text", class="form-control", placeholder="Name", maxlength="75" required)
p(id="nameInfo" class="font-italic font-weight-light") <small>Ihre Webseite wird unter folgender URL veröffentlicht: <strong>https://transfer.hft-stuttgart.de/pages/#{gitlabUsername}/<span id="websiteName"></span></strong></small>
div(class="form-group row")
label(for="description", class="col-sm-2") Beschreibung
div(class="col-sm-8")
textarea#description(name="description", type="text", class="form-control", placeholder="Beschreibung", maxlength="500" required)
div(class="form-group row")
label(for="logo", class="col-sm-2") Projektlogo
div(class="col-sm-8")
div(class="form-group row px-4")
- let defaultLogo = "/img/footer/M4_LAB_LOGO_Graustufen.png"
img(src=defaultLogo, width="100" height="100")
div(class="form-group row px-3")
input#logo(name="logo", class="form-control-file", type="file")
p <small>(Max file size is 80 KB.)</small>
input(type="submit", class="btn btn-primary", value="Senden")
hr
div(class="mx-4", style="color: gray;")
h4(class="pb-1") Schritt 2: Dateneingabe
p Bitte stellen Sie sicher in GitLab, dass sie Folgendes abgeschlossen haben, bevor Sie Ihre Webseite veröffentlichen:
ol
li Bearbeiten Sie ihre <i>index.html</i>
li Anpassen der Einstellungen in <i>settings.js</i>
// jQuery
script(src="https://code.jquery.com/jquery-3.3.1.min.js")
script(src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js", integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1", crossorigin="anonymous")
// jquery-loading-overlay
script(src="https://cdn.jsdelivr.net/npm/gasparesganga-jquery-loading-overlay@2.1.7/dist/loadingoverlay.min.js")
// Bootstrap
script(src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous")
// M4_LAB
script(src="/js/headfoot.js")
script(src="/js/mobile.js")
script.
// website URL
function showWebsiteURL() {
if ($("#name").val()) {
$("#nameInfo").show()
let webName = $("#name").val().toLowerCase().replace(/\s/g, '-')
document.getElementById("websiteName").innerText = webName+"/home/"
}
else {
$("#nameInfo").hide()
}
}
$('#name').on('input',function(e){
showWebsiteURL()
})
showWebsiteURL()
$("form").submit(function(){
$.LoadingOverlay("show")
});
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment