Skip to content

Commit

Permalink
Merge branch 'release/20.2.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
Parnswir committed Jan 22, 2020
2 parents 08cf360 + b439733 commit 24aa528
Show file tree
Hide file tree
Showing 104 changed files with 1,637 additions and 1,254 deletions.
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
10.16
10.17
24 changes: 24 additions & 0 deletions .pullapprove.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,31 @@ notifications:
comment: "The review is completed. Thanks @{{ author }}, we'll take it from here."

groups:
integrathors:
conditions:
- "'IntegraTHORs' in labels"
reviews:
required: 1 # 1 approval from this group are required
request: 2 # 2 reviews requests will be sent at a time
request_order: shuffle # reviewers will be chosen in a random order
reviewers:
teams:
- integrathors

loki:
conditions:
- "'Loki' in labels"
reviews:
required: 1 # 1 approval from this group are required
request: 2 # 2 reviews requests will be sent at a time
request_order: shuffle # reviewers will be chosen in a random order
reviewers:
teams:
- loki

client-core:
conditions:
- "'Loki' not in labels and 'IntegraTHORs' not in labels"
reviewers:
teams:
- client-core
Expand Down
34 changes: 3 additions & 31 deletions api.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,4 @@
const request = require('request');
const rp = require('request-promise');
const api = require('./helpers/apiHelper');
const { KEEP_ALIVE, BACKEND_URL } = require('./config/global');

const api = (req, { useCallback = false, json = true, backend = 'server' } = {}) => {
const headers = {};
if (req && req.cookies && req.cookies.jwt) {
headers.Authorization = (req.cookies.jwt.startsWith('Bearer ') ? '' : 'Bearer ') + req.cookies.jwt;
}
if (process.env.KEEP_ALIVE) {
headers.Connection = 'Keep-Alive';
}

const handler = useCallback ? request : rp;

let baseUrl;
switch (backend) {
case 'editor':
baseUrl = process.env.EDITOR_URL || 'http://localhost:4001';
break;
case 'server':
default:
baseUrl = process.env.BACKEND_URL || 'http://localhost:3030/';
}

return handler.defaults({
baseUrl,
json,
headers,
});
};

module.exports = api;
module.exports = api(BACKEND_URL, { keepAlive: KEEP_ALIVE });
4 changes: 4 additions & 0 deletions apiEditor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const api = require('./helpers/apiHelper');
const { EDITOR_URL } = require('./config/global');

module.exports = api(EDITOR_URL);
75 changes: 52 additions & 23 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,32 @@ const handlebars = require('handlebars');
const layouts = require('handlebars-layouts');
const handlebarsWax = require('handlebars-wax');
const Sentry = require('@sentry/node');
const { tokenInjector, duplicateTokenHandler } = require('./helpers/csrf');
const { Configuration } = require('@schul-cloud/commons');
const { tokenInjector, duplicateTokenHandler, csrfErrorHandler } = require('./helpers/csrf');

const { version } = require('./package.json');
const { sha } = require('./helpers/version');
const logger = require('./helpers/logger');

const {
KEEP_ALIVE,
SENTRY_DSN,
SC_DOMAIN,
SC_THEME,
REDIS_URI,
JWT_SHOW_TIMEOUT_WARNING_SECONDS,
JWT_TIMEOUT_SECONDS,
BACKEND_URL,
PUBLIC_BACKEND_URL,
} = require('./config/global');

const app = express();
const Config = new Configuration();
Config.init(app);

