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

Merge branch 'devel' into 'testing'

Refactoring and codes cleaning

See merge request !144
parents 961ab112 4450156e
Pipeline #6621 failed with stage
in 20 seconds
var isEmailValid = false
var isPasswordValid = false
// check if email already exist
$('#inputEmail').change(function(){
var email = $('#inputEmail').val()
$.get("email/"+email, function(data) {
$('#emailWarning').empty()
isEmailValid = data
if(!isEmailValid) {
$('#emailWarning').html('Mit dieser E-Mail-Adresse existiert bereits ein Benutzerkonto in unserem Transferportal.')
}
switchSubmitButton()
})
.fail(function() {
console.log("cannot check email")
})
});
// check password
$('#inputPassword').on('keyup', function () {
isPasswordValid = checkPasswordReq($('#inputPassword').val())
$('#passwordWarning').empty();
if (!isPasswordValid) {
//$('#passwordWarning').html('Must be at least 8 characters')
$('#passwordWarning').html('Das Passwort muss mindestens 8 Zeichen haben')
}
switchSubmitButton()
});
function switchSubmitButton() {
if (isEmailValid && isPasswordValid) {
$('#submitBtn').prop('disabled', false)
}
else {
$('#submitBtn').prop('disabled', true)
}
}
\ No newline at end of file
// check password and password confirmation input fields
// used in Security and Reset Password
$('#inputNewPwd, #inputConfirm').on('keyup', function () {
var isBest, isMatch;
isBest = checkPasswordReq($('#inputNewPwd').val())
$('#recommendation').empty();
if (!isBest) {
//$('#recommendation').html('Must be at least 8 characters').css('color', 'red');
$('#recommendation').html('Das Passwort muss mindestens 8 Zeichen haben').css('color', 'red');
}
// match or not?
if ($('#inputNewPwd').val() == $('#inputConfirm').val()) {
//$('#message').html('Matching').css('color', 'green');
$('#message').html('Übereinstimmend').css('color', 'green');
isMatch = true;
} else {
//$('#message').html('Not Matching').css('color', 'red');
$('#message').html('Nicht übereinstimmend').css('color', 'red');
isMatch = false;
}
// enable/disable update button
if (isBest && isMatch) {
$('#updateBtn').prop('disabled', false);
} else {
$('#updateBtn').prop('disabled', true);
}
});
\ No newline at end of file
-----BEGIN CERTIFICATE-----
MIIFpDCCA4ygAwIBAgIJAKOpWVnPZyUUMA0GCSqGSIb3DQEBCwUAMGcxCzAJBgNV
BAYTAkRFMRIwEAYDVQQIDAlTdHV0dGdhcnQxEjAQBgNVBAcMCVN0dXR0Z2FydDEM
MAoGA1UECgwDSEZUMQ4wDAYDVQQLDAVNNExBQjESMBAGA1UEAwwJU2lob21iaW5n
MB4XDTE5MTEwODE0MzI0M1oXDTIyMDQyNjE0MzI0M1owZzELMAkGA1UEBhMCREUx
EjAQBgNVBAgMCVN0dXR0Z2FydDESMBAGA1UEBwwJU3R1dHRnYXJ0MQwwCgYDVQQK
DANIRlQxDjAMBgNVBAsMBU00TEFCMRIwEAYDVQQDDAlTaWhvbWJpbmcwggIiMA0G
CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDmPKgA2gn8KOBe73p3Tsdve90n2itC
wno8qs3XyTatdk84PZWOJz7iyWElLOgKUThvbQ7Z6yDKSFxmuwX+cMqqdmaJY6Dz
vKOPOQT0adGWUlRRP0QucTYKvV8euqr+vKBWo6HN73RYXgwSVapOfNCh71s09cmh
2jkGPvPgQ0ZhoO85fdn4xf328bP0b4pG5oCJu/oOWxesCXlyHcOGx0jrR8H7Nsee
36vOrOg3CJWM+LNWhemKOC0WBj+3zEyVxiHZgy/3XAIBY2vohnU8osaOdVqT9sBr
DrW4zkwAbGQiiDoUVfZw0ERS3YkBPbTtY3dkRviEabRn7WGCCsGRXNRIAm9pRl7W
osddMIu4tmkmNeJvfBFv3fM/aVS6UYuSmUAdd5g5M82U9BFz5IRXZITODbgLO6jM
dZ5XM3sffadrneC0r/IKnX57XvC6jUvSuAtum6Zct2sr5tEJRrrkZ52ZVLydBQtW
kvcqD/C+t4sJpLXn+2Dt+FRc5NTy/zu5kNJ4FKBx+aBMdWVk336y40yjlAFcWu82
dKL0RzTlPGdp7IGsrCRsPozVrawtM/5OPcAMow/Tg8q9Z67wbpeB3OGiG1PmpjNq
iG/+l/CrU8PSBF+RaSRNg+VfPTw+0lAatV0RstHJzXN4a+fQVGt54rN+mkNE7LrV
TTgWPqAk9AcPuQIDAQABo1MwUTAdBgNVHQ4EFgQUQXEm5SdEh/kQ5cjAhQxgVkL/
GQowHwYDVR0jBBgwFoAUQXEm5SdEh/kQ5cjAhQxgVkL/GQowDwYDVR0TAQH/BAUw
AwEB/zANBgkqhkiG9w0BAQsFAAOCAgEA1yuHFmrzoVMLC0f+puPT7ob9Efhyk17G
mYHu5IWGzovDjkFv2w0ZzI86XhIBjpyVHgivVQjCFmnnb6FdFHCVJD3eNKHJTRD+
TBi42mU9AOm+lcK39jL4+Nhnr5rmob+UsOgqhUxx76Y0BSIUm7ax3ezHp7mmbr68
hxQcPv1YEmrSE0NQvXl1ck5CeK/p8KOsGKGaOnnfvMp7QICTLeCiRnBSCTk0pWgY
KP3DSAsp4OtuaHXh7xnNKOMrK2mvZJux3U2z6BC2JGWZGnBGjmwHr7xA7P2gg642
IsSvcYBR9QHoQHJZT8x2904igVIxHUjz4H3oAgL4e8ksTANKkudmtAD/YDW1rLTY
mpWUyMf5UwVXzd8/VoAkzX7gNh7oTXPmo0gQ1XyWQRKokoUGdkz38bb3J8yOlpwN
1XojKDyucM/CWB3zUmoXgjQwKlf+oF5AyYv5ElIHoZK3S6WciKjYjJqfZA7RqPml
LVBbDZNcDZm/e5qtYz7r4TOW75GNJLzXnafGwqeNmbHprgYdvjlNLmtAeojuKr8n
Pi3Lu89e/8IKbX6+GkuYcv6XjnQc+keTBb4Lo17+HXduixgMyEy+ErIOUx6UMiLs
8UgrEsOaxhrzEufC5B6tqYGQzMXTBuSW/Mzv6BddX4W3+pnOa9m7B3+JMFlh0lgC
GobuGUHz6X4=
-----END CERTIFICATE-----
MIIEOzCCAyOgAwIBAgIJAMG8Ts0h95sVMA0GCSqGSIb3DQEBCwUAMIGzMQswCQYDVQQGEwJERTEdMBsGA1UECAwUQmFkZW4tV8ODwrxydHRlbWJlcmcxEjAQBgNVBAcMCVN0dXR0Z2FydDEWMBQGA1UECgwNSGZUIFN0dXR0Z2FydDEPMA0GA1UECwwGSVotSVRPMRcwFQYDVQQDDA4xOTMuMTk2LjUyLjIxNzEvMC0GCSqGSIb3DQEJARYgd29sZmdhbmcua25vcGtpQGhmdC1zdHV0dGdhcnQuZGUwHhcNMTkxMDEwMDg0OTU2WhcNMTkxMTA5MDg0OTU2WjCBszELMAkGA1UEBhMCREUxHTAbBgNVBAgMFEJhZGVuLVfDg8K8cnR0ZW1iZXJnMRIwEAYDVQQHDAlTdHV0dGdhcnQxFjAUBgNVBAoMDUhmVCBTdHV0dGdhcnQxDzANBgNVBAsMBklaLUlUTzEXMBUGA1UEAwwOMTkzLjE5Ni41Mi4yMTcxLzAtBgkqhkiG9w0BCQEWIHdvbGZnYW5nLmtub3BraUBoZnQtc3R1dHRnYXJ0LmRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwD4SZ+XT2HRmjGGanHLAPu792pv4GSB8Z8vwz+w7k8W4R4pWG9IH/L0ftroy/BsE/kZbbpIDXk1XbkEX4OGhYguVr5snCZZYZx0aRewrqcXPZNLeRQ7EGfencrcZgnNLMvE+QHAAl52wqNaZlpiEsBlKg21SUyb4o9kgo5clQOwk4wMrrMI+hMWEszR3ehgcyPZkS6cFEjic0dvzDgpCWkHm6TQD8x1W2xiQcOzOjZBziObuR+NmtD/1m37kjwUXLOz6YCgStf0cdoNDxdIrxKiImcqV7cBJ83NAAcIGXXlqLYgNpFVwenUjyKky2hu1N+Qzfs7fk5nDdjny+5LotQIDAQABo1AwTjAdBgNVHQ4EFgQUBiJg3KXaFUobk3xkDsueM4w7jrowHwYDVR0jBBgwFoAUBiJg3KXaFUobk3xkDsueM4w7jrowDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAHw6iugiOhHO6KovpCRPSTUc0TP67T7X8y9FrpI7yKB+CpadkaLH1NhUN6vexCDQssS5Z4HNW/Er6/4aNHJj53Cgkury73xugcJZ0XUeHNTAF+IZmkDnUj3FMQGZJJ6yvOp14PmDWZLmu1lriQGv85+rrd8jwNeGXy6OCmuqYtV1oWvHom9NkkRlELbJO7UPC/h6FAuU3YBNAqhPrEDkNT1FLBJJzDDC7J6zY4U7U2Nqx2gDG6pbHiiXxw+AY2a+z+BzGPnfmbgODP7gu0VvKRR40NEs9bdimA9rUN9N3YIwWJt2LAW4zshZEPv7vCj/qSUHqsFTNh2LZzThbCbz5TQ==
\ No newline at end of file
-----BEGIN PRIVATE KEY-----
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
7lI0pJL0b06GCO5cXcrZizZJIcQf7g==
-----END PRIVATE KEY-----
import express from 'express'
import path from 'path'
import passport from 'passport'
import morgan from 'morgan'
import cookieParser from 'cookie-parser'
import bodyParser from 'body-parser'
import session from 'express-session'
import flash from 'express-flash-2'
import fileUpload from 'express-fileupload'
import helmet from 'helmet'
import compression from 'compression'
import methodOverride from 'method-override'
const env = process.env.NODE_ENV ?? 'testing'
const config = require('./config/config')[env]
const lang = 'DE'
const app = express()
app.set('port', config.app.port)
app.set('views', path.join(path.join(__dirname, '/views')))
app.set('view engine', 'pug')
// enable files upload
app.use(fileUpload({
createParentPath: true,
limits: {
fileSize: 1000000 // 1 MB max. file size
}
}))
app.use(methodOverride('_method'))
app.use(
helmet.contentSecurityPolicy({
useDefaults: true,
directives: {
'font-src': ["'self'", 'https://use.fontawesome.com'],
'img-src': ["'self'", 'https://transfer.hft-stuttgart.de'],
'script-src': ["'self'", 'https://code.jquery.com/jquery-3.3.1.min.js', 'https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js',
'https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js', 'https://unpkg.com/bootstrap-show-password@1.2.1/dist/bootstrap-show-password.min.js'],
'style-src': ["'self'", 'https://use.fontawesome.com/releases/v5.8.2/css/all.css'],
'frame-src': ["'self'"]
},
reportOnly: true
})
)
app.use(compression())
app.use(morgan('combined'))
app.use(cookieParser(config.app.sessionSecret))
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: false }))
app.use(express.static(path.join(__dirname, 'public')))
app.use((req, res, next) => {
next()
})
app.use(session({
resave: true,
saveUninitialized: true,
secret: config.app.sessionSecret
}))
app.use(flash())
app.use(passport.initialize())
app.use(passport.session())
// caching disabled for every route
// NOTE: Works in Firefox and Opera. Does not work in Edge
app.use(function (req, res, next) {
res.set('Cache-Control', 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0')
next()
})
require('./routes/public')(app, config, lang)
require('./routes/account')(app, config, passport, lang)
// Handle 404
app.use(function (req: any, res: any) {
res.status(404).render(lang + '/404')
})
// Handle 500 - any server error
app.use(function (err: any, req: any, res: any, next: any) {
console.error(err.stack)
res.status(500).render(lang + '/500', {
error: err
})
})
app.listen(app.get('port'), function () {
console.log('Express server listening on port ' + app.get('port'))
})
class Project {
ownerGitlabId: number
name: string
desc: string
id?: number
logo?: string
path?: string
constructor (ownerGitlabId: number, name: string, desc: string, id?: number, logo?: string, path?: string) {
this.ownerGitlabId = ownerGitlabId
this.name = name
this.desc = desc
this.id = id
this.logo = logo
this.path = path
}
// getter
getOwnerGitlabId () {
return this.ownerGitlabId
}
getId () {
return this.id
}
getName () {
return this.name
}
getDesc () {
return this.desc
}
getLogo () {
return this.logo
}
getPath () {
return this.path
}
// setter
setOwnerGitlabId (newOwnerGitlabId: number) {
this.ownerGitlabId = newOwnerGitlabId
}
setId (newId: number) {
this.id = newId
}
setName (newName: string) {
this.name = newName
}
setDesc (newDesc: string) {
this.desc = newDesc
}
setLogo (newLogoUrl: string) {
this.logo = newLogoUrl
}
setPath (newPath: string) {
this.path = newPath
}
}
export { Project }
import { Project } from './project'
class Repo extends Project {
constructor (ownerGitlabId: number, name: string, desc: string, id?: number, logo?: string, path?: string) {
super(ownerGitlabId, name, desc, id, logo, path)
}
}
export { Repo }
class User {
id: number
email: string
salutation: string // should be enum
title: string // should be enum
firstName: string
lastName: string
industry: string
organisation: string
speciality: string
isM4labIdp: number // 1 or 0
verificationStatus: number // 1 or 0 - // should be boolean
gitlabUserId?: number
constructor (id: number, email: string, salutation: string, title: string, firstName: string, lastName: string, industry: string, organisation: string,
speciality: string, isM4labIdp: number, verificationStatus: number, gitlabUserId?: number) {
this.id = id
this.email = email
this.salutation = salutation
this.title = title
this.firstName = firstName
this.lastName = lastName
this.industry = industry
this.organisation = organisation
this.speciality = speciality
this.isM4labIdp = isM4labIdp
this.verificationStatus = verificationStatus
this.gitlabUserId = gitlabUserId
}
// getter
getId () {
return this.id
}
getEmail () {
return this.email
}
getFullName () {
return this.firstName + ' ' + this.lastName
}
getIdpStatus () {
return this.isM4labIdp
}
getVerificationStatus () {
return this.verificationStatus
}
getGitlabUserId () {
return this.gitlabUserId
}
// setter
setEmail (email: string) {
this.email = email
}
setSalutation (salutation: string) {
this.salutation = salutation
}
setTitle (title: string) {
this.title = title
}
setFirstName (firstName: string) {
this.firstName = firstName
}
setLastName (lastName: string) {
this.lastName = lastName
}
setIndustry (industry: string) {
this.industry = industry
}
setOrganisation (organisation: string) {
this.organisation = organisation
}
setSpeciality (speciality: string) {
this.speciality = speciality
}
setM4lab_idp (m4labIdp: number) {
this.isM4labIdp = m4labIdp
}
setVerificationStatus (verificationStatus: number) {
this.verificationStatus = verificationStatus
}
setGitlabUserId (newGitlabUserId: number) {
this.gitlabUserId = newGitlabUserId
}
updateProfile (newSalutation: string, newTitle: string, newFirstname: string, newLastname: string, newEmail: string, newOrganisation: string, newIndustry: string, newSpeciality: string) {
this.salutation = newSalutation
this.title = newTitle
this.firstName = newFirstname
this.lastName = newLastname
this.email = newEmail
this.organisation = newOrganisation
this.industry = newIndustry
this.speciality = newSpeciality
}
}
export { User }
import { Project } from './project'
class Website extends Project {
constructor (ownerGitlabId: number, name: string, desc: string, id?: number, logo?: string, path?: string) {
super(ownerGitlabId, name, desc, id, logo, path)
}
}
export { Website }
export = {
module.exports = {
development: {
app: {
name: 'User Account Management',
port: process.env.PORT || 9989,
port: process.env.PORT ?? 9989,
host: 'http://localhost:9989',
sessionSecret: 'thisisasecret'
},
passport: {
strategy: 'saml',
saml: {
path: process.env.SAML_PATH || '/saml/SSO',
entryPoint: process.env.SAML_ENTRY_POINT || 'Saml Entry Point',
issuer: 'SAML issuer', //local metadata
path: process.env.SAML_PATH ?? '/saml/SSO',
entryPoint: process.env.SAML_ENTRY_POINT || 'saml entry point',
issuer: 'SAML issuer',
logoutUrl: 'SAML logout URL'
}
},
database: {
host: 'localhost', // DB host
user: 'usernamedb', // DB username
password: 'passworddb', // DB password
port: 3306, // MySQL port
dbUser: 'userdb', // User DB
host: 'localhost', // DB host
user: 'dbuser', // DB username
password: 'dbpass', // DB password
port: 3306, // MySQL port
dbUser: 'userdb', // User DB
host_project: 'localhost', // DB host project db
dbProject: 'projectdb' // Project DB
dbProject: 'projectdb' // Project DB
},
mailer: {
host: 'mailhost', // hostname
secureConnection: false, // TLS requires secureConnection to be false
port: 587, // port for secure SMTP
host: 'mailhost', // hostname
secureConnection: false, // TLS requires secureConnection to be false
port: 587, // port for secure SMTP
TLS: true,
authUser: 'mailuser',
authPass: 'mailpass',
tlsCiphers: 'SSLv3',
from: 'mailfrom',
from: 'mailfrom'
},
gitlab: {
token_readWriteProjects: 'token-goes-here'
......@@ -41,40 +41,42 @@ export = {
testing: {
app: {
name: 'User Account Management',
port: process.env.PORT || 9989,
port: process.env.PORT ?? 9989,
host: 'https://m4lab.hft-stuttgart.de/account',
sessionSecret: 'thisisasecret'
},
passport: {
strategy: 'saml',
saml: {
path: process.env.SAML_PATH || '/saml/SSO',
entryPoint: process.env.SAML_ENTRY_POINT || 'saml entry point',
issuer: 'SAML issuer', //testing metadata
path: process.env.SAML_PATH ?? '/saml/SSO',
entryPoint: process.env.SAML_ENTRY_POINT ?? 'saml entry point',
issuer: 'SAML issuer', // testing metadata
logoutUrl: 'SAML logout URL'
}
},
database: {
host: 'dbhost', // DB host
user: 'dbuser', // DB username
password: 'dbpass', // DB password
port: 3306, // MySQL port
dbUser: 'userdb', // User DB
host: 'dbhost', // DB host
user: 'dbuser', // DB username
password: 'dbpass', // DB password
port: 3306, // MySQL port
dbUser: 'userdb', // User DB
host_project: 'dbhost', // DB host project db
dbProject: 'projectdb' // Project DB
dbProject: 'projectdb' // Project DB
},
mailer: {
host: 'mailhost', // hostname
secureConnection: false, // TLS requires secureConnection to be false
port: 587, // port for secure SMTP
host: 'mailhost', // hostname
secureConnection: false, // TLS requires secureConnection to be false
port: 587, // port for secure SMTP
TLS: true,
authUser: 'mailuser',
authPass: 'mailpass',
tlsCiphers: 'SSLv3',
from: 'mailfrom',
from: 'mailfrom'
},
gitlab: {
token_readWriteProjects: 'token-goes-here'
}
}
}
\ No newline at end of file
}
export {}
export = {
const miscConst = {
mailSignature: 'Mit den besten Grüßen,<br/>das Transferportal-Team der HFT Stuttgart<br/><br/>' +
mailSignature: 'Mit den besten Grüßen,<br/>das Transferportal-Team der HFT Stuttgart<br/><br/>' +
'Transferportal der Hochschule für Technik Stuttgart<br/>' +
'Schellingstr. 24 70174 Stuttgart<br/>' +
'm4lab@hft-stuttgart.de<br/>' +
'<a href="https://transfer.hft-stuttgart.de">https://transfer.hft-stuttgart.de</a><br/>' +
'<a mailConsthref="https://transfer.hft-stuttgart.de">https://transfer.hft-stuttgart.de</a><br/>' +
'<a href="http://www.hft-stuttgart.de/Aktuell/"><img border="0" alt="HFT" src="https://m4lab.hft-stuttgart.de/img/signature/hft_logo.png" width="30" height="30"></a> &nbsp;' +
'<a href="http://www.facebook.com/hftstuttgart"><img border="0" alt="Facebook" src="https://m4lab.hft-stuttgart.de/img/signature/fb_bw.png" width="30" height="30"></a> &nbsp;' +
'<a href="https://www.instagram.com/hft_stuttgart/"><img border="0" alt="Instagram" src="https://m4lab.hft-stuttgart.de/img/signature/instagram_bw.png" width="30" height="30"></a> &nbsp;' +
......@@ -13,7 +13,9 @@ export = {
'<a href="http://www.hft-stuttgart.de/Aktuell/Presse-Marketing/SocialMedia/Snapcode HFT_Stuttgart.jpg/photo_view">' +
'<img border="0" alt="Snapchat" src="https://m4lab.hft-stuttgart.de/img/signature/snapchat_bw.png" width="30" height="30"></a>' +
'<br/><img border="0" src="https://m4lab.hft-stuttgart.de/img/signature/inno_bw.png" width="150" height="100">',
updatePasswordMailSubject: "Ihr Passwort für das Transferportal wurde gespeichert.",
updatePasswordMailContent: '<div>Lieber Nutzer,<br/><br/>Ihr Passwort wurde erfolgreich geändert.<br/><br/></div>'
updatePasswordMailSubject: 'Ihr Passwort für das Transferportal wurde gespeichert.',
updatePasswordMailContent: '<div>Lieber Nutzer,<br/><br/>Ihr Passwort wurde erfolgreich geändert.<br/><br/></div>'
}
\ No newline at end of file
}
export { miscConst }
import mysql from 'mysql2'
const env = process.env.NODE_ENV ?? 'development'
const config = require('./config')[env]
// ==== USER ACOOUNT DB CONNECTION ====
const userConnection = mysql.createPool({
host: config.database.host,
user: config.database.user,
password: config.database.password,
port: config.database.port,
database: config.database.dbUser,
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
})
userConnection.query('USE ' + config.database.dbUser)
// ==== PROJECT DB CONNECTION ====
const projectConnection = mysql.createPool({
host: config.database.host_project,
user: config.database.user,
password: config.database.password,
port: config.database.port,
database: config.database.dbProject,
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
})
projectConnection.query('USE ' + config.database.dbProject)
const dbConnection = {
user: userConnection,
project: projectConnection
}
export { dbConnection }
const nodemailer = require('nodemailer')
const nodemailerNTLMAuth = require('nodemailer-ntlm-auth')
var env = process.env.NODE_ENV || 'testing'
const env = process.env.NODE_ENV ?? 'testing'
const config = require('./config')[env]
var smtpTransporter = nodemailer.createTransport({
const smtpTransporter = nodemailer.createTransport({
host: config.mailer.host,
secure: config.mailer.secureConnection,
port: config.mailer.port,
......@@ -18,23 +18,23 @@ var smtpTransporter = nodemailer.createTransport({
domain: 'ad'
}
},
customAuth:{
customAuth: {
NTLM: nodemailerNTLMAuth
}
});
})
var mailOptions:any = {
to: "",
cc: "",
from: config.mailer.from,
subject: "",
text: "",
html: ""
const mailOptions: any = {
to: '',
cc: '',
from: config.mailer.from,
subject: '',
text: '',
html: ''
}
var mailer:any = {
transporter: smtpTransporter,
options: mailOptions
const mailer: any = {
transporter: smtpTransporter,
options: mailOptions
}
export = mailer
\ No newline at end of file
export { mailer }
import { dbConnection } from '../config/dbconn'
const dbController = {
// ===================== user db =====================
registerNewUser: function (data: any, callback: any) {
dbConnection.user.getConnection(function (err: any, thisconn) {
thisconn.beginTransaction(function (err: any) { // START TRANSACTION
if (err) { throw err }
// insert profile
thisconn.query('INSERT INTO user SET ?', data.profile, function (err: any, results: any, fields: any) {
if (err) {
return thisconn.rollback(function () {
throw err
})
}
const newUserId: number = results.insertId
// set password
const credentialData: any = {
user_id: newUserId,
password: data.password
}
thisconn.query('INSERT INTO credential SET ?', credentialData, function (err: any, results: any, fields: any) {
if (err) {
return thisconn.rollback(function () {
throw err
})
}
// set default user-project-role
const projectRoleData: any = {
project_id: 1, // M4_LAB
role_id: 2, // USER
user_id: newUserId
}
thisconn.query('INSERT INTO user_project_role SET ?', projectRoleData, function (err: any, results: any, fields: any) {
if (err) {
return thisconn.rollback(function () {
throw err
})
}
// MLAB-129: INSERT verification token
const verificationData: any = {
user_id: newUserId,
token: data.verificationToken
}
thisconn.query('INSERT INTO verification SET ?', verificationData, function (err: any, results: any, fields: any) {
if (err) {
return thisconn.rollback(function () {
throw err
})
}
// COMMIT
thisconn.commit(function (err: any) {
if (err) {
return thisconn.rollback(function () {
throw err
})
}
})
})
})
})
})
})
callback(err)
})
},
getUserByEmail: async function (email: any) {
try {
const rows: any = await dbConnection.user.promise().query('SELECT id, verificationStatus, salutation, title, firstname, lastname, industry, organisation, speciality, m4lab_idp FROM user WHERE email = "' + email + '"')
if (rows[0][0]) {
return rows[0][0]
} else { return null }
} catch (err) {
console.error(err)
}
return null
},
getUserEmailById: async function (userId: number) {
try {
const rows: any = await dbConnection.user.promise().query('SELECT email FROM user WHERE id = ' + userId)
if (rows[0][0]) {
return rows[0][0].email
} else { return null }
} catch (err) {
console.error(err)
}
return null
},
checkUserEmail: async function (email: any) {
try {
const rows: any = await dbConnection.user.promise().query('SELECT id, email FROM user WHERE email = "' + email + '"')
if (rows[0][0]) {
return rows[0][0]
} else { return null }
} catch (err) {
console.error(err)
}
return null
},
getUserByToken: async function (token: any) {
try {
const rows: any = await dbConnection.user.promise().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())
if (rows[0][0]) {
return rows[0][0]
} else { return null }
} catch (err) {
console.error(err)
}
return null
},
updateUserById: async function (userId: number, userData: any) {
try {
const result: any = await dbConnection.user.promise().query('UPDATE user SET ? WHERE id = ' + userId, userData)
return result
} catch (err) {
console.error(err)
}
return null
},
updateCredential: async function (data: any) {
try {
const result: any = await dbConnection.user.promise().query('UPDATE credential SET ? WHERE user_id = ' + data.user_id, data)
return result
} catch (err) {
console.error(err)
}
return null
},
addUserProjectRole_OBSOLETE: function (data: any, callback: any) {
dbConnection.user.query('INSERT INTO user_project_role SET ?', data, function (err: any) {
if (err) throw err
callback(err)
})
},
getVerificationTokenByUserId: async function (userId: number) {
try {
const rows: any = await dbConnection.user.promise().query('SELECT token FROM verification WHERE user_id = "' + userId + '"')
if (rows[0][0]) {
return rows[0][0].token
} else { return null }
} catch (err) {
console.error(err)
}
return null
},
getUserIdByVerificationToken: async function (token: any) {
try {
const rows: any = await dbConnection.user.promise().query('SELECT user_id FROM verification WHERE token = "' + token + '"')
if (rows[0][0]) {
return rows[0][0].user_id
} else {
return null
}
} catch (err) {
console.error(err)
}
return null
},
verifyUserAccount: function (userData: any, callback: any) {
dbConnection.user.getConnection(function (err: any, thisconn) {
thisconn.beginTransaction(function (err: any) { // START TRANSACTION
if (err) { throw err }
// update user status
thisconn.query('UPDATE user SET ? WHERE id =' + userData.id, userData, function (err: any, rows: any, fields: any) {
if (err) {
return thisconn.rollback(function () { throw err })
}
// delete verification token
thisconn.query('DELETE FROM verification WHERE user_id = ' + userData.id, function (err: any, rows: any, fields: any) {
if (err) {
return thisconn.rollback(function () { throw err })
}
// COMMIT
thisconn.commit(function (err: any) {
if (err) {
return thisconn.rollback(function () { throw err })
}
})
})
})
})
callback(err)
})
},
/* ===== GitLab ===== */
getGitlabId: async function (userId: number) {
try {
const rows: any = await dbConnection.user.promise().query('SELECT gu.gitlab_userId FROM user_gitlab gu, user u WHERE u.id = "' + userId + '" and gu.user_id = u.id')
if (rows[0][0]) {
return rows[0][0].gitlab_userId
} else {
return null
}
} catch (err) {
console.error(err)
return err
}
},
addGitlabUser: function (data: any, callback: any) {
dbConnection.user.query('INSERT INTO user_gitlab SET ?', data, function (err: any) {
if (err) throw err
callback(err)
})
}
}
export { dbController }
import axios from 'axios'
import fs from 'fs'
import formData from 'form-data'
const env = process.env.NODE_ENV ?? 'testing'
const config = require('../config/config')[env]
const gitlabController = {
getUserByEmail: async function (email: string) {
return await axios({
method: 'get',
url: 'https://transfer.hft-stuttgart.de/gitlab/api/v4/users?search=' + email,
headers: { Authorization: 'Bearer ' + config.gitlab.token_readWriteProjects }
})
.then(res => res.data[0])
.catch(function (err) {
console.error(err)
return null
})
},
createNewPages: async function (newPagesData: any, newLogoFile: string, template: any) {
const data = new formData()
data.append('avatar', fs.createReadStream(newLogoFile))
return await axios({
method: 'post',
url: 'https://transfer.hft-stuttgart.de/gitlab/api/v4/projects/user/' + String(newPagesData.getOwnerGitlabId()) +
'?name=' + String(newPagesData.getName()) + '&description=' + String(newPagesData.getDesc()) + '&tag_list=website' +
'&use_custom_template=true&template_name=' + template,
headers: {
Authorization: 'Bearer ' + config.gitlab.token_readWriteProjects,
...data.getHeaders()
},
data: data
})
.then(res => res.data)
.catch(function (err) {
console.error('ERR Status: ' + err.response.status)
console.error('ERR Name: ' + err.response.data.message.name)
console.error('ERR Path: ' + err.response.data.message.path)
return err.response
})
},
updateProject: async function (updatedProjectData: any, newLogoFile: string) {
const data = new formData()
if (newLogoFile) {
data.append('avatar', fs.createReadStream(newLogoFile))
}
return await axios({
method: 'put',
url: 'https://transfer.hft-stuttgart.de/gitlab/api/v4/projects/' + updatedProjectData.getId() +
'?name=' + updatedProjectData.getName() + '&description=' + updatedProjectData.getDesc(),
headers: {
Authorization: 'Bearer ' + config.gitlab.token_readWriteProjects,
...data.getHeaders()
},
data: data
})
// .then(res => res.data[0])
.then(res => res.data)
.catch(function (err) {
console.error('ERR Status: ' + err.response.status)
console.error('ERR Name: ' + err.response.data.message.name)
console.error('ERR Path: ' + err.response.data.message.path)
return err.response
})
},
deleteProjectById: async function (projectId: number) {
// https://docs.gitlab.com/ee/api/projects.html#delete-project
return await axios({
method: 'delete',
url: 'https://transfer.hft-stuttgart.de/gitlab/api/v4/projects/' + projectId,
headers: {
Authorization: 'Bearer ' + config.gitlab.token_readWriteProjects
}
})
.then(res => true)
.catch(function (err) {
console.error('ERR Status: ' + err.response.status)
console.error('ERR Name: ' + err.response.data.message.name)
console.error('ERR Path: ' + err.response.data.message.path)
return false
})
},
getUserProjects: async function (gitlabUserId: number) {
return await axios({
method: 'get',
url: 'https://transfer.hft-stuttgart.de/gitlab/api/v4/users/' + gitlabUserId + '/projects?owned=true&visibility=public',
headers: {
Authorization: 'Bearer ' + config.gitlab.token_readWriteProjects
}
})
.then(res => res.data)
.catch(function (err) {
console.error(err)
return null
})
},
getProjectById: async function (projectId: number) {
return await axios({
method: 'get',
url: 'https://transfer.hft-stuttgart.de/gitlab/api/v4/projects/' + projectId,
headers: {
Authorization: 'Bearer ' + config.gitlab.token_readWriteProjects
}
})
.then(res => res.data)
.catch(function (err) {
console.error(err)
return null
})
},
getProjectPipelineLatestStatus: async function (projectId: number) {
return await axios({
method: 'get',
url: 'https://transfer.hft-stuttgart.de/gitlab/api/v4/projects/' + projectId + '/pipelines'
})
.then(res => res.data[0].status)
.catch(function (err) {
console.error(err)
return null
})
}
}
export { gitlabController }
// password requirement
function checkPasswordReq (pwd) {
if (pwd.length < 8) {
isBest = false
} else {
isBest = true
}
return isBest
}
const menu = [{ name: 'Informationen', combos: [{ name: 'Projekte', link: '/project' }, { name: 'Über das M4_LAB', link: '/projectoverview?projectID=1' }, { name: 'Kontakt', link: '/account/contact' }], type: 'dropdown', link: '#' }, { name: 'Zusammenarbeit', combos: [{ name: 'Mailinglisten', link: '/mailinglists' }, { name: 'Videokonferenzen', link: '/videoconference.html' }/* {'name':'...', 'link':'#'} */], type: 'dropdown', link: '#' }, { name: 'Events', combos: [{ name: 'Veranstaltungen der HfT', link: 'http://www.hft-stuttgart.de/Aktuell/Veranstaltungen/' }, { name: 'Veranstaltungen der HfT Forschung', link: 'https://www.hft-stuttgart.de/forschung/veranstaltungen' }], type: 'dropdown', link: '#' }, { name: 'Benutzerkonto', combos: [], type: '', link: '/account/' }]
const hft_links = [{ url: '/account/contact', name: 'Kontakt' }, { url: 'https://www.hft-stuttgart.de/impressum', name: 'Impressum' }, { url: 'https://www.hft-stuttgart.de/datenschutz', name: 'Datenschutz' }]
const socialmedias = [{ url: 'https://twitter.com/InnolabM4', name: 'fa-twitter' }, { url: 'https://www.facebook.com/HfTStuttgart/', name: 'fa-facebook-square' }, { url: 'https://www.instagram.com/m4_lab/', name: 'fa-instagram' }, { url: 'https://de.linkedin.com/school/hochschule-f%C3%BCr-technik-stuttgart-%E2%80%93-university-of-applied-sciences/', name: 'fa-linkedin' }, { url: 'https://www.youtube.com/channel/UCi0_JfF2qMZbOhOnNH5PyHA', name: 'fa-youtube' }]
const footer_images = [{ src: '/images/demo/Innovative_Hochschule_Initiative_BMBF_GWK_RGB.jpg', alt: 'Innovative Hochschule' }]
function prependChild (parent, child) {
parent.insertBefore(child, parent.childNodes[0])
}
function readCookie (cname) {
const name = cname + '='
const decodedCookie = decodeURIComponent(document.cookie)
const ca = decodedCookie.split(';')
for (let i = 0; i < ca.length; i++) {
let c = ca[i]
while (c.charAt(0) == ' ') {
c = c.substring(1)
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length)
}
}
return ''
}
function sendRequest (URL) {
console.log(document.cookie)
const xhr = new XMLHttpRequest()
xhr.open('POST', URL, true)
const token = readCookie('XSRF-TOKEN')
// Send the proper header information along with the request
xhr.setRequestHeader('X-CSRF-TOKEN', token)
xhr.send()
}
/* function head()
* creates header and prepends it to the documents body
*/
function head () {
const navheader = document.createElement('header')
navheader.id = 'header'
navheader.classList.add('clear')
// disclaimer
const alertdiv = document.createElement('div')
alertdiv.classList.add('alert', 'alert-danger', 'alert-dismissible', 'fade', 'show')
alertdiv.style = 'text-align:center;'
alertdiv.innerHTML = '<strong>Disclaimer</strong> This website is under construction and in prototype-phase. It is not for public use.'
const alertbutton = document.createElement('button')
alertbutton.type = 'button'
alertbutton.classList.add('close')
alertbutton.setAttribute('data-dismiss', 'alert')
alertbutton.innerHTML = '&times;'
prependChild(alertdiv, alertbutton)
// navigation header
const navbar = document.createElement('nav')
navbar.classList.add('navbar', 'navbar-expand-md', 'navbar-light')
navbar.style = 'background-color: #ffffff;'
const navbarcontainer = document.createElement('div')
navbarcontainer.classList.add('container')
const navbarheader = document.createElement('div')
navbarheader.classList.add('navbar-header')
// navigation header - logo
const link_m4lab = document.createElement('a')
link_m4lab.href = '/'
link_m4lab.classList.add('navbar-brand')
link_m4lab.innerHTML = "<img src='/img/header/Logozeile_Header.png' alt='Logo Innovationslabor M4_LAB'>"
navbarheader.appendChild(link_m4lab)
// navigation header - toggle button menu for mobile devices
const togglebutton = document.createElement('button')
togglebutton.classList.add('navbar-toggler')
togglebutton.type = 'button'
togglebutton.setAttribute('data-toggle', 'collapse')
togglebutton.setAttribute('data-target', '#navbarCollapse')
togglebutton.setAttribute('aria-controls', 'navbarCollapse')
togglebutton.setAttribute('aria-expanded', 'false')
togglebutton.setAttribute('aria-label', 'Toggle navigation')
togglebutton.innerHTML = "<span class='navbar-toggler-icon'></span>"
// nav menu
const navelements = document.createElement('ul')
navelements.id = 'navbarCollapse'
navelements.classList.add('collapse', 'nav', 'navbar-collapse', 'navbar-nav', 'justify-content-end')
for (let j = 0; j < menu.length; j++) {
const headitem = document.createElement('li')
const itemtype = menu[j].type
headitem.classList.add('nav-item')
const headlink = document.createElement('a')
headlink.href = menu[j].link
headlink.id = 'navbarDropdown' + j
headlink.classList.add('nav-link')
headlink.setAttribute('role', 'button')
if (itemtype == 'dropdown') {
headitem.classList.add('dropdown')
headlink.classList.add('dropdown-toggle')
headlink.setAttribute('data-toggle', 'dropdown')
headlink.setAttribute('aria-haspopup', 'true')
headlink.setAttribute('aria-expanded', 'false')
}
headlink.innerHTML = menu[j].name
if (itemtype == 'dropdown') {
const combodiv = document.createElement('div')
combodiv.id = headlink.id + '_par'
combodiv.setAttribute('aria-labelledby', headlink.id)
combodiv.classList.add('dropdown-menu')
for (let k = 0; k < menu[j].combos.length; k++) {
const combolink = document.createElement('a')
combolink.classList.add('dropdown-item')
combolink.href = menu[j].combos[k].link
combolink.innerHTML = menu[j].combos[k].name
combodiv.appendChild(combolink)
}
headitem.appendChild(combodiv)
}
prependChild(headitem, headlink)
navelements.appendChild(headitem)
}
navbarcontainer.appendChild(navbarheader)
navbarcontainer.appendChild(togglebutton)
navbarcontainer.appendChild(navelements)
navbar.appendChild(navbarcontainer)
navheader.appendChild(alertdiv)
navheader.appendChild(navbar)
prependChild(document.body, navheader)
}
/* function foot()
* creates footer and appends it to the documents body
*/
function foot () {
// add styles to <head> to manage sticky footer
const styles = `
@media only screen and (min-width: 768px) {
html {
position: relative;
min-height: 100%;
}
body {
margin-bottom: 120px; /* Margin bottom by footer height */
}
#homepage {
position: absolute;
bottom: 0;
width: 100%;
text-align: center;
}
}
`
const styleSheet = document.createElement('style')
styleSheet.type = 'text/css'
styleSheet.innerText = styles
document.head.appendChild(styleSheet)
const footerdiv = document.createElement('div')
footerdiv.id = 'homepage'
// footerdiv.classList.add("last", "clear");
footerdiv.innerHTML = '<hr>'
const containerdiv = document.createElement('div')
containerdiv.classList.add('container')
const containerdivrow = document.createElement('div')
containerdivrow.classList.add('row')
// bmbf
const bmbf = document.createElement('div')
bmbf.classList.add('col-md-auto')
bmbf.innerHTML = "<img src='/img/footer/Innovative_Hochschule_Initiative_BMBF_GWK_RGB.png' alt='Innovative Hochschule' style='height:90px'/>"
// m4labgrau
const m4labgrau = document.createElement('div')
m4labgrau.classList.add('col-md-auto')
m4labgrau.innerHTML = "<img src='/img/footer/M4_LAB_LOGO_Graustufen.png' alt='M4_LAB' style='height:80px'/>"
// socmed
const socialdiv = document.createElement('div')
socialdiv.classList.add('col-md-auto')
const socialrow = document.createElement('div')
socialrow.id = 'socialmediabuttons'
for (let j = 0; j < socialmedias.length; j++) {
const sociallink = document.createElement('a')
sociallink.href = socialmedias[j].url
const socialcontent = document.createElement('i')
socialcontent.classList.add('fab', socialmedias[j].name)
sociallink.appendChild(socialcontent)
socialrow.appendChild(sociallink)
socialrow.innerHTML += '&nbsp;'
}
socialdiv.appendChild(socialrow)
// contact
const contactdiv = document.createElement('div')
contactdiv.classList.add('col-md-auto', 'footer-unten')
contactdiv.innerHTML = 'Hochschule für Technik Stuttgart'
const rowdiv = document.createElement('div')
rowdiv.classList.add('row')
for (let i = 0; i < hft_links.length; i++) {
const coldiv = document.createElement('div')
coldiv.classList.add('contactrow', 'footer-unten')
const collink = document.createElement('a')
collink.innerHTML = hft_links[i].name
collink.classList.add('contact-lower')
collink.href = hft_links[i].url
coldiv.appendChild(collink)
rowdiv.appendChild(coldiv)
}
contactdiv.appendChild(rowdiv)
containerdivrow.appendChild(bmbf)
containerdivrow.appendChild(m4labgrau)
containerdivrow.appendChild(socialdiv)
containerdivrow.appendChild(contactdiv)
containerdiv.appendChild(containerdivrow)
footerdiv.appendChild(containerdiv)
document.body.appendChild(footerdiv)
}
head()
foot()
Markdown is supported
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