Fix most glaring bugs and vulnerabilities
This commit is contained in:
@@ -11,6 +11,25 @@ exports.listComments = async (req, res) => {
|
||||
filters.ctxId = null
|
||||
}
|
||||
|
||||
if (filters.ctxType === 'entry_dict_int') {
|
||||
const { dictionary_id: dictionaryId } = await Entry.fetch(filters.ctxId)
|
||||
const isEditor = req.user.hasAnyDictionaryRole(dictionaryId)
|
||||
const isPortalAdmin = req.user.hasRole('portal admin')
|
||||
const isDictionariesAdmin = req.user.hasRole('dictionaries admin')
|
||||
if (!(isEditor || isPortalAdmin || isDictionariesAdmin)) {
|
||||
return res.status(400).end()
|
||||
}
|
||||
} else if (filters.ctxType === 'entry_consult_int') {
|
||||
const isConsultantForEntry = req.user.isEditorOfConsultancyEntry(
|
||||
filters.ctxId
|
||||
)
|
||||
const isPortalAdmin = req.user.hasRole('portal admin')
|
||||
const isConsultancyAdmin = req.user.hasRole('consultancy admin')
|
||||
if (!(isConsultantForEntry || isPortalAdmin || isConsultancyAdmin)) {
|
||||
return res.status(400).end()
|
||||
}
|
||||
}
|
||||
|
||||
const {
|
||||
pages_total: numberOfAllPages,
|
||||
comments,
|
||||
@@ -38,20 +57,55 @@ exports.createComment = async (req, res) => {
|
||||
res.send({ comments, pagesTotal })
|
||||
}
|
||||
|
||||
exports.seedComments = async (req, res) => {
|
||||
const { commentCount } = req.params
|
||||
await Comment.seed(commentCount)
|
||||
res.send(`${commentCount} new comments generated`)
|
||||
}
|
||||
|
||||
exports.clearComments = async (req, res) => {
|
||||
await Comment.clear()
|
||||
res.send('All comments cleared')
|
||||
}
|
||||
|
||||
exports.updateStatus = async (req, res) => {
|
||||
const commentId = req.body.params.id
|
||||
const commentStatus = req.body.params.status
|
||||
|
||||
const { ctxType, ctxId } = await Comment.fetchContextById(commentId)
|
||||
|
||||
let canUpdateStatus = false
|
||||
switch (ctxType) {
|
||||
case 'portal':
|
||||
if (req.user.hasRole('portal admin')) canUpdateStatus = true
|
||||
break
|
||||
|
||||
case 'dictionary':
|
||||
if (
|
||||
req.user.hasRole('portal admin') ||
|
||||
req.user.hasRole('dictionaries admin')
|
||||
) {
|
||||
canUpdateStatus = true
|
||||
}
|
||||
break
|
||||
|
||||
case 'consultancy':
|
||||
if (
|
||||
req.user.hasRole('portal admin') ||
|
||||
req.user.hasRole('consultancy admin')
|
||||
) {
|
||||
canUpdateStatus = true
|
||||
}
|
||||
break
|
||||
|
||||
case 'entry_dict_ext': {
|
||||
const { dictionary_id: dictionaryId } = await Entry.fetch(ctxId)
|
||||
|
||||
if (
|
||||
req.user.hasRole('portal admin') ||
|
||||
req.user.hasRole('dictionaries admin') ||
|
||||
req.user.hasDictionaryRole(dictionaryId, 'administration')
|
||||
) {
|
||||
canUpdateStatus = true
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
default:
|
||||
throw Error('Invalid context type')
|
||||
}
|
||||
|
||||
if (!canUpdateStatus) return res.status(400).end()
|
||||
|
||||
await Comment.updateStatus(commentId, commentStatus)
|
||||
res.send('Visibility changed')
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
const user = require('../../../middleware/user')
|
||||
const ConsultancyEntry = require('../../../models/consultancy-entry')
|
||||
const Domain = require('../../../models/domain')
|
||||
const User = require('../../../models/user')
|
||||
@@ -16,20 +17,6 @@ const generateQuery = require('../../../models/helpers/search/generate-query')
|
||||
|
||||
const consultancy = {}
|
||||
|
||||
consultancy.listEntries = async (req, res) => {
|
||||
const consultancyEntryList = await ConsultancyEntry.fetchAll()
|
||||
const data = {}
|
||||
data.consEntryList = consultancyEntryList
|
||||
res.send(data)
|
||||
}
|
||||
|
||||
consultancy.listNewEntries = async (req, res) => {
|
||||
const consultancyNewEntryList = await ConsultancyEntry.fetchAllNew()
|
||||
const data = {}
|
||||
data.consultancyNewEntryList = consultancyNewEntryList
|
||||
res.send(data)
|
||||
}
|
||||
|
||||
consultancy.sendPaginationData = async (req, res) => {
|
||||
let requestType = req.query.type
|
||||
const isAdminPage = req.query.isAdmin === 'true'
|
||||
@@ -325,9 +312,12 @@ consultancy.publish = async (req, res) => {
|
||||
const author = await User.fetchUser(entry.authorId)
|
||||
const portalName = await getInstanceSetting(`portal_name_${author.language}`)
|
||||
const renderAsync = promisify(req.app.render.bind(req.app))
|
||||
const emailHtml = await renderAsync('email/consultancy-publish-notify', {
|
||||
portalName
|
||||
})
|
||||
const emailHtml = await renderAsync(
|
||||
`email/consultancy-publish-notify_${author.language}`,
|
||||
{
|
||||
portalName
|
||||
}
|
||||
)
|
||||
await email.send({
|
||||
to: author.email,
|
||||
subject: i18next.t('Objava terminološkega vprašanja', {
|
||||
@@ -342,29 +332,38 @@ consultancy.publish = async (req, res) => {
|
||||
res.send()
|
||||
}
|
||||
|
||||
consultancy.updateQuestion = async (req, res) => {
|
||||
const { id, questionTitle, domain: domainId, question, answer } = req.body
|
||||
consultancy.updateQuestion = [
|
||||
(req, res, next) => {
|
||||
const { id } = req.body
|
||||
|
||||
if (!id) return res.status(400).send({})
|
||||
if (!id) return res.status(400).send({})
|
||||
|
||||
if (questionTitle === '' || question === '' || answer === '') {
|
||||
return res
|
||||
.status(422)
|
||||
.send(req.t('Polja naslov, vprašanje in mnenje so obvezna!'))
|
||||
req.entryId = id
|
||||
next()
|
||||
},
|
||||
user.canConsultEntry,
|
||||
async (req, res) => {
|
||||
const { id, questionTitle, domain: domainId, question, answer } = req.body
|
||||
|
||||
if (questionTitle === '' || question === '' || answer === '') {
|
||||
return res
|
||||
.status(422)
|
||||
.send(req.t('Polja naslov, vprašanje in mnenje so obvezna!'))
|
||||
}
|
||||
|
||||
const entry = await ConsultancyEntry.fetchById(id)
|
||||
entry.domainPrimaryId = domainId > 0 ? domainId : null
|
||||
entry.question = question
|
||||
entry.answer = answer // helper.removeHtmlTags(answer).trim()
|
||||
entry.title = questionTitle
|
||||
|
||||
// TODO Luka: Miha, update only fields that were updated.
|
||||
await ConsultancyEntry.updateQuestion(entry)
|
||||
await ConsultancyEntry.indexIntoSearchEngine(id, true)
|
||||
|
||||
res.send({})
|
||||
}
|
||||
|
||||
const entry = await ConsultancyEntry.fetchById(id)
|
||||
entry.domainPrimaryId = domainId > 0 ? domainId : null
|
||||
entry.question = question
|
||||
entry.answer = answer // helper.removeHtmlTags(answer).trim()
|
||||
entry.title = questionTitle
|
||||
|
||||
// TODO Luka: Miha, update only fields that were updated.
|
||||
await ConsultancyEntry.updateQuestion(entry)
|
||||
await ConsultancyEntry.indexIntoSearchEngine(id, true)
|
||||
|
||||
res.send({})
|
||||
}
|
||||
]
|
||||
|
||||
consultancy.insertNonModerator = async (req, res) => {
|
||||
const questionId = req.body.question_id
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
const DemoPaginacija = require('../../../models/demo-paginacija')
|
||||
const { DEFAULT_HITS_PER_PAGE } = require('../../../config/settings')
|
||||
|
||||
exports.list = async (req, res) => {
|
||||
const resultsPerPage = req.user?.hitsPerPage || DEFAULT_HITS_PER_PAGE
|
||||
|
||||
const page = +req.query.p > 0 ? +req.query.p : 1
|
||||
|
||||
const { pages_total: numberOfAllPages, results } = await DemoPaginacija.fetch(
|
||||
resultsPerPage,
|
||||
page
|
||||
)
|
||||
|
||||
res.send({ page, numberOfAllPages, results })
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
const { rm } = require('fs/promises')
|
||||
const user = require('../../../middleware/user')
|
||||
const Dictionary = require('../../../models/dictionary')
|
||||
const Entry = require('../../../models/entry')
|
||||
const Extraction = require('../../../models/extraction')
|
||||
@@ -69,7 +70,11 @@ dictionary.deleteEntry = async (req, res) => {
|
||||
await Promise.all([
|
||||
Dictionary.updateMetadataAfterModifyingEntries(dictionaryId),
|
||||
deleteEntryFromIndex(entryId, true),
|
||||
minEntriesRequirementCheckAndAct.onDelete(dictionaryId, req.app)
|
||||
minEntriesRequirementCheckAndAct.onDelete(
|
||||
dictionaryId,
|
||||
req.app,
|
||||
req.determinedLanguage
|
||||
)
|
||||
])
|
||||
|
||||
res.end()
|
||||
@@ -84,7 +89,11 @@ dictionary.deleteAllEntries = async (req, res) => {
|
||||
await Promise.all([
|
||||
Dictionary.updateMetadataAfterModifyingEntries(dictionaryId),
|
||||
deleteDictionaryEntriesFromIndex(dictionaryId),
|
||||
minEntriesRequirementCheckAndAct.onDelete(dictionaryId, req.app)
|
||||
minEntriesRequirementCheckAndAct.onDelete(
|
||||
dictionaryId,
|
||||
req.app,
|
||||
req.determinedLanguage
|
||||
)
|
||||
])
|
||||
|
||||
res.end()
|
||||
@@ -124,12 +133,19 @@ dictionary.delete = async (req, res) => {
|
||||
res.end()
|
||||
}
|
||||
|
||||
dictionary.updateDomainLabels = async (req, res) => {
|
||||
const { dictionaryId, payload } = req.body.params
|
||||
dictionary.updateDomainLabels = [
|
||||
(req, res, next) => {
|
||||
req.dictionaryId = req.body.params.dictionaryId
|
||||
next()
|
||||
},
|
||||
user.canAdministrateDictionary,
|
||||
async (req, res) => {
|
||||
const { dictionaryId, payload } = req.body.params
|
||||
|
||||
await Dictionary.updateDomainLabel(dictionaryId, payload)
|
||||
res.end()
|
||||
}
|
||||
await Dictionary.updateDomainLabel(dictionaryId, payload)
|
||||
res.end()
|
||||
}
|
||||
]
|
||||
|
||||
dictionary.renovateSecondaryDomains = async (req, res) => {
|
||||
const data = req.body.params.payload
|
||||
@@ -152,7 +168,11 @@ dictionary.listDictionaries = async (req, res) => {
|
||||
const page = +req.query.p > 0 ? +req.query.p : 1
|
||||
|
||||
const { pages_total: numberOfAllPages, results } =
|
||||
await Dictionary.fetchAllAdminDictionaries(resultsPerPage, page)
|
||||
await Dictionary.fetchAllAdminDictionaries(
|
||||
req.determinedLanguage,
|
||||
resultsPerPage,
|
||||
page
|
||||
)
|
||||
|
||||
res.send({ page, numberOfAllPages, results })
|
||||
}
|
||||
@@ -222,15 +242,6 @@ dictionary.listSecondaryDomainData = async (req, res) => {
|
||||
})
|
||||
}
|
||||
|
||||
dictionary.listSecondaryDomains = async (req, res) => {
|
||||
const resultsPerPage = req.user?.hitsPerPage || DEFAULT_HITS_PER_PAGE
|
||||
const page = +req.query.p > 0 ? +req.query.p : 1
|
||||
const { pages_total: numberOfAllPages, results } =
|
||||
await Dictionary.fetchAllSecondaryDomains(resultsPerPage, page)
|
||||
|
||||
res.send({ page, numberOfAllPages, results })
|
||||
}
|
||||
|
||||
dictionary.showImportFromFileForm = async (req, res) => {
|
||||
const resultsPerPage = req.user?.hitsPerPage || DEFAULT_HITS_PER_PAGE
|
||||
const { dictionaryId } = req.params
|
||||
@@ -252,7 +263,7 @@ dictionary.showExportToFileForm = async (req, res) => {
|
||||
}
|
||||
|
||||
dictionary.importFromExtraction = async (req, res) => {
|
||||
const { id: dictionaryId, extractionId } = req.params
|
||||
const { dictionaryId, extractionId } = req.params
|
||||
const { from, to } = req.body
|
||||
const fromIndex = +from > 1 ? Math.floor(from) - 1 : 0
|
||||
const toIndex = Number.isInteger(+(to === '' ? undefined : to))
|
||||
@@ -279,7 +290,7 @@ dictionary.importFromExtraction = async (req, res) => {
|
||||
}
|
||||
|
||||
dictionary.exportBegin = async (req, res) => {
|
||||
const dictionaryId = req.params.id
|
||||
const { dictionaryId } = req.params
|
||||
const exportParams = {
|
||||
isValidFilter:
|
||||
req.body.isValidFilter === 'on' ? undefined : req.body.isValidFilter,
|
||||
|
||||
@@ -166,7 +166,7 @@ extraction.ossSearch = [
|
||||
|
||||
extraction.ossConfirmParams = async (req, res) => {
|
||||
const { id: extractionId } = req.params
|
||||
const { ossParams } = await Extraction.fetch(extractionId)
|
||||
const { ossParams } = req.extractionData
|
||||
if (ossParams.status !== 'valid') throw Error('OSS params not valid')
|
||||
await Extraction.updateOssParams(extractionId, {
|
||||
params: ossParams.params,
|
||||
@@ -177,7 +177,7 @@ extraction.ossConfirmParams = async (req, res) => {
|
||||
|
||||
extraction.begin = async (req, res) => {
|
||||
const extractionId = req.params.id
|
||||
const extraction = await Extraction.fetch(extractionId)
|
||||
const extraction = req.extractionData
|
||||
const canBegin = await checkIfcanBegin(extraction)
|
||||
if (!canBegin) throw Error('Extraction does not qualify to be ran')
|
||||
|
||||
@@ -268,11 +268,6 @@ extraction.termCandidatesExport = async (req, res) => {
|
||||
}
|
||||
}
|
||||
|
||||
extraction.listFinishedForUser = async (req, res) => {
|
||||
const extractions = await Extraction.fetchFinishedForUser(req.user.id)
|
||||
res.send(extractions)
|
||||
}
|
||||
|
||||
extraction.listTermCandidates = async (req, res) => {
|
||||
const extractionId = req.params.id
|
||||
const termCandidatesJson = await Extraction.fetchTermCandidatesJson(
|
||||
|
||||
@@ -178,7 +178,8 @@ exports.listFilteredDictionaries = async (req, res) => {
|
||||
hitsPerPage,
|
||||
page,
|
||||
orderAttribute,
|
||||
orderIndex
|
||||
orderIndex,
|
||||
req.determinedLanguage
|
||||
)
|
||||
|
||||
dictionaries = dictionaries.map(e => {
|
||||
@@ -246,6 +247,9 @@ exports.showModalFilterResults = async (req, res) => {
|
||||
|
||||
const aggregationRaw = await searchEntryIndex(aggregateQuery)
|
||||
|
||||
const aggregation = await prepareAggregation(aggregationRaw)
|
||||
const aggregation = await prepareAggregation(
|
||||
aggregationRaw,
|
||||
req.determinedLanguage
|
||||
)
|
||||
res.send(prepareSeachFilterData(aggregation, filters))
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
const debug = require('debug')('termPortal:controllers/api/v1/system')
|
||||
const Eurotermbank = require('../../../models/system/eurotermbank')
|
||||
// const debug = require('debug')('termPortal:controllers/api/v1/system')
|
||||
|
||||
exports.handleCspReports = (req, res) => {
|
||||
debug(req.body)
|
||||
res.sendStatus(200)
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(req.body)
|
||||
res.end()
|
||||
}
|
||||
|
||||
exports.syncWithEurotermbank = async (req, res) => {
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
const { randomBytes } = require('crypto')
|
||||
const { promisify } = require('util')
|
||||
const RandomBytesAsync = promisify(randomBytes)
|
||||
const User = require('../../../models/user')
|
||||
const { DEFAULT_HITS_PER_PAGE } = require('../../../config/settings')
|
||||
const email = require('../../../models/email')
|
||||
const { logout: logoutUser } = require('../../../middleware/user')
|
||||
const { origin } = require('../../../config/keys')
|
||||
const {
|
||||
DEFAULT_HITS_PER_PAGE,
|
||||
CHANGE_EMAIL_TOKEN_VALID_DAYS
|
||||
} = require('../../../config/settings')
|
||||
|
||||
const users = {}
|
||||
users.listUsers = async (req, res) => {
|
||||
@@ -23,13 +32,103 @@ users.updateHitsPerPage = async (req, res) => {
|
||||
res.status(200).send()
|
||||
}
|
||||
|
||||
users.updateFristNameAndSurname = async (req, res) => {
|
||||
const firstname = req.body.name
|
||||
const surname = req.body.surname
|
||||
users.updateBasicData = async (req, res) => {
|
||||
const { firstName, lastName, email: newEmail } = req.body
|
||||
|
||||
await User.updateFirstNameAndLastName(req.user.userName, firstname, surname)
|
||||
// TODO Validation (valid email format, ...).
|
||||
|
||||
res.status(200).send()
|
||||
const oldEmail = await User.updateFirstNameAndLastName(
|
||||
req.user.id,
|
||||
firstName,
|
||||
lastName
|
||||
)
|
||||
|
||||
if (newEmail === oldEmail) return res.send()
|
||||
|
||||
if (await User.isEmailAlreadyTaken(newEmail)) {
|
||||
req.flash('info', req.t('Elektronski naslov uporablja že drug uporabnik.'))
|
||||
return res.send()
|
||||
}
|
||||
|
||||
const changeEmailToken = (await RandomBytesAsync(32)).toString('hex')
|
||||
await User.saveChangeEmailToken(req.user.id, changeEmailToken, newEmail)
|
||||
let changeEmailLink = new URL('/sprememba-elektronskega-naslova', origin)
|
||||
changeEmailLink.searchParams.set('token', changeEmailToken)
|
||||
changeEmailLink = changeEmailLink.href
|
||||
const renderAsync = promisify(req.app.render.bind(req.app))
|
||||
const emailHtml = await renderAsync(
|
||||
`email/user-change-email-token_${req.language}`,
|
||||
{
|
||||
username: req.user.userName,
|
||||
changeEmailLink
|
||||
}
|
||||
)
|
||||
await email.send({
|
||||
to: newEmail,
|
||||
subject: req.t('Sprememba elektronskega naslova'),
|
||||
html: emailHtml
|
||||
})
|
||||
|
||||
const message =
|
||||
req.t(
|
||||
'Na vaš elektronski naslov smo vam poslali sporočilo s povezavo, s katero boste potrdili menjavo elektronskega naslova. Povezava za potrditev je veljavna '
|
||||
) +
|
||||
`${CHANGE_EMAIL_TOKEN_VALID_DAYS} ` +
|
||||
req.t('dni.')
|
||||
|
||||
req.flash('info', message)
|
||||
res.send()
|
||||
}
|
||||
|
||||
users.updatePassword = async (req, res) => {
|
||||
const { passwordOld, passwordNew, passwordNewRepeat } = req.body
|
||||
|
||||
// TODO Validation (mirror front end validation, ...).
|
||||
if (passwordNew !== passwordNewRepeat) {
|
||||
const err = Error(req.t('Gesli se ne ujemata'))
|
||||
err.status = 403
|
||||
err.displayInProd = true
|
||||
|
||||
throw err
|
||||
}
|
||||
|
||||
await User.changePassword(req.user.id, passwordOld, passwordNew, req.t)
|
||||
|
||||
// TODO Invalidate or log out all session for this user. More details in deleteCurrent method TODO.
|
||||
|
||||
const renderAsync = promisify(req.app.render.bind(req.app))
|
||||
const emailHtml = await renderAsync(
|
||||
`email/user-change-password_${req.language}`,
|
||||
{
|
||||
username: req.user.userName
|
||||
}
|
||||
)
|
||||
await email.send({
|
||||
to: req.user.email,
|
||||
subject: req.t('Sprememba gesla'),
|
||||
html: emailHtml
|
||||
})
|
||||
|
||||
req.flash('info', 'Geslo je bilo spremenjeno.')
|
||||
res.send()
|
||||
}
|
||||
|
||||
users.deleteCurrent = [
|
||||
async (req, res, next) => {
|
||||
await User.closeAccount(req.user.id)
|
||||
next()
|
||||
},
|
||||
logoutUser,
|
||||
(req, res) => {
|
||||
// TODO Invalidate or log out all session for this user. Current workaround is in passport.deserializeUser.
|
||||
// You can probably do it in 1 of 3 ways:
|
||||
// 1. Brute force; loop through all sessions (using session store's all or ids methods),
|
||||
// look up their values and remote the ones with user's id
|
||||
// 2. Include user Id as part of session key; something similar to https://github.com/tj/connect-redis/issues/210#issuecomment-1336545115
|
||||
// 3. Create some kind of inverse index, mapping user id to his/hers sessions (also mentioned in issue linked above)
|
||||
req.flash('info', req.t('Vaš uporabniški račun je bil uspešno izbrisan.'))
|
||||
res.send()
|
||||
}
|
||||
]
|
||||
|
||||
module.exports = users
|
||||
|
||||
@@ -46,11 +46,15 @@ consultancy.search = async (req, res) => {
|
||||
consultancy.specificQuestion = async (req, res) => {
|
||||
const { id } = req.params
|
||||
|
||||
// TODO validation: is id of proper format and does a question with it actually exist.
|
||||
|
||||
// TODO i18n TIME FORMAT
|
||||
const entry = await ConsultancyEntry.fetchByIdWithFormattedTime(id)
|
||||
// const author = await User.fetchUser(entry.authorId)
|
||||
|
||||
const allPrimaryDomains = await Dictionary.fetchAllPrimaryDomains()
|
||||
const allPrimaryDomains = await Dictionary.fetchAllPrimaryDomains(
|
||||
req.determinedLanguage
|
||||
)
|
||||
|
||||
entry.answerAuthors = entry.answerAuthors.filter(author => author !== '')
|
||||
|
||||
@@ -86,7 +90,9 @@ consultancy.specificQuestion = async (req, res) => {
|
||||
}
|
||||
|
||||
consultancy.new = async (req, res) => {
|
||||
const allPrimaryDomains = await Dictionary.fetchAllPrimaryDomains()
|
||||
const allPrimaryDomains = await Dictionary.fetchAllPrimaryDomains(
|
||||
req.determinedLanguage
|
||||
)
|
||||
|
||||
res.locals.isOwnConsultancyEnabled =
|
||||
(await getInstanceSetting('consultancy_type')) === 'own'
|
||||
@@ -110,12 +116,9 @@ consultancyAdmin.new = async (req, res) => {
|
||||
}
|
||||
|
||||
consultancyAdmin.users = async (req, res) => {
|
||||
const allPrimaryDomains = await Dictionary.fetchAllPrimaryDomains()
|
||||
|
||||
const users = await User.fetchConsultants()
|
||||
|
||||
res.render('pages/consultancy/admin/users', {
|
||||
allPrimaryDomains,
|
||||
users,
|
||||
title: req.t('Svetovalci')
|
||||
})
|
||||
@@ -175,11 +178,7 @@ consultancyAdmin.inProgress = async (req, res) => {
|
||||
}
|
||||
|
||||
consultancyAdmin.statistics = async (req, res) => {
|
||||
const allPrimaryDomains = await Dictionary.fetchAllPrimaryDomains()
|
||||
|
||||
res.render('pages/consultancy/admin/statistics', {
|
||||
allPrimaryDomains
|
||||
})
|
||||
res.render('pages/consultancy/admin/statistics')
|
||||
}
|
||||
|
||||
consultancyAdmin.edit = async (req, res) => {
|
||||
@@ -189,18 +188,11 @@ consultancyAdmin.edit = async (req, res) => {
|
||||
sentFrom[key] = true
|
||||
|
||||
const moderator = await ConsultancyEntry.getModerator(id)
|
||||
const editors = await ConsultancyEntry.getEditors(id)
|
||||
if (
|
||||
req.user.hasRole('consultancy admin') ||
|
||||
req.user.hasRole('portal admin')
|
||||
) {
|
||||
console.log('Editor guard omitted due to being administrator')
|
||||
} else if (editors.filter(editors => editors.id === req.user.id) < 1) {
|
||||
return res.send('You do not have permsisions to edit this answer')
|
||||
}
|
||||
// TODO i18n TIME FORMAT
|
||||
const entry = await ConsultancyEntry.fetchByIdWithFormattedTime(id)
|
||||
const allPrimaryDomains = await Dictionary.fetchAllPrimaryDomains()
|
||||
const allPrimaryDomains = await Dictionary.fetchAllPrimaryDomains(
|
||||
req.determinedLanguage
|
||||
)
|
||||
const author = await User.fetchUser(entry.authorId)
|
||||
|
||||
const isPublished = entry.status === 'published'
|
||||
@@ -318,7 +310,9 @@ async function consultancyRequest(
|
||||
) {
|
||||
const searchString = req.query.q?.trim() ?? ''
|
||||
|
||||
let allPrimaryDomains = await Dictionary.fetchAllPrimaryDomains()
|
||||
let allPrimaryDomains = await Dictionary.fetchAllPrimaryDomains(
|
||||
req.determinedLanguage
|
||||
)
|
||||
|
||||
/// filter selected domains for the prompt ///
|
||||
// Not duplicates of this code arise...
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
const DemoPaginacija = require('../models/demo-paginacija')
|
||||
const { DEFAULT_HITS_PER_PAGE } = require('../config/settings')
|
||||
|
||||
const demoPaginacija = {}
|
||||
|
||||
demoPaginacija.izrišiStran = async (req, res) => {
|
||||
const resultsPerPage = req.user?.hitsPerPage || DEFAULT_HITS_PER_PAGE
|
||||
|
||||
const { pages_total: numberOfAllPages, results } = await DemoPaginacija.fetch(
|
||||
resultsPerPage,
|
||||
1
|
||||
)
|
||||
|
||||
res.render('pages/demo-paginacija', { numberOfAllPages, results })
|
||||
}
|
||||
|
||||
module.exports = demoPaginacija
|
||||
@@ -2,6 +2,7 @@ const { unlink } = require('fs/promises')
|
||||
const { promisify } = require('util')
|
||||
const multer = require('multer')
|
||||
const debug = require('debug')('termPortal:controllers/dictionary')
|
||||
const user = require('../middleware/user')
|
||||
const Dictionary = require('../models/dictionary')
|
||||
const Entry = require('../models/entry')
|
||||
const User = require('../models/user')
|
||||
@@ -19,6 +20,7 @@ const {
|
||||
const SFDSuggestionImporter = require('./helpers/search-filter-data-suggestion-importer')
|
||||
const Extraction = require('../models/extraction')
|
||||
const { isGeneratorFunction } = require('util/types')
|
||||
const { capitalize } = require('../utils')
|
||||
|
||||
const importFileBodyParser = multer({
|
||||
dest: `${DATA_FILES_PATH}/dict_import_temp`,
|
||||
@@ -38,7 +40,10 @@ const dictionary = {}
|
||||
dictionary.list = async (req, res) => {
|
||||
let dictionaries
|
||||
if (req.isAuthenticated()) {
|
||||
dictionaries = await Dictionary.fetchAllByUser(req.user.id)
|
||||
dictionaries = await Dictionary.fetchAllByUser(
|
||||
req.user.id,
|
||||
req.determinedLanguage
|
||||
)
|
||||
}
|
||||
res.render('pages/dictionaries/list', {
|
||||
title: req.t('Seznam slovarjev'),
|
||||
@@ -47,13 +52,11 @@ dictionary.list = async (req, res) => {
|
||||
}
|
||||
|
||||
dictionary.new = async (req, res) => {
|
||||
// TODO Once english language is implemented, gather selected language (sl/en) from request ~ (cookies?)
|
||||
const language = 'name_sl'
|
||||
const [allPrimaryDomains, allSecondaryDomains, allLanguages] =
|
||||
await Promise.all([
|
||||
Dictionary.fetchAllPrimaryDomains(),
|
||||
Dictionary.fetchAllPrimaryDomains(req.determinedLanguage),
|
||||
Dictionary.fetchAllApprovedSecondaryDomains(),
|
||||
Dictionary.fetchAllLanguages(language, true)
|
||||
Dictionary.fetchAllLanguages(req.determinedLanguage, true)
|
||||
])
|
||||
|
||||
res.render('pages/dictionaries/new', {
|
||||
@@ -66,7 +69,7 @@ dictionary.new = async (req, res) => {
|
||||
|
||||
dictionary.create = async (req, res) => {
|
||||
await Dictionary.create(req.body, req.user.id)
|
||||
res.redirect('/slovarji/moji')
|
||||
res.redirect(303, '/slovarji/moji')
|
||||
}
|
||||
|
||||
dictionary.editDescription = async (req, res) => {
|
||||
@@ -77,7 +80,7 @@ dictionary.editDescription = async (req, res) => {
|
||||
dictionary,
|
||||
associatedSecondaryDomains
|
||||
] = await Promise.all([
|
||||
Dictionary.fetchAllPrimaryDomains(),
|
||||
Dictionary.fetchAllPrimaryDomains(req.determinedLanguage),
|
||||
Dictionary.fetchAllApprovedSecondaryDomains(),
|
||||
Dictionary.fetchEditDescription(dictionaryId),
|
||||
Dictionary.fetchSecondaryDomains(dictionaryId)
|
||||
@@ -103,14 +106,14 @@ dictionary.updateDescription = async (req, res) => {
|
||||
Dictionary.updateSecondaryDomains(dictionaryId, body)
|
||||
])
|
||||
|
||||
res.redirect('back')
|
||||
res.redirect(303, 'back')
|
||||
}
|
||||
|
||||
dictionary.editUsers = async (req, res) => {
|
||||
const dictionaryId = req.params.dictionaryId
|
||||
const [dictionary, userRights, entriesCount, minEntries, publishApproval] =
|
||||
await Promise.all([
|
||||
Dictionary.fetchEditUsers(dictionaryId),
|
||||
Dictionary.fetchEditUsers(dictionaryId, req.determinedLanguage),
|
||||
User.fetchAllWithDictionaryRights(dictionaryId),
|
||||
Dictionary.countPublishedEntries(dictionaryId),
|
||||
getInstanceSetting('min_entries_per_dictionary'),
|
||||
@@ -144,9 +147,9 @@ dictionary.updateUsers = async (req, res) => {
|
||||
|
||||
const newDictStatus = await determineNewStatus(isPublished)
|
||||
|
||||
// TODO I18n - nameSl
|
||||
const { nameSl, status: oldDictStatus } = await Dictionary.fetchEditUsers(
|
||||
dictionaryId
|
||||
const { name, status: oldDictStatus } = await Dictionary.fetchEditUsers(
|
||||
dictionaryId,
|
||||
req.determinedLanguage
|
||||
)
|
||||
|
||||
await Promise.all([
|
||||
@@ -165,23 +168,20 @@ dictionary.updateUsers = async (req, res) => {
|
||||
dictionaryId,
|
||||
isPublished,
|
||||
oldDictStatus,
|
||||
nameSl,
|
||||
name,
|
||||
req.app,
|
||||
req.user
|
||||
)
|
||||
|
||||
res.redirect('back')
|
||||
res.redirect(303, 'back')
|
||||
}
|
||||
|
||||
dictionary.editStructure = async (req, res) => {
|
||||
// TODO Once english language is implemented, gather selected language (sl/en) from request ~ (cookies?)
|
||||
// TODO I18n - nameSl
|
||||
const language = 'name_sl'
|
||||
const { dictionaryId } = req.params
|
||||
const [dictionary, associatedLanguages, allLanguages] = await Promise.all([
|
||||
Dictionary.fetchEditStructure(dictionaryId),
|
||||
Dictionary.fetchLanguages(dictionaryId),
|
||||
Dictionary.fetchAllLanguages(language, true)
|
||||
Dictionary.fetchLanguages(dictionaryId, req.determinedLanguage),
|
||||
Dictionary.fetchAllLanguages(req.determinedLanguage, true)
|
||||
])
|
||||
|
||||
let viewPath
|
||||
@@ -211,12 +211,15 @@ dictionary.updateStructure = async (req, res) => {
|
||||
Dictionary.deleteLanguages(dictionaryId),
|
||||
Dictionary.updateLanguages(dictionaryId, body)
|
||||
])
|
||||
res.redirect('back')
|
||||
res.redirect(303, 'back')
|
||||
}
|
||||
|
||||
dictionary.editAdvanced = async (req, res) => {
|
||||
const { dictionaryId } = req.params
|
||||
const dictionaryName = await Dictionary.fetchName(dictionaryId)
|
||||
const dictionaryName = await Dictionary.fetchName(
|
||||
dictionaryId,
|
||||
req.determinedLanguage
|
||||
)
|
||||
let viewPath
|
||||
switch (req.baseUrl) {
|
||||
case '/slovarji':
|
||||
@@ -243,7 +246,7 @@ dictionary.comments = async (req, res) => {
|
||||
const [{ comments, pages_total: numberOfAllPages }, dictionaryName] =
|
||||
await Promise.all([
|
||||
Comment.list(filters, req.user, resultsPerPage, 1),
|
||||
Dictionary.fetchName(dictionaryId)
|
||||
Dictionary.fetchName(dictionaryId, req.determinedLanguage)
|
||||
])
|
||||
|
||||
switch (req.baseUrl) {
|
||||
@@ -269,7 +272,7 @@ dictionary.showImportFromFileForm = async (req, res) => {
|
||||
const [{ pages_total: numberOfAllPages, results }, dictionaryName] =
|
||||
await Promise.all([
|
||||
Dictionary.fetchAllImports(dictionaryId, resultsPerPage, 1),
|
||||
Dictionary.fetchName(dictionaryId)
|
||||
Dictionary.fetchName(dictionaryId, req.determinedLanguage)
|
||||
])
|
||||
let viewPath
|
||||
switch (req.baseUrl) {
|
||||
@@ -293,7 +296,11 @@ dictionary.listAdminDictionaries = async (req, res) => {
|
||||
const resultsPerPage = req.user?.hitsPerPage || DEFAULT_HITS_PER_PAGE
|
||||
|
||||
const { pages_total: numberOfAllPages, results } =
|
||||
await Dictionary.fetchAllAdminDictionaries(resultsPerPage, 1)
|
||||
await Dictionary.fetchAllAdminDictionaries(
|
||||
req.determinedLanguage,
|
||||
resultsPerPage,
|
||||
1
|
||||
)
|
||||
|
||||
res.render('pages/admin/dictionaries-list', {
|
||||
title: req.t('Seznam slovarjev'),
|
||||
@@ -311,7 +318,7 @@ dictionary.adminEditDescription = async (req, res) => {
|
||||
associatedSecondaryDomains,
|
||||
status
|
||||
] = await Promise.all([
|
||||
Dictionary.fetchAllPrimaryDomains(),
|
||||
Dictionary.fetchAllPrimaryDomains(req.determinedLanguage),
|
||||
Dictionary.fetchAllApprovedSecondaryDomains(),
|
||||
Dictionary.fetchEditDescription(dictionaryId),
|
||||
Dictionary.fetchSecondaryDomains(dictionaryId),
|
||||
@@ -357,15 +364,19 @@ dictionary.updateAdminDescription = async (req, res) => {
|
||||
newDictStatus,
|
||||
oldDictStatus,
|
||||
req.app,
|
||||
req.determinedLanguage,
|
||||
req.user
|
||||
)
|
||||
|
||||
res.redirect('back')
|
||||
res.redirect(303, 'back')
|
||||
}
|
||||
|
||||
dictionary.showImportFromExtractionForm = async (req, res) => {
|
||||
const { dictionaryId } = req.params
|
||||
const dictionaryName = await Dictionary.fetchName(dictionaryId)
|
||||
const dictionaryName = await Dictionary.fetchName(
|
||||
dictionaryId,
|
||||
req.determinedLanguage
|
||||
)
|
||||
const extractions = await Extraction.fetchFinishedForUser(req.user.id)
|
||||
let viewPath, title
|
||||
switch (req.baseUrl) {
|
||||
@@ -391,7 +402,7 @@ dictionary.showExportToFileForm = async (req, res) => {
|
||||
const resultsPerPage = req.user?.hitsPerPage || DEFAULT_HITS_PER_PAGE
|
||||
const [dictionaryName, { pages_total: numberOfAllPages, results }] =
|
||||
await Promise.all([
|
||||
Dictionary.fetchName(dictionaryId),
|
||||
Dictionary.fetchName(dictionaryId, req.determinedLanguage),
|
||||
Dictionary.fetchExports(dictionaryId, resultsPerPage, 1)
|
||||
])
|
||||
let viewPath
|
||||
@@ -418,7 +429,7 @@ dictionary.editDomainLabels = async (req, res) => {
|
||||
const [{ pages_total: numberOfAllPages, results }, dictionaryName] =
|
||||
await Promise.all([
|
||||
Dictionary.fetchPaginationDomainLabels(dictionaryId, resultsPerPage, 1),
|
||||
Dictionary.fetchName(dictionaryId)
|
||||
Dictionary.fetchName(dictionaryId, req.determinedLanguage)
|
||||
])
|
||||
|
||||
let viewPath
|
||||
@@ -445,16 +456,14 @@ dictionary.showContent = async (req, res) => {
|
||||
const [
|
||||
hits,
|
||||
canPublishEntriesInEdit,
|
||||
dictionaryName,
|
||||
structure,
|
||||
languages,
|
||||
entryDomainLabels
|
||||
] = await Promise.all([
|
||||
searchEntryIndex(hitsQuery),
|
||||
getInstanceSetting('can_publish_entries_in_edit'),
|
||||
Dictionary.fetchName(dictionaryId),
|
||||
Dictionary.fetchEditStructure(dictionaryId),
|
||||
Dictionary.fetchLanguages(dictionaryId),
|
||||
Dictionary.fetchLanguages(dictionaryId, req.determinedLanguage),
|
||||
Dictionary.fetchDomainLabels(dictionaryId)
|
||||
])
|
||||
|
||||
@@ -464,7 +473,7 @@ dictionary.showContent = async (req, res) => {
|
||||
title: req.t('Vsebina slovarja'),
|
||||
terms,
|
||||
canPublishEntriesInEdit,
|
||||
dictionaryName,
|
||||
dictionaryName: structure[`name${capitalize(req.determinedLanguage)}`],
|
||||
structure,
|
||||
languages,
|
||||
dictionaryId,
|
||||
@@ -510,7 +519,8 @@ dictionary.dictionaryList = async (req, res) => {
|
||||
hitsPerPage,
|
||||
page,
|
||||
orderAttribute,
|
||||
orderIndex
|
||||
orderIndex,
|
||||
req.determinedLanguage
|
||||
)
|
||||
|
||||
const numberOfAllHits = parseInt(
|
||||
@@ -518,7 +528,9 @@ dictionary.dictionaryList = async (req, res) => {
|
||||
)
|
||||
const numberOfAllPages = Math.ceil(numberOfAllHits / hitsPerPage)
|
||||
|
||||
const allPrimaryDomains = await Dictionary.fetchAllPrimaryDomains()
|
||||
const allPrimaryDomains = await Dictionary.fetchAllPrimaryDomains(
|
||||
req.determinedLanguage
|
||||
)
|
||||
|
||||
/*
|
||||
/// filter selected domains for the prompt ///
|
||||
@@ -567,9 +579,12 @@ dictionary.dictionaryDetails = async (req, res) => {
|
||||
targetLanguages,
|
||||
allDictionaryNames,
|
||||
portals
|
||||
} = await SFDSuggestionImporter.initialize()
|
||||
} = await SFDSuggestionImporter.initialize(req.determinedLanguage)
|
||||
|
||||
const dictionaryData = await Dictionary.fetchDictionaryBasicInfo(dictId)
|
||||
const dictionaryData = await Dictionary.fetchDictionaryBasicInfo(
|
||||
dictId,
|
||||
req.determinedLanguage
|
||||
)
|
||||
|
||||
const filters = { ctxType: 'dictionary', ctxId: dictId }
|
||||
// TODO: integrate numberOfAllPages, commentCount with pug
|
||||
@@ -711,21 +726,34 @@ dictionary.importFromFile = async (req, res) => {
|
||||
}
|
||||
}
|
||||
|
||||
dictionary.exportDownload = async (req, res) => {
|
||||
// TODO Add authentication and authorization.
|
||||
dictionary.exportDownload = [
|
||||
async (req, res, next) => {
|
||||
const { exportId } = req.params
|
||||
const exportDownloadMetadata = await Dictionary.fetchExportDownloadMetadata(
|
||||
exportId
|
||||
)
|
||||
|
||||
const { exportId } = req.params
|
||||
const { exportStatus, dictionaryId, nameString, timeString, fileFormat } =
|
||||
await Dictionary.fetchExportDownloadMetadata(exportId)
|
||||
if (exportStatus !== 'finished') {
|
||||
throw Error("Can't request file for unfinished export")
|
||||
req.dictionaryId = exportDownloadMetadata.dictionaryId
|
||||
req.exportDownloadMetadata = exportDownloadMetadata
|
||||
|
||||
next()
|
||||
},
|
||||
user.isDictionaryEditor,
|
||||
(req, res) => {
|
||||
const { exportId } = req.params
|
||||
const { exportStatus, dictionaryId, nameString, timeString, fileFormat } =
|
||||
req.exportDownloadMetadata
|
||||
|
||||
if (exportStatus !== 'finished') {
|
||||
throw Error("Can't request file for unfinished export")
|
||||
}
|
||||
const exportFilesPath = getExportFilesPath(dictionaryId)
|
||||
const exportFilePath = `${exportFilesPath}/${exportId}`
|
||||
const exportFileName = `${nameString}_${timeString}.${fileFormat}`
|
||||
|
||||
res.download(exportFilePath, exportFileName)
|
||||
}
|
||||
const exportFilesPath = getExportFilesPath(dictionaryId)
|
||||
const exportFilePath = `${exportFilesPath}/${exportId}`
|
||||
const exportFileName = `${nameString}_${timeString}.${fileFormat}`
|
||||
|
||||
res.download(exportFilePath, exportFileName)
|
||||
}
|
||||
]
|
||||
|
||||
function importFileFilter(req, file, cb) {
|
||||
if (file.mimetype !== 'text/xml') {
|
||||
|
||||
@@ -1,150 +0,0 @@
|
||||
const { mkdir } = require('fs/promises')
|
||||
const {
|
||||
getDocumentsPath,
|
||||
getStopTermsPath
|
||||
} = require('../models/helpers/extraction')
|
||||
const { checkIfcanBegin } = require('./helpers/extraction')
|
||||
const { MAX_EXTRACTIONS_PER_USER } = require('../config/settings')
|
||||
const Extraction = require('../models/extraction')
|
||||
const Dictionary = require('../models/dictionary')
|
||||
const Domain = require('../models/domain')
|
||||
const { intoDbArray } = require('../models/helpers')
|
||||
const { DEFAULT_HITS_PER_PAGE } = require('../config/settings')
|
||||
|
||||
const extraction = {}
|
||||
|
||||
extraction.list = async (req, res) => {
|
||||
let extractions = await Extraction.fetchAllForUser(req.user.id)
|
||||
extractions = await Promise.all(
|
||||
extractions.map(async extraction => {
|
||||
extraction.canBegin = await checkIfcanBegin(extraction)
|
||||
if (extraction.status === 'finished') {
|
||||
extraction.termCandidatesCount =
|
||||
await Extraction.fetchTermCandidatesCount(extraction.id)
|
||||
}
|
||||
return extraction
|
||||
})
|
||||
)
|
||||
res.render('extraction-poc/list', { extractions })
|
||||
}
|
||||
|
||||
extraction.create = async (req, res) => {
|
||||
const extractionCount = await Extraction.countAllForUser(req.user.id)
|
||||
if (extractionCount >= MAX_EXTRACTIONS_PER_USER) {
|
||||
// TODO Tukaj bo treba prikazati tudi obvestilo uporabniku skladno s trenutno metodologijo prikaza obvestil.
|
||||
return res.redirect(303, 'back')
|
||||
}
|
||||
|
||||
const extractionName = `Luščenje ${extractionCount + 1}`
|
||||
const { extractionType } = req.body
|
||||
|
||||
let extractionId
|
||||
if (extractionType === 'own') {
|
||||
extractionId = await Extraction.createOwn(req.user.id, extractionName)
|
||||
|
||||
const documentsPath = getDocumentsPath(extractionId)
|
||||
const stopTermsPath = getStopTermsPath(extractionId)
|
||||
await Promise.all([
|
||||
mkdir(documentsPath, { recursive: true }),
|
||||
mkdir(stopTermsPath, { recursive: true })
|
||||
])
|
||||
} else {
|
||||
extractionId = await Extraction.createOss(req.user.id, extractionName)
|
||||
|
||||
const stopTermsPath = getStopTermsPath(extractionId)
|
||||
await mkdir(stopTermsPath, { recursive: true })
|
||||
}
|
||||
|
||||
// Redirect to extraction edit page.
|
||||
res.redirect(`poc/${extractionId}`)
|
||||
}
|
||||
|
||||
extraction.edit = async (req, res) => {
|
||||
const extractionId = req.params.id
|
||||
const extraction = await Extraction.fetch(extractionId)
|
||||
|
||||
if (extraction.ossParams) {
|
||||
const [allPrimaryDomains, stopTermsFiles] = await Promise.all([
|
||||
Dictionary.fetchAllPrimaryDomains(),
|
||||
Extraction.fetchAllStopTermsFilesStats(extractionId)
|
||||
])
|
||||
const { params } = extraction.ossParams
|
||||
const domainUdk = params?.domainUdk?.[0]
|
||||
if (domainUdk)
|
||||
extraction.domainId = await Domain.fetchIdByUdkCode(domainUdk)
|
||||
extraction.documentType = intoDbArray(params.documentType, 'always')
|
||||
extraction.year = intoDbArray(params.year, 'always')
|
||||
extraction.keywords = intoDbArray(params.keywords, 'always')
|
||||
|
||||
res.render('extraction-poc/edit-oss', {
|
||||
id: extractionId,
|
||||
extraction,
|
||||
allPrimaryDomains,
|
||||
stopTermsFiles
|
||||
})
|
||||
} else {
|
||||
const [extractionDocuments, stopTermsFiles] = await Promise.all([
|
||||
Extraction.fetchAllDocumentsStats(extractionId),
|
||||
Extraction.fetchAllStopTermsFilesStats(extractionId)
|
||||
])
|
||||
res.render('extraction-poc/edit-own', {
|
||||
id: extractionId,
|
||||
extraction,
|
||||
extractionDocuments,
|
||||
stopTermsFiles
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
extraction.updateOwn = async (req, res) => {
|
||||
const extractionId = req.params.id
|
||||
await Extraction.update(extractionId, req.body.name)
|
||||
|
||||
// Reload page.
|
||||
res.redirect(`./${extractionId}`)
|
||||
}
|
||||
|
||||
extraction.docsEdit = async (req, res) => {
|
||||
const extractionId = req.params.id
|
||||
const extractionDocuments = await Extraction.fetchAllDocumentsStats(
|
||||
extractionId
|
||||
)
|
||||
|
||||
res.render('extraction-poc/docs-edit', {
|
||||
id: extractionId,
|
||||
extractionDocuments
|
||||
})
|
||||
}
|
||||
|
||||
extraction.stopTermsEdit = async (req, res) => {
|
||||
const extractionId = req.params.id
|
||||
const stopTermsFiles = await Extraction.fetchAllStopTermsFilesStats(
|
||||
extractionId
|
||||
)
|
||||
|
||||
res.render('extraction-poc/stop-terms-edit', {
|
||||
id: extractionId,
|
||||
stopTermsFiles
|
||||
})
|
||||
}
|
||||
|
||||
extraction.listTermCandidates = async (req, res) => {
|
||||
const extractionId = req.params.id
|
||||
const termCandidatesJson = await Extraction.fetchTermCandidatesJson(
|
||||
extractionId
|
||||
)
|
||||
const termCandidates = JSON.parse(termCandidatesJson).terminoloski_kandidati
|
||||
const hitsPerPage = +req.user?.hitsPerPage || DEFAULT_HITS_PER_PAGE
|
||||
const numberOfAllPages = Math.ceil(termCandidates.length / hitsPerPage)
|
||||
const firstPageOfTermCandidates = termCandidates.slice(0, hitsPerPage)
|
||||
|
||||
res.render('extraction-poc/term-candidates', {
|
||||
extractionId,
|
||||
termCandidatesJson,
|
||||
firstPageOfTermCandidates,
|
||||
hitsPerPage,
|
||||
numberOfAllPages
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = extraction
|
||||
@@ -63,22 +63,36 @@ extraction.create = async (req, res) => {
|
||||
}
|
||||
|
||||
// Redirect to extraction edit page.
|
||||
res.redirect(`luscenje/${extractionId}`)
|
||||
res.redirect(303, `luscenje/${extractionId}`)
|
||||
}
|
||||
|
||||
extraction.validateOwnership = async (req, res, next) => {
|
||||
const { id: extractionId } = req.params
|
||||
if (!extractionId) return res.redirect(303, '/')
|
||||
|
||||
const extraction = await Extraction.fetch(extractionId)
|
||||
if (extraction.userId !== req.user.id) return res.redirect(303, '/')
|
||||
|
||||
req.extractionData = extraction
|
||||
next()
|
||||
}
|
||||
|
||||
extraction.edit = async (req, res) => {
|
||||
const extractionId = req.params.id
|
||||
const extraction = await Extraction.fetch(extractionId)
|
||||
const extraction = req.extractionData
|
||||
|
||||
if (extraction.ossParams) {
|
||||
const [allPrimaryDomains, stopTermsFiles] = await Promise.all([
|
||||
Dictionary.fetchAllPrimaryDomains(),
|
||||
Extraction.fetchAllStopTermsFilesStats(extractionId)
|
||||
])
|
||||
const [allPrimaryDomains, ossDocumentTypes, stopTermsFiles] =
|
||||
await Promise.all([
|
||||
Dictionary.fetchAllPrimaryDomains(req.determinedLanguage),
|
||||
Extraction.fetchOssDocumentTypes(req.determinedLanguage),
|
||||
Extraction.fetchAllStopTermsFilesStats(extractionId)
|
||||
])
|
||||
const { params } = extraction.ossParams
|
||||
const domainUdk = params?.domainUdk?.[0]
|
||||
if (domainUdk)
|
||||
if (domainUdk) {
|
||||
extraction.domainId = await Domain.fetchIdByUdkCode(domainUdk)
|
||||
}
|
||||
extraction.documentType = intoDbArray(params.documentType, 'always')
|
||||
extraction.year = intoDbArray(params.year, 'always')
|
||||
extraction.keywords = intoDbArray(params.keywords, 'always')
|
||||
@@ -88,6 +102,7 @@ extraction.edit = async (req, res) => {
|
||||
id: extractionId,
|
||||
extraction,
|
||||
allPrimaryDomains,
|
||||
ossDocumentTypes,
|
||||
stopTermsFiles
|
||||
})
|
||||
} else {
|
||||
@@ -110,7 +125,7 @@ extraction.updateOwn = async (req, res) => {
|
||||
await Extraction.update(extractionId, req.body.name)
|
||||
|
||||
// Reload page.
|
||||
res.redirect(`./${extractionId}`)
|
||||
res.redirect(303, `./${extractionId}`)
|
||||
}
|
||||
|
||||
extraction.docsEdit = async (req, res) => {
|
||||
|
||||
@@ -42,7 +42,7 @@ const minEntriesEmailBookmark = {
|
||||
// Exports actions related to checking and acting on minimum entries per dictionary setting.
|
||||
exports.minEntriesRequirementCheckAndAct = {
|
||||
// Checks required criteria and sends notifications emails if required.
|
||||
async onDelete(dictionaryId, appRef) {
|
||||
async onDelete(dictionaryId, appRef, determinedLanguage) {
|
||||
const minEntries = await getInstanceSetting('min_entries_per_dictionary')
|
||||
|
||||
// Only proceed if a valid and positive minimum entries per dictionary setting is set.
|
||||
@@ -58,9 +58,8 @@ exports.minEntriesRequirementCheckAndAct = {
|
||||
if (!isBelowMinEntriesThreshold || wasEmailAlreadySent) return
|
||||
|
||||
// Prepare and send notification emails.
|
||||
// TODO I18n - nameSl
|
||||
const [nameSl, adminEmails, dictionariesAdminEmails] = await Promise.all([
|
||||
Dictionary.fetchName(dictionaryId),
|
||||
const [name, adminEmails, dictionariesAdminEmails] = await Promise.all([
|
||||
Dictionary.fetchName(dictionaryId, determinedLanguage),
|
||||
Dictionary.fetchAdminEmails(dictionaryId),
|
||||
Dictionary.fetchDictionariesAdminEmails()
|
||||
])
|
||||
@@ -71,10 +70,9 @@ exports.minEntriesRequirementCheckAndAct = {
|
||||
|
||||
const type = 'delete'
|
||||
const renderAsync = promisify(appRef.render.bind(appRef))
|
||||
// TODO I18n - nameSl
|
||||
const emailHtml = await renderAsync('email/dictionary-status-change', {
|
||||
type,
|
||||
nameSl
|
||||
name
|
||||
})
|
||||
|
||||
// TODO i18n - What language are the email title and content (we already have email translated)
|
||||
@@ -123,12 +121,11 @@ exports.determineNewStatus = async isPublished => {
|
||||
// Exports actions related to checking and acting on dictionary status changes.
|
||||
exports.statusChangeCheckAndAct = {
|
||||
// Notify dictionaries admins by email on dictionary status changes.
|
||||
// TODO I18n - nameSl
|
||||
async updateUsers(
|
||||
dictionaryId,
|
||||
isPublishedNew,
|
||||
oldDictStatus,
|
||||
nameSl,
|
||||
name,
|
||||
appRef,
|
||||
user
|
||||
) {
|
||||
@@ -139,12 +136,11 @@ exports.statusChangeCheckAndAct = {
|
||||
const dictionariesAdminEmails =
|
||||
await Dictionary.fetchDictionariesAdminEmails()
|
||||
const type = 'unpublish'
|
||||
// TODO I18n - nameSl
|
||||
await renderAndSendStatusChangeEmails(
|
||||
appRef,
|
||||
type,
|
||||
user.email,
|
||||
nameSl,
|
||||
name,
|
||||
dictionariesAdminEmails
|
||||
)
|
||||
|
||||
@@ -157,12 +153,11 @@ exports.statusChangeCheckAndAct = {
|
||||
const type =
|
||||
isApprovalRequired === 'T' ? 'publish-approval' : 'publish-no-approval'
|
||||
|
||||
// TODO I18n - nameSl
|
||||
await renderAndSendStatusChangeEmails(
|
||||
appRef,
|
||||
type,
|
||||
user.email,
|
||||
nameSl,
|
||||
name,
|
||||
dictionariesAdminEmails
|
||||
)
|
||||
}
|
||||
@@ -175,12 +170,12 @@ exports.statusChangeCheckAndAct = {
|
||||
statusNew,
|
||||
statusOld,
|
||||
appRef,
|
||||
determinedLanguage,
|
||||
user
|
||||
) {
|
||||
if (statusOld === 'reviewed' && statusNew !== 'reviewed') {
|
||||
// TODO I18n - nameSl
|
||||
const [nameSl, adminEmails] = await Promise.all([
|
||||
Dictionary.fetchName(dictionaryId),
|
||||
const [name, adminEmails] = await Promise.all([
|
||||
Dictionary.fetchName(dictionaryId, determinedLanguage),
|
||||
Dictionary.fetchAdminEmails(dictionaryId)
|
||||
])
|
||||
const type = 'status'
|
||||
@@ -189,7 +184,7 @@ exports.statusChangeCheckAndAct = {
|
||||
appRef,
|
||||
type,
|
||||
user.email,
|
||||
nameSl,
|
||||
name,
|
||||
adminEmails
|
||||
)
|
||||
}
|
||||
@@ -197,19 +192,18 @@ exports.statusChangeCheckAndAct = {
|
||||
}
|
||||
|
||||
// Helper function used by statusChangeCheckAndAct methods.
|
||||
// TODO I18n - nameSl
|
||||
async function renderAndSendStatusChangeEmails(
|
||||
appRef,
|
||||
type,
|
||||
changerEmail,
|
||||
nameSl,
|
||||
name,
|
||||
targetEmails
|
||||
) {
|
||||
const renderAsync = promisify(appRef.render.bind(appRef))
|
||||
const emailHtml = await renderAsync('email/dictionary-status-change', {
|
||||
type,
|
||||
changerEmail,
|
||||
nameSl
|
||||
name
|
||||
})
|
||||
|
||||
// TODO i18n - What language are the email title and content (we already have email translated)
|
||||
|
||||
@@ -4,24 +4,23 @@ const { getInstanceSetting } = require('../../models/helpers')
|
||||
|
||||
const helper = {}
|
||||
|
||||
helper.initialize = async () => {
|
||||
helper.initialize = async determinedLanguage => {
|
||||
const initializers = {}
|
||||
|
||||
// TODO Once english language is implemented, gather selected language (sl/en) from request ~ (cookies?)
|
||||
// TODO i18n name_sl
|
||||
const language = 'name_sl'
|
||||
|
||||
// TODO Consider parallelizing following queries. Single vs pooled clients?
|
||||
initializers.allPrimaryDomains = await Dictionary.fetchAllPrimaryDomains()
|
||||
initializers.sourceLanguages = await Dictionary.fetchAllLanguages(language)
|
||||
initializers.targetLanguages = (
|
||||
await Dictionary.fetchAllLanguages(language)
|
||||
).filter(
|
||||
initializers.allPrimaryDomains = await Dictionary.fetchAllPrimaryDomains(
|
||||
determinedLanguage
|
||||
)
|
||||
const allLanguages = await Dictionary.fetchAllLanguages(determinedLanguage)
|
||||
initializers.sourceLanguages = allLanguages
|
||||
initializers.targetLanguages = allLanguages.filter(
|
||||
// drop slovene language
|
||||
l => l.id !== 32
|
||||
)
|
||||
|
||||
initializers.allDictionaryNames = await Dictionary.fetchAll()
|
||||
initializers.allDictionaryNames = await Dictionary.fetchAll(
|
||||
determinedLanguage
|
||||
)
|
||||
|
||||
initializers.portals = []
|
||||
initializers.portals.push({
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
const { promisify } = require('util')
|
||||
const Entry = require('../models/entry')
|
||||
const { getInstanceSetting } = require('../models/helpers')
|
||||
const Dictionary = require('../models/dictionary')
|
||||
@@ -13,10 +14,12 @@ const {
|
||||
prepareSeachFilterData,
|
||||
prepareConsultancyEntries
|
||||
} = require('../models/helpers/search')
|
||||
const email = require('../models/email')
|
||||
const generateQuery = require('../models/helpers/search/generate-query')
|
||||
const { DEFAULT_HITS_PER_PAGE } = require('../config/settings')
|
||||
const SFDSuggestionImporter = require('./helpers/search-filter-data-suggestion-importer')
|
||||
const User = require('../models/user')
|
||||
const { capitalize } = require('../utils')
|
||||
|
||||
// TODO Luka (note to self): Measure performance, consider caching.
|
||||
exports.index = async (req, res) => {
|
||||
@@ -27,12 +30,10 @@ exports.index = async (req, res) => {
|
||||
targetLanguages,
|
||||
allDictionaryNames,
|
||||
portals
|
||||
} = await SFDSuggestionImporter.initialize()
|
||||
|
||||
const englishLanguageEnabled = false // dummy variable for future edit
|
||||
} = await SFDSuggestionImporter.initialize(req.determinedLanguage)
|
||||
|
||||
const latestDicts = await Dictionary.fetchLatest3DictsByPublishDate(
|
||||
englishLanguageEnabled
|
||||
req.determinedLanguage
|
||||
)
|
||||
|
||||
const portalName = await getInstanceSetting(`portal_name_${language}`)
|
||||
@@ -58,7 +59,7 @@ exports.index = async (req, res) => {
|
||||
exports.search = async (req, res) => {
|
||||
const searchString = req.query.q?.trim()
|
||||
|
||||
if (!searchString) return res.redirect('/')
|
||||
if (!searchString) return res.redirect(303, '/')
|
||||
|
||||
const title = req.t('Iskanje')
|
||||
|
||||
@@ -68,7 +69,7 @@ exports.search = async (req, res) => {
|
||||
targetLanguages,
|
||||
allDictionaryNames,
|
||||
portals
|
||||
} = await SFDSuggestionImporter.initialize()
|
||||
} = await SFDSuggestionImporter.initialize(req.determinedLanguage)
|
||||
|
||||
const filters = {
|
||||
sourceLanguages: intoDbArray(req.query.sl, 'always'),
|
||||
@@ -131,7 +132,10 @@ exports.search = async (req, res) => {
|
||||
// Similar to search query without any extra filters, this is required for modal to diplay ALL res.
|
||||
// const allAggregation = await indexAllResultsNoFiltering(req, res)
|
||||
|
||||
const aggregation = await prepareAggregation(aggregationRaw)
|
||||
const aggregation = await prepareAggregation(
|
||||
aggregationRaw,
|
||||
req.determinedLanguage
|
||||
)
|
||||
const searchFilterData = prepareSeachFilterData(aggregation, filters)
|
||||
|
||||
// TODO Luka (note to self): Consider reworking Miha's logic below. It's hacky and possibly error prone.
|
||||
@@ -328,7 +332,7 @@ exports.entryDetails = async (req, res) => {
|
||||
|
||||
// If external url, just redirect
|
||||
if (entry.external_url) {
|
||||
return res.redirect(entry.external_url)
|
||||
return res.redirect(303, entry.external_url)
|
||||
}
|
||||
|
||||
// unnecessary legacy assigment, refactor when time is available
|
||||
@@ -340,12 +344,15 @@ exports.entryDetails = async (req, res) => {
|
||||
targetLanguages,
|
||||
allDictionaryNames,
|
||||
portals
|
||||
} = await SFDSuggestionImporter.initialize()
|
||||
} = await SFDSuggestionImporter.initialize(req.determinedLanguage)
|
||||
|
||||
const [dictStruct, dictionaryData, selectedDomainLabelsForEntry] =
|
||||
await Promise.all([
|
||||
Dictionary.fetchDictionaryWithEditStructure(entry.dictionary_id),
|
||||
Dictionary.fetchDictionaryBasicInfo(entry.dictionary_id),
|
||||
Dictionary.fetchDictionaryBasicInfo(
|
||||
entry.dictionary_id,
|
||||
req.determinedLanguage
|
||||
),
|
||||
Entry.fetchDomainLabels(termId)
|
||||
])
|
||||
|
||||
@@ -399,7 +406,7 @@ exports.entryDetails = async (req, res) => {
|
||||
prevHref: '/iskanje',
|
||||
portalCode: dictionaryData[0].portalcode,
|
||||
portalName: dictionaryData[0].portalname,
|
||||
dictName: structure.nameSl,
|
||||
dictName: structure[`name${capitalize(req.determinedLanguage)}`],
|
||||
dictHref: `/slovarji/${structure.id}/o-slovarju?sentFromEntryId=${termId}`,
|
||||
fullAuthorName: reducedData.author ? reducedData.author.join(', ') : '',
|
||||
areas: dictionaryData[0].domain_primary,
|
||||
@@ -438,11 +445,13 @@ exports.entryDetails = async (req, res) => {
|
||||
entry.foreignEntries[idx] = await
|
||||
}) */
|
||||
|
||||
const langs = await Dictionary.fetchLanguages(entryData.dictionary_id)
|
||||
const langs = await Dictionary.fetchLanguages(
|
||||
entryData.dictionary_id,
|
||||
req.determinedLanguage
|
||||
)
|
||||
entryData.foreign_entries.forEach((val, idx) => {
|
||||
try {
|
||||
entry.foreign_entries[idx].name_sl = langs[idx].nameSl
|
||||
entry.foreign_entries[idx].name_en = langs[idx].nameEn
|
||||
entry.foreign_entries[idx].name = langs[idx].name
|
||||
} catch (e) {}
|
||||
})
|
||||
|
||||
@@ -479,16 +488,44 @@ exports.changePassword = async (req, res) => {
|
||||
}
|
||||
|
||||
exports.resetPassword = async (req, res) => {
|
||||
if (req.user) return res.redirect(303, '/spremeni-geslo')
|
||||
|
||||
const { token } = req.query
|
||||
if (!token) return res.redirect(303, '/')
|
||||
|
||||
const isTokenValid = await User.isResetPasswordTokenValid(token)
|
||||
|
||||
// console.log(token)
|
||||
res.render('pages/reset-password/reset-password', {
|
||||
// title: 'Pozabljeno geslo'
|
||||
isValidToken: token === '123',
|
||||
title: 'Ponastavitev gesla',
|
||||
isTokenValid,
|
||||
token
|
||||
})
|
||||
}
|
||||
|
||||
exports.changeEmail = async (req, res) => {
|
||||
const { token } = req.query
|
||||
if (!token) return res.redirect(303, '/')
|
||||
|
||||
const user = await User.changeEmailWithToken(token, req.t)
|
||||
|
||||
const renderAsync = promisify(req.app.render.bind(req.app))
|
||||
const emailHtml = await renderAsync(
|
||||
`email/user-change-email-success_${req.language}`,
|
||||
{
|
||||
username: user.username
|
||||
}
|
||||
)
|
||||
await email.send({
|
||||
to: user.email,
|
||||
subject: req.t('Sprememba elektronskega naslova - uspeh'),
|
||||
html: emailHtml
|
||||
})
|
||||
|
||||
req.flash('info', req.t('Uspešno ste spremenili svoj elektronski naslov.'))
|
||||
if (req.user) return res.redirect(303, '/moj-racun')
|
||||
res.redirect(303, '/')
|
||||
}
|
||||
|
||||
exports.userSettings = async (req, res) => {
|
||||
const hitsPerPageArr = await User.fetchAllowedHitsPerPage()
|
||||
res.render('pages/profile/change-profile-settings', {
|
||||
@@ -513,7 +550,7 @@ exports.changeUserLanguage = async (req, res) => {
|
||||
req.session.language = languageCode
|
||||
}
|
||||
|
||||
res.redirect('/')
|
||||
res.redirect(303, '/')
|
||||
}
|
||||
|
||||
function mergeDomains(
|
||||
|
||||
@@ -17,7 +17,7 @@ portal.updateInstaceSettings = async (req, res) => {
|
||||
const payload = req.body
|
||||
await Portal.updateInstaceSettings(payload)
|
||||
await clearCachedInstanceSettings()
|
||||
res.redirect('/admin/nastavitve/portal')
|
||||
res.redirect(303, '/admin/nastavitve/portal')
|
||||
}
|
||||
|
||||
portal.instanceDictSettings = async (req, res) => {
|
||||
@@ -33,7 +33,7 @@ portal.updateInstanceDictSettings = async (req, res) => {
|
||||
const payload = req.body
|
||||
await Portal.updateInstaceDictSettings(payload)
|
||||
await clearCachedInstanceSettings()
|
||||
res.redirect('/admin/nastavitve/slovarji')
|
||||
res.redirect(303, '/admin/nastavitve/slovarji')
|
||||
}
|
||||
|
||||
portal.instanceConsultancySettings = async (req, res) => {
|
||||
@@ -48,7 +48,7 @@ portal.updateInstanceConusltacySettings = async (req, res) => {
|
||||
const payload = req.body
|
||||
await Portal.updateInstaceConsultancySettings(payload)
|
||||
await clearCachedInstanceSettings()
|
||||
res.redirect('/admin/nastavitve/svetovalnica')
|
||||
res.redirect(303, '/admin/nastavitve/svetovalnica')
|
||||
}
|
||||
|
||||
portal.new = async (req, res) => {
|
||||
@@ -80,7 +80,7 @@ portal.updatePortal = async (req, res) => {
|
||||
const portalId = req.params.portalId
|
||||
const payload = req.body
|
||||
await Portal.update(portalId, payload)
|
||||
res.redirect('/admin/povezave/seznam')
|
||||
res.redirect(303, '/admin/povezave/seznam')
|
||||
}
|
||||
|
||||
portal.fetchSelectedLinkedDictionaries = async (req, res) => {
|
||||
@@ -101,7 +101,7 @@ portal.fetchSelectedLinkedDictionaries = async (req, res) => {
|
||||
portal.updateSelectedDictionaries = async (req, res) => {
|
||||
const linkedId = req.params.portalId
|
||||
await Portal.updateSelectedDictionaries(linkedId, req.body)
|
||||
res.redirect('back')
|
||||
res.redirect(303, 'back')
|
||||
}
|
||||
|
||||
portal.fetchAllLinkedDictionaries = async (req, res) => {
|
||||
@@ -119,7 +119,7 @@ portal.fetchAllLinkedDictionaries = async (req, res) => {
|
||||
|
||||
portal.updateAllDictionaries = async (req, res) => {
|
||||
await Portal.updateAllDictionaries(req.body)
|
||||
res.redirect('back')
|
||||
res.redirect(303, 'back')
|
||||
}
|
||||
|
||||
portal.comments = async (req, res) => {
|
||||
|
||||
@@ -3,6 +3,7 @@ const { promisify } = require('util')
|
||||
const passport = require('passport')
|
||||
const User = require('../models/user')
|
||||
const email = require('../models/email')
|
||||
const { logout: logoutUser } = require('../middleware/user')
|
||||
const { origin } = require('../config/keys')
|
||||
const { rememberMeCookieSettings } = require('../config/settings')
|
||||
const RandomBytesAsync = promisify(randomBytes)
|
||||
@@ -12,10 +13,14 @@ const user = {}
|
||||
|
||||
user.register = async (req, res) => {
|
||||
// TODO Add validation.
|
||||
const userId = await User.create({
|
||||
...req.body,
|
||||
language: req.session.language
|
||||
})
|
||||
|
||||
const userId = await User.create(
|
||||
{
|
||||
...req.body,
|
||||
language: req.session.language
|
||||
},
|
||||
req.t
|
||||
)
|
||||
const activationToken = (await RandomBytesAsync(32)).toString('hex')
|
||||
await User.saveActivationToken(userId, activationToken)
|
||||
const { email: userEmail, username } = req.body
|
||||
@@ -38,8 +43,9 @@ user.register = async (req, res) => {
|
||||
user.activateAccount = async (req, res) => {
|
||||
// TODO Add validation. What if user is already logged in? What if account is already active? ...
|
||||
const { token } = req.query
|
||||
const user = await User.fetchByActivationToken(token)
|
||||
await User.activateAccount(user)
|
||||
if (!token) return res.redirect(303, '/')
|
||||
|
||||
const user = await User.activateAccountWithToken(token, req.t)
|
||||
const loginAsync = promisify(req.login.bind(req))
|
||||
await loginAsync(user)
|
||||
|
||||
@@ -48,7 +54,11 @@ user.activateAccount = async (req, res) => {
|
||||
delete req.session.language
|
||||
}
|
||||
|
||||
res.redirect('/')
|
||||
req.flash(
|
||||
'info',
|
||||
req.t('Uspešno ste aktivirali svoj uporabniški račun in se prijavili.')
|
||||
)
|
||||
res.redirect(303, '/')
|
||||
}
|
||||
|
||||
user.login = async (req, res, next) => {
|
||||
@@ -89,20 +99,86 @@ user.login = async (req, res, next) => {
|
||||
)(req, res, next)
|
||||
}
|
||||
|
||||
user.logout = async (req, res) => {
|
||||
const rememberMeToken = req.signedCookies.remember_me
|
||||
user.logout = [logoutUser, (req, res) => res.redirect(303, '/')]
|
||||
|
||||
if (rememberMeToken) {
|
||||
res.clearCookie('remember_me')
|
||||
await User.clearRememberMeToken(rememberMeToken)
|
||||
user.generateResetPasswordToken = async (req, res) => {
|
||||
const { usernameOrEmail } = req.body
|
||||
const user = await User.fetchByUsernameOrEmail(usernameOrEmail)
|
||||
|
||||
if (!user) {
|
||||
return res
|
||||
.status(400)
|
||||
.send(req.t('Nepravilno uporabniško ime ali elektronski naslov.'))
|
||||
}
|
||||
|
||||
req.session.language = req.user.language
|
||||
if (user.status !== 'active') {
|
||||
return res
|
||||
.status(400)
|
||||
.send(
|
||||
req.t(
|
||||
'Uporabniški račun še ni aktiviran. Kliknite aktivacijsko povezavo, katero smo vam poslali po elektronski pošti.'
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
req.logout()
|
||||
// Manually clear session.passport due to bug in current passport version.
|
||||
delete req.session.passport.user
|
||||
res.redirect('/')
|
||||
const resetPasswordToken = (await RandomBytesAsync(32)).toString('hex')
|
||||
await User.saveResetPasswordToken(user.id, resetPasswordToken)
|
||||
const { email: userEmail, username } = user
|
||||
let resetPasswordLink = new URL('/ponastavitev-gesla', origin)
|
||||
resetPasswordLink.searchParams.set('token', resetPasswordToken)
|
||||
resetPasswordLink = resetPasswordLink.href
|
||||
const renderAsync = promisify(req.app.render.bind(req.app))
|
||||
// TODO i18n - prepare proper slovenian an english email templates
|
||||
const emailHtml = await renderAsync(
|
||||
`email/user-reset-password-token_${req.language}`,
|
||||
{
|
||||
username,
|
||||
resetPasswordLink
|
||||
}
|
||||
)
|
||||
await email.send({
|
||||
to: userEmail,
|
||||
subject: req.t('Ponastavitev gesla'),
|
||||
html: emailHtml
|
||||
})
|
||||
res.send()
|
||||
}
|
||||
|
||||
user.changePassword = async (req, res) => {
|
||||
const { token, password, passwordRepeat } = req.body
|
||||
|
||||
if (password !== passwordRepeat) {
|
||||
return res.status(400).send(req.t('Gesli se ne ujemata'))
|
||||
}
|
||||
// TODO Add additional password validation (min length, ...)
|
||||
|
||||
const user = await User.resetPasswordWithToken(token, password, req.t)
|
||||
|
||||
const renderAsync = promisify(req.app.render.bind(req.app))
|
||||
// TODO i18n - prepare proper slovenian an english email templates
|
||||
const emailHtml = await renderAsync(
|
||||
`email/user-reset-password-success_${req.language}`,
|
||||
{
|
||||
username: user.username
|
||||
}
|
||||
)
|
||||
await email.send({
|
||||
to: user.email,
|
||||
subject: req.t('Uspešna ponastavitev gesla'),
|
||||
html: emailHtml
|
||||
})
|
||||
|
||||
req.flash('info', req.t('Vaše geslo je bilo uspešno ponastavljeno.'))
|
||||
|
||||
const loginAsync = promisify(req.login.bind(req))
|
||||
await loginAsync(user)
|
||||
|
||||
if (req.session.language) {
|
||||
await User.updateLanguage(user.id, req.session.language)
|
||||
delete req.session.language
|
||||
}
|
||||
|
||||
res.send()
|
||||
}
|
||||
|
||||
user.list = async (req, res) => {
|
||||
@@ -135,7 +211,7 @@ user.findByUsernameOrEmail = async (req, res) => {
|
||||
|
||||
user.updateRoles = async (req, res) => {
|
||||
await User.updatePortalRoles(req.body.rolesPerUser)
|
||||
res.redirect('back')
|
||||
res.redirect(303, 'back')
|
||||
}
|
||||
|
||||
user.adminEdit = async (req, res) => {
|
||||
@@ -144,6 +220,9 @@ user.adminEdit = async (req, res) => {
|
||||
User.fetchUser(userId),
|
||||
User.fetchUserRoles(userId)
|
||||
])
|
||||
|
||||
if (userData.status === 'closed') return res.redirect(303, '/')
|
||||
|
||||
res.render('pages/admin/user-edit', {
|
||||
title: req.t('Uporabnik'),
|
||||
userData,
|
||||
@@ -156,7 +235,7 @@ user.adminEdit = async (req, res) => {
|
||||
user.adminUpdate = async (req, res) => {
|
||||
const { userId } = req.params
|
||||
await User.updateUser(userId, req.body)
|
||||
res.redirect('back')
|
||||
res.redirect(303, 'back')
|
||||
}
|
||||
|
||||
module.exports = user
|
||||
|
||||
Reference in New Issue
Block a user