diff --git a/client/gulp/config.js b/client/gulp/config.js deleted file mode 100644 index 2525122c..00000000 --- a/client/gulp/config.js +++ /dev/null @@ -1,31 +0,0 @@ -'use strict'; - -module.exports = { - - 'serverport': 3006, - - 'scripts': { - 'src': './src/*.js', - 'dest': './build/js/' - }, - - 'images': { - 'src': './src/assets/images/**/*.{jpeg,jpg,png}', - 'dest': './build/images/' - }, - - 'styles': { - 'src': './src/**/*.scss', - 'dest': './build/css/' - }, - - 'fonts': { - 'src': './src/scss/font_awesome/fonts/*', - 'dest': './build/fonts/' - }, - - 'sourceDir': './src/', - - 'buildDir': './build/' - -}; diff --git a/client/gulp/index.js b/client/gulp/index.js deleted file mode 100644 index 2ae5b73c..00000000 --- a/client/gulp/index.js +++ /dev/null @@ -1,11 +0,0 @@ -'use strict'; - -var fs = require('fs'); -var onlyScripts = require('./util/script-filter'); -var tasks = fs.readdirSync('./gulp/tasks/').filter(onlyScripts); - -process.env.NODE_PATH = './src'; - -tasks.forEach(function(task) { - require('./tasks/' + task); -}); \ No newline at end of file diff --git a/client/gulp/tasks/browserSync.js b/client/gulp/tasks/browserSync.js deleted file mode 100644 index 20417584..00000000 --- a/client/gulp/tasks/browserSync.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; - -var config = require('../config'); -var browserSync = require('browser-sync'); -var gulp = require('gulp'); - -gulp.task('browserSync', function() { - - browserSync({ - proxy: 'localhost:' + config.serverport, - startPath: '/' - }); - -}); \ No newline at end of file diff --git a/client/gulp/tasks/browserify.js b/client/gulp/tasks/browserify.js deleted file mode 100644 index bee38653..00000000 --- a/client/gulp/tasks/browserify.js +++ /dev/null @@ -1,78 +0,0 @@ -'use strict'; - -var gulp = require('gulp'); -var gulpif = require('gulp-if'); -var gutil = require('gulp-util'); -var source = require('vinyl-source-stream'); -var streamify = require('gulp-streamify'); -var sourcemaps = require('gulp-sourcemaps'); -var rename = require('gulp-rename'); -var watchify = require('watchify'); -var browserify = require('browserify'); -var babelify = require('babelify'); -var uglify = require('gulp-uglify'); -var browserSync = require('browser-sync'); -var debowerify = require('debowerify'); -var handleErrors = require('../util/handle-errors'); -var config = require('../config'); -var util = require('gulp-util'); - -// Based on: http://blog.avisi.nl/2014/04/25/how-to-keep-a-fast-build-with-browserify-and-reactjs/ -function buildScript(file, watch) { - - var bundler = browserify({ - entries: [config.sourceDir + file], - debug: !global.isProd, - insertGlobalVars: { - isProd: function () { - return (global.isProd) ? "'enabled'" : "'disabled'"; - }, - noFixtures: function() { - return (util.env['api']) ? "'enabled'" : "'disabled'"; - } - }, - cache: {}, - packageCache: {}, - fullPaths: false - }); - - if ( watch ) { - bundler = watchify(bundler); - bundler.on('update', rebundle); - } - - bundler.transform(babelify, {'optional': ['es7.classProperties']}); - bundler.transform(debowerify); - - function rebundle() { - var stream = bundler.bundle(); - - gutil.log('Rebundle...'); - - return stream.on('error', handleErrors) - .pipe(source(file)) - .pipe(gulpif(global.isProd, streamify(uglify()))) - .pipe(streamify(rename({ - basename: 'main' - }))) - .pipe(gulpif(!global.isProd, sourcemaps.write('./'))) - .pipe(gulp.dest(config.scripts.dest)) - .pipe(gulpif(browserSync.active, browserSync.reload({ stream: true, once: true }))); - } - - return rebundle(); - -} - -gulp.task('browserify', function() { - - // Only run watchify if NOT production - return buildScript('index.js', !global.isProd); - -}); - -gulp.task('config', function() { - - return gulp.src(config.sourceDir + 'config.js') - .pipe(gulp.dest(config.scripts.dest)) -}); \ No newline at end of file diff --git a/client/gulp/tasks/clean.js b/client/gulp/tasks/clean.js deleted file mode 100644 index 3486df25..00000000 --- a/client/gulp/tasks/clean.js +++ /dev/null @@ -1,11 +0,0 @@ -'use strict'; - -var config = require('../config'); -var gulp = require('gulp'); -var del = require('del'); - -gulp.task('clean', function(cb) { - - del([config.buildDir], cb); - -}); \ No newline at end of file diff --git a/client/gulp/tasks/copyFonts.js b/client/gulp/tasks/copyFonts.js deleted file mode 100644 index 02d09f49..00000000 --- a/client/gulp/tasks/copyFonts.js +++ /dev/null @@ -1,10 +0,0 @@ -'use strict'; - -var gulp = require('gulp'); -var config = require('../config'); - -gulp.task('copyFonts', function() { - - return gulp.src(config.fonts.src) - .pipe(gulp.dest(config.fonts.dest)) -}); \ No newline at end of file diff --git a/client/gulp/tasks/copyIcons.js b/client/gulp/tasks/copyIcons.js deleted file mode 100644 index 56e2bb4d..00000000 --- a/client/gulp/tasks/copyIcons.js +++ /dev/null @@ -1,11 +0,0 @@ -'use strict'; - -var gulp = require('gulp'); - -gulp.task('copyIcons', function() { - - // Copy icons from root directory to build/ - return gulp.src(['./*.png', './favicon.ico']) - .pipe(gulp.dest('build/')); - -}); \ No newline at end of file diff --git a/client/gulp/tasks/copyIndex.js b/client/gulp/tasks/copyIndex.js deleted file mode 100644 index d526e3c6..00000000 --- a/client/gulp/tasks/copyIndex.js +++ /dev/null @@ -1,12 +0,0 @@ -'use strict'; - -var gulp = require('gulp'); -var config = require('../config'); - -gulp.task('copyIndex', function() { - - gulp.src(config.sourceDir + 'index.html').pipe(gulp.dest(config.buildDir)); - gulp.src(config.sourceDir + 'index.php').pipe(gulp.dest(config.buildDir)); - gulp.src(config.sourceDir + '.htaccess').pipe(gulp.dest(config.buildDir)); - -}); \ No newline at end of file diff --git a/client/gulp/tasks/deploy.js b/client/gulp/tasks/deploy.js deleted file mode 100644 index b6d986c3..00000000 --- a/client/gulp/tasks/deploy.js +++ /dev/null @@ -1,10 +0,0 @@ -'use strict'; - -var gulp = require('gulp'); -//var config = require('../config'); - -gulp.task('deploy', ['prod'], function() { - - // Deploy to hosting environment - -}); \ No newline at end of file diff --git a/client/gulp/tasks/development.js b/client/gulp/tasks/development.js deleted file mode 100644 index e7dbdcae..00000000 --- a/client/gulp/tasks/development.js +++ /dev/null @@ -1,15 +0,0 @@ -'use strict'; - -var gulp = require('gulp'); -var runSequence = require('run-sequence'); - -gulp.task('dev', ['clean'], function(callback) { - - callback = callback || function() {}; - - global.isProd = false; - - // Run all tasks once - return runSequence(['sass', 'imagemin', 'browserify', 'copyFonts', 'copyIndex', 'copyIcons', 'config'], 'watch', callback); - -}); \ No newline at end of file diff --git a/client/gulp/tasks/imagemin.js b/client/gulp/tasks/imagemin.js deleted file mode 100644 index d8803427..00000000 --- a/client/gulp/tasks/imagemin.js +++ /dev/null @@ -1,17 +0,0 @@ -'use strict'; - -var gulp = require('gulp'); -var gulpif = require('gulp-if'); -var imagemin = require('gulp-imagemin'); -var browserSync = require('browser-sync'); -var config = require('../config'); - -gulp.task('imagemin', function() { - - // Run imagemin task on all images - return gulp.src(config.images.src) - .pipe(gulpif(global.isProd, imagemin())) - .pipe(gulp.dest(config.images.dest)) - .pipe(gulpif(browserSync.active, browserSync.reload({ stream: true, once: true }))); - -}); \ No newline at end of file diff --git a/client/gulp/tasks/production.js b/client/gulp/tasks/production.js deleted file mode 100644 index a2de9a81..00000000 --- a/client/gulp/tasks/production.js +++ /dev/null @@ -1,15 +0,0 @@ -'use strict'; - -var gulp = require('gulp'); -var runSequence = require('run-sequence'); - -gulp.task('prod', ['clean'], function(callback) { - process.env.NODE_ENV = 'production'; - - callback = callback || function() {}; - - global.isProd = true; - - runSequence(['sass', 'imagemin', 'browserify', 'copyFonts', 'copyIndex', 'copyIcons'], callback); - -}); diff --git a/client/gulp/tasks/sass.js b/client/gulp/tasks/sass.js deleted file mode 100644 index fa329d55..00000000 --- a/client/gulp/tasks/sass.js +++ /dev/null @@ -1,29 +0,0 @@ -'use strict'; - -var gulp = require('gulp'); -var sass = require('gulp-sass'); -var gulpif = require('gulp-if'); -var browserSync = require('browser-sync'); -var autoprefixer = require('gulp-autoprefixer'); -var bulkSass = require('gulp-sass-bulk-import'); -var plumber = require('gulp-plumber'); -var handleErrors = require('../util/handle-errors'); -var config = require('../config'); - -gulp.task('sass', function () { - - return gulp.src(config.styles.src) - .pipe(bulkSass()) - .pipe(plumber()) - .pipe(sass({ - sourceComments: global.isProd ? 'none' : 'map', - sourceMap: 'sass', - outputStyle: global.isProd ? 'compressed' : 'nested' - })) - .on('error', handleErrors) - .pipe(autoprefixer("last 2 versions", "> 1%", "ie 8")) - .on('error', handleErrors) - .pipe(gulp.dest(config.styles.dest)) - .pipe(gulpif(browserSync.active, browserSync.reload({ stream: true }))); - -}); diff --git a/client/gulp/tasks/server.js b/client/gulp/tasks/server.js deleted file mode 100644 index 4242f39d..00000000 --- a/client/gulp/tasks/server.js +++ /dev/null @@ -1,44 +0,0 @@ -'use strict'; - -var config = require('../config'); -var http = require('http'); -var express = require('express'); -var gulp = require('gulp'); -var gutil = require('gulp-util'); -var morgan = require('morgan'); -var proxy = require('express-http-proxy'); - -gulp.task('server', function() { - - var server = express(); - - // log all requests to the console - server.use(morgan('dev')); - server.use(express.static(config.buildDir)); - - // Proxy php server api - server.use('/api', proxy('http://localhost:8080', { - forwardPath: function(req, res) { - return require('url').parse(req.url).path; - } - })); - - // Serve index.html for all routes to leave routing up to react-router - server.all('/*', function(req, res) { - res.sendFile('index.html', { root: 'build' }); - }); - - // Start webserver if not already running - var s = http.createServer(server); - s.on('error', function(err){ - if(err.code === 'EADDRINUSE'){ - gutil.log('Development server is already started at port ' + config.serverport); - } - else { - throw err; - } - }); - - s.listen(config.serverport); - -}); diff --git a/client/gulp/tasks/tests.js b/client/gulp/tasks/tests.js deleted file mode 100644 index cf4aa3b6..00000000 --- a/client/gulp/tasks/tests.js +++ /dev/null @@ -1,10 +0,0 @@ -'use strict'; - -var gulp = require('gulp'); -//var config = require('../config'); - -gulp.task('test', function() { - - // Run all tests - -}); \ No newline at end of file diff --git a/client/gulp/tasks/watch.js b/client/gulp/tasks/watch.js deleted file mode 100644 index 8c7207c2..00000000 --- a/client/gulp/tasks/watch.js +++ /dev/null @@ -1,13 +0,0 @@ -'use strict'; - -var gulp = require('gulp'); -var config = require('../config'); - -gulp.task('watch', ['browserSync', 'server'], function() { - - // Scripts are automatically watched by Watchify inside Browserify task - gulp.watch(config.styles.src, ['sass']); - gulp.watch(config.images.src, ['imagemin']); - gulp.watch(config.sourceDir + 'index.html', ['copyIndex']); - -}); \ No newline at end of file diff --git a/client/gulp/util/handle-errors.js b/client/gulp/util/handle-errors.js deleted file mode 100644 index 3cf398a3..00000000 --- a/client/gulp/util/handle-errors.js +++ /dev/null @@ -1,27 +0,0 @@ -'use strict'; - -var notify = require('gulp-notify'); - -module.exports = function(error) { - - if( !global.isProd ) { - - var args = Array.prototype.slice.call(arguments); - - // Send error to notification center with gulp-notify - notify.onError({ - title: 'Compile Error', - message: '<%= error.message %>' - }).apply(this, args); - - // Keep gulp from hanging on this task - this.emit('end'); - - } else { - // Log the error and stop the process - // to prevent broken code from building - console.log(error); - process.exit(1); - } - -}; \ No newline at end of file diff --git a/client/gulp/util/script-filter.js b/client/gulp/util/script-filter.js deleted file mode 100644 index 3157bf6e..00000000 --- a/client/gulp/util/script-filter.js +++ /dev/null @@ -1,9 +0,0 @@ -'use strict'; - -var path = require('path'); - -// Filters out non .coffee and .js files. Prevents -// accidental inclusion of possible hidden files -module.exports = function(name) { - return /(\.(js|coffee)$)/i.test(path.extname(name)); -}; \ No newline at end of file diff --git a/client/gulpfile.js b/client/gulpfile.js deleted file mode 100644 index 4c1b4387..00000000 --- a/client/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -global.isProd = false; - -require('./gulp'); diff --git a/client/src/actions/login-form-actions.js b/client/src/actions/login-form-actions.js new file mode 100644 index 00000000..f9c418cf --- /dev/null +++ b/client/src/actions/login-form-actions.js @@ -0,0 +1,15 @@ + +export default { + showLoginForm() { + return { + type: 'SHOW_LOGIN_FORM', + payload: true + }; + }, + hideLoginForm() { + return { + type: 'HIDE_LOGIN_FORM', + payload: false + }; + } +}; diff --git a/client/src/actions/session-actions.js b/client/src/actions/session-actions.js index 910d8ea1..412e37af 100644 --- a/client/src/actions/session-actions.js +++ b/client/src/actions/session-actions.js @@ -101,6 +101,7 @@ export default { }, initSession() { + console.log('sessionStore.isLoggedIn()', sessionStore.isLoggedIn()); return { type: 'CHECK_SESSION', payload: new Promise((resolve, reject) => { diff --git a/client/src/app-components/ticket-list.js b/client/src/app-components/ticket-list.js index b567b862..8971f1ab 100644 --- a/client/src/app-components/ticket-list.js +++ b/client/src/app-components/ticket-list.js @@ -60,7 +60,15 @@ class TicketList extends React.Component { renderFilterCheckbox() { - return + return ( + + ); } renderDepartmentsDropDown() { diff --git a/client/src/app-components/ticket-viewer.js b/client/src/app-components/ticket-viewer.js index ee223281..5772d688 100644 --- a/client/src/app-components/ticket-viewer.js +++ b/client/src/app-components/ticket-viewer.js @@ -635,7 +635,7 @@ class TicketViewer extends React.Component { path: '/ticket/comment', dataAsForm: true, data: _.extend({ - ticketNumber: this.props.ticket.ticketNumber + ticketNumber: this.props.ticket.ticketNumber, }, formState, {private: formState.private ? 1 : 0}, TextEditor.getContentFormData(formState.content)) }).then(this.onCommentSuccess.bind(this), this.onCommentFail.bind(this)); } @@ -712,7 +712,6 @@ export default connect((store) => { staffMembers: store.adminData.staffMembers, staffMembersLoaded: store.adminData.staffMembersLoaded, allowAttachments: store.config['allow-attachments'], - userSystemEnabled: store.config['user-system-enabled'], userLevel: store.session.userLevel, tags: store.config['tags'] }; diff --git a/client/src/app/App.js b/client/src/app/App.js index c62353cf..8ca072d8 100644 --- a/client/src/app/App.js +++ b/client/src/app/App.js @@ -50,7 +50,7 @@ class App extends React.Component { 'application': true, 'application_modal-opened': (this.props.modal.opened), 'application_full-width': (this.props.config.layout === 'full-width' && !_.includes(this.props.location.pathname, '/admin')), - 'application_user-system': (this.props.config['user-system-enabled']) + 'application_mandatory-login': (this.props.config['mandatory-login']) }; return classNames(classes); @@ -99,7 +99,7 @@ class App extends React.Component { history.push('/'); } - if(props.config['user-system-enabled'] && _.includes(props.location.pathname, '/check-ticket')) { + if(props.config['mandatory-login'] && _.includes(props.location.pathname, '/check-ticket')) { history.push('/'); } diff --git a/client/src/app/admin/panel/admin-panel-menu.js b/client/src/app/admin/panel/admin-panel-menu.js index 9627947a..e33ad820 100644 --- a/client/src/app/admin/panel/admin-panel-menu.js +++ b/client/src/app/admin/panel/admin-panel-menu.js @@ -155,7 +155,7 @@ class AdminPanelMenu extends React.Component { ...customLists ]) }, - this.props.config['user-system-enabled'] ? { + { groupName: i18n('USERS'), path: '/admin/panel/users', icon: 'user', @@ -177,7 +177,7 @@ class AdminPanelMenu extends React.Component { level: 1 } ]) - } : null, + }, { groupName: i18n('ARTICLES'), path: '/admin/panel/articles', diff --git a/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js b/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js index f401baf5..7e65e631 100644 --- a/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js +++ b/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js @@ -17,6 +17,7 @@ import Listing from 'core-components/listing'; import Form from 'core-components/form'; import FormField from 'core-components/form-field'; import SubmitButton from 'core-components/submit-button'; +import Checkbox from 'core-components/checkbox'; class AdminPanelAdvancedSettings extends React.Component { @@ -36,24 +37,33 @@ class AdminPanelAdvancedSettings extends React.Component { } render() { + const { config } = this.props; return (
{(this.state.messageType) ? this.renderMessage() : null}
-
-
- - {i18n('ENABLE_USER_SYSTEM')} - - -
+
+
- {i18n('ENABLE_USER_REGISTRATION')} - +
@@ -95,7 +105,9 @@ class AdminPanelAdvancedSettings extends React.Component { renderMessage() { return ( - {this.state.messageContent} + + {this.state.messageContent} + ); } @@ -182,17 +194,21 @@ class AdminPanelAdvancedSettings extends React.Component { }); } - onToggleButtonUserSystemChange() { + onCheckboxMandatoryLoginChange() { AreYouSure.openModal(null, this.onAreYouSureUserSystemOk.bind(this), 'secure'); } - onToggleButtonRegistrationChange() { + onCheckboxRegistrationChange() { AreYouSure.openModal(null, this.onAreYouSureRegistrationOk.bind(this), 'secure'); } onAreYouSureUserSystemOk(password) { - return API.call({ - path: this.props.config['user-system-enabled'] ? '/system/disable-user-system' : '/system/enable-user-system', + const { + config, + dispatch + } = this.props; + API.call({ + path: config['mandatory-login'] ? '/system/disable-mandatory-login' : '/system/enable-mandatory-login', data: { password: password } @@ -200,15 +216,19 @@ class AdminPanelAdvancedSettings extends React.Component { this.setState({ messageType: 'success', messageTitle: null, - messageContent: this.props.config['user-system-enabled'] ? i18n('USER_SYSTEM_DISABLED') : i18n('USER_SYSTEM_ENABLED') + messageContent: config['mandatory-login'] ? i18n('MANDATORY_LOGIN_DISABLED') : i18n('MANDATORY_LOGIN_ENABLED') }); - this.props.dispatch(ConfigActions.updateData()); + dispatch(ConfigActions.updateData()); }).catch(() => this.setState({messageType: 'error', messageTitle: null, messageContent: i18n('ERROR_UPDATING_SETTINGS')})); } onAreYouSureRegistrationOk(password) { - return API.call({ - path: this.props.config['registration'] ? '/system/disable-registration' : '/system/enable-registration', + const { + config, + dispatch + } = this.props; + API.call({ + path: config['registration'] ? '/system/disable-registration' : '/system/enable-registration', data: { password: password } @@ -216,9 +236,9 @@ class AdminPanelAdvancedSettings extends React.Component { this.setState({ messageType: 'success', messageTitle: null, - messageContent: this.props.config['registration'] ? i18n('REGISTRATION_DISABLED') : i18n('REGISTRATION_ENABLED') + messageContent: config['registration'] ? i18n('REGISTRATION_DISABLED') : i18n('REGISTRATION_ENABLED') }); - this.props.dispatch(ConfigActions.updateData()); + dispatch(ConfigActions.updateData()); }).catch(() => this.setState({messageType: 'error', messageTitle: null, messageContent: i18n('ERROR_UPDATING_SETTINGS')})); } diff --git a/client/src/app/admin/panel/settings/admin-panel-advanced-settings.scss b/client/src/app/admin/panel/settings/admin-panel-advanced-settings.scss index 86ec9150..81082aea 100644 --- a/client/src/app/admin/panel/settings/admin-panel-advanced-settings.scss +++ b/client/src/app/admin/panel/settings/admin-panel-advanced-settings.scss @@ -1,7 +1,7 @@ @import "../../../../scss/vars"; .admin-panel-advanced-settings { - &__user-system-enabled { + &__mandatory-login { } @@ -9,13 +9,6 @@ } - &__toggle-button { - display: inline-block; - margin-left: 20px; - margin-top: 20px; - margin-bottom: 20px; - } - &__text { margin-top: 30px; margin-bottom: 20px; @@ -61,4 +54,8 @@ font-size: $font-size--md; } } + + &__message { + margin-bottom: 20px; + } } diff --git a/client/src/app/admin/panel/tickets/admin-panel-view-ticket.js b/client/src/app/admin/panel/tickets/admin-panel-view-ticket.js index f1273c20..dab34323 100644 --- a/client/src/app/admin/panel/tickets/admin-panel-view-ticket.js +++ b/client/src/app/admin/panel/tickets/admin-panel-view-ticket.js @@ -15,12 +15,14 @@ class AdminPanelViewTicket extends React.Component { static propTypes = { avoidSeen: React.PropTypes.bool, onRetrieveFail: React.PropTypes.func, - assignmentAllowed: React.PropTypes.bool + assignmentAllowed: React.PropTypes.bool, + editable: React.PropTypes.bool, }; static defaultProps = { avoidSeen: false, - assignmentAllowed: true + assignmentAllowed: true, + editable: true, }; state = { @@ -75,7 +77,7 @@ class AdminPanelViewTicket extends React.Component { onChange: this.retrieveTicket.bind(this), assignmentAllowed: this.props.assignmentAllowed, customResponses: this.props.customResponses, - editable: true + editable: this.props.editable, }; } diff --git a/client/src/app/app.scss b/client/src/app/app.scss index 77a8ea7a..c25ac3f2 100644 --- a/client/src/app/app.scss +++ b/client/src/app/app.scss @@ -105,7 +105,7 @@ } } - &.application_user-system { + &.application_mandatory-login { .main-layout { background-color: white; diff --git a/client/src/app/install/install-layout.js b/client/src/app/install/install-layout.js index c276340b..1ff5ae8e 100644 --- a/client/src/app/install/install-layout.js +++ b/client/src/app/install/install-layout.js @@ -13,7 +13,6 @@ const steps = [ 'LANGUAGE', 'SERVER_REQUIREMENTS', 'DATABASE_CONFIGURATION', - 'USER_SYSTEM', 'SETTINGS', 'ADMIN_SETUP', 'COMPLETED' diff --git a/client/src/app/install/install-step-1-language.js b/client/src/app/install/install-step-1-language.js index 240b3d1b..c8f9507e 100644 --- a/client/src/app/install/install-step-1-language.js +++ b/client/src/app/install/install-step-1-language.js @@ -17,7 +17,7 @@ class InstallStep1Language extends React.Component {
-
diff --git a/client/src/app/install/install-step-2-requirements.js b/client/src/app/install/install-step-2-requirements.js index bfcbe802..12a490b0 100644 --- a/client/src/app/install/install-step-2-requirements.js +++ b/client/src/app/install/install-step-2-requirements.js @@ -38,14 +38,14 @@ class InstallStep2Requirements extends React.Component {
+
+ +
-
-
- -
); diff --git a/client/src/app/install/install-step-2-requirements.scss b/client/src/app/install/install-step-2-requirements.scss index 00566801..d0f860b1 100644 --- a/client/src/app/install/install-step-2-requirements.scss +++ b/client/src/app/install/install-step-2-requirements.scss @@ -43,12 +43,16 @@ } &__previous { - float: left; + } + + &__buttons { + width: 55%; + display: inline-flex; + flex-direction: row; + justify-content: space-between; + align-items: center; } &__next { - float: left; - position: absolute; - margin-left: 103px; } } \ No newline at end of file diff --git a/client/src/app/install/install-step-3-database.js b/client/src/app/install/install-step-3-database.js index 27b13c80..d008e229 100644 --- a/client/src/app/install/install-step-3-database.js +++ b/client/src/app/install/install-step-3-database.js @@ -21,19 +21,20 @@ class InstallStep3Database extends React.Component { }; render() { + const { loading } = this.state; return (
{this.renderMessage()} -
+
- {i18n('NEXT')} - + + {i18n('NEXT')}
diff --git a/client/src/app/install/install-step-3-database.scss b/client/src/app/install/install-step-3-database.scss index 6a4bac27..2c9a6c7f 100644 --- a/client/src/app/install/install-step-3-database.scss +++ b/client/src/app/install/install-step-3-database.scss @@ -10,9 +10,14 @@ float: left; } + &__buttons { + width: 55%; + display: inline-flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + } + &__next { - float: left; - position: absolute; - margin-left: 286px; } } \ No newline at end of file diff --git a/client/src/app/install/install-step-4-user-system.js b/client/src/app/install/install-step-4-user-system.js index d4ae18c0..ec6de823 100644 --- a/client/src/app/install/install-step-4-user-system.js +++ b/client/src/app/install/install-step-4-user-system.js @@ -6,7 +6,6 @@ import i18n from 'lib-app/i18n'; import ConfigActions from 'actions/config-actions'; import ToggleButton from 'app-components/toggle-button'; -import Button from 'core-components/button'; import Header from 'core-components/header'; import Form from 'core-components/form'; import FormField from 'core-components/form-field'; @@ -16,20 +15,31 @@ class InstallStep4UserSystem extends React.Component { state = { form: { - 'user-system-enabled': true, + 'mandatory-login': true, 'registration': true } }; render() { + const { form } = this.state return (
-
- - + +
+ + +
- {i18n('NEXT')} + {i18n('NEXT')}
@@ -39,24 +49,20 @@ class InstallStep4UserSystem extends React.Component { onChange(form) { this.setState({ form: { - 'user-system-enabled': form['user-system-enabled'], - 'registration': form['user-system-enabled'] && form['registration'] + 'mandatory-login': form['mandatory-login'], + 'registration': form['registration'] } }); } onSubmit(form) { this.props.dispatch(ConfigActions.updateUserSystemSettings({ - 'user-system-enabled': form['user-system-enabled'] * 1, + 'mandatory-login': form['mandatory-login'] * 1, 'registration': form['registration'] * 1 })); history.push('/install/step-5'); } - - isDisabled() { - return !this.state.form['user-system-enabled']; - } } export default connect((store) => { diff --git a/client/src/app/install/install-step-4-user-system.scss b/client/src/app/install/install-step-4-user-system.scss index ad8ac7c7..3b135417 100644 --- a/client/src/app/install/install-step-4-user-system.scss +++ b/client/src/app/install/install-step-4-user-system.scss @@ -1,15 +1,17 @@ @import "../../scss/vars"; .install-step-4 { + &__container { + display: inline-flex; + justify-content: space-between; + width: 70%; + } + &__previous { margin-right: 20px; } &__next { - float: left; - position: absolute; - margin-left: 230px; - min-width: 70px; } } \ No newline at end of file diff --git a/client/src/app/install/install-step-5-settings.js b/client/src/app/install/install-step-5-settings.js index 6ed8c770..291edcd1 100755 --- a/client/src/app/install/install-step-5-settings.js +++ b/client/src/app/install/install-step-5-settings.js @@ -24,11 +24,16 @@ class InstallStep5Settings extends React.Component { }; render() { + const { + loading, + form + } = this.state; + return (
{this.renderMessage()} -
this.setState({form})}> + this.setState({form})}> @@ -37,13 +42,22 @@ class InstallStep5Settings extends React.Component { - + {i18n('TEST_SMTP_CONNECTION')}
- {i18n('NEXT')} - + + {i18n('NEXT')} + +
@@ -103,8 +117,8 @@ class InstallStep5Settings extends React.Component { data: _.extend({}, form, { 'url': root, 'language': this.props.language, - 'user-system-enabled': this.props['user-system-enabled'], - 'registration': this.props['registration'] + 'mandatory-login': this.props['mandatory-login'] ? 1 : 0, + 'registration': this.props['registration'] ? 1 : 0 }) }) .then(() => history.push('/install/step-6')) @@ -119,7 +133,7 @@ class InstallStep5Settings extends React.Component { export default connect((store) => { return { - 'user-system-enabled': store.config['user-system-enabled'], + 'mandatory-login': store.config['mandatory-login'], 'registration': store.config['registration'], language: store.config.language }; diff --git a/client/src/app/install/install-step-6-admin.js b/client/src/app/install/install-step-6-admin.js index 7109ae71..c627e59e 100644 --- a/client/src/app/install/install-step-6-admin.js +++ b/client/src/app/install/install-step-6-admin.js @@ -28,7 +28,7 @@ class InstallStep6Admin extends React.Component {
- {i18n('NEXT')} + {i18n('NEXT')}
diff --git a/client/src/app/main/dashboard/dashboard-create-ticket/dashboard-create-ticket-page.js b/client/src/app/main/dashboard/dashboard-create-ticket/dashboard-create-ticket-page.js index eb9f65a2..47f05ba6 100644 --- a/client/src/app/main/dashboard/dashboard-create-ticket/dashboard-create-ticket-page.js +++ b/client/src/app/main/dashboard/dashboard-create-ticket/dashboard-create-ticket-page.js @@ -44,7 +44,7 @@ class DashboardCreateTicketPage extends React.Component { let classes = { 'dashboard-create-ticket-page': true, 'dashboard-create-ticket-page_wrapped': (this.props.location.pathname === '/create-ticket'), - 'col-md-10 col-md-offset-1': (!this.props.config['user-system-enabled']) + 'col-md-10 col-md-offset-1': !this.props.isLogged }; return classNames(classes); @@ -53,6 +53,7 @@ class DashboardCreateTicketPage extends React.Component { export default connect((store) => { return { + isLogged: store.session.logged, config: store.config }; })(DashboardCreateTicketPage); diff --git a/client/src/app/main/dashboard/dashboard-list-articles/dashboard-list-articles-page.js b/client/src/app/main/dashboard/dashboard-list-articles/dashboard-list-articles-page.js index 3ab6516a..dad1eecf 100644 --- a/client/src/app/main/dashboard/dashboard-list-articles/dashboard-list-articles-page.js +++ b/client/src/app/main/dashboard/dashboard-list-articles/dashboard-list-articles-page.js @@ -77,7 +77,7 @@ class DashboardListArticlesPage extends React.Component { let classes = { 'dashboard-list-articles-page': true, 'dashboard-list-articles-page_wrapped': (this.props.location.pathname == '/dashboard/articles'), - 'col-md-10 col-md-offset-1': (!this.props.config['user-system-enabled']) + 'col-md-10 col-md-offset-1': !this.props.isLogged }; return classNames(classes); @@ -125,6 +125,7 @@ class DashboardListArticlesPage extends React.Component { export default connect((store) => { return { + isLogged: store.session.logged, config: store.config, topics: store.articles.topics, loading: store.articles.loading diff --git a/client/src/app/main/main-check-ticket-page.js b/client/src/app/main/main-check-ticket-page.js index d03e12b8..3e278ff7 100644 --- a/client/src/app/main/main-check-ticket-page.js +++ b/client/src/app/main/main-check-ticket-page.js @@ -52,7 +52,6 @@ class MainCheckTicketPage extends React.Component { getClass() { let classes = { 'main-check-ticket-page': true, - 'col-md-10 col-md-offset-1': (!this.props.config['user-system-enabled']) }; return classNames(classes); @@ -98,7 +97,7 @@ class MainCheckTicketPage extends React.Component { } onTicketGetSuccess(result) { - SessionStore.setItem('token', result.data.token); + SessionStore.createSession(result.data.userId, result.data.token, this.state.form.ticketNumber); setTimeout(() => {history.push('/view-ticket/' + this.state.form.ticketNumber)}, 2000); } } diff --git a/client/src/app/main/main-home/main-home-page-login-widget.scss b/client/src/app/main/main-home/main-home-page-login-widget.scss index c1b42380..899b3eb3 100644 --- a/client/src/app/main/main-home/main-home-page-login-widget.scss +++ b/client/src/app/main/main-home/main-home-page-login-widget.scss @@ -2,6 +2,7 @@ &__container { height: 361px; + width: 324px; } &__inputs { @@ -17,4 +18,14 @@ &__message { margin-top: 18px; } -} + + @media screen and (min-width: 379px) { + .login-widget__container { + min-width: 324px; + } + } + @media screen and (max-width: 409px) { + .login-widget__container { + min-width: 313px; + } + }} diff --git a/client/src/app/main/main-home/main-home-page.js b/client/src/app/main/main-home/main-home-page.js index 5bc6d323..3dca00e1 100644 --- a/client/src/app/main/main-home/main-home-page.js +++ b/client/src/app/main/main-home/main-home-page.js @@ -11,13 +11,20 @@ import Message from 'core-components/message'; class MainHomePage extends React.Component { render() { + const { + config, + loginForm + } = this.props; return ( -
+
{this.renderMessage()} - {(this.props.config['user-system-enabled']) ? this.renderLoginWidget() : null} -
- -
+ {(config['mandatory-login']) || loginForm.loginFormShown ? this.renderLoginWidget() : null} + {!loginForm.loginFormShown ? +
+ +
: + null + }
); } @@ -35,7 +42,7 @@ class MainHomePage extends React.Component { renderLoginWidget() { return ( -
+
); @@ -57,11 +64,23 @@ class MainHomePage extends React.Component { ); } + getLoginWidgetClass() { + const { config } = this.props; + let classes = { + 'col-md-4': config['mandatory-login'], + 'main-home-page__login-widget': config['mandatory-login'], + 'main-home-page__center': !config['mandatory-login'] + }; + + return classNames(classes); + } + getPortalClass() { + const { config } = this.props; let classes = { 'main-home-page__portal-wrapper': true, - 'col-md-8': (this.props.config['user-system-enabled'] && this.props.config['layout'] === 'boxed'), - 'col-md-10 col-md-offset-1' : (!this.props.config['user-system-enabled']) + 'col-md-8': (this.props.config['mandatory-login'] && this.props.config['layout'] === 'boxed'), + 'col-md-10 col-md-offset-1' : (!this.props.config['mandatory-login']) }; return classNames(classes); @@ -71,6 +90,7 @@ class MainHomePage extends React.Component { export default connect((store) => { return { session: store.session, - config: store.config + config: store.config, + loginForm: store.loginForm }; })(MainHomePage); \ No newline at end of file diff --git a/client/src/app/main/main-home/main-home-page.scss b/client/src/app/main/main-home/main-home-page.scss index b21ec3d0..3283f970 100644 --- a/client/src/app/main/main-home/main-home-page.scss +++ b/client/src/app/main/main-home/main-home-page.scss @@ -1,5 +1,10 @@ .main-home-page { + &__center { + display: flex; + justify-content: center; + } + &__message { margin-bottom: 20px; margin-left: 20px; diff --git a/client/src/app/main/main-layout-header.js b/client/src/app/main/main-layout-header.js index 57979555..6cad5ac2 100644 --- a/client/src/app/main/main-layout-header.js +++ b/client/src/app/main/main-layout-header.js @@ -6,33 +6,52 @@ import ConfigActions from 'actions/config-actions'; import LanguageSelector from 'app-components/language-selector'; import Button from 'core-components/button'; +import loginFormActions from '../../actions/login-form-actions'; class MainLayoutHeader extends React.Component { render() { return (
- {(this.props.config['user-system-enabled']) ? this.renderAccessLinks() : this.renderHomeLink()} + {this.renderAccessLinks()}
); } renderAccessLinks() { + const { + session, + config + } = this.props; let result; - if (this.props.session.logged) { + if (session.logged) { result = (
{i18n('WELCOME')}, - {this.props.session.userName} + {session.userName}
); } else { result = (
- - {(!!(this.props.config['registration'] * 1)) ? : null} + + {(config['registration'] * 1) ? + : + null} + {!config['mandatory-login'] ? + : + null}
); } @@ -40,14 +59,6 @@ class MainLayoutHeader extends React.Component { return result; } - renderHomeLink() { - return ( -
- -
- ); - } - getLanguageSelectorProps() { return { className: 'main-layout-header__languages', @@ -60,11 +71,19 @@ class MainLayoutHeader extends React.Component { changeLanguage(event) { this.props.dispatch(ConfigActions.changeLanguage(event.target.value)); } + + onShowLoginForm() { + this.props.dispatch(loginFormActions.showLoginForm()) + } + + onHideLoginForm() { + this.props.dispatch(loginFormActions.hideLoginForm()) + } } export default connect((store) => { return { session: store.session, - config: store.config + config: store.config, }; })(MainLayoutHeader); diff --git a/client/src/app/main/main-layout.js b/client/src/app/main/main-layout.js index 5a259324..74be940d 100644 --- a/client/src/app/main/main-layout.js +++ b/client/src/app/main/main-layout.js @@ -9,7 +9,7 @@ class MainLayout extends React.Component { return (
-
+
{this.props.children}
diff --git a/client/src/app/main/main-view-ticket-page.js b/client/src/app/main/main-view-ticket-page.js index 08f2cbb8..6933be76 100644 --- a/client/src/app/main/main-view-ticket-page.js +++ b/client/src/app/main/main-view-ticket-page.js @@ -12,16 +12,19 @@ class MainViewTicketPage extends React.Component { return (
- +
); } onRetrieveFail() { - if (!this.props.config['user-system-enabled']) { - setTimeout(() => {history.push('/check-ticket')}, 2000); - } + setTimeout(() => {history.push('/check-ticket')}, 2000); } } diff --git a/client/src/core-components/widget-transition.scss b/client/src/core-components/widget-transition.scss index d52a76d5..f8024ce3 100644 --- a/client/src/core-components/widget-transition.scss +++ b/client/src/core-components/widget-transition.scss @@ -6,9 +6,9 @@ -webkit-perspective: 0; -webkit-backface-visibility: hidden; -webkit-transform: translate3d(0,0,0); - display: inline-block; visibility: visible; backface-visibility: hidden; + display: inline-block; position: absolute; left: 0; } diff --git a/client/src/data/fixtures/system-fixtures.js b/client/src/data/fixtures/system-fixtures.js index a84b2b25..76d9f00a 100755 --- a/client/src/data/fixtures/system-fixtures.js +++ b/client/src/data/fixtures/system-fixtures.js @@ -30,7 +30,7 @@ module.exports = [ 'allowedLanguages': ['en', 'es', 'de', 'fr', 'pt', 'jp', 'ru', 'cn', 'in', 'tr'], 'supportedLanguages': ['en', 'es', 'de'], 'registration': true, - 'user-system-enabled': true, + 'mandatory-login': true, 'tags': [{id:1,name:'bug', color:'#eb144c'},{id: 2,name:'suggestion',color:'#ff6900'}] } }; @@ -52,7 +52,7 @@ module.exports = [ 'allowedLanguages': ['en', 'es', 'de', 'fr', 'pt', 'jp', 'ru', 'cn', 'in', 'tr'], 'supportedLanguages': ['en', 'es', 'de'], 'registration': true, - 'user-system-enabled': true, + 'mandatory-login': true, 'tags': [{id:1,name:'bug', color:'#eb144c'},{id: 2,name:'suggestion',color:'#ff6900'}] } }; diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js index a8380b5b..3bceeb42 100644 --- a/client/src/data/languages/en.js +++ b/client/src/data/languages/en.js @@ -174,7 +174,7 @@ export default { 'ALL_NOTIFICATIONS': 'All notifications', 'VERIFY_SUCCESS': 'User verified', 'VERIFY_FAILED': 'Could not verify', - 'ENABLE_USER_SYSTEM': 'Use user system for customers', + 'ENABLE_MANDATORY_LOGIN': 'Mandatory login for customers', 'ENABLE_USER_REGISTRATION': 'Enable user registration', 'INCLUDE_USERS_VIA_CSV': 'Include users via CSV file', 'BACKUP_DATABASE': 'Backup database', @@ -324,8 +324,8 @@ export default { 'VERIFY_FAILED_DESCRIPTION': 'The verification could not be done.', 'STATISTICS_DESCRIPTION': 'Here you can view statistics related to tickets and signups.', 'ADVANCED_SETTINGS_DESCRIPTION': 'Here you can change the advanced settings of your system. Please be careful, the changes you make can not be reversed.', - 'USER_SYSTEM_DISABLED': 'User system has been disabled', - 'USER_SYSTEM_ENABLED': 'User system has been enabled', + 'MANDATORY_LOGIN_DISABLED': 'Mandatory login has been disabled', + 'MANDATORY_LOGIN_ENABLED': 'Mandatory login has been enabled', 'REGISTRATION_DISABLED': 'Registration has been disabled', 'REGISTRATION_ENABLED': 'Registration has been enabled', 'ADD_API_KEY_DESCRIPTION': 'Insert the name and a registration api key will be generated.', diff --git a/client/src/lib-app/session-store.js b/client/src/lib-app/session-store.js index f221df5b..995a32f0 100644 --- a/client/src/lib-app/session-store.js +++ b/client/src/lib-app/session-store.js @@ -6,9 +6,10 @@ class SessionStore { this.storage = LocalStorage; } - createSession(userId, token) { + createSession(userId, token, ticketNumber = '') { this.setItem('userId', userId); this.setItem('token', token); + this.setItem('ticketNumber', ticketNumber); } getSessionData() { @@ -19,12 +20,17 @@ class SessionStore { } isLoggedIn() { - return !!this.getItem('userId'); + return !!this.getItem('userId') && !this.getItem('ticketNumber'); + } + + isLoggedInWithTicket() { + return !!this.getItem('userId') && this.getItem('ticketNumber'); } closeSession() { this.removeItem('userId'); this.removeItem('token'); + this.removeItem('ticketNumber'); this.clearRememberData(); this.clearUserData(); @@ -58,7 +64,7 @@ class SessionStore { this.setItem('layout', configs.layout); this.setItem('title', configs.title); this.setItem('registration', configs.registration); - this.setItem('user-system-enabled', configs['user-system-enabled']); + this.setItem('mandatory-login', configs['mandatory-login']); this.setItem('allow-attachments', configs['allow-attachments']); this.setItem('maintenance-mode', configs['maintenance-mode']); this.setItem('max-size', configs['max-size']); @@ -76,7 +82,7 @@ class SessionStore { layout: this.getItem('layout'), title: this.getItem('title'), registration: (this.getItem('registration') * 1), - 'user-system-enabled': (this.getItem('user-system-enabled') * 1), + 'mandatory-login': (this.getItem('mandatory-login') * 1), 'allow-attachments': (this.getItem('allow-attachments') * 1), 'maintenance-mode': (this.getItem('maintenance-mode') * 1), 'max-size': this.getItem('max-size'), diff --git a/client/src/reducers/_reducers.js b/client/src/reducers/_reducers.js index ff73dfc3..0fa0bc68 100644 --- a/client/src/reducers/_reducers.js +++ b/client/src/reducers/_reducers.js @@ -6,10 +6,12 @@ import configReducer from 'reducers/config-reducer'; import modalReducer from 'reducers/modal-reducer'; import articlesReducer from 'reducers/articles-reducer'; import adminDataReducer from 'reducers/admin-data-reducer'; +import loginFormReducer from './login-form-reducer'; export default combineReducers({ session: sessionReducer, config: configReducer, + loginForm: loginFormReducer, modal: modalReducer, articles: articlesReducer, adminData: adminDataReducer, diff --git a/client/src/reducers/config-reducer.js b/client/src/reducers/config-reducer.js index 3d8fe52f..53a471f4 100644 --- a/client/src/reducers/config-reducer.js +++ b/client/src/reducers/config-reducer.js @@ -46,7 +46,7 @@ class ConfigReducer extends Reducer { return _.extend({}, state, payload.data, { language: currentLanguage || payload.data.language || 'en', registration: !!(payload.data.registration * 1), - 'user-system-enabled': !!(payload.data['user-system-enabled']* 1), + 'mandatory-login': !!(payload.data['mandatory-login']* 1), 'allow-attachments': !!(payload.data['allow-attachments']* 1), 'maintenance-mode': !!(payload.data['maintenance-mode']* 1), departments: payload.data.departments && payload.data.departments.map(department => _.extend({}, department, {private: department.private * 1})), @@ -56,7 +56,7 @@ class ConfigReducer extends Reducer { onUserSystemSettingsChange(state, payload) { return _.extend({}, state, { - 'user-system-enabled': !!(payload['user-system-enabled'] * 1), + 'mandatory-login': !!(payload['mandatory-login'] * 1), 'registration': !!(payload['registration'] * 1) }); } diff --git a/client/src/reducers/login-form-reducer.js b/client/src/reducers/login-form-reducer.js new file mode 100644 index 00000000..7b748b8f --- /dev/null +++ b/client/src/reducers/login-form-reducer.js @@ -0,0 +1,34 @@ +import _ from 'lodash'; + +import Reducer from 'reducers/reducer'; + +class loginFormReducer extends Reducer { + + getInitialState() { + return { + loginFormShown: false, + }; + } + + getTypeHandlers() { + return { + 'SHOW_LOGIN_FORM': this.showLoginForm, + 'HIDE_LOGIN_FORM': this.hideLoginForm, + }; + } + + showLoginForm(state, payload) { + return _.extend({}, state, { + loginFormShown: payload + }); + } + + hideLoginForm(state, payload) { + return _.extend({}, state, { + loginFormShown: payload + }); + } +} + +export default loginFormReducer.getInstance(); + diff --git a/server/controllers/article/get-all.php b/server/controllers/article/get-all.php index 7f37dedf..4b8a272a 100755 --- a/server/controllers/article/get-all.php +++ b/server/controllers/article/get-all.php @@ -25,7 +25,7 @@ class GetAllArticlesController extends Controller { public function validations() { return [ - 'permission' => (Controller::isUserSystemEnabled()) ? 'user' : 'any', + 'permission' => (Controller::isLoginMandatory()) ? 'user' : 'any', 'requestData' => [] ]; } diff --git a/server/controllers/system.php b/server/controllers/system.php index 51aca2bc..9d0d48e7 100755 --- a/server/controllers/system.php +++ b/server/controllers/system.php @@ -27,8 +27,8 @@ $systemControllerGroup->addController(new DeleteAllUsersController); $systemControllerGroup->addController(new BackupDatabaseController); $systemControllerGroup->addController(new DownloadController); $systemControllerGroup->addController(new CSVImportController); -$systemControllerGroup->addController(new DisableUserSystemController); -$systemControllerGroup->addController(new EnableUserSystemController); +$systemControllerGroup->addController(new EnableMandatoryLoginController); +$systemControllerGroup->addController(new DisableMandatoryLoginController); $systemControllerGroup->addController(new TestSMTPController); $systemControllerGroup->addController(new TestIMAPController); $systemControllerGroup->addController(new EmailPollingController); diff --git a/server/controllers/system/disable-mandatory-login.php b/server/controllers/system/disable-mandatory-login.php new file mode 100644 index 00000000..bc4227a5 --- /dev/null +++ b/server/controllers/system/disable-mandatory-login.php @@ -0,0 +1,54 @@ + 'staff_3', + 'requestData' => [] + ]; + } + + public function handler() { + $password = Controller::request('password'); + + if(!Setting::getSetting('registration')->getValue()) { + throw new Exception(ERRORS::REGISTRATION_IS_DESACTIVATED); + } + + if(!Hashing::verifyPassword($password, Controller::getLoggedUser()->password)) { + throw new RequestException(ERRORS::INVALID_PASSWORD); + } + + $mandatoryLoginRow = Setting::getSetting('mandatory-login'); + + $mandatoryLoginRow->value = 0; + $mandatoryLoginRow->store(); + + Response::respondSuccess(); + } +} \ No newline at end of file diff --git a/server/controllers/system/disable-registration.php b/server/controllers/system/disable-registration.php index f1ba1b9c..776fe17e 100755 --- a/server/controllers/system/disable-registration.php +++ b/server/controllers/system/disable-registration.php @@ -16,6 +16,7 @@ * * @apiUse NO_PERMISSION * @apiUse INVALID_PASSWORD + * @apiUse MANDATORY_LOGIN_IS_DESACTIVATED * * @apiSuccess {Object} data Empty object * @@ -39,7 +40,9 @@ class DisableRegistrationController extends Controller { throw new RequestException(ERRORS::INVALID_PASSWORD); return; } - + if(!Setting::getSetting('mandatory-login')->getValue()) { + throw new Exception(ERRORS::MANDATORY_LOGIN_IS_DESACTIVATED); + } $registrationRow = Setting::getSetting('registration'); $registrationRow->value = false; diff --git a/server/controllers/system/disable-user-system.php b/server/controllers/system/disable-user-system.php deleted file mode 100755 index 522a5e91..00000000 --- a/server/controllers/system/disable-user-system.php +++ /dev/null @@ -1,82 +0,0 @@ - 'staff_3', - 'requestData' => [] - ]; - } - - public function handler() { - $password = Controller::request('password'); - - if(!Hashing::verifyPassword($password, Controller::getLoggedUser()->password)) { - throw new RequestException(ERRORS::INVALID_PASSWORD); - - } - - if(!Controller::isUserSystemEnabled()) { - throw new RequestException(ERRORS::SYSTEM_USER_IS_ALREADY_DISABLED); - } - - $userSystemEnabled = Setting::getSetting('user-system-enabled'); - $userSystemEnabled->value = 0 ; - $userSystemEnabled->store(); - - $userList = User::getAll(); - - foreach($userList as $user) { - $ticketNumberList = ''; - - foreach($user->sharedTicketList as $ticket) { - $ticket->authorEmail = $user->email; - $ticket->authorName = $user->name; - $ticket->author = null; - - $ticketNumberList .= $ticket->ticketNumber . ' - ' . $ticket->title . '
'; - $ticket->store(); - } - - $mailSender = MailSender::getInstance(); - - $mailSender->setTemplate(MailTemplate::USER_SYSTEM_DISABLED, [ - 'to' => $user->email, - 'name' => $user->name, - 'tickets' => $ticketNumberList, - 'url' => Setting::getSetting('url')->getValue() - ]); - - $mailSender->send(); - - $user->delete(); - } - - Response::respondSuccess(); - } -} diff --git a/server/controllers/system/download.php b/server/controllers/system/download.php index a8027f2f..29009f5d 100755 --- a/server/controllers/system/download.php +++ b/server/controllers/system/download.php @@ -57,7 +57,7 @@ class DownloadController extends Controller { } break; case FileManager::PERMISSION_ARTICLE: - if(Controller::isUserSystemEnabled() && !$session->sessionExists()) { + if(!$session->sessionExists()) { return Response::respond403(); } break; diff --git a/server/controllers/system/email-polling.php b/server/controllers/system/email-polling.php index 092da5e3..0725b7f5 100755 --- a/server/controllers/system/email-polling.php +++ b/server/controllers/system/email-polling.php @@ -20,6 +20,8 @@ class EmailPollingController extends Controller { } public function handler() { + throw new RequestException(ERRORS::NO_PERMISSION); + $commentController = new CommentController(); $createController = new CreateController(); $defaultLanguage = Setting::getSetting('language')->getValue(); @@ -29,8 +31,6 @@ class EmailPollingController extends Controller { if(Controller::request('token') !== Setting::getSetting('imap-token')->getValue()) throw new RequestException(ERRORS::INVALID_TOKEN); - if(Controller::isUserSystemEnabled()) - throw new RequestException(ERRORS::USER_SYSTEM_ENABLED); $this->mailbox = new \PhpImap\Mailbox( Setting::getSetting('imap-host')->getValue(), diff --git a/server/controllers/system/enable-mandatory-login.php b/server/controllers/system/enable-mandatory-login.php new file mode 100644 index 00000000..a01ee12a --- /dev/null +++ b/server/controllers/system/enable-mandatory-login.php @@ -0,0 +1,50 @@ + 'staff_3', + 'requestData' => [] + ]; + } + + public function handler() { + $password = Controller::request('password'); + + if(!Hashing::verifyPassword($password, Controller::getLoggedUser()->password)) { + throw new RequestException(ERRORS::INVALID_PASSWORD); + return; + } + + $mandatoryLoginRow = Setting::getSetting('mandatory-login'); + + $mandatoryLoginRow->value = 1; + $mandatoryLoginRow->store(); + + Response::respondSuccess(); + } +} \ No newline at end of file diff --git a/server/controllers/system/enable-user-system.php b/server/controllers/system/enable-user-system.php deleted file mode 100755 index 59342b5e..00000000 --- a/server/controllers/system/enable-user-system.php +++ /dev/null @@ -1,104 +0,0 @@ - 'staff_3', - 'requestData' => [] - ]; - } - - public function handler() { - $password = Controller::request('password'); - - if(!Hashing::verifyPassword($password, Controller::getLoggedUser()->password)) { - throw new RequestException(ERRORS::INVALID_PASSWORD); - - } - - if(Controller::isUserSystemEnabled()) { - throw new RequestException(ERRORS::SYSTEM_USER_IS_ALREADY_ENABLED); - } - - $userSystemEnabled = Setting::getSetting('user-system-enabled'); - $userSystemEnabled->value = 1 ; - $userSystemEnabled->store(); - - $ticketList = Ticket::getAll(); - - foreach($ticketList as $ticket) { - if($ticket->authorStaff) { - continue; - } - - $userInstance = User::getDataStore($ticket->authorEmail, 'email'); - - if($userInstance->isNull()) { - $userInstance = $this->createUser($ticket->authorEmail, $ticket->authorName); - } - - $userInstance->tickets = $userInstance->tickets + 1; - $userInstance->sharedTicketList->add($ticket); - $userInstance->store(); - - $ticket->author = $userInstance; - $ticket->authorName = null; - $ticket->authorEmail = null; - $ticket->store(); - } - - Response::respondSuccess(); - } - public function createUser($email,$name) { - $userInstance = new User(); - - $password = Hashing::generateRandomToken(); - - $userInstance->setProperties([ - 'name' => $name, - 'signupDate' => Date::getCurrentDate(), - 'tickets' => 0, - 'email' => $email, - 'password' => Hashing::hashPassword($password), - 'verificationToken' => null - ]); - - $userInstance->store(); - - $mailSender = MailSender::getInstance(); - $mailSender->setTemplate(MailTemplate::USER_SYSTEM_ENABLED, [ - 'to' => $email, - 'name' => $name, - 'password' => $password, - 'url' => Setting::getSetting('url')->getValue(), - ]); - $mailSender->send(); - - return $userInstance; - } -} diff --git a/server/controllers/system/get-settings.php b/server/controllers/system/get-settings.php index ae59cb97..581bc002 100755 --- a/server/controllers/system/get-settings.php +++ b/server/controllers/system/get-settings.php @@ -57,7 +57,8 @@ class GetSettingsController extends Controller { 'allowedLanguages' => Language::getAllowedLanguages(), 'session-prefix' => Setting::getSetting('session-prefix')->getValue(), 'mail-template-header-image' => Setting::getSetting('mail-template-header-image')->getValue(), - 'tags' => Tag::getAll()->toArray() + 'tags' => Tag::getAll()->toArray(), + 'mandatory-login' => Setting::getSetting('mandatory-login')->getValue(), ]; } else { $settingsList = [ @@ -73,9 +74,9 @@ class GetSettingsController extends Controller { 'departments' => Controller::isStaffLogged() ? Department::getAllDepartmentNames() : Department::getPublicDepartmentNames(), 'supportedLanguages' => Language::getSupportedLanguages(), 'allowedLanguages' => Language::getAllowedLanguages(), - 'user-system-enabled' => intval(Setting::getSetting('user-system-enabled')->getValue()), 'session-prefix' => Setting::getSetting('session-prefix')->getValue(), - 'tags' => Tag::getAll()->toArray() + 'tags' => Tag::getAll()->toArray(), + 'mandatory-login' => Setting::getSetting('mandatory-login')->getValue(), ]; } } diff --git a/server/controllers/system/init-settings.php b/server/controllers/system/init-settings.php index 2fd51214..1b32de2f 100755 --- a/server/controllers/system/init-settings.php +++ b/server/controllers/system/init-settings.php @@ -16,7 +16,6 @@ DataValidator::with('CustomValidations', true); * @apiPermission any * * @apiParam {String} language Indicates the default language of the system. - * @apiParam {String} user-system-enabled Indicates if the user system should be enabled. * @apiParam {String} registration Indicates if the registration should be enabled. * @apiParam {String} server-email Email from where automated emails will be sent. * @apiParam {String} smtp-host SMTP Server address. @@ -26,6 +25,7 @@ DataValidator::with('CustomValidations', true); * @apiParam {String} allow-attachments Indicates if files can be attached to tickets and comments. * @apiParam {String} title Title of the support center * @apiParam {String} url Url of the frontend client. + * @apiParam {Boolean} mandatory-login Indicates if the login is mandatory. * * @apiUse INVALID_LANGUAGE * @apiUse INIT_SETTINGS_DONE @@ -85,13 +85,13 @@ class InitSettingsController extends Controller { 'title' => Controller::request('title') ? Controller::request('title') : 'Support Center', 'url' => Controller::request('url') ? Controller::request('url') : ('http://' . $_SERVER['HTTP_HOST']), 'registration' => !!Controller::request('registration'), - 'user-system-enabled' => !!Controller::request('user-system-enabled'), 'last-stat-day' => date('YmdHi', strtotime(' -12 day ')), 'ticket-gap' => Hashing::generateRandomPrime(100000, 999999), 'ticket-first-number' => Hashing::generateRandomNumber(100000, 999999), 'session-prefix' => 'opensupports-'.Hashing::generateRandomToken().'_', 'mail-template-header-image' => 'https://s3.amazonaws.com/opensupports/logo.png', 'imap-token' => '', + 'mandatory-login' => !!Controller::request('mandatory-login'), ]); } diff --git a/server/controllers/ticket/check.php b/server/controllers/ticket/check.php index fd1004e1..66082e40 100755 --- a/server/controllers/ticket/check.php +++ b/server/controllers/ticket/check.php @@ -54,20 +54,23 @@ class CheckTicketController extends Controller { } public function handler() { - if (Controller::isUserSystemEnabled() || Controller::isStaffLogged()) { + if (Controller::isLoginMandatory()) { throw new RequestException(ERRORS::NO_PERMISSION); } $email = Controller::request('email'); - $ticket = Ticket::getByTicketNumber(Controller::request('ticketNumber')); + $ticketNumber = Controller::request('ticketNumber'); + $ticket = Ticket::getByTicketNumber($ticketNumber); if($ticket->authorEmail === $email) { $session = Session::getInstance(); - $session->createTicketSession($ticket->ticketNumber); + $user = User::getUser($email, 'email'); + $session->createSession($user->id, false, $ticketNumber); Response::respondSuccess([ 'token' => $session->getToken(), - 'ticketNumber' => $ticket->ticketNumber + 'userId' => $session->getUserId(), + 'ticketNumber' => $session->getTicketNumber() ]); } else { throw new RequestException(ERRORS::NO_PERMISSION); diff --git a/server/controllers/ticket/close.php b/server/controllers/ticket/close.php index f585db25..ac8b4a03 100755 --- a/server/controllers/ticket/close.php +++ b/server/controllers/ticket/close.php @@ -32,43 +32,22 @@ class CloseController extends Controller { public function validations() { $session = Session::getInstance(); - if (Controller::isUserSystemEnabled() || Controller::isStaffLogged()) { return [ - 'permission' => 'user', - 'requestData' => [ - 'ticketNumber' => [ - 'validation' => DataValidator::validTicketNumber(), - 'error' => ERRORS::INVALID_TICKET + 'permission' => 'user', + 'requestData' => [ + 'ticketNumber' => [ + 'validation' => DataValidator::validTicketNumber(), + 'error' => ERRORS::INVALID_TICKET + ] ] - ] ]; - } else { - return [ - 'permission' => 'any', - 'requestData' => [ - 'ticketNumber' => [ - 'validation' => DataValidator::equals($session->getTicketNumber()), - 'error' => ERRORS::INVALID_TICKET - ], - 'csrf_token' => [ - 'validation' => DataValidator::equals($session->getToken()), - 'error' => ERRORS::INVALID_TOKEN - ] - ] - ]; - } } public function handler() { $this->ticket = Ticket::getByTicketNumber(Controller::request('ticketNumber')); $user = Controller::getLoggedUser(); - if(!Controller::isStaffLogged() && Controller::isUserSystemEnabled() && - !$user->canManageTicket($this->ticket)){ - throw new RequestException(ERRORS::NO_PERMISSION); - } - - if(Controller::isStaffLogged() && (!$user->canManageTicket($this->ticket))){ + if(!$user->canManageTicket($this->ticket)){ throw new RequestException(ERRORS::NO_PERMISSION); } diff --git a/server/controllers/ticket/comment.php b/server/controllers/ticket/comment.php index 277d153b..63fe0a1d 100755 --- a/server/controllers/ticket/comment.php +++ b/server/controllers/ticket/comment.php @@ -42,53 +42,33 @@ class CommentController extends Controller { public function validations() { $this->session = Session::getInstance(); - - if (Controller::isUserSystemEnabled() || Controller::isStaffLogged()) { - return [ - 'permission' => 'user', - 'requestData' => [ - 'content' => [ - 'validation' => DataValidator::content(), - 'error' => ERRORS::INVALID_CONTENT - ], - 'ticketNumber' => [ - 'validation' => DataValidator::validTicketNumber(), - 'error' => ERRORS::INVALID_TICKET - ] + return [ + 'permission' => 'user', + 'requestData' => [ + 'content' => [ + 'validation' => DataValidator::content(), + 'error' => ERRORS::INVALID_CONTENT + ], + 'ticketNumber' => [ + 'validation' => DataValidator::validTicketNumber(), + 'error' => ERRORS::INVALID_TICKET ] - ]; - } else { - return [ - 'permission' => 'any', - 'requestData' => [ - 'content' => [ - 'validation' => DataValidator::content(), - 'error' => ERRORS::INVALID_CONTENT - ], - 'ticketNumber' => [ - 'validation' => DataValidator::equals($this->session->getTicketNumber()), - 'error' => ERRORS::INVALID_TICKET - ], - 'csrf_token' => [ - 'validation' => DataValidator::equals($this->session->getToken()), - 'error' => ERRORS::INVALID_TOKEN - ] - ] - ]; - } + ] + ]; } public function handler() { - $this->requestData(); + $ticketNumber = Controller::request('ticketNumber'); + $this->ticket = Ticket::getByTicketNumber($ticketNumber); + $this->content = Controller::request('content', true); + $this->user = Controller::getLoggedUser(); + $ticketAuthor = $this->ticket->authorToArray(); - $isAuthor = $this->session->isTicketSession() || $this->ticket->isAuthor($this->user); + $isAuthor = $this->ticket->isAuthor($this->user); $isOwner = $this->ticket->isOwner($this->user); $private = Controller::request('private'); - if(!Controller::isStaffLogged() && Controller::isUserSystemEnabled() && !$isAuthor){ - throw new RequestException(ERRORS::NO_PERMISSION); - } - - if(!$this->session->isTicketSession() && !$this->user->canManageTicket($this->ticket)) { + + if(!$this->user->canManageTicket($this->ticket)) { throw new RequestException(ERRORS::NO_PERMISSION); } @@ -97,6 +77,7 @@ class CommentController extends Controller { if(!$isAuthor && !$private) { $this->sendMail($ticketAuthor); } + if($this->ticket->owner && !$isOwner) { $this->sendMail([ 'email' => $this->ticket->owner->email, @@ -110,13 +91,6 @@ class CommentController extends Controller { Response::respondSuccess(); } - private function requestData() { - $ticketNumber = Controller::request('ticketNumber'); - $this->ticket = Ticket::getByTicketNumber($ticketNumber); - $this->content = Controller::request('content', true); - $this->user = Controller::getLoggedUser(); - } - private function storeComment() { $fileUploader = FileUploader::getInstance(); $fileUploader->setPermission(FileManager::PERMISSION_TICKET, $this->ticket->ticketNumber); @@ -134,11 +108,9 @@ class CommentController extends Controller { $this->ticket->unread = !$this->ticket->isAuthor($this->user); $this->ticket->unreadStaff = !$this->ticket->isOwner($this->user); $comment->authorStaff = $this->user; - } else if(Controller::isUserSystemEnabled()) { - $this->ticket->unreadStaff = true; - $comment->authorUser = $this->user; } else { $this->ticket->unreadStaff = true; + $comment->authorUser = $this->user; } $this->ticket->addEvent($comment); @@ -154,11 +126,10 @@ class CommentController extends Controller { $url = Setting::getSetting('url')->getValue(); - if(!Controller::isUserSystemEnabled() && !$isStaff) { - $url .= '/check-ticket/' . $this->ticket->ticketNumber; - $url .= '/' . $email; + if(!Controller::isLoginMandatory() && !$isStaff){ + $url .= '/check-ticket/' . $this->ticket->ticketNumber; + $url .= '/' . $email; } - $mailSender->setTemplate(MailTemplate::TICKET_RESPONDED, [ 'to' => $email, 'name' => $name, diff --git a/server/controllers/ticket/create.php b/server/controllers/ticket/create.php index 6455a776..eef41a9f 100755 --- a/server/controllers/ticket/create.php +++ b/server/controllers/ticket/create.php @@ -71,8 +71,7 @@ class CreateController extends Controller { ] ] ]; - - if(!Controller::isUserSystemEnabled() && !Controller::isStaffLogged()) { + if (!Controller::isLoginMandatory() && !Controller::isStaffLogged() && !Controller::isUserLogged()) { $validations['permission'] = 'any'; $validations['requestData']['captcha'] = [ 'validation' => DataValidator::captcha(APIKey::TICKET_CREATE), @@ -83,7 +82,7 @@ class CreateController extends Controller { 'error' => ERRORS::INVALID_EMAIL ]; $validations['requestData']['name'] = [ - 'validation' => DataValidator::notBlank()->length(2, 40), + 'validation' => DataValidator::notBlank()->length(2, 55), 'error' => ERRORS::INVALID_NAME ]; } @@ -98,13 +97,22 @@ class CreateController extends Controller { $this->language = Controller::request('language'); $this->email = Controller::request('email'); $this->name = Controller::request('name'); - + if(!Controller::isStaffLogged() && Department::getDataStore($this->departmentId)->private){ throw new Exception(ERRORS::INVALID_DEPARTMENT); } + + if(!Staff::getUser($this->email,'email')->isNull() || $this->isEmailInvalid()) { + throw new Exception(ERRORS::INVALID_EMAIL); + } + + if(!Controller::isLoginMandatory() && !Controller::isStaffLogged() && !Controller::isUserLogged() && !User::getUser($this->email, 'email')->email){ + $this->createNewUser(); + } + $this->storeTicket(); - if(!Controller::isUserSystemEnabled()) { + if(!Controller::isLoginMandatory() && !Controller::isUserLogged()) { $this->sendMail(); } @@ -114,22 +122,46 @@ class CreateController extends Controller { $this->sendMailStaff($staff->email); } } + + Log::createLog('CREATE_TICKET', $this->ticketNumber); Response::respondSuccess([ 'ticketNumber' => $this->ticketNumber ]); - - if(!Controller::isUserSystemEnabled() && !Controller::isStaffLogged()) { - $session = Session::getInstance(); - $session->createTicketSession($this->ticketNumber); - } - - Log::createLog('CREATE_TICKET', $this->ticketNumber); + } + private function isEmailInvalid(){ + $session = Session::getInstance(); + $sessionUser = User::getUser($session->getUserId() ,'id'); + + return ($session->sessionExists() && $sessionUser && $this->email && !($sessionUser->email == $this->email)); + } + + private function createNewUser() { + + $signupController = new SignUpController(true); + + Controller::setDataRequester(function ($key) { + switch ($key) { + case 'email': + return $this->email; + case 'password': + return Hashing::generateRandomToken(); + case 'name': + return $this->name; + case 'indirectSignUp' : + return true; + } + + return null; + }); + $signupController->validations(); + $signupController->handler(); + } private function storeTicket() { $department = Department::getDataStore($this->departmentId); - $author = Controller::getLoggedUser(); + $author = $this->getAuthor(); $ticket = new Ticket(); $fileUploader = FileUploader::getInstance(); @@ -153,12 +185,9 @@ class CreateController extends Controller { )); $ticket->setAuthor($author); + $author->sharedTicketList->add($ticket); - if(Controller::isUserSystemEnabled() || Controller::isStaffLogged()) { - $author->sharedTicketList->add($ticket); - } - - if(Controller::isUserSystemEnabled() && !Controller::isStaffLogged()) { + if(!Controller::isStaffLogged()) { $author->tickets++; $this->email = $author->email; @@ -171,6 +200,14 @@ class CreateController extends Controller { $this->ticketNumber = $ticket->ticketNumber; } + private function getAuthor() { + if(Controller::getLoggedUser()->email) { + return Controller::getLoggedUser(); + }else{ + return User::getUser($this->email, 'email'); + } + } + private function sendMail() { $mailSender = MailSender::getInstance(); diff --git a/server/controllers/ticket/edit-comment.php b/server/controllers/ticket/edit-comment.php index fefaefd9..f4e84b87 100644 --- a/server/controllers/ticket/edit-comment.php +++ b/server/controllers/ticket/edit-comment.php @@ -31,39 +31,19 @@ class EditCommentController extends Controller { const METHOD = 'POST'; public function validations() { - if(Controller::isUserSystemEnabled()){ - return [ - 'permission' => 'user', - 'requestData' => [ - 'content' => [ - 'validation' => DataValidator::content(), - 'error' => ERRORS::INVALID_CONTENT - ], - 'ticketNumber' => [ - 'validation' => DataValidator::oneOf(DataValidator::validTicketNumber(),DataValidator::nullType()), - 'error' => ERRORS::INVALID_TICKET - ] + return [ + 'permission' => 'user', + 'requestData' => [ + 'content' => [ + 'validation' => DataValidator::content(), + 'error' => ERRORS::INVALID_CONTENT + ], + 'ticketNumber' => [ + 'validation' => DataValidator::oneOf(DataValidator::validTicketNumber(),DataValidator::nullType()), + 'error' => ERRORS::INVALID_TICKET ] - ]; - } else { - return [ - 'permission' => 'any', - 'requestData' => [ - 'content' => [ - 'validation' => DataValidator::content(), - 'error' => ERRORS::INVALID_CONTENT - ], - 'ticketNumber' => [ - 'validation' => DataValidator::oneOf(DataValidator::validTicketNumber(),DataValidator::nullType()), - 'error' => ERRORS::INVALID_TICKET - ], - 'csrf_token' => [ - 'validation' => DataValidator::equals(Session::getInstance()->getToken()), - 'error' => ERRORS::INVALID_TOKEN - ] - ] - ]; - } + ] + ]; } public function handler() { @@ -74,7 +54,7 @@ class EditCommentController extends Controller { $ticketevent = Ticketevent::getTicketEvent(Controller::request('ticketEventId')); $ticket = Ticket::getByTicketNumber(Controller::request('ticketNumber')); - if(Controller::isUserSystemEnabled() && !Controller::isStaffLogged() && ($user->id !== $ticketevent->authorUserId && $user->id !== $ticket->authorId ) ){ + if(!Controller::isStaffLogged() && ($user->id !== $ticketevent->authorUserId && $user->id !== $ticket->authorId ) ){ throw new RequestException(ERRORS::NO_PERMISSION); } diff --git a/server/controllers/ticket/edit-title.php b/server/controllers/ticket/edit-title.php index 7adca12d..a115b4a7 100644 --- a/server/controllers/ticket/edit-title.php +++ b/server/controllers/ticket/edit-title.php @@ -30,39 +30,19 @@ class EditTitleController extends Controller { const METHOD = 'POST'; public function validations() { - if(Controller::isUserSystemEnabled()){ - return [ - 'permission' => 'user', - 'requestData' => [ - 'title' => [ - 'validation' => DataValidator::notBlank()->length(1, 200), - 'error' => ERRORS::INVALID_TITLE - ], - 'ticketNumber' => [ - 'validation' => DataValidator::validTicketNumber(), - 'error' => ERRORS::INVALID_TICKET - ] + return [ + 'permission' => 'user', + 'requestData' => [ + 'title' => [ + 'validation' => DataValidator::notBlank()->length(1, 200), + 'error' => ERRORS::INVALID_TITLE + ], + 'ticketNumber' => [ + 'validation' => DataValidator::validTicketNumber(), + 'error' => ERRORS::INVALID_TICKET ] - ]; - } else { - return [ - 'permission' => 'any', - 'requestData' => [ - 'title' => [ - 'validation' => DataValidator::notBlank()->length(1, 200), - 'error' => ERRORS::INVALID_TITLE - ], - 'ticketNumber' => [ - 'validation' => DataValidator::validTicketNumber(), - 'error' => ERRORS::INVALID_TICKET - ], - 'csrf_token' => [ - 'validation' => DataValidator::equals(Session::getInstance()->getToken()), - 'error' => ERRORS::INVALID_TOKEN - ] - ] - ]; - } + ] + ]; } public function handler() { @@ -70,7 +50,7 @@ class EditTitleController extends Controller { $newtitle = Controller::request('title'); $ticket = Ticket::getByTicketNumber(Controller::request('ticketNumber')); - if(Controller::isUserSystemEnabled() && !$user->canManageTicket($ticket)) { + if(!$user->canManageTicket($ticket)) { throw new RequestException(ERRORS::NO_PERMISSION); } diff --git a/server/controllers/ticket/get.php b/server/controllers/ticket/get.php index 05f8b37a..03f2814b 100755 --- a/server/controllers/ticket/get.php +++ b/server/controllers/ticket/get.php @@ -32,43 +32,22 @@ class TicketGetController extends Controller { public function validations() { $session = Session::getInstance(); - - if (Controller::isUserSystemEnabled() || Controller::isStaffLogged()) { - return [ - 'permission' => 'user', - 'requestData' => [ - 'ticketNumber' => [ - 'validation' => DataValidator::validTicketNumber(), - 'error' => ERRORS::INVALID_TICKET - ] + return [ + 'permission' => 'any', + 'requestData' => [ + 'ticketNumber' => [ + 'validation' => DataValidator::validTicketNumber(), + 'error' => ERRORS::INVALID_TICKET ] - ]; - } else { - return [ - 'permission' => 'any', - 'requestData' => [ - 'ticketNumber' => [ - 'validation' => DataValidator::equals($session->getTicketNumber()), - 'error' => ERRORS::INVALID_TICKET - ], - 'csrf_token' => [ - 'validation' => DataValidator::equals($session->getToken()), - 'error' => ERRORS::INVALID_TOKEN - ] - ] - ]; - } + ] + ]; } public function handler() { $this->ticket = Ticket::getByTicketNumber(Controller::request('ticketNumber')); - - if(Controller::isUserSystemEnabled() || Controller::isStaffLogged()) { - if ($this->shouldDenyPermission()) { - throw new RequestException(ERRORS::NO_PERMISSION); - } else { - Response::respondSuccess($this->ticket->toArray()); - } + + if ($this->shouldDenyPermission()) { + throw new RequestException(ERRORS::NO_PERMISSION); } else { Response::respondSuccess($this->ticket->toArray()); } @@ -76,8 +55,6 @@ class TicketGetController extends Controller { private function shouldDenyPermission() { $user = Controller::getLoggedUser(); - - return (!Controller::isStaffLogged() && (Controller::isUserSystemEnabled() && !$user->canManageTicket($this->ticket))) || - (Controller::isStaffLogged() && !$user->canManageTicket($this->ticket)); + return !$user->canManageTicket($this->ticket); } } diff --git a/server/controllers/user/delete.php b/server/controllers/user/delete.php index fa59a068..44df97ee 100755 --- a/server/controllers/user/delete.php +++ b/server/controllers/user/delete.php @@ -18,7 +18,6 @@ use RedBeanPHP\Facade as RedBean; * * @apiUse NO_PERMISSION * @apiUse INVALID_USER - * @apiUse USER_SYSTEM_DISABLED * * @apiSuccess {Object} data Empty object * @@ -43,9 +42,6 @@ class DeleteUserController extends Controller { } public function handler() { - if(!Controller::isUserSystemEnabled()) { - throw new RequestException(ERRORS::USER_SYSTEM_DISABLED); - } $userId = Controller::request('userId'); $user = User::getDataStore($userId); @@ -56,7 +52,7 @@ class DeleteUserController extends Controller { foreach($user->sharedTicketList as $ticket) { $ticket->delete(); } - + $user->delete(); Response::respondSuccess(); diff --git a/server/controllers/user/get-user.php b/server/controllers/user/get-user.php index dfe175b5..f8187753 100755 --- a/server/controllers/user/get-user.php +++ b/server/controllers/user/get-user.php @@ -18,7 +18,6 @@ DataValidator::with('CustomValidations', true); * * @apiUse NO_PERMISSION * @apiUse INVALID_USER - * @apiUse USER_SYSTEM_DISABLED * * @apiSuccess {Object} data Information about an user * @apiSuccess {String} data.name Name of the user @@ -46,10 +45,7 @@ class GetUserByIdController extends Controller { } public function handler() { - if(!Controller::isUserSystemEnabled()) { - throw new RequestException(ERRORS::USER_SYSTEM_DISABLED); - } - + $userId = Controller::request('userId'); $user = User::getDataStore($userId); $staff = Controller::getLoggedUser(); diff --git a/server/controllers/user/get-users.php b/server/controllers/user/get-users.php index 33f3e4f1..a2df0418 100755 --- a/server/controllers/user/get-users.php +++ b/server/controllers/user/get-users.php @@ -21,7 +21,6 @@ use Respect\Validation\Validator as DataValidator; * @apiUse NO_PERMISSION * @apiUse INVALID_PAGE * @apiUse INVALID_ORDER - * @apiUse USER_SYSTEM_DISABLED * * @apiSuccess {Object} data * @apiSuccess {[User](#api-Data_Structures-ObjectUser)[]} data.users Array of users found @@ -53,9 +52,6 @@ class GetUsersController extends Controller { } public function handler() { - if(!Controller::isUserSystemEnabled()) { - throw new RequestException(ERRORS::USER_SYSTEM_DISABLED); - } $userList = $this->getUserList(); $userListArray = []; diff --git a/server/controllers/user/invite.php b/server/controllers/user/invite.php index 1e412c63..899ceaf6 100755 --- a/server/controllers/user/invite.php +++ b/server/controllers/user/invite.php @@ -64,9 +64,6 @@ class InviteUserController extends Controller { } public function handler() { - if (!Controller::isUserSystemEnabled()) { - throw new RequestException(ERRORS::USER_SYSTEM_DISABLED); - } $this->storeRequestData(); diff --git a/server/controllers/user/login.php b/server/controllers/user/login.php index 9bda4c7d..77c50d93 100755 --- a/server/controllers/user/login.php +++ b/server/controllers/user/login.php @@ -20,8 +20,6 @@ use RedBeanPHP\Facade as RedBean; * @apiParam {Number} userId The id of the user to login. * @apiParam {String} rememberToken Token to login automatically. It replaces the password. * - * @apiUse USER_SYSTEM_DISABLED - * @apiUse SESSION_EXISTS * @apiUse UNVERIFIED_USER * @apiUse INVALID_CREDENTIALS * @@ -50,16 +48,8 @@ class LoginController extends Controller { } public function handler() { - if(!Controller::isUserSystemEnabled() && !Controller::request('staff')) { - throw new RequestException(ERRORS::USER_SYSTEM_DISABLED); - } - - if ($this->isAlreadyLoggedIn()) { - throw new RequestException(ERRORS::SESSION_EXISTS); - } - $this->clearOldRememberTokens(); - + if ($this->checkInputCredentials() || $this->checkRememberToken()) { if($this->userInstance->verificationToken !== null) { throw new RequestException(ERRORS::UNVERIFIED_USER); @@ -82,10 +72,6 @@ class LoginController extends Controller { } } - private function isAlreadyLoggedIn() { - return Session::getInstance()->sessionExists(); - } - private function checkInputCredentials() { $this->userInstance = $this->getUserByInputCredentials(); diff --git a/server/controllers/user/recover-password.php b/server/controllers/user/recover-password.php index 45a51726..55c99433 100755 --- a/server/controllers/user/recover-password.php +++ b/server/controllers/user/recover-password.php @@ -20,7 +20,6 @@ DataValidator::with('CustomValidations', true); * * @apiUse INVALID_EMAIL * @apiUse INVALID_PASSWORD - * @apiUse USER_SYSTEM_DISABLED * @apiUse NO_PERMISSION * * @apiSuccess {Object} data Empty object @@ -73,10 +72,6 @@ class RecoverPasswordController extends Controller { throw new RequestException(ERRORS::NO_PERMISSION); } - if(!Controller::isUserSystemEnabled() && !$recoverPassword->staff) { - throw new RequestException(ERRORS::USER_SYSTEM_DISABLED); - } - if($recoverPassword->staff) { $this->user = Staff::getDataStore($this->email, 'email'); } else { @@ -88,7 +83,8 @@ class RecoverPasswordController extends Controller { $recoverPassword->delete(); $this->user->setProperties([ - 'password' => Hashing::hashPassword($this->password) + 'password' => Hashing::hashPassword($this->password), + 'notRegistered' => null ]); $this->user->store(); diff --git a/server/controllers/user/send-recover-password.php b/server/controllers/user/send-recover-password.php index 12b27f80..bce17dea 100755 --- a/server/controllers/user/send-recover-password.php +++ b/server/controllers/user/send-recover-password.php @@ -51,10 +51,6 @@ class SendRecoverPasswordController extends Controller { public function handler() { $this->staff = Controller::request('staff'); - if(!Controller::isUserSystemEnabled() && !$this->staff) { - throw new RequestException(ERRORS::USER_SYSTEM_DISABLED); - } - $email = Controller::request('email'); if($this->staff){ diff --git a/server/controllers/user/signup.php b/server/controllers/user/signup.php index 46758175..69cd493b 100755 --- a/server/controllers/user/signup.php +++ b/server/controllers/user/signup.php @@ -20,12 +20,12 @@ DataValidator::with('CustomValidations', true); * @apiParam {String} password The password of the new user. * @apiParam {String} apiKey APIKey to sign up an user if the registration system is disabled. * @apiParam {String} customfield_ Custom field values for this user. + * @apiParam {Boolean} indirectSignUp Indicates if the new User has been created by ticket/create * * @apiUse INVALID_NAME * @apiUse INVALID_EMAIL * @apiUse INVALID_PASSWORD * @apiUse INVALID_CAPTCHA - * @apiUse USER_SYSTEM_DISABLED * @apiUse USER_EXISTS * @apiUse ALREADY_BANNED * @apiUse NO_PERMISSION @@ -81,16 +81,13 @@ class SignUpController extends Controller { } public function handler() { - if(!Controller::isUserSystemEnabled()) { - throw new RequestException(ERRORS::USER_SYSTEM_DISABLED); - } $this->storeRequestData(); $apiKey = APIKey::getDataStore(Controller::request('apiKey'), 'token'); - $existentUser = User::getUser($this->userEmail, 'email'); - - if (!$existentUser->isNull()) { + $user = User::getUser($this->userEmail, 'email'); + + if (!$user->isNull() && !$user->notRegistered) { throw new RequestException(ERRORS::USER_EXISTS); } $banRow = Ban::getDataStore($this->userEmail,'email'); @@ -106,7 +103,7 @@ class SignUpController extends Controller { if(!$apiKey->isNull() && $apiKey->type !== APIKey::REGISTRATION) { throw new RequestException(ERRORS::INVALID_API_KEY_TYPE); } - + $userId = $this->createNewUserAndRetrieveId(); if(MailSender::getInstance()->isConnected()) { @@ -129,15 +126,19 @@ class SignUpController extends Controller { } public function createNewUserAndRetrieveId() { - $userInstance = new User(); + $user = User::getUser($this->userEmail,'email'); + + $userInstance = ($user->isNull() ? new User() : $user ); + $UserTickets = ($user->isNull() ? 0 : $user->tickets); $userInstance->setProperties([ 'name' => $this->userName, 'signupDate' => Date::getCurrentDate(), - 'tickets' => 0, + 'tickets' => $UserTickets, 'email' => $this->userEmail, 'password' => Hashing::hashPassword($this->userPassword), 'verificationToken' => (MailSender::getInstance()->isConnected()) ? $this->verificationToken : null, + 'notRegistered' => Controller::request('indirectSignUp') ? true : null, 'xownCustomfieldvalueList' => $this->getCustomFieldValues() ]); @@ -154,6 +155,6 @@ class SignUpController extends Controller { 'verificationToken' => $this->verificationToken ]); - $mailSender->send(); + if(!Controller::request('indirectSignUp')) $mailSender->send(); } } diff --git a/server/controllers/user/verify.php b/server/controllers/user/verify.php index dc66e8c2..40072b6b 100755 --- a/server/controllers/user/verify.php +++ b/server/controllers/user/verify.php @@ -17,7 +17,6 @@ use Respect\Validation\Validator as DataValidator; * @apiParam {String} token The validation token sent by email to the user. * * @apiUse INVALID_EMAIL - * @apiUse USER_SYSTEM_DISABLED * @apiUse INVALID_TOKEN * * @apiSuccess {Object} data Empty object @@ -41,15 +40,11 @@ class VerifyController extends Controller{ } public function handler() { - if(!Controller::isUserSystemEnabled()) { - throw new RequestException(ERRORS::USER_SYSTEM_DISABLED); - } $email = Controller::request('email'); $token = Controller::request('token'); $userRow = User::getDataStore($email, 'email'); - if(!$userRow) { throw new RequestException(ERRORS::INVALID_EMAIL); } diff --git a/server/data/ERRORS.php b/server/data/ERRORS.php index a1c35504..11971fd5 100755 --- a/server/data/ERRORS.php +++ b/server/data/ERRORS.php @@ -199,14 +199,6 @@ * @apiDefine INVALID_BODY * @apiError {String} INVALID_BODY The body is invalid. */ -/** - * @apiDefine USER_SYSTEM_ENABLED - * @apiError {String} USER_SYSTEM_ENABLED The user system is enabled. - */ -/** - * @apiDefine USER_SYSTEM_DISABLED - * @apiError {String} USER_SYSTEM_DISABLED The user system is disabled. - */ /** * @apiDefine SYSTEM_USER_IS_ALREADY_DISABLED * @apiError {String} SYSTEM_USER_IS_ALREADY_DISABLED The system user is already disabled. @@ -307,6 +299,14 @@ * @apiDefine INVALID_API_KEY_TYPE * @apiError {String} INVALID_API_KEY_TYPE Api key type is not one of the availables */ +/** + * @apiDefine MANDATORY_LOGIN_IS_DESACTIVATED + * @apiError {String} MANDATORY_LOGIN_IS_DESACTIVATED Mandatory login is disactivated + */ +/** + * @apiDefine REGISTRATION_IS_DESACTIVATED + * @apiError {String} REGISTRATION_IS_DESACTIVATED Registration is disactivated + */ class ERRORS { const INVALID_CREDENTIALS = 'INVALID_CREDENTIALS'; @@ -360,8 +360,6 @@ class ERRORS { const INVALID_TEMPLATE = 'INVALID_TEMPLATE'; const INVALID_SUBJECT = 'INVALID_SUBJECT'; const INVALID_BODY = 'INVALID_BODY'; - const USER_SYSTEM_ENABLED = 'USER_SYSTEM_ENABLED'; - const USER_SYSTEM_DISABLED = 'USER_SYSTEM_DISABLED'; const SYSTEM_USER_IS_ALREADY_DISABLED = 'SYSTEM_USER_IS_ALREADY_DISABLED'; const SYSTEM_USER_IS_ALREADY_ENABLED = 'SYSTEM_USER_IS_ALREADY_ENABLED'; const INVALID_PERIOD = 'INVALID_PERIOD'; @@ -387,4 +385,6 @@ class ERRORS { const UNAVAILABLE_STATS = 'UNAVAILABLE_STATS'; const INVALID_COLOR = 'INVALID_COLOR'; const INVALID_API_KEY_TYPE = 'INVALID_API_KEY_TYPE'; + const MANDATORY_LOGIN_IS_DESACTIVATED = 'MANDATORY_LOGIN_IS_DESACTIVATED'; + const REGISTRATION_IS_DESACTIVATED = 'REGISTRATION_IS_DESACTIVATED'; } diff --git a/server/libs/Controller.php b/server/libs/Controller.php index 04711b5f..8bd566a8 100755 --- a/server/libs/Controller.php +++ b/server/libs/Controller.php @@ -71,7 +71,10 @@ abstract class Controller { if ($session->isStaffLogged()) { return Staff::getUser($session->getUserId()); } else { - return User::getUser($session->getUserId()); + $user = User::getUser($session->getUserId()); + if($session->getTicketNumber()) $user->ticketNumber = $session->getTicketNumber(); + + return $user; } } @@ -145,8 +148,8 @@ abstract class Controller { return str_replace(array_map(function($index) { return "IMAGE_PATH_$index"; }, array_keys($imagePaths)), $imagePaths, $content); } - public static function isUserSystemEnabled() { - return Setting::getSetting('user-system-enabled')->getValue(); + public static function isLoginMandatory() { + return Setting::getSetting('mandatory-login')->getValue(); } public static function getCustomFieldValues() { diff --git a/server/models/DataStore.php b/server/models/DataStore.php index 888a3ca4..9e56df92 100755 --- a/server/models/DataStore.php +++ b/server/models/DataStore.php @@ -96,6 +96,8 @@ abstract class DataStore { public function __set($prop, $value) { if (in_array($prop, static::getProps())) { $this->properties[$prop] = $value; + } else if(property_exists($this, $prop)){ + $this->{$prop} = $value; } else { throw new Exception("Invalid prop: $prop"); } diff --git a/server/models/MailTemplate.php b/server/models/MailTemplate.php index 008ba9b2..68a3979a 100755 --- a/server/models/MailTemplate.php +++ b/server/models/MailTemplate.php @@ -34,8 +34,6 @@ class MailTemplate extends DataStore { 'USER_EMAIL' => 'data/mail-templates/user-edit-email.html', 'PASSWORD_FORGOT' => 'data/mail-templates/user-password-forgot.html', 'USER_INVITE' => 'data/mail-templates/user-invite.html', - 'USER_SYSTEM_DISABLED' => 'data/mail-templates/user-system-disabled.html', - 'USER_SYSTEM_ENABLED' => 'data/mail-templates/user-system-enabled.html', 'TICKET_CREATED' => 'data/mail-templates/ticket-created.html', 'TICKET_RESPONDED' => 'data/mail-templates/ticket-responded.html', 'TICKET_CLOSED' => 'data/mail-templates/ticket-closed.html', diff --git a/server/models/Session.php b/server/models/Session.php index a193e88a..ab3de6db 100755 --- a/server/models/Session.php +++ b/server/models/Session.php @@ -30,13 +30,9 @@ class Session { $this->store($key, $value); } - public function createSession($userId, $staff = false) { + public function createSession($userId, $staff = false, $ticketNumber = null) { $this->store('userId', $userId); $this->store('staff', $staff); - $this->store('token', Hashing::generateRandomToken()); - } - - public function createTicketSession($ticketNumber) { $this->store('ticketNumber', $ticketNumber); $this->store('token', Hashing::generateRandomToken()); } diff --git a/server/models/User.php b/server/models/User.php index 4140459c..7c033461 100755 --- a/server/models/User.php +++ b/server/models/User.php @@ -9,16 +9,17 @@ use RedBeanPHP\Facade as RedBean; * @apiParam {Number} id The id of the user. * @apiParam {String} name The name of the user. * @apiParam {Boolean} verified Indicates if the user has verified the email. + * @apiParam {Boolean} notRegistered Indicates if the user had logged at least one time. * @apiParam {[CustomField](#api-Data_Structures-ObjectCustomfield)[]} customfields Indicates the values for custom fields. */ class User extends DataStore { const TABLE = 'user'; - + public $ticketNumber = null; public static function authenticate($userEmail, $userPassword) { $user = User::getUser($userEmail, 'email'); - return ($user && Hashing::verifyPassword($userPassword, $user->password)) ? $user : new NullDataStore(); + return ($user && Hashing::verifyPassword($userPassword, $user->password) && !$user->notRegistered) ? $user : new NullDataStore(); } public static function getProps() { @@ -31,7 +32,8 @@ class User extends DataStore { 'sharedTicketList', 'verificationToken', 'disabled', - 'xownCustomfieldvalueList' + 'xownCustomfieldvalueList', + 'notRegistered' ]; } @@ -44,7 +46,13 @@ class User extends DataStore { } public function canManageTicket(Ticket $ticket){ - return $ticket->isAuthor($this); + $ticketNumberInstanceValidation = true; + + if($this->ticketNumber) { + $ticketNumberInstanceValidation = $this->ticketNumber == $ticket->ticketNumber; + } + + return ($ticket->isAuthor($this) && $ticketNumberInstanceValidation); } public function toArray() { @@ -55,6 +63,7 @@ class User extends DataStore { 'verified' => !$this->verificationToken, 'disabled' => $this->disabled, 'customfields' => $this->xownCustomfieldvalueList->toArray(), + 'notRegistered' => $this->notRegistered ]; } } diff --git a/tests/init.rb b/tests/init.rb index a0d9f4b7..548150e0 100644 --- a/tests/init.rb +++ b/tests/init.rb @@ -23,6 +23,7 @@ require './user/recover-password.rb' require './user/edit-password.rb' require './user/edit-email.rb' require './user/get.rb' + require './user/enable-disable.rb' require './ticket/create.rb' require './ticket/seen.rb' @@ -73,6 +74,6 @@ require './ticket/edit-comment.rb' require './ticket/edit-title.rb' require './system/custom-fields.rb' require './ticket/get-authors.rb' -require './system/disable-user-system.rb' require './ticket/search.rb' +require './system/mandatory-login.rb' # require './system/get-stats.rb' diff --git a/tests/system/disable-user-system.rb b/tests/system/disable-user-system.rb deleted file mode 100644 index f0dd5f21..00000000 --- a/tests/system/disable-user-system.rb +++ /dev/null @@ -1,236 +0,0 @@ -describe'system/disable-user-system' do - request('/user/logout') - Scripts.login($staff[:email], $staff[:password], true) - - it 'should disable the user system' do - result = request('/system/disable-user-system', { - csrf_userid: $csrf_userid, - csrf_token: $csrf_token, - password:$staff[:password] - }) - - (result['status']).should.equal('success') - - row = $database.getRow('setting', 'user-system-enabled', 'name') - - (row['value']).should.equal('0') - row = $database.getRow('user', 1, 'id') - (row).should.equal(nil) - - numberOftickets = $database.query("SELECT * FROM ticket WHERE author_id IS NULL AND author_email IS NOT NULL AND author_name IS NOT NULL") - - (numberOftickets.num_rows).should.equal(53) - - request('/user/logout') - - result = request('/user/signup', { - :name => 'test name', - :email => 'steve@mail.com', - :password => 'customm' - }) - - (result['status']).should.equal('fail') - (result['message']).should.equal('USER_SYSTEM_DISABLED') - - result = request('/user/login', { - email: @loginEmail, - password: @loginPass - }) - - (result['status']).should.equal('fail') - (result['message']).should.equal('USER_SYSTEM_DISABLED') - end - - it 'should create a ticket without user' do - request('/user/logout') - result = request('/ticket/create', { - title: 'test ticket without user', - content: 'The north remembers', - departmentId: 1, - language: 'en', - }) - - (result['status']).should.equal('fail') - (result['message']).should.equal('INVALID_EMAIL') - - result = request('/ticket/create', { - title: 'test ticket without user', - content: 'The north remembers', - departmentId: 1, - language: 'en', - name: 'Test Subject', - email: 'emailtest@opensupports.com' - }) - - (result['status']).should.equal('success') - end - - it 'should be able to comment on ticket as a non-logged user' do - result = request('/ticket/create', { - title: 'Doubt about Russian language', - content: 'Stariy means old in Russian?', - departmentId: 1, - language: 'en', - name: 'Abraham Einstein', - email: 'abrahameinstein@opensupports.com' - }) - (result['status']).should.equal('success') - - ticketNumber = result['data']['ticketNumber'] - - result = request('/ticket/check', { - ticketNumber: ticketNumber, - email: 'abrahameinstein@opensupports.com', - captcha: 'valid' - }) - token = result['data']['token'] - (result['status']).should.equal('success'); - - result = request('/ticket/comment', { - content: 'I actually think it is not like that, but anyways, thanks', - ticketNumber: ticketNumber, - csrf_token: token - }) - (result['status']).should.equal('success') - end - - it 'should be able to assign and respond tickets' do - Scripts.login($staff[:email], $staff[:password], true); - ticket = $database.getLastRow('ticket'); - result = request('/staff/assign-ticket', { - ticketNumber: ticket['ticket_number'], - csrf_userid: $csrf_userid, - csrf_token: $csrf_token, - }) - (result['status']).should.equal('success') - - result = request('/ticket/comment', { - ticketNumber: ticket['ticket_number'], - content: 'This is a staff response for a ticket without an user', - csrf_userid: $csrf_userid, - csrf_token: $csrf_token, - }) - (result['status']).should.equal('success') - end - - it 'should be able to get the latest events as admin' do - result = request('/staff/last-events', { - page: 1, - csrf_userid: $csrf_userid, - csrf_token: $csrf_token - }) - (result['status']).should.equal('success') - (result['data'].size).should.equal(10) - end - - it 'should be able to get system logs as admin' do - result = request('/system/get-logs', { - page: 1, - csrf_userid: $csrf_userid, - csrf_token: $csrf_token - }) - (result['status']).should.equal('success') - (result['data'].size).should.equal(10) - end - - it 'should be be able to create a ticket as an admin' do - result = request('/ticket/create', { - title: 'created by staff with user system disabled', - content: 'an staff created this ticket while user system disabled', - departmentId: 1, - language: 'en', - csrf_userid: $csrf_userid, - csrf_token: $csrf_token - }) - (result['status']).should.equal('success') - ticket = $database.getRow('ticket', result['data']['ticketNumber'], 'ticket_number') - (ticket['author_id']).should.equal(nil) - (ticket['author_staff_id']).should.equal('1') - end - - it 'should be able to create a ticket using api' do - api_key = Scripts.createAPIKey('ticketCreateKey', 'TICKET_CREATE')['data'] - request('/user/logout') - result = request('/ticket/create', { - email: 'fromapi@testemail.com', - name: 'Random user', - title: 'created by api', - content: 'this ticket was created using anapi key while user system is disabled', - departmentId: 1, - language: 'en', - apiKey: api_key - }) - (result['status']).should.equal('success') - end - - it 'should not disable the user system if it is already disabled 'do - request('/user/logout') - Scripts.login($staff[:email], $staff[:password], true) - - result = request('/system/disable-user-system', { - csrf_userid: $csrf_userid, - csrf_token: $csrf_token, - password:$staff[:password] - }) - - (result['status']).should.equal('fail') - (result['message']).should.equal('SYSTEM_USER_IS_ALREADY_DISABLED') - end - - it 'should allow staff members to recover their passwords' do - request('/user/logout') - result = request('/user/send-recover-password', { - email: 'jorah@opensupports.com', - staff: true - }) - (result['status']).should.equal('success') - - token = $database.getLastRow('recoverpassword')['token']; - - result = request('/user/recover-password', { - email: 'jorah@opensupports.com', - password: 's3cur3p455w0rd', - token: token - }) - (result['status']).should.equal('success') - (result['data']['staff']).should.equal('1') - - result = request('/user/login', { - email: 'jorah@opensupports.com', - password: 's3cur3p455w0rd', - staff: true - }) - (result['status']).should.equal('success') - (result['data']['userEmail']).should.equal('jorah@opensupports.com') - end - - it 'should enable the user system' do - request('/user/logout') - Scripts.login($staff[:email], $staff[:password], true) - result = request('/system/enable-user-system', { - csrf_userid: $csrf_userid, - csrf_token: $csrf_token, - password:$staff[:password] - }) - - (result['status']).should.equal('success') - - row = $database.getRow('setting', 'user-system-enabled', 'name') - (row['value']).should.equal('1') - - numberOftickets= $database.query("SELECT * FROM ticket WHERE author_email IS NULL AND author_name IS NULL AND author_id IS NOT NULL" ) - - (numberOftickets.num_rows).should.equal(56) - end - - it 'should not enable the user system' do - result = request('/system/enable-user-system', { - csrf_userid: $csrf_userid, - csrf_token: $csrf_token, - password:$staff[:password] - }) - - (result['status']).should.equal('fail') - (result['message']).should.equal('SYSTEM_USER_IS_ALREADY_ENABLED') - end -end diff --git a/tests/system/get-settings.rb b/tests/system/get-settings.rb index 84ac35bd..9b25efe4 100644 --- a/tests/system/get-settings.rb +++ b/tests/system/get-settings.rb @@ -5,6 +5,7 @@ describe '/system/get-settings' do (result['status']).should.equal('success') (result['data']['language']).should.equal('en') (result['data']['departments'][0]['name']).should.equal('Help and Support') + (result['data']['mandatory-login']).should.equal('1') (result['data']['allowedLanguages'][0]).should.equal('en') (result['data']['allowedLanguages'][1]).should.equal('es') (result['data']['allowedLanguages'][2]).should.equal('de') diff --git a/tests/system/init-settings.rb b/tests/system/init-settings.rb index 36f909d9..4e0a7821 100755 --- a/tests/system/init-settings.rb +++ b/tests/system/init-settings.rb @@ -14,14 +14,14 @@ describe '/system/init-settings' do it 'should initialize correctly' do result = request('/system/init-settings', { - 'user-system-enabled' => true, 'registration' => true, 'title' => 'Support Center', 'smtp-host' => 'localhost:7070', 'smtp-user' => 'testemail@opensupports.com', 'smtp-pass' => 'password', 'server-email' => 'testemail@opensupports.com', - 'language' => 'en' + 'language' => 'en', + 'mandatory-login' => true }) (result['status']).should.equal('success') diff --git a/tests/system/mandatory-login.rb b/tests/system/mandatory-login.rb new file mode 100644 index 00000000..44776a61 --- /dev/null +++ b/tests/system/mandatory-login.rb @@ -0,0 +1,386 @@ +describe'system/mandatory-login' do + + it 'should fail if a creator tries to create a ticket without login' do + + result = request('/ticket/create', { + email: 'nonuser@os4.com', + language: 'en', + name: 'nonuser', + title: 'ticket created without login', + content: 'THis is the first content created without login', + departmentId: 1 + }) + (result['status']).should.equal('fail') + (result['message']).should.equal('NO_PERMISSION') + end + + request('/user/logout') + Scripts.login($staff[:email], $staff[:password], true) + + it 'should fail trying to disable mandatory login when registration is off' do + request('/system/disable-registration', { + "csrf_userid" => $csrf_userid, + "csrf_token" => $csrf_token, + "password" => "staff" + }) + result = request('/system/disable-mandatory-login', { + "csrf_userid" => $csrf_userid, + "csrf_token" => $csrf_token, + "password" => "staff" + }) + + (result['status']).should.equal('fail') + (result['message']).should.equal('REGISTRATION_IS_DESACTIVATED') + row = $database.getRow('setting', 'mandatory-login', 'name') + + (row['value']).should.equal('1') + + request('/system/enable-registration', { + "csrf_userid" => $csrf_userid, + "csrf_token" => $csrf_token, + "password" => "staff" + }) + end + + it 'should disable the mandatory login' do + result = request('/system/disable-mandatory-login', { + "csrf_userid" => $csrf_userid, + "csrf_token" => $csrf_token, + "password" => "invalidPassword" + }) + + (result['status']).should.equal('fail') + (result['message']).should.equal('INVALID_PASSWORD') + + row = $database.getRow('setting', 'mandatory-login', 'name') + + (row['value']).should.equal('1') + + result = request('/system/disable-mandatory-login', { + "csrf_userid" => $csrf_userid, + "csrf_token" => $csrf_token, + "password" => "staff" + }) + + (result['status']).should.equal('success') + + row = $database.getRow('setting', 'mandatory-login', 'name') + + (row['value']).should.equal('0') + end + + it 'should fail trying to disable registration if mandatory login is false' do + result = request('/system/disable-registration', { + "csrf_userid" => $csrf_userid, + "csrf_token" => $csrf_token, + "password" => "staff" + }) + + (result['status']).should.equal('fail') + (result['message']).should.equal('MANDATORY_LOGIN_IS_DESACTIVATED') + row = $database.getRow('setting', 'registration', 'name') + + (row['value']).should.equal('1') + end + it 'should allow Staff invite Users when Mandatory-login is off' do + result = request('/user/invite', { + "csrf_userid" => $csrf_userid, + "csrf_token" => $csrf_token, + email: 'inviteduser@opensupports.com', + name: 'inviteduser' + }) + (result['status']).should.equal('success') + (result['data']['userEmail']).should.equal('inviteduser@opensupports.com') + + $row = $database.getRow('recoverpassword','inviteduser@opensupports.com','email') + ($row['email']).should.equal('inviteduser@opensupports.com') + + end + + it 'should allow a creator creates a ticket and create him a user' do + request('/user/logout') + result = request('/ticket/create', { + email: 'nonuser@os4.com', + language: 'en', + name: 'nonuser', + title: 'ticket created without login', + content: 'THis is a content created without login', + departmentId: 1 + }) + $ticketRow = $database.getRow('ticket','ticket created without login','title') + $userRow = $database.getRow('user','nonuser@os4.com','email') + + (result['status']).should.equal('success') + (result['data']['ticketNumber']).should.equal($ticketRow['ticket_number'].to_i) + ($userRow['email']).should.equal('nonuser@os4.com') + ($userRow['not_registered']).should.equal('1') + ($userRow['tickets']).should.equal('1') + end + + it 'should allow the creator creates another ticket and not create another user' do + result = request('/ticket/create', { + email: 'nonuser@os4.com', + language: 'en', + name: 'nonuser', + title: 'ticket2 created without login', + content: 'THis is the second content created without login', + departmentId: 1 + }) + + $ticketRow = $database.getRow('ticket','ticket2 created without login','title') + $userRow = $database.getRow('user','nonuser@os4.com','email') + + (result['status']).should.equal('success') + (result['data']['ticketNumber']).should.equal($ticketRow['ticket_number'].to_i) + ($userRow['email']).should.equal('nonuser@os4.com') + ($userRow['tickets']).should.equal('2') + + end + + it 'should fail if a creator check others ticket' do + $ticketRow = $database.getRow('ticket',1,'id') + + result = request('/ticket/check', { + email: 'nonuser@os4.com', + ticketNumber: $ticketRow['ticket_number'] + }) + + (result['status']).should.equal('fail') + (result['message']).should.equal('NO_PERMISSION') + end + + it 'should fail if a creator tries to check an inexistant ticket' do + + result = request('/ticket/check', { + email: 'nonuser@os4.com', + ticketNumber: 111111 + }) + + (result['status']).should.equal('fail') + (result['message']).should.equal('INVALID_TICKET') + end + + it 'should allow a creator check a own ticket' do + $ticketRow = $database.getRow('ticket','ticket created without login','title') + $userRow = $database.getRow('user','nonuser@os4.com','email') + + result = request('/ticket/check', { + email: 'nonuser@os4.com', + ticketNumber: $ticketRow['ticket_number'] + }) + + (result['status']).should.equal('success') + (result['data']['userId']).should.equal($userRow['id']) + (result['data']['ticketNumber']).should.equal($ticketRow['ticket_number']) + + $sessionToken = result['data']['token'] + $sessionId = result['data']['userId'] + $sessionTicketNumber = result['data']['ticketNumber'] + end + + it 'should fail if the creator creates a ticket using a diferent email of the session' do + result = request('/ticket/create', { + email: 'nonuser2@os4.com', + language: 'en', + name: 'nonuser2', + title: 'ticket3 created without login', + content: 'THis is the third content created without login', + departmentId: 1 + }) + + (result['status']).should.equal('fail') + (result['message']).should.equal('INVALID_EMAIL') + end + + it 'should allow the creator get the ticket checked' do + result = request('/ticket/get', { + csrf_token: $sessionToken, + csrf_userid: $sessionId, + ticketNumber: $sessionTicketNumber + }) + (result['status']).should.equal('success') + (result['data']['title']).should.equal($ticketRow['title']) + (result['data']['content']).should.equal($ticketRow['content']) + end + + it 'should allow the creator handle the ticket checked' do + + result = request('/ticket/edit-title', { + csrf_token: $sessionToken, + csrf_userid: $sessionId, + ticketNumber: $sessionTicketNumber, + title: 'new title of ticket created without login' + }) + (result['status']).should.equal('success') + + result = request('/ticket/edit-comment', { + csrf_token: $sessionToken, + csrf_userid: $sessionId, + ticketNumber: $sessionTicketNumber, + content: 'this is the new content of the ticket created without login' + }) + (result['status']).should.equal('success') + + result = request('/ticket/comment', { + csrf_token: $sessionToken, + csrf_userid: $sessionId, + ticketNumber: $sessionTicketNumber, + content: 'this is the first comment without login' + }) + (result['status']).should.equal('success') + + result = request('/ticket/comment', { + csrf_token: $sessionToken, + csrf_userid: $sessionId, + ticketNumber: $sessionTicketNumber, + content: 'this is the second comment without login' + }) + (result['status']).should.equal('success') + + result = request('/ticket/edit-comment', { + csrf_token: $sessionToken, + csrf_userid: $sessionId, + ticketNumber: $sessionTicketNumber, + ticketEventId: 0, + content: 'this is the first edited-comment without login' + }) + (result['status']).should.equal('success') + + result = request('/ticket/close', { + csrf_token: $sessionToken, + csrf_userid: $sessionId, + ticketNumber: $sessionTicketNumber, + }) + (result['status']).should.equal('success') + + $ticketRow = $database.getRow('ticket','new title of ticket created without login','title') + + ($ticketRow['title']).should.equal('new title of ticket created without login') + ($ticketRow['content']).should.equal('this is the first edited-comment without login') + ($ticketRow['closed']).should.equal('1') + + result = request('/ticket/delete', { + csrf_token: $sessionToken, + csrf_userid: $sessionId, + ticketNumber: $sessionTicketNumber, + }) + (result['status']).should.equal('success') + + end + + it 'should fail if the creator tries to get a own ticket not checked' do + $ticketRow = $database.getRow('ticket','ticket2 created without login','title') + + result = request('/ticket/get', { + csrf_token: $sessionToken, + csrf_userid: $sessionId, + ticketNumber: $ticketRow['ticket_number'], + }) + (result['status']).should.equal('fail') + (result['message']).should.equal('NO_PERMISSION') + end + + it 'should re-login if the creator tries to check another ticket with a existent session' do + $ticketRow = $database.getRow('ticket','ticket2 created without login','title') + + result = request('/ticket/check', { + email: 'nonuser@os4.com', + ticketNumber: $ticketRow['ticket_number'] + }) + + (result['status']).should.equal('success') + end + + it 'should fail if the creator tries to login with email used to create tickets' do + result = request('/user/login', { + email: 'nonuser@os4.com' + }) + + (result['status']).should.equal('fail') + (result['message']).should.equal('INVALID_CREDENTIALS') + + request('/user/logout') + + result = request('/user/login', { + email: 'nonuser@os4.com' + }) + + (result['status']).should.equal('fail') + (result['message']).should.equal('INVALID_CREDENTIALS') + end + + it 'should allow the creator sign up' do + request('/user/logout') + Scripts.createUser('nonuser@os4.com', 'customPassword', 'nonuser') + $userRow = $database.getRow('user','nonuser@os4.com','email') + ($userRow['never_logged']).should.equal(nil) + ($userRow['verification_token']).should.equal(nil) + end + + it 'should allow the creator login and get more than 1 own ticket' do + request('/user/logout') + result = request('/user/login', { + email: 'nonuser@os4.com', + password: 'customPassword' + }) + (result['status']).should.equal('success') + + $sessionToken = result['data']['token'] + $sessionUserId = result['data']['userId'] + + result = request('/ticket/create', { + title: 'Valid titlee', + content: 'ticket created to see ifcreator can handle 2 tickets', + departmentId: 1, + language: 'en', + csrf_userid: $sessionUserId, + csrf_token: $sessionToken + }) + $ticket2 = $database.getRow('ticket', 'ticket2 created without login', 'title') + $ticket3 = $database.getRow('ticket', 'ticket created to see ifcreator can handle 2 tickets', 'content') + + result = request('/ticket/get', { + csrf_userid: $sessionUserId, + csrf_token: $sessionToken, + ticketNumber: $ticket3['ticket_number'], + }) + (result['status']).should.equal('success') + + result = request('/ticket/get', { + csrf_userid: $sessionUserId, + csrf_token: $sessionToken, + ticketNumber: $ticket2['ticket_number'], + }) + (result['status']).should.equal('success') + end + + request('/user/logout') + Scripts.login($staff[:email], $staff[:password], true) + + it 'should allow staff enable the mandatory login' do + result = request('/system/enable-mandatory-login', { + "csrf_userid" => $csrf_userid, + "csrf_token" => $csrf_token, + "password" => "invalidPassword" + }) + + (result['status']).should.equal('fail') + (result['message']).should.equal('INVALID_PASSWORD') + + row = $database.getRow('setting', 'mandatory-login', 'name') + + (row['value']).should.equal('0') + + result = request('/system/enable-mandatory-login', { + "csrf_userid" => $csrf_userid, + "csrf_token" => $csrf_token, + "password" => "staff" + }) + + (result['status']).should.equal('success') + + row = $database.getRow('setting', 'mandatory-login', 'name') + + (row['value']).should.equal('1') + end +end diff --git a/tests/ticket/get-authors.rb b/tests/ticket/get-authors.rb index 04982816..b5ba93a1 100644 --- a/tests/ticket/get-authors.rb +++ b/tests/ticket/get-authors.rb @@ -1,6 +1,6 @@ describe '/ticket/get-authors/' do - it 'should fail if a user is loged' do + it 'should fail if a user is logged' do request('/user/logout') Scripts.login('tyrion@opensupports.com', 'tyrionl') diff --git a/tests/user/login.rb b/tests/user/login.rb index 373d7050..15d5e98b 100644 --- a/tests/user/login.rb +++ b/tests/user/login.rb @@ -22,14 +22,13 @@ describe '/user/login' do (result['status']).should.equal('success') end - it 'should fail if already logged in' do + it 'should not fail if already logged in' do result = request('/user/login', { email: @loginEmail, password: @loginPass }) - (result['status']).should.equal('fail') - (result['message']).should.equal('SESSION_EXISTS') + (result['status']).should.equal('success') end it 'should login staff member' do