if (process.env.SENTRY_DSN) {
if (SENTRY_DSN) {
Sentry.init({
dsn: process.env.SENTRY_DSN,
dsn: SENTRY_DSN,
environment: app.get('env'),
release: version,
integrations: [
Expand All @@ -33,7 +48,7 @@ if (process.env.SENTRY_DSN) {
Sentry.configureScope((scope) => {
scope.setTag('frontend', false);
scope.setLevel('warning');
scope.setTag('domain', process.env.SC_DOMAIN || 'localhost');
scope.setTag('domain', SC_DOMAIN);
scope.setTag('sha', sha);
});
app.use(Sentry.Handlers.requestHandler());
Expand All @@ -43,7 +58,7 @@ if (process.env.SENTRY_DSN) {
const authHelper = require('./helpers/authentication');

// set custom response header for ha proxy
if (process.env.KEEP_ALIVE) {
if (KEEP_ALIVE) {
app.use((req, res, next) => {
res.setHeader('Connection', 'Keep-Alive');
next();
Expand All @@ -62,14 +77,14 @@ app.use(cors);

app.use(compression());
app.set('trust proxy', true);
const themeName = process.env.SC_THEME || 'default';
const themeName = SC_THEME;
// view engine setup
const handlebarsHelper = require('./helpers/handlebars');

const wax = handlebarsWax(handlebars)
.partials(path.join(__dirname, 'views/**/*.{hbs,js}'))
.helpers(layouts)
.helpers(handlebarsHelper.helpers);
.helpers(handlebarsHelper.helpers(app));

wax.partials(path.join(__dirname, `theme/${themeName}/views/**/*.{hbs,js}`));

Expand All @@ -84,14 +99,18 @@ app.set('view cache', true);

// uncomment after placing your favicon in /public
// app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(morgan('dev'));
app.use(morgan('dev', {
skip(req, res) {
return req && ((req.route || {}).path || '').includes('tsp-login');
},
}));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, `build/${themeName}`)));

let sessionStore;
const redisUrl = process.env.REDIS_URI;
const redisUrl = REDIS_URI;
if (redisUrl) {
logger.info(`Using Redis session store at '${redisUrl}'.`);
const RedisStore = connectRedis(session);
Expand Down Expand Up @@ -127,13 +146,27 @@ function removeIds(url) {

// Custom flash middleware
app.use(async (req, res, next) => {
// if there's a flash message in the session request, make it available in the response, then delete it
res.locals.notification = req.session.notification;
res.locals.inline = req.query.inline || false;
setTheme(res);
res.locals.domain = SC_DOMAIN;
res.locals.production = req.app.get('env') === 'production';
res.locals.env = req.app.get('env') || false; // TODO: ist das false hier nicht quatsch?
res.locals.SENTRY_DSN = SENTRY_DSN;
res.locals.JWT_SHOW_TIMEOUT_WARNING_SECONDS = Number(JWT_SHOW_TIMEOUT_WARNING_SECONDS);
res.locals.JWT_TIMEOUT_SECONDS = Number(JWT_TIMEOUT_SECONDS);
res.locals.BACKEND_URL = PUBLIC_BACKEND_URL || BACKEND_URL;
res.locals.version = version;
res.locals.sha = sha;
delete req.session.notification;
try {
await authHelper.populateCurrentUser(req, res);
} catch (error) {
logger.error('could not populate current user', error);
return next(error);
}
if (process.env.SENTRY_DSN) {
if (SENTRY_DSN) {
Sentry.configureScope((scope) => {
if (res.locals.currentUser) {
scope.setTag({ schoolId: res.locals.currentUser.schoolId });
Expand All @@ -142,18 +175,7 @@ app.use(async (req, res, next) => {
scope.request = { url: removeIds(url), header };
});
}
// if there's a flash message in the session request, make it available in the response, then delete it
res.locals.notification = req.session.notification;
res.locals.inline = req.query.inline || false;
setTheme(res);
res.locals.domain = process.env.SC_DOMAIN || 'localhost';
res.locals.production = req.app.get('env') === 'production';
res.locals.env = req.app.get('env') || false;
res.locals.SENTRY_DSN = process.env.SENTRY_DSN || false;
res.locals.version = version;
res.locals.sha = sha;
delete req.session.notification;
next();
return next();
});


Expand Down Expand Up @@ -185,7 +207,8 @@ app.use((req, res, next) => {
next(err);
});

// error handler
// error handlers
app.use(csrfErrorHandler);
app.use((err, req, res, next) => {
// set locals, only providing error in development
const status = err.status || err.statusCode || 500;
Expand All @@ -195,6 +218,12 @@ app.use((err, req, res, next) => {
} else {
res.locals.message = err.message;
}

if (res.locals && res.locals.message.includes('ESOCKETTIMEDOUT') && err.options) {
const message = `ESOCKETTIMEDOUT by route: ${err.options.baseUrl + err.options.uri}`;
logger.warn(message);
Sentry.captureMessage(message);
}
res.locals.error = req.app.get('env') === 'development' ? err : { status };

if (res.locals.currentUser) res.locals.loggedin = true;
Expand Down
20 changes: 20 additions & 0 deletions config/default.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"title": "HPI Schul-Cloud Configuration",
"type": "object",
"properties": {
"TEACHER_VISIBILITY_FOR_EXTERNAL_TEAM_INVITATION": {
"type": "string",
"default": "opt-out",
"enum": [
"disabled",
"opt-in",
"opt-out",
"enabled"
],
"description": "Defines wether external team invitation shows teachers from different schools or not. if enabled system wide there are options general enabled or opt-in/-out by user required."
}
},
"required": [
"TEACHER_VISIBILITY_FOR_EXTERNAL_TEAM_INVITATION"
]
}
38 changes: 38 additions & 0 deletions config/global.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const util = require('util');
const logger = require('../helpers/logger');

const {
KEEP_ALIVE = false,
BACKEND_URL = 'http://localhost:3030/',
PUBLIC_BACKEND_URL,
EDITOR_URL = 'http://localhost:4001',
SENTRY_DSN = false,
SC_DOMAIN = 'localhost',
SC_THEME = 'default',
REDIS_URI,
REQUEST_TIMEOUT = 15000, // 15 sec
NODE_ENV = 'development',
JWT_SHOW_TIMEOUT_WARNING_SECONDS = 3600, // 60 min
JWT_TIMEOUT_SECONDS,
MAXIMUM_ALLOWABLE_TOTAL_ATTACHMENTS_SIZE_BYTE = (5 * 1024 * 1024), // 5MB
} = process.env;

const exp = {
KEEP_ALIVE,
BACKEND_URL,
PUBLIC_BACKEND_URL,
EDITOR_URL,
SENTRY_DSN,
SC_DOMAIN,
SC_THEME,
REDIS_URI,
REQUEST_TIMEOUT,
NODE_ENV,
JWT_SHOW_TIMEOUT_WARNING_SECONDS,
JWT_TIMEOUT_SECONDS,
MAXIMUM_ALLOWABLE_TOTAL_ATTACHMENTS_SIZE_BYTE,
};

logger.info(util.inspect(exp, { depth: 1, compact: false }));

module.exports = exp;
54 changes: 37 additions & 17 deletions controllers/account.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,20 @@ router.post('/', (req, res) => {
password,
passwordNew,
} = req.body;
const discoverable = !!req.body.discoverable;
return api(req).patch(`/accounts/${res.locals.currentPayload.accountId}`, {
json: {
password_verification: password,
password: passwordNew !== '' ? passwordNew : undefined,
}
}).then(() => {
return api(req).patch(`/users/${res.locals.currentUser._id}`, {
json: {
firstName,
lastName,
email,
discoverable,
},
}).then(authHelper.populateCurrentUser.bind(this, req, res)).then(() => {
res.redirect('/account/');
});
}).catch((err) => {
},
}).then(() => api(req).patch(`/users/${res.locals.currentUser._id}`, {
json: {
firstName,
lastName,
email,
},
}).then(authHelper.populateCurrentUser.bind(this, req, res)).then(() => {
res.redirect('/account/');
})).catch((err) => {
res.render('account/settings', {
title: 'Dein Account',
notification: {
Expand All @@ -47,7 +43,6 @@ router.post('/', (req, res) => {
router.get('/', (req, res, next) => {
const isSSO = Boolean(res.locals.currentPayload.systemId);
const isDiscoverable = res.locals.currentUser.discoverable;
const hideVisibilitySettings = (res.locals.currentRole === 'Schüler' || process.env.IGNORE_DISCOVERABILITY);
Promise.all([
api(req).get(`/oauth2/auth/sessions/consent/${res.locals.currentUser._id}`),
(process.env.NOTIFICATION_SERVICE_ENABLED ? api(req).get('/notification/devices') : null),
Expand All @@ -67,15 +62,13 @@ router.get('/', (req, res, next) => {
session,
userId: res.locals.currentUser._id,
sso: isSSO,
hideVisibilitySettings,
isDiscoverable,
});
}).catch(() => {
res.render('account/settings', {
title: 'Dein Account',
userId: res.locals.currentUser._id,
sso: isSSO,
hideVisibilitySettings,
isDiscoverable,
});
});
Expand Down Expand Up @@ -116,4 +109,31 @@ router.post('/preferences', (req, res, next) => {
.catch(() => 'Es ist ein Fehler bei den Präferenzen aufgetreten!');
});

router.post('/teamSettings', (req, res) => {
let discoverable = null;
if (req.body.discoverable === 'true') {
discoverable = true;
}
if (req.body.discoverable === 'false') {
discoverable = false;
}
return api(req).patch(`/users/${res.locals.currentUser._id}`, {
json: {
discoverable,
},
})
.then(authHelper.populateCurrentUser.bind(this, req, res)).then(() => {
res.redirect('/account/');
})
.catch((err) => {
res.render('account/settings', {
title: 'Dein Account',
notification: {
type: 'danger',
message: err.error.message,
},
});
});
});

module.exports = router;
Loading

0 comments on commit 24aa528

Please sign in to comment.