From 03778f0e9519089b9b88b1a74cd5e1d709779755 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Fri, 14 Sep 2018 01:14:15 -0300 Subject: [PATCH 1/6] Fix TextEditor, improve image uploading --- client/package.json | 6 +- .../src/app-components/article-add-modal.js | 21 ++-- client/src/app-components/ticket-viewer.js | 5 +- .../articles/admin-panel-view-article.js | 14 ++- .../create-ticket-form.js | 12 +- .../app/main/main-signup/main-signup-page.js | 4 +- client/src/core-components/form.js | 15 +-- client/src/core-components/text-editor.js | 108 ++++++++---------- client/src/lib-core/base64-image-parser.js | 42 +++++++ client/src/main.scss | 1 + client/src/scss/quill.snow.min.css | 7 ++ server/controllers/article/add.php | 8 +- server/controllers/article/edit.php | 12 +- server/controllers/staff/edit.php | 3 + server/controllers/system/download.php | 48 ++++---- server/controllers/ticket/comment.php | 5 +- server/controllers/ticket/create.php | 10 +- server/libs/Controller.php | 31 +++++ server/libs/FileDownloader.php | 28 +++++ server/libs/FileManager.php | 10 +- server/libs/FileUploader.php | 24 ++-- server/models/Ticket.php | 1 + server/models/Ticketevent.php | 2 +- 23 files changed, 276 insertions(+), 141 deletions(-) create mode 100644 client/src/lib-core/base64-image-parser.js create mode 100644 client/src/scss/quill.snow.min.css diff --git a/client/package.json b/client/package.json index 1aa67b0f..a0f03980 100644 --- a/client/package.json +++ b/client/package.json @@ -58,16 +58,15 @@ "axios": "^0.18.0", "chart.js": "^2.4.0", "classnames": "^2.2.5", - "draft-js": "^0.10.5", - "draftjs-to-html": "^0.8.4", "history": "^3.0.0", - "html-to-draftjs": "^1.4.0", "html-to-text": "^4.0.0", "keycode": "^2.1.4", "localStorage": "^1.0.3", "lodash": "^3.10.0", "messageformat": "^0.2.2", "qs": "^6.5.2", + "quill-image-resize-module-react": "^3.0.0", + "random-string": "^0.2.0", "react": "^15.4.2", "react-chartjs-2": "^2.0.0", "react-document-title": "^1.0.2", @@ -75,6 +74,7 @@ "react-draft-wysiwyg": "^1.12.13", "react-google-recaptcha": "^0.5.2", "react-motion": "^0.4.7", + "react-quill": "^1.3.1", "react-redux": "^4.4.5", "react-router": "^3.0.2", "react-router-redux": "^4.0.7", diff --git a/client/src/app-components/article-add-modal.js b/client/src/app-components/article-add-modal.js index 0a5e4346..8912cb52 100644 --- a/client/src/app-components/article-add-modal.js +++ b/client/src/app-components/article-add-modal.js @@ -1,4 +1,6 @@ import React from 'react'; +import _ from 'lodash'; +import {connect} from 'react-redux'; import i18n from 'lib-app/i18n'; import API from 'lib-app/api-call'; @@ -9,12 +11,14 @@ import Form from 'core-components/form'; import FormField from 'core-components/form-field'; import SubmitButton from 'core-components/submit-button'; import Button from 'core-components/button'; +import TextEditor from 'core-components/text-editor'; class ArticleAddModal extends React.Component { static propTypes = { topicId: React.PropTypes.number.isRequired, topicName: React.PropTypes.string.isRequired, - position: React.PropTypes.number.isRequired + position: React.PropTypes.number.isRequired, + allowAttachments: React.PropTypes.bool }; state = { @@ -27,7 +31,7 @@ class ArticleAddModal extends React.Component {
- + {i18n('ADD_ARTICLE')} - + ); } @@ -129,11 +130,11 @@ class AdminPanelViewArticle extends React.Component { onFormSubmit(form) { API.call({ path: '/article/edit', - data: { + dataAsForm: true, + data: _.extend(TextEditor.getContentFormData(form.content), { articleId: this.findArticle().id, - title: form.title, - content: form.content - } + title: form.title + }) }).then(() => { this.props.dispatch(ArticlesActions.retrieveArticles()); this.setState({ @@ -162,6 +163,7 @@ class AdminPanelViewArticle extends React.Component { export default connect((store) => { return { + allowAttachments: store.config['allow-attachments'], topics: store.articles.topics, loading: store.articles.loading }; diff --git a/client/src/app/main/dashboard/dashboard-create-ticket/create-ticket-form.js b/client/src/app/main/dashboard/dashboard-create-ticket/create-ticket-form.js index d4859a08..4247f9a7 100644 --- a/client/src/app/main/dashboard/dashboard-create-ticket/create-ticket-form.js +++ b/client/src/app/main/dashboard/dashboard-create-ticket/create-ticket-form.js @@ -1,6 +1,6 @@ import React from 'react'; import _ from 'lodash'; -import {connect} from 'react-redux'; +import {connect} from 'react-redux'; import history from 'lib-app/history'; import i18n from 'lib-app/i18n'; @@ -57,7 +57,13 @@ class CreateTicketForm extends React.Component { size: 'medium' }}/> - + {(this.props.allowAttachments) ? this.renderFileUpload() : null} {(!this.props.userLogged) ? this.renderCaptcha() : null} {i18n('CREATE_TICKET')} @@ -125,7 +131,7 @@ class CreateTicketForm extends React.Component { API.call({ path: '/ticket/create', dataAsForm: true, - data: _.extend({}, formState, { + data: _.extend({}, formState, TextEditor.getContentFormData(formState.content), { captcha: captcha && captcha.getValue(), departmentId: SessionStore.getDepartments()[formState.departmentIndex].id }) diff --git a/client/src/app/main/main-signup/main-signup-page.js b/client/src/app/main/main-signup/main-signup-page.js index 03f8fa7c..deeb4d89 100644 --- a/client/src/app/main/main-signup/main-signup-page.js +++ b/client/src/app/main/main-signup/main-signup-page.js @@ -47,7 +47,7 @@ class MainSignUpPageWidget extends React.Component { ); } - + renderMessage() { switch (this.state.message) { case 'success': @@ -109,4 +109,4 @@ class MainSignUpPageWidget extends React.Component { } } -export default MainSignUpPageWidget; \ No newline at end of file +export default MainSignUpPageWidget; diff --git a/client/src/core-components/form.js b/client/src/core-components/form.js index cd1a6642..dd9ad80f 100644 --- a/client/src/core-components/form.js +++ b/client/src/core-components/form.js @@ -160,13 +160,7 @@ class Form extends React.Component { handleSubmit(event) { event.preventDefault(); - const form = _.mapValues(this.getFormValue(), (field) => { - if (TextEditor.isEditorState(field)) { - return TextEditor.getHTMLFromEditorState(field); - } else { - return field; - } - }); + const form = this.getFormValue(); if (this.hasFormErrors()) { this.updateErrors(this.getAllFieldErrors(), this.focusFirstErrorField.bind(this)); @@ -180,10 +174,7 @@ class Form extends React.Component { form[fieldName] = event.target.value; - this.setState({ - form: form - }); - + if(this.props.values === undefined) this.setState({form}); if (this.props.onChange) { this.props.onChange(form); @@ -213,7 +204,7 @@ class Form extends React.Component { } getFormValue() { - return this.props.values || this.state.form; + return (this.props.values !== undefined) ? this.props.values : this.state.form; } focusFirstErrorField() { diff --git a/client/src/core-components/text-editor.js b/client/src/core-components/text-editor.js index 3223a37b..ebdc2b2f 100644 --- a/client/src/core-components/text-editor.js +++ b/client/src/core-components/text-editor.js @@ -1,62 +1,64 @@ import React from 'react'; import classNames from 'classnames'; -import {Editor} from 'react-draft-wysiwyg'; -import {EditorState, ContentState, convertToRaw} from 'draft-js'; -import draftToHtml from 'draftjs-to-html'; -import htmlToDraft from 'html-to-draftjs'; +import ReactQuill, { Quill } from 'react-quill'; +import ImageResize from 'quill-image-resize-module-react'; import {isIE} from 'lib-core/navigator'; +import Base64ImageParser from 'lib-core/base64-image-parser'; + +Quill.register('modules/ImageResize', ImageResize); class TextEditor extends React.Component { static propTypes = { errored: React.PropTypes.bool, onChange: React.PropTypes.func, - value: React.PropTypes.oneOfType([ - React.PropTypes.object, React.PropTypes.string - ]) + value: React.PropTypes.string, + allowImages: React.PropTypes.bool }; static createEmpty() { - if(isIE()) return ''; - return EditorState.createEmpty(); + return ''; } static getEditorStateFromHTML(htmlString) { - if(isIE()) return htmlString; - const blocksFromHTML = htmlToDraft(htmlString); - const state = ContentState.createFromBlockArray( - blocksFromHTML.contentBlocks, - blocksFromHTML.entityMap - ); - - return EditorState.createWithContent(state); + return htmlString; } static getHTMLFromEditorState(editorState) { - if(isIE()) return editorState; - return draftToHtml(convertToRaw(editorState.getCurrentContent())); + return editorState; } static isEditorState(editorState) { - if(isIE()) return typeof editorState === 'String'; - return editorState && editorState.getCurrentContent; + return typeof editorState === 'String'; + } + + static getContentFormData(content) { + const images = Base64ImageParser.getImagesSrc(content).map(Base64ImageParser.dataURLtoFile); + const contentFormData = { + 'content': Base64ImageParser.removeImagesSrc(content), + 'images': images.length, + }; + + images.forEach((image, index) => contentFormData[`image_${index}`] = image); + + return contentFormData; } state = { - value: TextEditor.createEmpty(), + value: '', focused: false }; render() { return (
- {isIE() ? this.renderTextArea() : this.renderDraftJS()} + {isIE() ? this.renderTextArea() : this.renderQuill()}
); } - renderDraftJS() { - return ; + renderQuill() { + return } renderTextArea() { @@ -67,7 +69,7 @@ class TextEditor extends React.Component { onFocus={this.onEditorFocus.bind(this)} onBlur={this.onBlur.bind(this)} ref="editor" - value={this.props.value || this.state.value} + value={this.props.value} /> ); } @@ -87,46 +89,36 @@ class TextEditor extends React.Component { getEditorProps() { return { - wrapperClassName: 'text-editor__editor', - editorState: this.props.value || this.state.value, - ref: 'editor', - toolbar: this.getToolbarOptions(), - onEditorStateChange: this.onEditorChange.bind(this), + className: 'text-editor__editor', + value: (this.props.value !== undefined) ? this.props.value : this.state.value, + ref: "editor", + modules: this.getModulesOptions(), + onChange: this.onEditorChange.bind(this), onFocus: this.onEditorFocus.bind(this), - onBlur: this.onBlur.bind(this) + onBlur: this.onBlur.bind(this), + onKeyDown: (e) => { if(e.key == "Tab") { e.preventDefault(); e.stopPropagation(); }} }; } - getToolbarOptions() { + getModulesOptions() { return { - options: ['inline', 'blockType', 'list', 'link', 'image', 'textAlign'], - inline: { - inDropdown: false, - options: ['bold', 'italic', 'underline', 'strikethrough', 'monospace'] - }, - blockType: { - inDropdown: true, - options: [ 'Normal', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'Blockquote'] - }, - list: { - inDropdown: false, - options: ['unordered', 'ordered'] - }, - image: { - urlEnabled: true, - uploadEnabled: false, - alignmentEnabled: false - }, - textAlign: { - inDropdown: false, - options: ['left', 'center', 'right', 'justify'], + toolbar: { + container: [ + [{ 'header': [1, 2, 3, 4, 5, 6, false] }], + [{ align: [] }], + ['bold', 'italic', 'underline','strike', 'blockquote'], + [{'list': 'ordered'}, {'list': 'bullet'}], + ['blockquote', 'code-block' ], + (this.props.allowImages) ? ['link', 'image'] : ['link'] + ], }, + ImageResize: {parchment: Quill.import('parchment')}, }; } onEditorChange(value) { if(isIE()) value = value.target.value; - this.setState({value}); + if(this.props.value === undefined) this.setState({value}); if (this.props.onChange) { this.props.onChange({target: {value}}); @@ -151,11 +143,7 @@ class TextEditor extends React.Component { focus() { if (this.refs.editor) { - if(isIE()) { - this.refs.editor.focus(); - } else { - this.refs.editor.focusEditor(); - } + this.refs.editor.focus(); } } } diff --git a/client/src/lib-core/base64-image-parser.js b/client/src/lib-core/base64-image-parser.js new file mode 100644 index 00000000..1dd5f7ce --- /dev/null +++ b/client/src/lib-core/base64-image-parser.js @@ -0,0 +1,42 @@ +import randomString from 'random-string'; + +export default { + removeImagesSrc(str) { + let index=-1; + str = str.replace(/src="(data:image\/[^;]+;base64[^"]+)"/g, () => { + index++; + return `src="IMAGE_PATH_${index}"`; + }); + + return str; + }, + + getImagesSrc(str) { + let m, + urls = [], + rex = /src="(data:image\/[^;]+;base64[^"]+)"/g; + + while ( m = rex.exec( str ) ) { + urls.push( m[1] ); + } + + return urls; + }, + + dataURLtoFile(dataurl) { + var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], + bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); + + while(n--){ + u8arr[n] = bstr.charCodeAt(n); + } + + let extension=".jpg"; + if(dataurl.indexOf("image/png") !== -1) extension=".png"; + else if(dataurl.indexOf("image/tiff") !== -1) extension=".tiff"; + else if(dataurl.indexOf("image/bmp") !== -1) extension=".bmp"; + else if(dataurl.indexOf("image/gif") !== -1) extension=".gif"; + + return new File([u8arr], randomString() + extension, {type:mime}); + }, +}; diff --git a/client/src/main.scss b/client/src/main.scss index e53982b3..3297c2c4 100644 --- a/client/src/main.scss +++ b/client/src/main.scss @@ -4,6 +4,7 @@ @import 'scss/base'; @import 'scss/font_awesome/font-awesome'; @import 'scss/react-draft-wysiwyg'; +@import 'scss/quill.snow.min'; @import 'core-components/*'; @import 'app-components/*'; diff --git a/client/src/scss/quill.snow.min.css b/client/src/scss/quill.snow.min.css new file mode 100644 index 00000000..cad49ac3 --- /dev/null +++ b/client/src/scss/quill.snow.min.css @@ -0,0 +1,7 @@ +/*! + * Quill Editor v1.3.6 + * https://quilljs.com/ + * Copyright (c) 2014, Jason Chen + * Copyright (c) 2013, salesforce.com + */.ql-container{box-sizing:border-box;font-family:Helvetica,Arial,sans-serif;font-size:13px;height:100%;margin:0;position:relative}.ql-container.ql-disabled .ql-tooltip{visibility:hidden}.ql-container.ql-disabled .ql-editor ul[data-checked]>li::before{pointer-events:none}.ql-clipboard{left:-100000px;height:1px;overflow-y:hidden;position:absolute;top:50%}.ql-clipboard p{margin:0;padding:0}.ql-editor{box-sizing:border-box;line-height:1.42;height:100%;outline:0;overflow-y:auto;padding:12px 15px;tab-size:4;-moz-tab-size:4;text-align:left;white-space:pre-wrap;word-wrap:break-word}.ql-editor>*{cursor:text}.ql-editor blockquote,.ql-editor h1,.ql-editor h2,.ql-editor h3,.ql-editor h4,.ql-editor h5,.ql-editor h6,.ql-editor ol,.ql-editor p,.ql-editor pre,.ql-editor ul{margin:0;padding:0;counter-reset:list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}.ql-editor ol,.ql-editor ul{padding-left:1.5em}.ql-editor ol>li,.ql-editor ul>li{list-style-type:none}.ql-editor ul>li::before{content:'\2022'}.ql-editor ul[data-checked=false],.ql-editor ul[data-checked=true]{pointer-events:none}.ql-editor ul[data-checked=false]>li *,.ql-editor ul[data-checked=true]>li *{pointer-events:all}.ql-editor ul[data-checked=false]>li::before,.ql-editor ul[data-checked=true]>li::before{color:#777;cursor:pointer;pointer-events:all}.ql-editor ul[data-checked=true]>li::before{content:'\2611'}.ql-editor ul[data-checked=false]>li::before{content:'\2610'}.ql-editor li::before{display:inline-block;white-space:nowrap;width:1.2em}.ql-editor li:not(.ql-direction-rtl)::before{margin-left:-1.5em;margin-right:.3em;text-align:right}.ql-editor li.ql-direction-rtl::before{margin-left:.3em;margin-right:-1.5em}.ql-editor ol li:not(.ql-direction-rtl),.ql-editor ul li:not(.ql-direction-rtl){padding-left:1.5em}.ql-editor ol li.ql-direction-rtl,.ql-editor ul li.ql-direction-rtl{padding-right:1.5em}.ql-editor ol li{counter-reset:list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;counter-increment:list-0}.ql-editor ol li:before{content:counter(list-0,decimal) '. '}.ql-editor ol li.ql-indent-1{counter-increment:list-1}.ql-editor ol li.ql-indent-1:before{content:counter(list-1,lower-alpha) '. '}.ql-editor ol li.ql-indent-1{counter-reset:list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}.ql-editor ol li.ql-indent-2{counter-increment:list-2}.ql-editor ol li.ql-indent-2:before{content:counter(list-2,lower-roman) '. '}.ql-editor ol li.ql-indent-2{counter-reset:list-3 list-4 list-5 list-6 list-7 list-8 list-9}.ql-editor ol li.ql-indent-3{counter-increment:list-3}.ql-editor ol li.ql-indent-3:before{content:counter(list-3,decimal) '. '}.ql-editor ol li.ql-indent-3{counter-reset:list-4 list-5 list-6 list-7 list-8 list-9}.ql-editor ol li.ql-indent-4{counter-increment:list-4}.ql-editor ol li.ql-indent-4:before{content:counter(list-4,lower-alpha) '. '}.ql-editor ol li.ql-indent-4{counter-reset:list-5 list-6 list-7 list-8 list-9}.ql-editor ol li.ql-indent-5{counter-increment:list-5}.ql-editor ol li.ql-indent-5:before{content:counter(list-5,lower-roman) '. '}.ql-editor ol li.ql-indent-5{counter-reset:list-6 list-7 list-8 list-9}.ql-editor ol li.ql-indent-6{counter-increment:list-6}.ql-editor ol li.ql-indent-6:before{content:counter(list-6,decimal) '. '}.ql-editor ol li.ql-indent-6{counter-reset:list-7 list-8 list-9}.ql-editor ol li.ql-indent-7{counter-increment:list-7}.ql-editor ol li.ql-indent-7:before{content:counter(list-7,lower-alpha) '. '}.ql-editor ol li.ql-indent-7{counter-reset:list-8 list-9}.ql-editor ol li.ql-indent-8{counter-increment:list-8}.ql-editor ol li.ql-indent-8:before{content:counter(list-8,lower-roman) '. '}.ql-editor ol li.ql-indent-8{counter-reset:list-9}.ql-editor ol li.ql-indent-9{counter-increment:list-9}.ql-editor ol li.ql-indent-9:before{content:counter(list-9,decimal) '. '}.ql-editor .ql-indent-1:not(.ql-direction-rtl){padding-left:3em}.ql-editor li.ql-indent-1:not(.ql-direction-rtl){padding-left:4.5em}.ql-editor .ql-indent-1.ql-direction-rtl.ql-align-right{padding-right:3em}.ql-editor li.ql-indent-1.ql-direction-rtl.ql-align-right{padding-right:4.5em}.ql-editor .ql-indent-2:not(.ql-direction-rtl){padding-left:6em}.ql-editor li.ql-indent-2:not(.ql-direction-rtl){padding-left:7.5em}.ql-editor .ql-indent-2.ql-direction-rtl.ql-align-right{padding-right:6em}.ql-editor li.ql-indent-2.ql-direction-rtl.ql-align-right{padding-right:7.5em}.ql-editor .ql-indent-3:not(.ql-direction-rtl){padding-left:9em}.ql-editor li.ql-indent-3:not(.ql-direction-rtl){padding-left:10.5em}.ql-editor .ql-indent-3.ql-direction-rtl.ql-align-right{padding-right:9em}.ql-editor li.ql-indent-3.ql-direction-rtl.ql-align-right{padding-right:10.5em}.ql-editor .ql-indent-4:not(.ql-direction-rtl){padding-left:12em}.ql-editor li.ql-indent-4:not(.ql-direction-rtl){padding-left:13.5em}.ql-editor .ql-indent-4.ql-direction-rtl.ql-align-right{padding-right:12em}.ql-editor li.ql-indent-4.ql-direction-rtl.ql-align-right{padding-right:13.5em}.ql-editor .ql-indent-5:not(.ql-direction-rtl){padding-left:15em}.ql-editor li.ql-indent-5:not(.ql-direction-rtl){padding-left:16.5em}.ql-editor .ql-indent-5.ql-direction-rtl.ql-align-right{padding-right:15em}.ql-editor li.ql-indent-5.ql-direction-rtl.ql-align-right{padding-right:16.5em}.ql-editor .ql-indent-6:not(.ql-direction-rtl){padding-left:18em}.ql-editor li.ql-indent-6:not(.ql-direction-rtl){padding-left:19.5em}.ql-editor .ql-indent-6.ql-direction-rtl.ql-align-right{padding-right:18em}.ql-editor li.ql-indent-6.ql-direction-rtl.ql-align-right{padding-right:19.5em}.ql-editor .ql-indent-7:not(.ql-direction-rtl){padding-left:21em}.ql-editor li.ql-indent-7:not(.ql-direction-rtl){padding-left:22.5em}.ql-editor .ql-indent-7.ql-direction-rtl.ql-align-right{padding-right:21em}.ql-editor li.ql-indent-7.ql-direction-rtl.ql-align-right{padding-right:22.5em}.ql-editor .ql-indent-8:not(.ql-direction-rtl){padding-left:24em}.ql-editor li.ql-indent-8:not(.ql-direction-rtl){padding-left:25.5em}.ql-editor .ql-indent-8.ql-direction-rtl.ql-align-right{padding-right:24em}.ql-editor li.ql-indent-8.ql-direction-rtl.ql-align-right{padding-right:25.5em}.ql-editor .ql-indent-9:not(.ql-direction-rtl){padding-left:27em}.ql-editor li.ql-indent-9:not(.ql-direction-rtl){padding-left:28.5em}.ql-editor .ql-indent-9.ql-direction-rtl.ql-align-right{padding-right:27em}.ql-editor li.ql-indent-9.ql-direction-rtl.ql-align-right{padding-right:28.5em}.ql-editor .ql-video{display:block;max-width:100%}.ql-editor .ql-video.ql-align-center{margin:0 auto}.ql-editor .ql-video.ql-align-right{margin:0 0 0 auto}.ql-editor .ql-bg-black{background-color:#000}.ql-editor .ql-bg-red{background-color:#e60000}.ql-editor .ql-bg-orange{background-color:#f90}.ql-editor .ql-bg-yellow{background-color:#ff0}.ql-editor .ql-bg-green{background-color:#008a00}.ql-editor .ql-bg-blue{background-color:#06c}.ql-editor .ql-bg-purple{background-color:#93f}.ql-editor .ql-color-white{color:#fff}.ql-editor .ql-color-red{color:#e60000}.ql-editor .ql-color-orange{color:#f90}.ql-editor .ql-color-yellow{color:#ff0}.ql-editor .ql-color-green{color:#008a00}.ql-editor .ql-color-blue{color:#06c}.ql-editor .ql-color-purple{color:#93f}.ql-editor .ql-font-serif{font-family:Georgia,Times New Roman,serif}.ql-editor .ql-font-monospace{font-family:Monaco,Courier New,monospace}.ql-editor .ql-size-small{font-size:.75em}.ql-editor .ql-size-large{font-size:1.5em}.ql-editor .ql-size-huge{font-size:2.5em}.ql-editor .ql-direction-rtl{direction:rtl;text-align:inherit}.ql-editor .ql-align-center{text-align:center}.ql-editor .ql-align-justify{text-align:justify}.ql-editor .ql-align-right{text-align:right}.ql-editor.ql-blank::before{color:rgba(0,0,0,.6);content:attr(data-placeholder);font-style:italic;left:15px;pointer-events:none;position:absolute;right:15px}.ql-snow .ql-toolbar:after,.ql-snow.ql-toolbar:after{clear:both;content:'';display:table}.ql-snow .ql-toolbar button,.ql-snow.ql-toolbar button{background:0 0;border:none;cursor:pointer;display:inline-block;float:left;height:24px;padding:3px 5px;width:28px}.ql-snow .ql-toolbar button svg,.ql-snow.ql-toolbar button svg{float:left;height:100%}.ql-snow .ql-toolbar button:active:hover,.ql-snow.ql-toolbar button:active:hover{outline:0}.ql-snow .ql-toolbar input.ql-image[type=file],.ql-snow.ql-toolbar input.ql-image[type=file]{display:none}.ql-snow .ql-toolbar .ql-picker-item.ql-selected,.ql-snow .ql-toolbar .ql-picker-item:hover,.ql-snow .ql-toolbar .ql-picker-label.ql-active,.ql-snow .ql-toolbar .ql-picker-label:hover,.ql-snow .ql-toolbar button.ql-active,.ql-snow .ql-toolbar button:focus,.ql-snow .ql-toolbar button:hover,.ql-snow.ql-toolbar .ql-picker-item.ql-selected,.ql-snow.ql-toolbar .ql-picker-item:hover,.ql-snow.ql-toolbar .ql-picker-label.ql-active,.ql-snow.ql-toolbar .ql-picker-label:hover,.ql-snow.ql-toolbar button.ql-active,.ql-snow.ql-toolbar button:focus,.ql-snow.ql-toolbar button:hover{color:#06c}.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-fill,.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill,.ql-snow .ql-toolbar .ql-picker-item:hover .ql-fill,.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill,.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-fill,.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill,.ql-snow .ql-toolbar .ql-picker-label:hover .ql-fill,.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill,.ql-snow .ql-toolbar button.ql-active .ql-fill,.ql-snow .ql-toolbar button.ql-active .ql-stroke.ql-fill,.ql-snow .ql-toolbar button:focus .ql-fill,.ql-snow .ql-toolbar button:focus .ql-stroke.ql-fill,.ql-snow .ql-toolbar button:hover .ql-fill,.ql-snow .ql-toolbar button:hover .ql-stroke.ql-fill,.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-fill,.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill,.ql-snow.ql-toolbar .ql-picker-item:hover .ql-fill,.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill,.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-fill,.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill,.ql-snow.ql-toolbar .ql-picker-label:hover .ql-fill,.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill,.ql-snow.ql-toolbar button.ql-active .ql-fill,.ql-snow.ql-toolbar button.ql-active .ql-stroke.ql-fill,.ql-snow.ql-toolbar button:focus .ql-fill,.ql-snow.ql-toolbar button:focus .ql-stroke.ql-fill,.ql-snow.ql-toolbar button:hover .ql-fill,.ql-snow.ql-toolbar button:hover .ql-stroke.ql-fill{fill:#06c}.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke,.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter,.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke,.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke-miter,.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke,.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke-miter,.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke,.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke-miter,.ql-snow .ql-toolbar button.ql-active .ql-stroke,.ql-snow .ql-toolbar button.ql-active .ql-stroke-miter,.ql-snow .ql-toolbar button:focus .ql-stroke,.ql-snow .ql-toolbar button:focus .ql-stroke-miter,.ql-snow .ql-toolbar button:hover .ql-stroke,.ql-snow .ql-toolbar button:hover .ql-stroke-miter,.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke,.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter,.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke,.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke-miter,.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke,.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke-miter,.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke,.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke-miter,.ql-snow.ql-toolbar button.ql-active .ql-stroke,.ql-snow.ql-toolbar button.ql-active .ql-stroke-miter,.ql-snow.ql-toolbar button:focus .ql-stroke,.ql-snow.ql-toolbar button:focus .ql-stroke-miter,.ql-snow.ql-toolbar button:hover .ql-stroke,.ql-snow.ql-toolbar button:hover .ql-stroke-miter{stroke:#06c}@media (pointer:coarse){.ql-snow .ql-toolbar button:hover:not(.ql-active),.ql-snow.ql-toolbar button:hover:not(.ql-active){color:#444}.ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-fill,.ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-stroke.ql-fill,.ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-fill,.ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-stroke.ql-fill{fill:#444}.ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-stroke,.ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-stroke-miter,.ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-stroke,.ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-stroke-miter{stroke:#444}}.ql-snow{box-sizing:border-box}.ql-snow *{box-sizing:border-box}.ql-snow .ql-hidden{display:none}.ql-snow .ql-out-bottom,.ql-snow .ql-out-top{visibility:hidden}.ql-snow .ql-tooltip{position:absolute;transform:translateY(10px)}.ql-snow .ql-tooltip a{cursor:pointer;text-decoration:none}.ql-snow .ql-tooltip.ql-flip{transform:translateY(-10px)}.ql-snow .ql-formats{display:inline-block;vertical-align:middle}.ql-snow .ql-formats:after{clear:both;content:'';display:table}.ql-snow .ql-stroke{fill:none;stroke:#444;stroke-linecap:round;stroke-linejoin:round;stroke-width:2}.ql-snow .ql-stroke-miter{fill:none;stroke:#444;stroke-miterlimit:10;stroke-width:2}.ql-snow .ql-fill,.ql-snow .ql-stroke.ql-fill{fill:#444}.ql-snow .ql-empty{fill:none}.ql-snow .ql-even{fill-rule:evenodd}.ql-snow .ql-stroke.ql-thin,.ql-snow .ql-thin{stroke-width:1}.ql-snow .ql-transparent{opacity:.4}.ql-snow .ql-direction svg:last-child{display:none}.ql-snow .ql-direction.ql-active svg:last-child{display:inline}.ql-snow .ql-direction.ql-active svg:first-child{display:none}.ql-snow .ql-editor h1{font-size:2em}.ql-snow .ql-editor h2{font-size:1.5em}.ql-snow .ql-editor h3{font-size:1.17em}.ql-snow .ql-editor h4{font-size:1em}.ql-snow .ql-editor h5{font-size:.83em}.ql-snow .ql-editor h6{font-size:.67em}.ql-snow .ql-editor a{text-decoration:underline}.ql-snow .ql-editor blockquote{border-left:4px solid #ccc;margin-bottom:5px;margin-top:5px;padding-left:16px}.ql-snow .ql-editor code,.ql-snow .ql-editor pre{background-color:#f0f0f0;border-radius:3px}.ql-snow .ql-editor pre{white-space:pre-wrap;margin-bottom:5px;margin-top:5px;padding:5px 10px}.ql-snow .ql-editor code{font-size:85%;padding:2px 4px}.ql-snow .ql-editor pre.ql-syntax{background-color:#23241f;color:#f8f8f2;overflow:visible}.ql-snow .ql-editor img{max-width:100%}.ql-snow .ql-picker{color:#444;display:inline-block;float:left;font-size:14px;font-weight:500;height:24px;position:relative;vertical-align:middle}.ql-snow .ql-picker-label{cursor:pointer;display:inline-block;height:100%;padding-left:8px;padding-right:2px;position:relative;width:100%}.ql-snow .ql-picker-label::before{display:inline-block;line-height:22px}.ql-snow .ql-picker-options{background-color:#fff;display:none;min-width:100%;padding:4px 8px;position:absolute;white-space:nowrap}.ql-snow .ql-picker-options .ql-picker-item{cursor:pointer;display:block;padding-bottom:5px;padding-top:5px}.ql-snow .ql-picker.ql-expanded .ql-picker-label{color:#ccc;z-index:2}.ql-snow .ql-picker.ql-expanded .ql-picker-label .ql-fill{fill:#ccc}.ql-snow .ql-picker.ql-expanded .ql-picker-label .ql-stroke{stroke:#ccc}.ql-snow .ql-picker.ql-expanded .ql-picker-options{display:block;margin-top:-1px;top:100%;z-index:1}.ql-snow .ql-color-picker,.ql-snow .ql-icon-picker{width:28px}.ql-snow .ql-color-picker .ql-picker-label,.ql-snow .ql-icon-picker .ql-picker-label{padding:2px 4px}.ql-snow .ql-color-picker .ql-picker-label svg,.ql-snow .ql-icon-picker .ql-picker-label svg{right:4px}.ql-snow .ql-icon-picker .ql-picker-options{padding:4px 0}.ql-snow .ql-icon-picker .ql-picker-item{height:24px;width:24px;padding:2px 4px}.ql-snow .ql-color-picker .ql-picker-options{padding:3px 5px;width:152px}.ql-snow .ql-color-picker .ql-picker-item{border:1px solid transparent;float:left;height:16px;margin:2px;padding:0;width:16px}.ql-snow .ql-picker:not(.ql-color-picker):not(.ql-icon-picker) svg{position:absolute;margin-top:-9px;right:0;top:50%;width:18px}.ql-snow .ql-picker.ql-font .ql-picker-item[data-label]:not([data-label=''])::before,.ql-snow .ql-picker.ql-font .ql-picker-label[data-label]:not([data-label=''])::before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-label]:not([data-label=''])::before,.ql-snow .ql-picker.ql-header .ql-picker-label[data-label]:not([data-label=''])::before,.ql-snow .ql-picker.ql-size .ql-picker-item[data-label]:not([data-label=''])::before,.ql-snow .ql-picker.ql-size .ql-picker-label[data-label]:not([data-label=''])::before{content:attr(data-label)}.ql-snow .ql-picker.ql-header{width:98px}.ql-snow .ql-picker.ql-header .ql-picker-item::before,.ql-snow .ql-picker.ql-header .ql-picker-label::before{content:'Normal'}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before,.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before{content:'Heading 1'}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before,.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before{content:'Heading 2'}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before,.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before{content:'Heading 3'}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before,.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before{content:'Heading 4'}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before,.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before{content:'Heading 5'}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before,.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before{content:'Heading 6'}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before{font-size:2em}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before{font-size:1.5em}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before{font-size:1.17em}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before{font-size:1em}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before{font-size:.83em}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before{font-size:.67em}.ql-snow .ql-picker.ql-font{width:108px}.ql-snow .ql-picker.ql-font .ql-picker-item::before,.ql-snow .ql-picker.ql-font .ql-picker-label::before{content:'Sans Serif'}.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=serif]::before,.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=serif]::before{content:'Serif'}.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=monospace]::before,.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=monospace]::before{content:'Monospace'}.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=serif]::before{font-family:Georgia,Times New Roman,serif}.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=monospace]::before{font-family:Monaco,Courier New,monospace}.ql-snow .ql-picker.ql-size{width:98px}.ql-snow .ql-picker.ql-size .ql-picker-item::before,.ql-snow .ql-picker.ql-size .ql-picker-label::before{content:'Normal'}.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=small]::before,.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=small]::before{content:'Small'}.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=large]::before,.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=large]::before{content:'Large'}.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=huge]::before,.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=huge]::before{content:'Huge'}.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=small]::before{font-size:10px}.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=large]::before{font-size:18px}.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=huge]::before{font-size:32px}.ql-snow .ql-color-picker.ql-background .ql-picker-item{background-color:#fff}.ql-snow .ql-color-picker.ql-color .ql-picker-item{background-color:#000}.ql-toolbar.ql-snow{border:1px solid #ccc;box-sizing:border-box;font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:8px}.ql-toolbar.ql-snow .ql-formats{margin-right:15px}.ql-toolbar.ql-snow .ql-picker-label{border:1px solid transparent}.ql-toolbar.ql-snow .ql-picker-options{border:1px solid transparent;box-shadow:rgba(0,0,0,.2) 0 2px 8px}.ql-toolbar.ql-snow .ql-picker.ql-expanded .ql-picker-label{border-color:#ccc}.ql-toolbar.ql-snow .ql-picker.ql-expanded .ql-picker-options{border-color:#ccc}.ql-toolbar.ql-snow .ql-color-picker .ql-picker-item.ql-selected,.ql-toolbar.ql-snow .ql-color-picker .ql-picker-item:hover{border-color:#000}.ql-toolbar.ql-snow+.ql-container.ql-snow{border-top:0}.ql-snow .ql-tooltip{background-color:#fff;border:1px solid #ccc;box-shadow:0 0 5px #ddd;color:#444;padding:5px 12px;white-space:nowrap}.ql-snow .ql-tooltip::before{content:"Visit URL:";line-height:26px;margin-right:8px}.ql-snow .ql-tooltip input[type=text]{display:none;border:1px solid #ccc;font-size:13px;height:26px;margin:0;padding:3px 5px;width:170px}.ql-snow .ql-tooltip a.ql-preview{display:inline-block;max-width:200px;overflow-x:hidden;text-overflow:ellipsis;vertical-align:top}.ql-snow .ql-tooltip a.ql-action::after{border-right:1px solid #ccc;content:'Edit';margin-left:16px;padding-right:8px}.ql-snow .ql-tooltip a.ql-remove::before{content:'Remove';margin-left:8px}.ql-snow .ql-tooltip a{line-height:26px}.ql-snow .ql-tooltip.ql-editing a.ql-preview,.ql-snow .ql-tooltip.ql-editing a.ql-remove{display:none}.ql-snow .ql-tooltip.ql-editing input[type=text]{display:inline-block}.ql-snow .ql-tooltip.ql-editing a.ql-action::after{border-right:0;content:'Save';padding-right:0}.ql-snow .ql-tooltip[data-mode=link]::before{content:"Enter link:"}.ql-snow .ql-tooltip[data-mode=formula]::before{content:"Enter formula:"}.ql-snow .ql-tooltip[data-mode=video]::before{content:"Enter video:"}.ql-snow a{color:#06c}.ql-container.ql-snow{border:1px solid #ccc} +/*# sourceMappingURL=quill.snow.min.css.map */ \ No newline at end of file diff --git a/server/controllers/article/add.php b/server/controllers/article/add.php index 8e309e5a..6896c95d 100755 --- a/server/controllers/article/add.php +++ b/server/controllers/article/add.php @@ -53,10 +53,16 @@ class AddArticleController extends Controller { } public function handler() { + $content = Controller::request('content', true); + + $fileUploader = FileUploader::getInstance(); + $fileUploader->setPermission(FileManager::PERMISSION_ARTICLE); + $imagePaths = $this->uploadImages(); + $article = new Article(); $article->setProperties([ 'title' => Controller::request('title'), - 'content' => Controller::request('content', true), + 'content' => $this->replaceWithImagePaths($imagePaths, $content), 'lastEdited' => Date::getCurrentDate(), 'position' => Controller::request('position') || 1 ]); diff --git a/server/controllers/article/edit.php b/server/controllers/article/edit.php index 2f30a62c..4982ed9a 100755 --- a/server/controllers/article/edit.php +++ b/server/controllers/article/edit.php @@ -19,7 +19,7 @@ DataValidator::with('CustomValidations', true); * @apiParam {String} content The new content of the article. Optional. * @apiParam {String} title The new title of the article. Optional. * @apiParam {Number} position The new position of the article. Optional. - * + * * @apiUse NO_PERMISSION * @apiUse INVALID_TOPIC * @@ -58,7 +58,13 @@ class EditArticleController extends Controller { } if(Controller::request('content')) { - $article->content = Controller::request('content', true); + $fileUploader = FileUploader::getInstance(); + $fileUploader->setPermission(FileManager::PERMISSION_ARTICLE); + + $content = Controller::request('content', true); + $imagePaths = $this->uploadImages(); + + $article->content = $this->replaceWithImagePaths($imagePaths, $content); } if(Controller::request('title')) { @@ -77,4 +83,4 @@ class EditArticleController extends Controller { Response::respondSuccess(); } -} \ No newline at end of file +} diff --git a/server/controllers/staff/edit.php b/server/controllers/staff/edit.php index 24311b44..46924126 100755 --- a/server/controllers/staff/edit.php +++ b/server/controllers/staff/edit.php @@ -100,6 +100,9 @@ class EditStaffController extends Controller { } } + $fileUploader = FileUploader::getInstance(); + $fileUploader->setPermission(FileManager::PERMISSION_PROFILE); + if($fileUploader = $this->uploadFile(true)) { $this->staffInstance->profilePic = ($fileUploader instanceof FileUploader) ? $fileUploader->getFileName() : null; } diff --git a/server/controllers/system/download.php b/server/controllers/system/download.php index 7ad437f4..b2c9ba72 100755 --- a/server/controllers/system/download.php +++ b/server/controllers/system/download.php @@ -42,36 +42,32 @@ class DownloadController extends Controller { $fileName = Controller::request('file'); $isStaffProfilePic = !Staff::getDataStore($fileName, 'profilePic')->isNull(); - if(!$isStaffProfilePic) { - $session = Session::getInstance(); - $loggedUser = Controller::getLoggedUser(); + $fileDownloader = FileDownloader::getInstance(); + $fileDownloader->setFileName($fileName); - if(!$session->sessionExists()) { - Response::respond403(); - return; - } + $session = Session::getInstance(); - $ticket = Ticket::getTicket($fileName, 'file'); - - if($ticket->isNull() || ($this->isNotAuthor($ticket, $loggedUser) && $this->isNotDepartmentOwner($ticket, $loggedUser))) { - $ticketEvent = Ticketevent::getDataStore($fileName, 'file'); - - if($ticketEvent->isNull()) { - Response::respond403(); - return; - } - - $ticket = $ticketEvent->ticket; - - if($this->isNotAuthor($ticket, $loggedUser) && $this->isNotDepartmentOwner($ticket, $loggedUser)) { - Response::respond403(); - return; - } + if(!$session->isStaffLogged()) { + switch($fileDownloader->getFilePermission()) { + case FileManager::PERMISSION_TICKET: + $ticketNumber = $fileDownloader->getTicketNumber(); + $ticket = Ticket::getByTicketNumber($ticketNumber); + if($this->isNotAuthor($ticket, Controller::getLoggedUser())) { + return Response::respond403(); + } + break; + case FileManager::PERMISSION_ARTICLE: + if(Controller::isUserSystemEnabled() && !$session->sessionExists()) { + return Response::respond403(); + } + break; + case FileManager::PERMISSION_PROFILE: + break; + default: + return Response::respond403(); } } - $fileDownloader = FileDownloader::getInstance(); - $fileDownloader->setFileName($fileName); $fileDownloader->download(); exit(); } @@ -82,7 +78,7 @@ class DownloadController extends Controller { if($session->getTicketNumber()) { return $session->getTicketNumber() !== $ticket->ticketNumber; } else { - return $loggedUser->level >= 1 || $ticket->author->id !== $loggedUser->id; + return $ticket->author->id !== $loggedUser->id || ($loggedUser instanceof Staff) !== $ticket->authorToArray()['staff']; } } diff --git a/server/controllers/ticket/comment.php b/server/controllers/ticket/comment.php index 8f09492b..f0ed5b01 100755 --- a/server/controllers/ticket/comment.php +++ b/server/controllers/ticket/comment.php @@ -105,11 +105,14 @@ class CommentController extends Controller { } private function storeComment() { + $fileUploader = FileUploader::getInstance(); + $fileUploader->setPermission(FileManager::PERMISSION_TICKET, $this->ticket->ticketNumber); + $imagePaths = $this->uploadImages(); $fileUploader = $this->uploadFile(); $comment = Ticketevent::getEvent(Ticketevent::COMMENT); $comment->setProperties(array( - 'content' => $this->content, + 'content' => $this->replaceWithImagePaths($imagePaths, $this->content), 'file' => ($fileUploader instanceof FileUploader) ? $fileUploader->getFileName() : null, 'date' => Date::getCurrentDate() )); diff --git a/server/controllers/ticket/create.php b/server/controllers/ticket/create.php index 6af609b5..e15ec627 100755 --- a/server/controllers/ticket/create.php +++ b/server/controllers/ticket/create.php @@ -21,7 +21,7 @@ DataValidator::with('CustomValidations', true); * @apiParam {String} email The email of the user who created the ticket. * @apiParam {String} name The Name of the author of the ticket. * - * @apiUse NO_PERMISSION + * @apiUse NO_PERMISSION$ticketNumber * @apiUse INVALID_TITLE * @apiUse INVALID_CONTENT * @apiUse INVALID_DEPARTMENT @@ -118,13 +118,17 @@ class CreateController extends Controller { private function storeTicket() { $department = Department::getDataStore($this->departmentId); $author = Controller::getLoggedUser(); + $ticket = new Ticket(); + $fileUploader = FileUploader::getInstance(); + $fileUploader->setPermission(FileManager::PERMISSION_TICKET, $ticket->generateUniqueTicketNumber()); + + $imagePaths = $this->uploadImages(); $fileUploader = $this->uploadFile(); - $ticket = new Ticket(); $ticket->setProperties(array( 'title' => $this->title, - 'content' => $this->content, + 'content' => $this->replaceWithImagePaths($imagePaths, $this->content), 'language' => $this->language, 'department' => $department, 'file' => ($fileUploader instanceof FileUploader) ? $fileUploader->getFileName() : null, diff --git a/server/libs/Controller.php b/server/libs/Controller.php index d84ca066..0f27fd28 100755 --- a/server/libs/Controller.php +++ b/server/libs/Controller.php @@ -95,6 +95,33 @@ abstract class Controller { return \Slim\Slim::getInstance(); } + public function uploadImages() { + $allowAttachments = Setting::getSetting('allow-attachments')->getValue(); + $totalImages = Controller::request('images') * 1; + + if(!$totalImages || (!$allowAttachments && !$forceUpload)) return ''; + + $maxSize = Setting::getSetting('max-size')->getValue(); + $fileGap = Setting::getSetting('file-gap')->getValue(); + $fileFirst = Setting::getSetting('file-first-number')->getValue(); + $fileQuantity = Setting::getSetting('file-quantity'); + + $fileUploader = FileUploader::getInstance(); + $fileUploader->setMaxSize($maxSize); + + $imagePaths = []; + $url = Setting::getSetting('url')->getValue(); + for($i=0;$i<$totalImages;$i++) { + $fileUploader->setGeneratorValues($fileGap, $fileFirst, $fileQuantity->getValue()); + $fileUploader->upload($_FILES["image_$i"]); + $imagePaths[] = $url . '/api/system/download?file=' . $fileUploader->getFileName(); + $fileQuantity->value++; + } + + $fileQuantity->store(); + return $imagePaths; + } + public function uploadFile($forceUpload = false) { $allowAttachments = Setting::getSetting('allow-attachments')->getValue(); @@ -119,6 +146,10 @@ abstract class Controller { } } + public function replaceWithImagePaths($imagePaths, $content) { + 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(); } diff --git a/server/libs/FileDownloader.php b/server/libs/FileDownloader.php index f8bc7435..3d069029 100755 --- a/server/libs/FileDownloader.php +++ b/server/libs/FileDownloader.php @@ -51,4 +51,32 @@ class FileDownloader extends FileManager { array_key_exists($fileExtension, $contentTypes) ? $fileExtension : 'default' ]; } + + public function getFilePermission() { + if(!strlen($this->getFileName())) return NULL; + $indicator = $this->getFileName()[0]; + + if($indicator === 'a') { + return FileManager::PERMISSION_ARTICLE; + } else if($indicator === 't') { + return FileManager::PERMISSION_TICKET; + } else if($indicator === 'p') { + return FileManager::PERMISSION_PROFILE; + } + + return NULL; + } + + public function getTicketNumber() { + $fileName = $this->getFileName(); + if(strlen($fileName) < 2) return NULL; + $ticketNumber = 0; + + for($i=1; $fileName[$i] !== '_'; $i++) { + $ticketNumber *= 10; + $ticketNumber += $fileName[$i]; + } + + return $ticketNumber; + } } diff --git a/server/libs/FileManager.php b/server/libs/FileManager.php index fd05bb13..d1b9f147 100755 --- a/server/libs/FileManager.php +++ b/server/libs/FileManager.php @@ -3,7 +3,11 @@ abstract class FileManager { private $fileName; private $localPath = 'files/'; - + + const PERMISSION_ARTICLE = 'PERMISSION_ARTICLE'; + const PERMISSION_TICKET = 'PERMISSION_TICKET'; + const PERMISSION_PROFILE = 'PERMISSION_PROFILE'; + public function setLocalPath($localPath) { $this->localPath = $localPath; } @@ -19,8 +23,8 @@ abstract class FileManager { public function getFileName() { return $this->fileName; } - + public function getFullFilePath() { return $this->getLocalPath() . $this->getFileName(); } -} \ No newline at end of file +} diff --git a/server/libs/FileUploader.php b/server/libs/FileUploader.php index d078927e..576a4b76 100755 --- a/server/libs/FileUploader.php +++ b/server/libs/FileUploader.php @@ -5,6 +5,7 @@ class FileUploader extends FileManager { private $linearCongruentialGenerator; private $linearCongruentialGeneratorOffset; private $fileName; + private $permission; private static $instance = null; @@ -24,7 +25,7 @@ class FileUploader extends FileManager { if($file['size'] > (1024 * $this->maxSize)) { return false; } - + move_uploaded_file($file['tmp_name'], $this->getLocalPath() . $this->getFileName()); return true; @@ -36,10 +37,18 @@ class FileUploader extends FileManager { $newName = preg_replace('/[^a-zA-Z0-9\d\.\-]/', '_', $newName); if ($this->linearCongruentialGenerator instanceof LinearCongruentialGenerator) { - $newName = $this->linearCongruentialGenerator->generate($this->linearCongruentialGeneratorOffset) . '_' . $newName; - } + if($this->permission) $this->fileName = $this->permission . '_'; + else $this->fileName = ''; - $this->fileName = $newName; + $this->fileName .= $this->linearCongruentialGenerator->generate($this->linearCongruentialGeneratorOffset) . '_' . $newName; + } + } + + public function setPermission($type = '', $extra = '') { + if($type === FileManager::PERMISSION_ARTICLE) $this->permission = 'a'; + else if($type === FileManager::PERMISSION_TICKET) $this->permission = 't' . $extra; + else if($type === FileManager::PERMISSION_PROFILE) $this->permission = 'p'; + else $this->permission = ''; } public function setGeneratorValues($gap, $first, $offset) { @@ -49,13 +58,12 @@ class FileUploader extends FileManager { $this->linearCongruentialGenerator->setGap($gap); $this->linearCongruentialGenerator->setFirst($first); } - + public function setMaxSize($maxSize) { $this->maxSize = $maxSize; } - + public function getFileName() { return $this->fileName; } - -} \ No newline at end of file +} diff --git a/server/models/Ticket.php b/server/models/Ticket.php index 119f56d5..03617b31 100755 --- a/server/models/Ticket.php +++ b/server/models/Ticket.php @@ -196,6 +196,7 @@ class Ticket extends DataStore { public function isAuthor($user) { $ticketAuthor = $this->authorToArray(); + if(is_string($user)) return $user == $ticketAuthor['email']; return $user->id == $ticketAuthor['id'] && ($user instanceof Staff) == $ticketAuthor['staff']; } diff --git a/server/models/Ticketevent.php b/server/models/Ticketevent.php index 91f6c831..07dddbae 100755 --- a/server/models/Ticketevent.php +++ b/server/models/Ticketevent.php @@ -87,4 +87,4 @@ class Ticketevent extends DataStore { ] ]; } -} \ No newline at end of file +} From 4df3bab1ffe899bee4baa2769fc07323cdfe3ede Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Thu, 20 Sep 2018 14:50:44 -0300 Subject: [PATCH 2/6] Add test for image upload --- server/libs/Controller.php | 1 + tests/system/disable-user-system.rb | 4 ++-- tests/system/file-upload-download.rb | 27 +++++++++++++++++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/server/libs/Controller.php b/server/libs/Controller.php index 0f27fd28..402d76c8 100755 --- a/server/libs/Controller.php +++ b/server/libs/Controller.php @@ -147,6 +147,7 @@ abstract class Controller { } public function replaceWithImagePaths($imagePaths, $content) { + if(!is_array($imagePaths)) return $content; return str_replace(array_map(function($index) { return "IMAGE_PATH_$index"; }, array_keys($imagePaths)), $imagePaths, $content); } diff --git a/tests/system/disable-user-system.rb b/tests/system/disable-user-system.rb index 210c45f5..81884ea8 100644 --- a/tests/system/disable-user-system.rb +++ b/tests/system/disable-user-system.rb @@ -19,7 +19,7 @@ describe'system/disable-user-system' do 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(38) + (numberOftickets.num_rows).should.equal(39) request('/user/logout') @@ -93,7 +93,7 @@ describe'system/disable-user-system' do 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(39) + (numberOftickets.num_rows).should.equal(40) end diff --git a/tests/system/file-upload-download.rb b/tests/system/file-upload-download.rb index 42da8593..b8ceef02 100644 --- a/tests/system/file-upload-download.rb +++ b/tests/system/file-upload-download.rb @@ -21,6 +21,7 @@ describe 'File Upload and Download' do ticket = $database.getLastRow('ticket') (ticket['file'].include? 'upload_3_.txt').should.equal(true) + (ticket['file'].include? ('' + ticket['ticket_number'] + '_')).should.equal(true) (File.exist? ('../server/files/' + ticket['file'])).should.equal(true) end @@ -66,6 +67,7 @@ describe 'File Upload and Download' do }) user = $database.getRow('staff', $csrf_userid) + (user['profile_pic'][0] == 'p').should.equal(true) result = plainRequest('/system/download', { 'csrf_userid' => $csrf_userid, @@ -75,4 +77,29 @@ describe 'File Upload and Download' do (result.body).should.include('file content') end + + it 'should add images to ticket content when creating a new ticket' do + request('/user/logout') + Scripts.login('creator@os4.com', 'creator') + + file = File.open( "../server/files/profile.jpg") + + result = request('/ticket/create', { + 'csrf_userid' => $csrf_userid, + 'csrf_token' => $csrf_token, + 'title' => 'Ticket with file', + 'content' => 'this is a ticket that contains images ', + 'language' => 'en', + 'departmentId' => 1, + 'images' => 2, + 'image_0' => File.open( "../server/files/profile.jpg"), + 'image_1' => File.open( "../server/files/profile.jpg"), + }) + + (result['status']).should.equal('success') + + ticket = $database.getLastRow('ticket') + + (ticket['content'].include? '_profile.jpg').should.equal(true) + end end From 285b62832ad97fb94ff693be8474a46568c348cc Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Thu, 20 Sep 2018 15:52:27 -0300 Subject: [PATCH 3/6] Add image file size validation --- client/preprocessor.js | 17 ------------- .../core-components/__tests__/form-test.js | 14 ----------- client/src/core-components/form.js | 1 - client/src/core-components/tooltip.js | 4 ++-- client/src/data/fixtures/system-fixtures.js | 2 +- client/src/data/languages/br.js | 1 + client/src/data/languages/cn.js | 1 + client/src/data/languages/de.js | 1 + client/src/data/languages/en.js | 1 + client/src/data/languages/es.js | 1 + client/src/data/languages/fr.js | 1 + client/src/data/languages/gr.js | 1 + client/src/data/languages/in.js | 1 + client/src/data/languages/it.js | 1 + client/src/data/languages/jp.js | 1 + client/src/data/languages/nl.js | 1 + client/src/data/languages/pt.js | 1 + client/src/data/languages/ru.js | 1 + client/src/data/languages/tr.js | 1 + client/src/lib-app/session-store.js | 4 +++- .../validations/image-size-validator.js | 24 +++++++++++++++++++ .../lib-app/validations/length-validator.js | 14 +++++------ .../lib-app/validations/validator-factory.js | 3 ++- client/src/lib-app/validations/validator.js | 8 +++---- client/src/lib-test/preprocessor.js | 1 + server/controllers/system/init-settings.php | 2 +- server/libs/Controller.php | 8 +++++++ server/libs/FileUploader.php | 8 +++++-- tests/system/edit-settings.rb | 4 ++-- 29 files changed, 74 insertions(+), 54 deletions(-) delete mode 100644 client/preprocessor.js create mode 100644 client/src/lib-app/validations/image-size-validator.js diff --git a/client/preprocessor.js b/client/preprocessor.js deleted file mode 100644 index 4a742dcf..00000000 --- a/client/preprocessor.js +++ /dev/null @@ -1,17 +0,0 @@ -'use strict'; - -var babel = require('babel-core'); - -module.exports = { - process: function(src, filename) { - // Ignore files other than .js, .es, .jsx or .es6 - if (!babel.canCompile(filename)) { - return ''; - } - // Ignore all files within node_modules - if (filename.indexOf('node_modules') === -1) { - return babel.transform(src, {filename: filename}).code; - } - return src; - } -}; \ No newline at end of file diff --git a/client/src/core-components/__tests__/form-test.js b/client/src/core-components/__tests__/form-test.js index 016ed26e..94530f15 100644 --- a/client/src/core-components/__tests__/form-test.js +++ b/client/src/core-components/__tests__/form-test.js @@ -1,13 +1,11 @@ // MOCKS const ValidationFactoryMock = require('lib-app/__mocks__/validations/validation-factory-mock'); -const TextEditorMock = require('core-components/__mocks__/text-editor-mock'); const FormField = ReactMock(); // COMPONENT const Form = requireUnit('core-components/form', { 'lib-app/validations/validator-factory': ValidationFactoryMock, 'core-components/form-field': FormField, - 'core-components/text-editor': TextEditorMock }); describe('Form component', function () { @@ -187,18 +185,6 @@ describe('Form component', function () { expect(form.props.onSubmit).to.not.have.been.called; }); - it('should transform TextEdit value to HTML', function () { - form.state.form.first = TextEditorMock.createEmpty(); - - TestUtils.Simulate.submit(ReactDOM.findDOMNode(form)); - expect(TextEditorMock.getHTMLFromEditorState).to.have.been.calledWith(form.state.form.first); - expect(form.props.onSubmit).to.have.been.calledWith({ - first: 'HTML_CODE', - second: 'value2', - third: 'value3' - }); - }); - it('should focus the first field with error', function () { ValidationFactoryMock.validators.defaultValidatorMock.performValidation = stub().returns('MOCK_ERROR'); ValidationFactoryMock.validators.customValidatorMock.performValidation = stub().returns('MOCK_ERROR_2'); diff --git a/client/src/core-components/form.js b/client/src/core-components/form.js index dd9ad80f..ea422d54 100644 --- a/client/src/core-components/form.js +++ b/client/src/core-components/form.js @@ -6,7 +6,6 @@ import {reactDFS, renderChildrenWithProps} from 'lib-core/react-dfs'; import ValidationFactory from 'lib-app/validations/validator-factory'; import FormField from 'core-components/form-field'; -import TextEditor from 'core-components/text-editor'; class Form extends React.Component { diff --git a/client/src/core-components/tooltip.js b/client/src/core-components/tooltip.js index 738b1051..c704b192 100644 --- a/client/src/core-components/tooltip.js +++ b/client/src/core-components/tooltip.js @@ -2,7 +2,7 @@ import React from 'react' import {Motion, spring} from 'react-motion'; class Tooltip extends React.Component { - + static propTypes = { children: React.PropTypes.node, content: React.PropTypes.node, @@ -105,4 +105,4 @@ class Tooltip extends React.Component { } } -export default Tooltip; \ No newline at end of file +export default Tooltip; diff --git a/client/src/data/fixtures/system-fixtures.js b/client/src/data/fixtures/system-fixtures.js index 50e1d5d8..a60dfba5 100644 --- a/client/src/data/fixtures/system-fixtures.js +++ b/client/src/data/fixtures/system-fixtures.js @@ -21,7 +21,7 @@ module.exports = [ 'session-prefix': 'opensupports-z6ctpq2winvfhchX2_', 'maintenance-mode': false, 'allow-attachments': true, - 'max-size': 500, + 'max-size': 1, 'departments': [ {id: 1, name: 'Sales Support', owners: 2}, {id: 2, name: 'Technical Issues', owners: 5}, diff --git a/client/src/data/languages/br.js b/client/src/data/languages/br.js index 12e23c8a..58c86ae1 100644 --- a/client/src/data/languages/br.js +++ b/client/src/data/languages/br.js @@ -321,6 +321,7 @@ export default { 'INVALID_EMAIL_OR_TICKET_NUMBER': 'Número de e-mail ou chamado inválido', 'INVALID_FILE': 'arquivo inválido', 'ERRORS_FOUND': 'Erros encontrados', + 'ERROR_IMAGE_SIZE': 'Nenhuma imagem pode ter um tamanho maior que {size} MB', //MESSAGES 'SIGNUP_SUCCESS': 'Você se registrou com sucesso em nosso sistema de suporte.', diff --git a/client/src/data/languages/cn.js b/client/src/data/languages/cn.js index ab259450..be3fc691 100644 --- a/client/src/data/languages/cn.js +++ b/client/src/data/languages/cn.js @@ -321,6 +321,7 @@ export default { 'INVALID_EMAIL_OR_TICKET_NUMBER': '電子郵件或機票號無效', 'INVALID_FILE': '無效文件', 'ERRORS_FOUND': '發現錯誤', + 'ERROR_IMAGE_SIZE': '没有图像的大小可以超过{size}MB', //MESSAGES 'SIGNUP_SUCCESS': '您已在我們的支持系統中成功註冊', diff --git a/client/src/data/languages/de.js b/client/src/data/languages/de.js index e6b172b6..b43b0bad 100644 --- a/client/src/data/languages/de.js +++ b/client/src/data/languages/de.js @@ -321,6 +321,7 @@ export default { 'INVALID_EMAIL_OR_TICKET_NUMBER': 'Ungültige E-Mail-Adresse oder Ticketnummer!', 'INVALID_FILE': 'Ungültige Datei!', 'ERRORS_FOUND': 'Fehler gefunden!', + 'ERROR_IMAGE_SIZE': 'Kein Bild darf größer als {size} MB sein', //MESSAGES 'SIGNUP_SUCCESS': 'Sie haben sich erfolgreich in unserem Support-System registriert.', diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js index 8a980634..4b95f899 100644 --- a/client/src/data/languages/en.js +++ b/client/src/data/languages/en.js @@ -322,6 +322,7 @@ export default { 'INVALID_EMAIL_OR_TICKET_NUMBER': 'Invalid email or ticket number', 'INVALID_FILE': 'Invalid file', 'ERRORS_FOUND': 'Errors found', + 'ERROR_IMAGE_SIZE': 'No image can have a size greater than {size} MB', //MESSAGES 'SIGNUP_SUCCESS': 'You have registered successfully in our support system.', diff --git a/client/src/data/languages/es.js b/client/src/data/languages/es.js index 072bcd83..8f604cc3 100644 --- a/client/src/data/languages/es.js +++ b/client/src/data/languages/es.js @@ -346,6 +346,7 @@ export default { 'WILL_RECOVER_EMAIL_TEMPLATE': 'Esta plantilla de correo electrónico se recuperará a su valor predeterminado en este idioma.', 'SUCCESS_IMPORTING_CSV_DESCRIPTION': 'El archivo CSV se ha importado correctamente', 'SUCCESS_DELETING_ALL_USERS': 'Los usuarios se han eliminado correctamente', + 'ERROR_IMAGE_SIZE': 'Ninguna imagen puede tener un tamaño superior a {size} MB', 'LAST_7_DAYS': 'Últimos 7 dias', 'LAST_30_DAYS': 'Últimos 30 dias', diff --git a/client/src/data/languages/fr.js b/client/src/data/languages/fr.js index ee88f58e..65152a60 100644 --- a/client/src/data/languages/fr.js +++ b/client/src/data/languages/fr.js @@ -321,6 +321,7 @@ export default { 'INVALID_EMAIL_OR_TICKET_NUMBER': 'Numéro de courriel ou de ticket invalide', 'INVALID_FILE': 'Fichier invalide', 'ERRORS_FOUND': 'Des erreurs sont survenues', + 'ERROR_IMAGE_SIZE': 'Aucune image ne peut avoir une taille supérieure à {size} MB', //MESSAGES 'SIGNUP_SUCCESS': 'Vous êtes inscrit avec succès dans notre système de support.', diff --git a/client/src/data/languages/gr.js b/client/src/data/languages/gr.js index 11af28a9..b961a00a 100644 --- a/client/src/data/languages/gr.js +++ b/client/src/data/languages/gr.js @@ -322,6 +322,7 @@ 'INVALID_EMAIL_OR_TICKET_NUMBER': 'Μη έγκυρη ηλεκτρονική διεύθυνση ή αριθμός εισιτηρίου', 'INVALID_FILE': 'Μη έγκυρο αρχείο', 'ERRORS_FOUND': 'Βρέθηκαν Σφάλματα', + 'ERROR_IMAGE_SIZE': 'Καμία εικόνα δεν μπορεί να έχει μέγεθος μεγαλύτερο από {size} MB', //MESSAGES 'SIGNUP_SUCCESS': 'Έχετε εγγραφεί με επιτυχία στο σύστημα υποστήριξης μας.', diff --git a/client/src/data/languages/in.js b/client/src/data/languages/in.js index dfb3c2be..569bfe85 100644 --- a/client/src/data/languages/in.js +++ b/client/src/data/languages/in.js @@ -321,6 +321,7 @@ export default { 'INVALID_EMAIL_OR_TICKET_NUMBER': 'अमान्य ईमेल या टिकट नंबर', 'INVALID_FILE': 'अवैध फाइल', 'ERRORS_FOUND': 'त्रुटियां मिलीं', + 'ERROR_IMAGE_SIZE': 'कोई छवि {size} एमबी से अधिक आकार नहीं हो सकती है', //MESSAGES 'SIGNUP_SUCCESS': 'आप हमारे समर्थन प्रणाली में सफलतापूर्वक दर्ज कर लिया है।', diff --git a/client/src/data/languages/it.js b/client/src/data/languages/it.js index cf94a0eb..92aa5904 100644 --- a/client/src/data/languages/it.js +++ b/client/src/data/languages/it.js @@ -321,6 +321,7 @@ export default { 'INVALID_EMAIL_OR_TICKET_NUMBER': 'E-mail o numero di ticket non validi', 'INVALID_FILE': 'File non valido', 'ERRORS_FOUND': 'Trovati errori', + 'ERROR_IMAGE_SIZE': 'Nessuna immagine può avere una dimensione superiore a {size} MB', //MESSAGES 'SIGNUP_SUCCESS': 'È stato registrato con successo nel nostro sistema di supporto.', diff --git a/client/src/data/languages/jp.js b/client/src/data/languages/jp.js index 3d1751f2..27d5fe7c 100644 --- a/client/src/data/languages/jp.js +++ b/client/src/data/languages/jp.js @@ -321,6 +321,7 @@ export default { 'INVALID_EMAIL_OR_TICKET_NUMBER': '電子メールまたはチケット番号が無効です', 'INVALID_FILE': '無効なファイル', 'ERRORS_FOUND': 'エラーが見つかりました', + 'ERROR_IMAGE_SIZE': 'イメージのサイズが{size} MBを超えることはできません', //MESSAGES 'SIGNUP_SUCCESS': 'あなたは私たちのサポートシステムに正常に登録しました。', diff --git a/client/src/data/languages/nl.js b/client/src/data/languages/nl.js index c7e96fa0..1355f2d0 100644 --- a/client/src/data/languages/nl.js +++ b/client/src/data/languages/nl.js @@ -322,6 +322,7 @@ export default { 'INVALID_EMAIL_OR_TICKET_NUMBER': 'Ongeldig e-mailadres of incidentnummer', 'INVALID_FILE': 'Ongeldig bestand', 'ERRORS_FOUND': 'Er is een fout opgetreden', + 'ERROR_IMAGE_SIZE': 'Geen enkele afbeelding kan groter zijn dan {size} MB', //MESSAGES 'SIGNUP_SUCCESS': 'U hebt zich succesvol geregistreerd in ons ondersteuningssysteem.', diff --git a/client/src/data/languages/pt.js b/client/src/data/languages/pt.js index d2eb7d54..67eecace 100644 --- a/client/src/data/languages/pt.js +++ b/client/src/data/languages/pt.js @@ -321,6 +321,7 @@ export default { 'INVALID_EMAIL_OR_TICKET_NUMBER': 'Número de e-mail ou bilhete inválido', 'INVALID_FILE': 'arquivo inválido', 'ERRORS_FOUND': 'Erros encontrados', + 'ERROR_IMAGE_SIZE': 'Nenhuma imagem pode ter um tamanho maior que {size} MB', //MESSAGES 'SIGNUP_SUCCESS': 'Você se registrou com sucesso em nosso sistema de suporte.', diff --git a/client/src/data/languages/ru.js b/client/src/data/languages/ru.js index 1d3dce2b..834a3293 100644 --- a/client/src/data/languages/ru.js +++ b/client/src/data/languages/ru.js @@ -320,6 +320,7 @@ export default { 'INVALID_EMAIL_OR_TICKET_NUMBER': 'Неправильный номер эл. Почты или номера билета.', 'INVALID_FILE': 'неверный файл', 'ERRORS_FOUND': 'Ошибки найдены', + 'ERROR_IMAGE_SIZE': 'Изображение не может иметь размер больше {size} МБ', //MESSAGES 'SIGNUP_SUCCESS': 'Вы успешно зарегистрировались в нашей системе поддержки.', diff --git a/client/src/data/languages/tr.js b/client/src/data/languages/tr.js index 0e5fb187..4858f522 100644 --- a/client/src/data/languages/tr.js +++ b/client/src/data/languages/tr.js @@ -321,6 +321,7 @@ export default { 'INVALID_EMAIL_OR_TICKET_NUMBER': 'Geçersiz e-posta veya bilet numarası', 'INVALID_FILE': 'geçersiz dosya', 'ERRORS_FOUND': 'Hatalar bulundu', + 'ERROR_IMAGE_SIZE': 'Hiçbir resmin boyutu {size} MB\'den büyük olabilir', //MESSAGES 'SIGNUP_SUCCESS': 'Destek sistemimize başarılı bir şekilde kayıt oldunuz.', diff --git a/client/src/lib-app/session-store.js b/client/src/lib-app/session-store.js index bfcf14cb..540c994b 100644 --- a/client/src/lib-app/session-store.js +++ b/client/src/lib-app/session-store.js @@ -61,6 +61,7 @@ class SessionStore { this.setItem('user-system-enabled', configs['user-system-enabled']); this.setItem('allow-attachments', configs['allow-attachments']); this.setItem('maintenance-mode', configs['maintenance-mode']); + this.setItem('max-size', configs['max-size']); } getConfigs() { @@ -75,7 +76,8 @@ class SessionStore { registration: (this.getItem('registration') * 1), 'user-system-enabled': (this.getItem('user-system-enabled') * 1), 'allow-attachments': (this.getItem('allow-attachments') * 1), - 'maintenance-mode': (this.getItem('maintenance-mode') * 1) + 'maintenance-mode': (this.getItem('maintenance-mode') * 1), + 'max-size': this.getItem('max-size'), }; } diff --git a/client/src/lib-app/validations/image-size-validator.js b/client/src/lib-app/validations/image-size-validator.js new file mode 100644 index 00000000..cd8b44d3 --- /dev/null +++ b/client/src/lib-app/validations/image-size-validator.js @@ -0,0 +1,24 @@ +import _ from 'lodash'; + +import Validator from 'lib-app/validations/validator'; +import SessionStore from 'lib-app/session-store'; +import Base64ImageParser from 'lib-core/base64-image-parser'; + +class ImageSizeValidator extends Validator { + constructor(errorKey = 'ERROR_IMAGE_SIZE', validator = null) { + super(validator); + + this.maxSize = 1; + this.errorKey = errorKey; + } + + validate(value = '', form = {}) { + let images = Base64ImageParser.getImagesSrc(value).map(Base64ImageParser.dataURLtoFile); + + if(_.some(images, f => f.size > 1048576 * SessionStore.getItem('max-size'))) { + return this.getError(this.errorKey, {size: SessionStore.getItem('max-size')}); + } + } +} + +export default ImageSizeValidator; diff --git a/client/src/lib-app/validations/length-validator.js b/client/src/lib-app/validations/length-validator.js index dcc03bec..3b120e07 100644 --- a/client/src/lib-app/validations/length-validator.js +++ b/client/src/lib-app/validations/length-validator.js @@ -1,22 +1,20 @@ -import TextEditor from 'core-components/text-editor'; - import Validator from 'lib-app/validations/validator'; class LengthValidator extends Validator { constructor(length, errorKey = 'INVALID_VALUE', validator = null) { super(validator); - + this.minlength = length; this.errorKey = errorKey; } validate(value = '', form = {}) { - if (TextEditor.isEditorState(value)) { - value = value.getCurrentContent().getPlainText(); - } + let div = document.createElement("div"); + div.innerHTML = value; + let text = div.textContent || div.innerText || ""; - if (value.length < this.minlength) return this.getError(this.errorKey); + if (text.length < this.minlength) return this.getError(this.errorKey); } } -export default LengthValidator; \ No newline at end of file +export default LengthValidator; diff --git a/client/src/lib-app/validations/validator-factory.js b/client/src/lib-app/validations/validator-factory.js index fdd63284..c84278f6 100644 --- a/client/src/lib-app/validations/validator-factory.js +++ b/client/src/lib-app/validations/validator-factory.js @@ -3,13 +3,14 @@ import EmailValidator from 'lib-app/validations/email-validator'; import RepeatPasswordValidator from 'lib-app/validations/repeat-password-validator'; import LengthValidator from 'lib-app/validations/length-validator'; import ListValidator from 'lib-app/validations/list-validator'; +import ImageSizeValidator from 'lib-app/validations/image-size-validator'; let validators = { 'DEFAULT': new Validator(), 'NAME': new LengthValidator(2, 'ERROR_NAME'), 'TITLE': new LengthValidator(1, 'ERROR_TITLE'), 'EMAIL': new EmailValidator(), - 'TEXT_AREA': new LengthValidator(10, 'ERROR_CONTENT_SHORT'), + 'TEXT_AREA': new ImageSizeValidator(undefined, new LengthValidator(10, 'ERROR_CONTENT_SHORT')), 'PASSWORD': new LengthValidator(6, 'ERROR_PASSWORD'), 'REPEAT_PASSWORD': new RepeatPasswordValidator(), 'URL': new LengthValidator(5, 'ERROR_URL'), diff --git a/client/src/lib-app/validations/validator.js b/client/src/lib-app/validations/validator.js index 6b98ced3..7ed2af44 100644 --- a/client/src/lib-app/validations/validator.js +++ b/client/src/lib-app/validations/validator.js @@ -6,7 +6,7 @@ class Validator { constructor(validator = null) { this.previousValidator = validator; } - + performValidation(value, form) { let error; @@ -27,9 +27,9 @@ class Validator { if (value.length === 0) return this.getError('ERROR_EMPTY'); } - getError(errorKey) { - return i18n(errorKey); + getError(errorKey, params) { + return i18n(errorKey, params); } } -export default Validator \ No newline at end of file +export default Validator diff --git a/client/src/lib-test/preprocessor.js b/client/src/lib-test/preprocessor.js index 1904b33c..fb3b5bcd 100644 --- a/client/src/lib-test/preprocessor.js +++ b/client/src/lib-test/preprocessor.js @@ -4,6 +4,7 @@ var jsdom = require('jsdom').jsdom; global.document = jsdom(''); global.window = document.defaultView; +global.Node = global.window.Node; global.navigator = { userAgent: 'node.js' }; diff --git a/server/controllers/system/init-settings.php b/server/controllers/system/init-settings.php index 97a87009..bbfad962 100755 --- a/server/controllers/system/init-settings.php +++ b/server/controllers/system/init-settings.php @@ -77,7 +77,7 @@ class InitSettingsController extends Controller { 'maintenance-mode' => 0, 'layout' => 'boxed', 'allow-attachments' => !!Controller::request('allow-attachments'), - 'max-size' => 1024, + 'max-size' => 1, 'title' => Controller::request('title') ? Controller::request('title') : 'Support Center', 'url' => Controller::request('url') ? Controller::request('url') : ('http://' . $_SERVER['HTTP_HOST']), 'registration' => !!Controller::request('registration'), diff --git a/server/libs/Controller.php b/server/libs/Controller.php index 402d76c8..572386cb 100755 --- a/server/libs/Controller.php +++ b/server/libs/Controller.php @@ -109,6 +109,14 @@ abstract class Controller { $fileUploader = FileUploader::getInstance(); $fileUploader->setMaxSize($maxSize); + $allImagesValidSize = true; + + for($i=0;$i<$totalImages;$i++) { + $allImagesValidSize = $allImagesValidSize && $fileUploader->isSizeValid($_FILES["image_$i"]); + } + + if(!$allImagesValidSize) throw new Exception(ERRORS::INVALID_FILE); + $imagePaths = []; $url = Setting::getSetting('url')->getValue(); for($i=0;$i<$totalImages;$i++) { diff --git a/server/libs/FileUploader.php b/server/libs/FileUploader.php index 576a4b76..71048155 100755 --- a/server/libs/FileUploader.php +++ b/server/libs/FileUploader.php @@ -1,7 +1,7 @@ maxSize); + } + public function upload($file) { $this->setNewName($file['name']); - if($file['size'] > (1024 * $this->maxSize)) { + if(!$this->isSizeValid($file)) { return false; } diff --git a/tests/system/edit-settings.rb b/tests/system/edit-settings.rb index 73684b26..5923d364 100644 --- a/tests/system/edit-settings.rb +++ b/tests/system/edit-settings.rb @@ -10,7 +10,7 @@ describe'system/edit-settings' do "time-zone" => -3, "layout" => 'full-width', "allow-attachments" => 1, - "max-size" => 2048, + "max-size" => 2, "language" => 'en', "no-reply-email" => 'testemail@hotmail.com' }) @@ -27,7 +27,7 @@ describe'system/edit-settings' do (row['value']).should.equal('full-width') row = $database.getRow('setting', 'max-size', 'name') - (row['value']).should.equal('2048') + (row['value']).should.equal('2') row = $database.getRow('setting', 'language', 'name') (row['value']).should.equal('en') From b4342167e43145bb562dcf69d733092f3f1cbe42 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Thu, 20 Sep 2018 17:19:47 -0300 Subject: [PATCH 4/6] Update API documentation --- README.md | 1 + server/API_STANDARD.md | 27 ++++++ server/Makefile | 3 + server/_apidoc.js | 82 ------------------- server/apidoc.json | 4 +- server/controllers/article/add-topic.php | 2 +- server/controllers/article/add.php | 7 +- server/controllers/article/delete-topic.php | 2 +- server/controllers/article/delete.php | 2 +- server/controllers/article/edit-topic.php | 2 +- server/controllers/article/edit.php | 7 +- server/controllers/article/get-all.php | 2 +- server/controllers/staff/add.php | 2 +- server/controllers/staff/assign-ticket.php | 2 +- server/controllers/staff/delete.php | 2 +- server/controllers/staff/edit.php | 2 +- server/controllers/staff/get-all-tickets.php | 2 +- server/controllers/staff/get-all.php | 2 +- server/controllers/staff/get-new-tickets.php | 2 +- server/controllers/staff/get-tickets.php | 2 +- server/controllers/staff/get.php | 2 +- server/controllers/staff/last-events.php | 2 +- server/controllers/staff/search-tickets.php | 2 +- server/controllers/staff/un-assign-ticket.php | 2 +- server/controllers/system/add-api-key.php | 2 +- server/controllers/system/add-department.php | 2 +- server/controllers/system/backup-database.php | 2 +- .../controllers/system/check-requirements.php | 2 +- server/controllers/system/csv-import.php | 2 +- .../controllers/system/delete-all-users.php | 2 +- server/controllers/system/delete-api-key.php | 2 +- .../controllers/system/delete-department.php | 2 +- .../system/disable-registration.php | 2 +- .../system/disable-user-system.php | 2 +- server/controllers/system/download.php | 2 +- server/controllers/system/edit-department.php | 2 +- .../controllers/system/edit-mail-template.php | 2 +- server/controllers/system/edit-settings.php | 2 +- .../system/enable-registration.php | 2 +- .../controllers/system/enable-user-system.php | 2 +- server/controllers/system/get-api-keys.php | 2 +- server/controllers/system/get-logs.php | 2 +- .../controllers/system/get-mail-templates.php | 2 +- server/controllers/system/get-settings.php | 2 +- server/controllers/system/get-stats.php | 2 +- server/controllers/system/init-admin.php | 2 +- server/controllers/system/init-database.php | 2 +- server/controllers/system/init-settings.php | 2 +- .../controllers/system/installation-done.php | 2 +- .../system/recover-mail-template.php | 2 +- server/controllers/system/test-smtp.php | 2 +- .../ticket/add-custom-response.php | 2 +- .../controllers/ticket/change-department.php | 2 +- server/controllers/ticket/change-priority.php | 2 +- server/controllers/ticket/check.php | 2 +- server/controllers/ticket/close.php | 2 +- server/controllers/ticket/comment.php | 10 ++- server/controllers/ticket/create.php | 13 +-- .../ticket/delete-custom-response.php | 2 +- .../ticket/edit-custom-response.php | 2 +- .../ticket/get-custom-responses.php | 2 +- server/controllers/ticket/get.php | 2 +- server/controllers/ticket/re-open.php | 2 +- server/controllers/ticket/seen.php | 2 +- server/controllers/user/ban.php | 2 +- server/controllers/user/check-session.php | 2 +- server/controllers/user/delete.php | 2 +- server/controllers/user/edit-email.php | 2 +- server/controllers/user/edit-password.php | 2 +- server/controllers/user/get-user.php | 2 +- server/controllers/user/get-users.php | 2 +- server/controllers/user/get.php | 2 +- server/controllers/user/list-ban.php | 2 +- server/controllers/user/login.php | 2 +- server/controllers/user/logout.php | 2 +- server/controllers/user/recover-password.php | 2 +- .../user/send-recover-password.php | 2 +- server/controllers/user/signup.php | 2 +- server/controllers/user/un-ban.php | 2 +- server/controllers/user/verify.php | 2 +- server/data/ERRORS.php | 2 +- server/libs/Controller.php | 8 +- server/models/APIKey.php | 2 +- server/models/Article.php | 2 +- server/models/Ban.php | 2 +- server/models/CustomResponse.php | 2 +- server/models/Department.php | 2 +- server/models/Log.php | 2 +- server/models/MailTemplate.php | 2 +- server/models/Staff.php | 2 +- server/models/Stat.php | 2 +- server/models/Ticket.php | 2 +- server/models/Ticketevent.php | 2 +- server/models/Topic.php | 2 +- server/models/User.php | 2 +- 95 files changed, 148 insertions(+), 184 deletions(-) delete mode 100644 server/_apidoc.js diff --git a/README.md b/README.md index 50f8b973..d73497dd 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ Just as there is a `gulp dev` task for development, there is also a `gulp prod` - `make db` access to mysql database console - `make sh` access to backend docker container bash - `make test` run phpunit tests +- `make doc` to build the documentation (requires `apidoc`) Server api runs on `http://localhost:8080/` Also, there's a *phpmyadmin* instance running on `http://localhost:6060/`, diff --git a/server/API_STANDARD.md b/server/API_STANDARD.md index 05ee15c4..edd75f24 100644 --- a/server/API_STANDARD.md +++ b/server/API_STANDARD.md @@ -38,3 +38,30 @@ This request will return you the session data with an `userId` and a `token`. Yo If you don't pass the userId and token, a `NO_PERMISSION` error will be returned. Additionally, if there are no users (only staff members), you can check a ticket you created by providing your email and the ticketNumber to the `/ticket/check` path. This path will return you a `token` and `ticketNumber` you will use to comment, retrieve, or do any other operations to the ticket. + +## File Attachments +We have two settings for file attachment: +* *allow-attachments* setting flag indicates if users can attach files. +* *max-size* setting indicates what is the file size limit in MB. + +When you want to attach images to a ticket, comment or article; you can place the string `IMAGE_PATH_i` inside the parameter `content`. +`IMAGE_PATH_i` indicates that it should be replaced with the path of the image of index `i` (zero-indexed). + +You may also include the `images` parameter indicating the number of images; and `image_i` parameters, which contain the image file object of index `i`. + +For example + +``` +/article/add +title = 'article title' +content = 'this is an article with two images ' +position = 1 +topicId = 1 +images = 2 +image_0 = +image_1 = +``` + +This request will upload `image_0` and `image_1`. After that, it will replace `IMAGE_PATH_0` and `IMAGE_PATH_1` with the corresponding urls for each image. The rest of the request will operate normal. + +**Please remember that `max-size` setting applies also to images.** diff --git a/server/Makefile b/server/Makefile index 37d92839..e9d473c1 100644 --- a/server/Makefile +++ b/server/Makefile @@ -37,3 +37,6 @@ db: sh: @docker exec -it opensupports-srv bash + +doc: + @apidoc -i models/ -i data/ -i libs/ -i controllers/ -o apidoc/ diff --git a/server/_apidoc.js b/server/_apidoc.js deleted file mode 100644 index 15f7c46b..00000000 --- a/server/_apidoc.js +++ /dev/null @@ -1,82 +0,0 @@ - -/** - * @api {post} /staff/get Get staff - * @apiVersion 4.0.0 - * - * @apiName Get staff - * - * @apiGroup Staff - * - * @apiDescription This path retrieves information about a staff member. - * - * @apiPermission staff1 - * - * @apiParam {Number} staffId The id of the staff member to be searched. - * - * @apiUse NO_PERMISSION - * - * @apiSuccess {Object} data Information about a staff member - * @apiSuccess {String} data.name Staff id - * @apiSuccess {String} data.email Staff id - * @apiSuccess {String} data.profilePic Staff id - * @apiSuccess {Number} data.level Staff id - * @apiSuccess {Boolean} data.staff Staff id - * @apiSuccess {[Department](#api-Data_Structures-ObjectDepartment)[]} data.departments Array of departments that has assigned. - * @apiSuccess {[Ticket](#api-Data_Structures-ObjectTicket)[]} data.tickets Array of tickets that has assigned. - * - */ - -/** - * @api {get} /system/download Download file - * @apiVersion 4.0.0 - * - * @apiName Download file - * - * @apiGroup System - * - * @apiDescription This path downloads a file. - * - * @apiPermission any - * - * @apiParam {String} file The filename to be downloaded. - * - * - * @apiSuccess {Object} file File content - * - */ - -/** - * @api {post} /system/init-settings Init settings - * @apiVersion 4.0.0 - * - * @apiName Init settings - * - * @apiGroup System - * - * @apiDescription This path sets the initial settings. It can only be used once during installation. - * - * @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. - * - * @apiUse INVALID_LANGUAGE - * @apiUse INIT_SETTINGS_DONE - * - * @apiSuccess {Object} data Empty object - * - */ - -/** - * @api {OBJECT} Staff Staff - * @apiVersion 4.0.0 - * @apiGroup Data Structures - * @apiParam {String} name Name of the staff member. - * @apiParam {String} email Email of the staff member. - * @apiParam {String} profilePic profilePic url of the staff member. - * @apiParam {Number} level Level of the staff member. - * @apiParam {Object[]} departments The departments the staff member has assigned. - * @apiParam {[Ticket](#api-Data_Structures-ObjectTicket)[]} tickets The tickets the staff member has assigned. - * @apiParam {Number} lastLogin The last login of the staff member. - */ \ No newline at end of file diff --git a/server/apidoc.json b/server/apidoc.json index 3fece29a..1feb7dab 100644 --- a/server/apidoc.json +++ b/server/apidoc.json @@ -1,10 +1,10 @@ { "name": "OpenSupports API Documentation", - "version": "4.1.0", + "version": "4.3.0", "title": "OpenSupports API Documentation", "description": "Backend API documentation for developers.", "header": { "title": "API Standards", "filename": "API_STANDARD.md" } -} \ No newline at end of file +} diff --git a/server/controllers/article/add-topic.php b/server/controllers/article/add-topic.php index 247f3f47..3f4e240d 100755 --- a/server/controllers/article/add-topic.php +++ b/server/controllers/article/add-topic.php @@ -4,7 +4,7 @@ DataValidator::with('CustomValidations', true); /** * @api {post} /article/add-topic Add topic - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Add topic * diff --git a/server/controllers/article/add.php b/server/controllers/article/add.php index 6896c95d..9881affb 100755 --- a/server/controllers/article/add.php +++ b/server/controllers/article/add.php @@ -4,7 +4,7 @@ DataValidator::with('CustomValidations', true); /** * @api {post} /article/add Add article - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Add article * @@ -18,11 +18,14 @@ DataValidator::with('CustomValidations', true); * @apiParam {String} content Content of the new article. * @apiParam {Number} position Position of the new article. * @apiParam {Number} topicId Id of the articles's topic. + * @apiParam {Number} images The number of images in the content + * @apiParam image_i The image file of index `i` (mutiple params accepted) * * @apiUse NO_PERMISSION * @apiUse INVALID_NAME * @apiUse INVALID_CONTENT * @apiUse INVALID_TOPIC + * @apiUse INVALID_FILE * * @apiSuccess {Object} data Article info * @apiSuccess {Number} data.articleId Article id @@ -57,7 +60,7 @@ class AddArticleController extends Controller { $fileUploader = FileUploader::getInstance(); $fileUploader->setPermission(FileManager::PERMISSION_ARTICLE); - $imagePaths = $this->uploadImages(); + $imagePaths = $this->uploadImages(true); $article = new Article(); $article->setProperties([ diff --git a/server/controllers/article/delete-topic.php b/server/controllers/article/delete-topic.php index 6e8f2174..e63aac9f 100755 --- a/server/controllers/article/delete-topic.php +++ b/server/controllers/article/delete-topic.php @@ -4,7 +4,7 @@ DataValidator::with('CustomValidations', true); /** * @api {post} /article/delete-topic Delete topic - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Delete topic * diff --git a/server/controllers/article/delete.php b/server/controllers/article/delete.php index 0d3ef1f7..49ce44a6 100755 --- a/server/controllers/article/delete.php +++ b/server/controllers/article/delete.php @@ -4,7 +4,7 @@ DataValidator::with('CustomValidations', true); /** * @api {post} /article/delete Delete article - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Delete article * diff --git a/server/controllers/article/edit-topic.php b/server/controllers/article/edit-topic.php index f60e5c3c..92df3653 100755 --- a/server/controllers/article/edit-topic.php +++ b/server/controllers/article/edit-topic.php @@ -4,7 +4,7 @@ DataValidator::with('CustomValidations', true); /** * @api {post} /article/edit-topic Edit topic - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Edit topic * diff --git a/server/controllers/article/edit.php b/server/controllers/article/edit.php index 4982ed9a..b91ba489 100755 --- a/server/controllers/article/edit.php +++ b/server/controllers/article/edit.php @@ -4,7 +4,7 @@ DataValidator::with('CustomValidations', true); /** * @api {post} /article/edit Edit article - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Edit a article * @@ -19,9 +19,12 @@ DataValidator::with('CustomValidations', true); * @apiParam {String} content The new content of the article. Optional. * @apiParam {String} title The new title of the article. Optional. * @apiParam {Number} position The new position of the article. Optional. + * @apiParam {Number} images The number of images in the content + * @apiParam image_i The image file of index `i` (mutiple params accepted) * * @apiUse NO_PERMISSION * @apiUse INVALID_TOPIC + * @apiUse INVALID_FILE * * @apiSuccess {Object} data Empty object * @@ -62,7 +65,7 @@ class EditArticleController extends Controller { $fileUploader->setPermission(FileManager::PERMISSION_ARTICLE); $content = Controller::request('content', true); - $imagePaths = $this->uploadImages(); + $imagePaths = $this->uploadImages(true); $article->content = $this->replaceWithImagePaths($imagePaths, $content); } diff --git a/server/controllers/article/get-all.php b/server/controllers/article/get-all.php index b3cb39b6..bcd76393 100755 --- a/server/controllers/article/get-all.php +++ b/server/controllers/article/get-all.php @@ -4,7 +4,7 @@ DataValidator::with('CustomValidations', true); /** * @api {post} /article/get-all Get all articles - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Get all articles * diff --git a/server/controllers/staff/add.php b/server/controllers/staff/add.php index c788cb02..d11c7b5e 100755 --- a/server/controllers/staff/add.php +++ b/server/controllers/staff/add.php @@ -4,7 +4,7 @@ DataValidator::with('CustomValidations', true); /** * @api {post} /staff/add Add staff - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Add staff * diff --git a/server/controllers/staff/assign-ticket.php b/server/controllers/staff/assign-ticket.php index e6735525..febc65d5 100755 --- a/server/controllers/staff/assign-ticket.php +++ b/server/controllers/staff/assign-ticket.php @@ -4,7 +4,7 @@ DataValidator::with('CustomValidations', true); /** * @api {post} /staff/assign-ticket Assign ticket - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Assign ticket * diff --git a/server/controllers/staff/delete.php b/server/controllers/staff/delete.php index f2a8c244..033d19a7 100755 --- a/server/controllers/staff/delete.php +++ b/server/controllers/staff/delete.php @@ -4,7 +4,7 @@ use RedBeanPHP\Facade as RedBean; /** * @api {post} /staff/delete Delete staff - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Delete staff * diff --git a/server/controllers/staff/edit.php b/server/controllers/staff/edit.php index 46924126..cf8e41d0 100755 --- a/server/controllers/staff/edit.php +++ b/server/controllers/staff/edit.php @@ -3,7 +3,7 @@ use Respect\Validation\Validator as DataValidator; /** * @api {post} /staff/edit Edit staff - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Edit staff * diff --git a/server/controllers/staff/get-all-tickets.php b/server/controllers/staff/get-all-tickets.php index a8f9781c..03d2c8bf 100755 --- a/server/controllers/staff/get-all-tickets.php +++ b/server/controllers/staff/get-all-tickets.php @@ -3,7 +3,7 @@ use Respect\Validation\Validator as DataValidator; /** * @api {post} /staff/get-all-tickets Get all tickets - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Get all tickets * diff --git a/server/controllers/staff/get-all.php b/server/controllers/staff/get-all.php index 0efe1d64..337859ae 100755 --- a/server/controllers/staff/get-all.php +++ b/server/controllers/staff/get-all.php @@ -3,7 +3,7 @@ use Respect\Validation\Validator as DataValidator; /** * @api {post} /staff/get-all Get all staffs - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Get all staffs * diff --git a/server/controllers/staff/get-new-tickets.php b/server/controllers/staff/get-new-tickets.php index 76e282b1..c342ac11 100755 --- a/server/controllers/staff/get-new-tickets.php +++ b/server/controllers/staff/get-new-tickets.php @@ -4,7 +4,7 @@ use Respect\Validation\Validator as DataValidator; /** * @api {post} /staff/get-new-tickets Get new tickets - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Get new tickets * diff --git a/server/controllers/staff/get-tickets.php b/server/controllers/staff/get-tickets.php index 9dd0269c..1f768042 100755 --- a/server/controllers/staff/get-tickets.php +++ b/server/controllers/staff/get-tickets.php @@ -3,7 +3,7 @@ use Respect\Validation\Validator as DataValidator; /** * @api {post} /staff/get-tickets Get tickets - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Get tickets * diff --git a/server/controllers/staff/get.php b/server/controllers/staff/get.php index 8b1e6793..85b7eacf 100755 --- a/server/controllers/staff/get.php +++ b/server/controllers/staff/get.php @@ -4,7 +4,7 @@ DataValidator::with('CustomValidations', true); /** * @api {post} /staff/get Get staff - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Get staff * diff --git a/server/controllers/staff/last-events.php b/server/controllers/staff/last-events.php index f915e375..970276a1 100755 --- a/server/controllers/staff/last-events.php +++ b/server/controllers/staff/last-events.php @@ -3,7 +3,7 @@ use Respect\Validation\Validator as DataValidator; /** * @api {post} /staff/last-events Get last events - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Get last events * diff --git a/server/controllers/staff/search-tickets.php b/server/controllers/staff/search-tickets.php index 6ac6cf3c..783e6424 100755 --- a/server/controllers/staff/search-tickets.php +++ b/server/controllers/staff/search-tickets.php @@ -3,7 +3,7 @@ use Respect\Validation\Validator as DataValidator; /** * @api {post} /staff/search-tickets Search tickets - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Search tickets * diff --git a/server/controllers/staff/un-assign-ticket.php b/server/controllers/staff/un-assign-ticket.php index 61866277..537e6cff 100755 --- a/server/controllers/staff/un-assign-ticket.php +++ b/server/controllers/staff/un-assign-ticket.php @@ -4,7 +4,7 @@ DataValidator::with('CustomValidations', true); /** * @api {post} /staff/un-assign-ticket Un-assign ticket - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Un-assign ticket * diff --git a/server/controllers/system/add-api-key.php b/server/controllers/system/add-api-key.php index cc6234f9..62477979 100755 --- a/server/controllers/system/add-api-key.php +++ b/server/controllers/system/add-api-key.php @@ -3,7 +3,7 @@ use Respect\Validation\Validator as DataValidator; /** * @api {post} /system/add-api-key Add APIKey - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Add APIKey * diff --git a/server/controllers/system/add-department.php b/server/controllers/system/add-department.php index 58cd7c06..be0ed503 100755 --- a/server/controllers/system/add-department.php +++ b/server/controllers/system/add-department.php @@ -3,7 +3,7 @@ use Respect\Validation\Validator as DataValidator; /** * @api {post} /system/add-department Add department - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Add department * diff --git a/server/controllers/system/backup-database.php b/server/controllers/system/backup-database.php index b1253252..df52f109 100755 --- a/server/controllers/system/backup-database.php +++ b/server/controllers/system/backup-database.php @@ -3,7 +3,7 @@ use Ifsnop\Mysqldump as IMysqldump; /** * @api {post} /system/backup-database Backup database - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Backup database * diff --git a/server/controllers/system/check-requirements.php b/server/controllers/system/check-requirements.php index 99bd57dd..4e732c5c 100755 --- a/server/controllers/system/check-requirements.php +++ b/server/controllers/system/check-requirements.php @@ -2,7 +2,7 @@ /** * @api {post} /system/check-requirements Checks requirements - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Check requirements * diff --git a/server/controllers/system/csv-import.php b/server/controllers/system/csv-import.php index 73fb2bb3..8a348a3e 100755 --- a/server/controllers/system/csv-import.php +++ b/server/controllers/system/csv-import.php @@ -2,7 +2,7 @@ /** * @api {post} /system/csv-import CSV import - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName CSV import * diff --git a/server/controllers/system/delete-all-users.php b/server/controllers/system/delete-all-users.php index 2dd6902d..db8c83b1 100755 --- a/server/controllers/system/delete-all-users.php +++ b/server/controllers/system/delete-all-users.php @@ -3,7 +3,7 @@ use RedBeanPHP\Facade as RedBean; /** * @api {post} /system/delete-all-users Delete all users - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Delete all users * diff --git a/server/controllers/system/delete-api-key.php b/server/controllers/system/delete-api-key.php index 86ffed5a..43b179e6 100755 --- a/server/controllers/system/delete-api-key.php +++ b/server/controllers/system/delete-api-key.php @@ -3,7 +3,7 @@ use Respect\Validation\Validator as DataValidator; /** * @api {post} /system/delete-api-key Delete APIKey - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Delete APIKey * diff --git a/server/controllers/system/delete-department.php b/server/controllers/system/delete-department.php index 17b4ac38..0c44792d 100755 --- a/server/controllers/system/delete-department.php +++ b/server/controllers/system/delete-department.php @@ -4,7 +4,7 @@ DataValidator::with('CustomValidations', true); /** * @api {post} /system/delete-department Delete department - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Delete department * diff --git a/server/controllers/system/disable-registration.php b/server/controllers/system/disable-registration.php index 2de734d8..777bb461 100755 --- a/server/controllers/system/disable-registration.php +++ b/server/controllers/system/disable-registration.php @@ -2,7 +2,7 @@ /** * @api {post} /system/disable-registration Disable registration - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Disable registration * diff --git a/server/controllers/system/disable-user-system.php b/server/controllers/system/disable-user-system.php index 16d36906..f3b5cfd3 100755 --- a/server/controllers/system/disable-user-system.php +++ b/server/controllers/system/disable-user-system.php @@ -2,7 +2,7 @@ /** * @api {post} /system/disable-user-system Disable user system - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Disable user system * diff --git a/server/controllers/system/download.php b/server/controllers/system/download.php index b2c9ba72..663ff51e 100755 --- a/server/controllers/system/download.php +++ b/server/controllers/system/download.php @@ -4,7 +4,7 @@ use Respect\Validation\Validator as DataValidator; /** * @api {get} /system/download Download file - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Download file * diff --git a/server/controllers/system/edit-department.php b/server/controllers/system/edit-department.php index a03b85f4..19de4de8 100755 --- a/server/controllers/system/edit-department.php +++ b/server/controllers/system/edit-department.php @@ -4,7 +4,7 @@ DataValidator::with('CustomValidations', true); /** * @api {post} /system/edit-department Edit department - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Edit department * diff --git a/server/controllers/system/edit-mail-template.php b/server/controllers/system/edit-mail-template.php index 6a76166b..8663538e 100755 --- a/server/controllers/system/edit-mail-template.php +++ b/server/controllers/system/edit-mail-template.php @@ -3,7 +3,7 @@ use Respect\Validation\Validator as DataValidator; /** * @api {post} /system/edit-mail-template Edit mail template - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Edit mail template * diff --git a/server/controllers/system/edit-settings.php b/server/controllers/system/edit-settings.php index 5aa92802..3a47a027 100755 --- a/server/controllers/system/edit-settings.php +++ b/server/controllers/system/edit-settings.php @@ -2,7 +2,7 @@ /** * @api {post} /system/edit-settings Edit settings - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Edit settings * diff --git a/server/controllers/system/enable-registration.php b/server/controllers/system/enable-registration.php index c39e33b5..7f568d48 100755 --- a/server/controllers/system/enable-registration.php +++ b/server/controllers/system/enable-registration.php @@ -3,7 +3,7 @@ use Respect\Validation\Validator as DataValidator; /** * @api {post} /system/enable-registration Enable registration - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Enable registration * diff --git a/server/controllers/system/enable-user-system.php b/server/controllers/system/enable-user-system.php index 83c4c3ba..22cc4237 100755 --- a/server/controllers/system/enable-user-system.php +++ b/server/controllers/system/enable-user-system.php @@ -2,7 +2,7 @@ /** * @api {post} /system/enable-user-system Enable user system - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Enable user system * diff --git a/server/controllers/system/get-api-keys.php b/server/controllers/system/get-api-keys.php index 870a69dc..8b01e04e 100755 --- a/server/controllers/system/get-api-keys.php +++ b/server/controllers/system/get-api-keys.php @@ -3,7 +3,7 @@ use Respect\Validation\Validator as DataValidator; /** * @api {post} /system/get-api-keys Get APIKeys - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Get APIKeys * diff --git a/server/controllers/system/get-logs.php b/server/controllers/system/get-logs.php index 9ef33f21..44fb4896 100755 --- a/server/controllers/system/get-logs.php +++ b/server/controllers/system/get-logs.php @@ -3,7 +3,7 @@ use Respect\Validation\Validator as DataValidator; /** * @api {post} /system/get-logs Get logs - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Get logs * diff --git a/server/controllers/system/get-mail-templates.php b/server/controllers/system/get-mail-templates.php index 85f9f3ae..8dfbffa5 100755 --- a/server/controllers/system/get-mail-templates.php +++ b/server/controllers/system/get-mail-templates.php @@ -3,7 +3,7 @@ use Respect\Validation\Validator as DataValidator; /** * @api {post} /system/get-mail-templates Get mail templates - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Get mail templates * diff --git a/server/controllers/system/get-settings.php b/server/controllers/system/get-settings.php index 53489d78..5dcd636b 100755 --- a/server/controllers/system/get-settings.php +++ b/server/controllers/system/get-settings.php @@ -2,7 +2,7 @@ /** * @api {post} /system/get-settings Get settings - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Get settings * diff --git a/server/controllers/system/get-stats.php b/server/controllers/system/get-stats.php index 7dbc7c04..4f432cbb 100755 --- a/server/controllers/system/get-stats.php +++ b/server/controllers/system/get-stats.php @@ -4,7 +4,7 @@ use RedBeanPHP\Facade as RedBean; /** * @api {post} /system/get-stats Get stats - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Get stats * diff --git a/server/controllers/system/init-admin.php b/server/controllers/system/init-admin.php index 599c354f..7e61d2bb 100755 --- a/server/controllers/system/init-admin.php +++ b/server/controllers/system/init-admin.php @@ -4,7 +4,7 @@ DataValidator::with('CustomValidations', true); /** * @api {post} /system/init-admin Init admin - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Init admin * diff --git a/server/controllers/system/init-database.php b/server/controllers/system/init-database.php index 2e16f121..67aefd8c 100755 --- a/server/controllers/system/init-database.php +++ b/server/controllers/system/init-database.php @@ -4,7 +4,7 @@ use RedBeanPHP\Facade as RedBean; /** * @api {post} /system/init-database Init database - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Init database * diff --git a/server/controllers/system/init-settings.php b/server/controllers/system/init-settings.php index bbfad962..ae177b14 100755 --- a/server/controllers/system/init-settings.php +++ b/server/controllers/system/init-settings.php @@ -4,7 +4,7 @@ DataValidator::with('CustomValidations', true); /** * @api {post} /system/init-settings Init settings - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Init settings * diff --git a/server/controllers/system/installation-done.php b/server/controllers/system/installation-done.php index af7ba9b9..f1e1eef6 100755 --- a/server/controllers/system/installation-done.php +++ b/server/controllers/system/installation-done.php @@ -3,7 +3,7 @@ use RedBeanPHP\Facade as RedBean; /** * @api {post} /system/installation-done Installation done - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Installation done * diff --git a/server/controllers/system/recover-mail-template.php b/server/controllers/system/recover-mail-template.php index 887cd8e4..73803a37 100755 --- a/server/controllers/system/recover-mail-template.php +++ b/server/controllers/system/recover-mail-template.php @@ -3,7 +3,7 @@ use Respect\Validation\Validator as DataValidator; /** * @api {post} /system/recover-mail-template Recover mail template - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Recover mail template * diff --git a/server/controllers/system/test-smtp.php b/server/controllers/system/test-smtp.php index 3d5e36c9..1bd3921b 100644 --- a/server/controllers/system/test-smtp.php +++ b/server/controllers/system/test-smtp.php @@ -3,7 +3,7 @@ use Respect\Validation\Validator as DataValidator; /** * @api {post} /system/test-smtp Test SMTP Connection - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Test SMTP Connection * diff --git a/server/controllers/ticket/add-custom-response.php b/server/controllers/ticket/add-custom-response.php index ce6f13ac..e8742163 100755 --- a/server/controllers/ticket/add-custom-response.php +++ b/server/controllers/ticket/add-custom-response.php @@ -4,7 +4,7 @@ DataValidator::with('CustomValidations', true); /** * @api {post} /ticket/add-custom-response Add custom responses - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Add a custom response * diff --git a/server/controllers/ticket/change-department.php b/server/controllers/ticket/change-department.php index 036a3120..47021b06 100755 --- a/server/controllers/ticket/change-department.php +++ b/server/controllers/ticket/change-department.php @@ -4,7 +4,7 @@ DataValidator::with('CustomValidations', true); /** * @api {post} /ticket/change-department Change department - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Change department * diff --git a/server/controllers/ticket/change-priority.php b/server/controllers/ticket/change-priority.php index 286d181e..ac7d47b0 100755 --- a/server/controllers/ticket/change-priority.php +++ b/server/controllers/ticket/change-priority.php @@ -3,7 +3,7 @@ use Respect\Validation\Validator as DataValidator; /** * @api {post} /ticket/change-priority Change priority - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Change priority * diff --git a/server/controllers/ticket/check.php b/server/controllers/ticket/check.php index 1edf1f53..59f1dd8b 100755 --- a/server/controllers/ticket/check.php +++ b/server/controllers/ticket/check.php @@ -4,7 +4,7 @@ DataValidator::with('CustomValidations', true); /** * @api {post} /ticket/check Check ticket - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Check ticket * diff --git a/server/controllers/ticket/close.php b/server/controllers/ticket/close.php index 1b0d71f6..9cacd543 100755 --- a/server/controllers/ticket/close.php +++ b/server/controllers/ticket/close.php @@ -4,7 +4,7 @@ DataValidator::with('CustomValidations', true); /** * @api {post} /ticket/close Close ticket - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Close * diff --git a/server/controllers/ticket/comment.php b/server/controllers/ticket/comment.php index f0ed5b01..11131ece 100755 --- a/server/controllers/ticket/comment.php +++ b/server/controllers/ticket/comment.php @@ -4,7 +4,7 @@ DataValidator::with('CustomValidations', true); /** * @api {post} /ticket/comment Comment ticket - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Comment ticket * @@ -16,11 +16,15 @@ DataValidator::with('CustomValidations', true); * * @apiParam {String} content Content of the comment. * @apiParam {Number} ticketNumber The number of the ticket to comment. + * @apiParam {Number} images The number of images in the content + * @apiParam image_i The image file of index `i` (mutiple params accepted) + * @apiParam file The file you with to upload. * * @apiUse NO_PERMISSION * @apiUse INVALID_CONTENT * @apiUse INVALID_TICKET * @apiUse INVALID_TOKEN + * @apiUse INVALID_FILE * * @apiSuccess {Object} data Empty object * @@ -107,8 +111,8 @@ class CommentController extends Controller { private function storeComment() { $fileUploader = FileUploader::getInstance(); $fileUploader->setPermission(FileManager::PERMISSION_TICKET, $this->ticket->ticketNumber); - $imagePaths = $this->uploadImages(); - $fileUploader = $this->uploadFile(); + $imagePaths = $this->uploadImages(Controller::isStaffLogged()); + $fileUploader = $this->uploadFile(Controller::isStaffLogged()); $comment = Ticketevent::getEvent(Ticketevent::COMMENT); $comment->setProperties(array( diff --git a/server/controllers/ticket/create.php b/server/controllers/ticket/create.php index e15ec627..d0059f95 100755 --- a/server/controllers/ticket/create.php +++ b/server/controllers/ticket/create.php @@ -4,7 +4,7 @@ DataValidator::with('CustomValidations', true); /** * @api {post} /ticket/create Create ticket - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Create ticket * @@ -19,15 +19,18 @@ DataValidator::with('CustomValidations', true); * @apiParam {Number} departmentId The id of the department of the current ticket. * @apiParam {String} language The language of the ticket. * @apiParam {String} email The email of the user who created the ticket. - * @apiParam {String} name The Name of the author of the ticket. + * @apiParam {Number} images The number of images in the content + * @apiParam image_i The image file of index `i` (mutiple params accepted) + * @apiParam file The file you with to upload. * - * @apiUse NO_PERMISSION$ticketNumber + * @apiUse NO_PERMISSION * @apiUse INVALID_TITLE * @apiUse INVALID_CONTENT * @apiUse INVALID_DEPARTMENT * @apiUse INVALID_LANGUAGE * @apiUse INVALID_CAPTCHA * @apiUse INVALID_EMAIL + * @apiUse INVALID_FILE * * @apiSuccess {Object} data Information of the new ticket * @apiSuccess {Number} data.ticketNumber Number of the new ticket @@ -123,8 +126,8 @@ class CreateController extends Controller { $fileUploader = FileUploader::getInstance(); $fileUploader->setPermission(FileManager::PERMISSION_TICKET, $ticket->generateUniqueTicketNumber()); - $imagePaths = $this->uploadImages(); - $fileUploader = $this->uploadFile(); + $imagePaths = $this->uploadImages(Controller::isStaffLogged()); + $fileUploader = $this->uploadFile(Controller::isStaffLogged()); $ticket->setProperties(array( 'title' => $this->title, diff --git a/server/controllers/ticket/delete-custom-response.php b/server/controllers/ticket/delete-custom-response.php index 204c1dcf..e77dc84b 100755 --- a/server/controllers/ticket/delete-custom-response.php +++ b/server/controllers/ticket/delete-custom-response.php @@ -4,7 +4,7 @@ DataValidator::with('CustomValidations', true); /** * @api {post} /ticket/delete-custom-response Delete custom response - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Delete custom response * diff --git a/server/controllers/ticket/edit-custom-response.php b/server/controllers/ticket/edit-custom-response.php index d4bad091..7837a80d 100755 --- a/server/controllers/ticket/edit-custom-response.php +++ b/server/controllers/ticket/edit-custom-response.php @@ -4,7 +4,7 @@ DataValidator::with('CustomValidations', true); /** * @api {post} /ticket/edit-custom-response Edit custom response - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Edit custom response * diff --git a/server/controllers/ticket/get-custom-responses.php b/server/controllers/ticket/get-custom-responses.php index 5697efb3..38510f81 100755 --- a/server/controllers/ticket/get-custom-responses.php +++ b/server/controllers/ticket/get-custom-responses.php @@ -4,7 +4,7 @@ DataValidator::with('CustomValidations', true); /** * @api {post} /ticket/get-custom-responses Get custom responses - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Get custom responses * diff --git a/server/controllers/ticket/get.php b/server/controllers/ticket/get.php index d1a62b4d..6bc30d2a 100755 --- a/server/controllers/ticket/get.php +++ b/server/controllers/ticket/get.php @@ -3,7 +3,7 @@ use Respect\Validation\Validator as DataValidator; DataValidator::with('CustomValidations', true); /** * @api {post} /ticket/get Get ticket - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Get ticket * diff --git a/server/controllers/ticket/re-open.php b/server/controllers/ticket/re-open.php index 56b1a183..e7956cff 100755 --- a/server/controllers/ticket/re-open.php +++ b/server/controllers/ticket/re-open.php @@ -3,7 +3,7 @@ use Respect\Validation\Validator as DataValidator; /** * @api {post} /ticket/re-open Reopen ticket - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Reopen ticket * diff --git a/server/controllers/ticket/seen.php b/server/controllers/ticket/seen.php index 5c40d406..90851994 100755 --- a/server/controllers/ticket/seen.php +++ b/server/controllers/ticket/seen.php @@ -3,7 +3,7 @@ use Respect\Validation\Validator as DataValidator; /** * @api {post} /ticket/seen See ticket - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName See ticket * diff --git a/server/controllers/user/ban.php b/server/controllers/user/ban.php index 52b72d66..c769070e 100755 --- a/server/controllers/user/ban.php +++ b/server/controllers/user/ban.php @@ -3,7 +3,7 @@ use Respect\Validation\Validator as DataValidator; /** * @api {post} /user/ban Ban email - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Ban email * diff --git a/server/controllers/user/check-session.php b/server/controllers/user/check-session.php index 613815f8..fec277ac 100755 --- a/server/controllers/user/check-session.php +++ b/server/controllers/user/check-session.php @@ -2,7 +2,7 @@ /** * @api {post} /user/check-session Check session - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Check session * diff --git a/server/controllers/user/delete.php b/server/controllers/user/delete.php index 5422e80e..ee24df2e 100755 --- a/server/controllers/user/delete.php +++ b/server/controllers/user/delete.php @@ -4,7 +4,7 @@ use RedBeanPHP\Facade as RedBean; /** * @api {post} /user/delete Delete user - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Delete user * diff --git a/server/controllers/user/edit-email.php b/server/controllers/user/edit-email.php index cd8e188a..b8003402 100755 --- a/server/controllers/user/edit-email.php +++ b/server/controllers/user/edit-email.php @@ -3,7 +3,7 @@ use Respect\Validation\Validator as DataValidator; /** * @api {post} /user/edit-email Edit email - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Edit email * diff --git a/server/controllers/user/edit-password.php b/server/controllers/user/edit-password.php index 758c254d..ef46c8b7 100755 --- a/server/controllers/user/edit-password.php +++ b/server/controllers/user/edit-password.php @@ -3,7 +3,7 @@ use Respect\Validation\Validator as DataValidator; /** * @api {post} /user/edit-password Edit password - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Edit password * diff --git a/server/controllers/user/get-user.php b/server/controllers/user/get-user.php index 812250e9..331001a6 100755 --- a/server/controllers/user/get-user.php +++ b/server/controllers/user/get-user.php @@ -4,7 +4,7 @@ DataValidator::with('CustomValidations', true); /** * @api {post} /user/get-user Get user information - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Get user information * diff --git a/server/controllers/user/get-users.php b/server/controllers/user/get-users.php index 5c53a796..03a6796f 100755 --- a/server/controllers/user/get-users.php +++ b/server/controllers/user/get-users.php @@ -3,7 +3,7 @@ use Respect\Validation\Validator as DataValidator; /** * @api {post} /user/get-users Get users list - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Get users list * diff --git a/server/controllers/user/get.php b/server/controllers/user/get.php index f85d4527..f871a870 100755 --- a/server/controllers/user/get.php +++ b/server/controllers/user/get.php @@ -4,7 +4,7 @@ DataValidator::with('CustomValidations', true); /** * @api {post} /user/get Get my information - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Get my Information * diff --git a/server/controllers/user/list-ban.php b/server/controllers/user/list-ban.php index 1f625391..5c3ba684 100755 --- a/server/controllers/user/list-ban.php +++ b/server/controllers/user/list-ban.php @@ -3,7 +3,7 @@ use Respect\Validation\Validator as DataValidator; /** * @api {post} /user/list-ban Get ban list - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Get ban list * diff --git a/server/controllers/user/login.php b/server/controllers/user/login.php index 14c2ffe3..711c6cc5 100755 --- a/server/controllers/user/login.php +++ b/server/controllers/user/login.php @@ -2,7 +2,7 @@ /** * @api {post} /user/login Login - * @apiVersion 4.2.0 + * @apiVersion 4.3.0 * * @apiName Login * diff --git a/server/controllers/user/logout.php b/server/controllers/user/logout.php index eb9dc091..e3e38f23 100755 --- a/server/controllers/user/logout.php +++ b/server/controllers/user/logout.php @@ -1,7 +1,7 @@ getValue(); $totalImages = Controller::request('images') * 1; - if(!$totalImages || (!$allowAttachments && !$forceUpload)) return ''; + if(!$allowAttachments && !$forceUpload) return []; + if(!$totalImages) return []; $maxSize = Setting::getSetting('max-size')->getValue(); $fileGap = Setting::getSetting('file-gap')->getValue(); @@ -133,7 +134,8 @@ abstract class Controller { public function uploadFile($forceUpload = false) { $allowAttachments = Setting::getSetting('allow-attachments')->getValue(); - if(!isset($_FILES['file']) || (!$allowAttachments && !$forceUpload)) return ''; + if(!$allowAttachments && !$forceUpload) return ''; + if(!isset($_FILES['file'])) return ''; $maxSize = Setting::getSetting('max-size')->getValue(); $fileGap = Setting::getSetting('file-gap')->getValue(); diff --git a/server/models/APIKey.php b/server/models/APIKey.php index 21f8e5da..a02e9887 100755 --- a/server/models/APIKey.php +++ b/server/models/APIKey.php @@ -1,7 +1,7 @@ Date: Thu, 20 Sep 2018 19:00:46 -0300 Subject: [PATCH 5/6] update .travis.yml --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7ed7d71f..2cd3045f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,8 +12,8 @@ before_install: - rvm use 2.2 --install --binary --fuzzy - ruby --version - mysql -e 'CREATE DATABASE development;' -- nvm install 4.4.7 -- npm install -g npm@2.15.8 +- nvm install 6.14.4 +- npm install -g npm@6.1.0 - npm install -g mocha - cd client - npm install From 77e302f191489695eadd52ff6c19daa8db9f7c48 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Fri, 21 Sep 2018 23:50:53 -0300 Subject: [PATCH 6/6] Fix text editor css --- client/src/app/main/main-signup/main-signup-page.js | 2 +- client/src/core-components/text-editor.scss | 9 ++------- server/controllers/ticket/create.php | 2 +- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/client/src/app/main/main-signup/main-signup-page.js b/client/src/app/main/main-signup/main-signup-page.js index f52d4586..b0634ea8 100644 --- a/client/src/app/main/main-signup/main-signup-page.js +++ b/client/src/app/main/main-signup/main-signup-page.js @@ -75,4 +75,4 @@ class MainSignUpPage extends React.Component { } } -export default MainSignUpPageWidget; +export default MainSignUpPage; diff --git a/client/src/core-components/text-editor.scss b/client/src/core-components/text-editor.scss index 07e81be1..4c516f8c 100644 --- a/client/src/core-components/text-editor.scss +++ b/client/src/core-components/text-editor.scss @@ -7,13 +7,8 @@ border: 1px solid $grey; border-radius: 3px; - .DraftEditor-root { - height: 200px; - padding-left: 10px; - } - - .public-DraftEditor-content { - height: 185px; + .ql-container { + min-height: 200px; } } diff --git a/server/controllers/ticket/create.php b/server/controllers/ticket/create.php index d0059f95..112f0391 100755 --- a/server/controllers/ticket/create.php +++ b/server/controllers/ticket/create.php @@ -72,7 +72,7 @@ class CreateController extends Controller { ] ]; - if(!Controller::isUserSystemEnabled()) { + if(!Controller::isUserSystemEnabled() && !Controller::isStaffLogged()) { $validations['permission'] = 'any'; $validations['requestData']['captcha'] = [ 'validation' => DataValidator::captcha(),