From b75660ec1d885675d99b8d6712f43f9157a06405 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 10 Jan 2017 16:45:58 -0300 Subject: [PATCH 01/84] Max Red - Created first layout and functionality of ToggleList component [skip ci] --- client/src/app-components/toggle-list.js | 52 ++++++++++++++++++++++ client/src/app-components/toggle-list.scss | 20 +++++++++ 2 files changed, 72 insertions(+) create mode 100644 client/src/app-components/toggle-list.js create mode 100644 client/src/app-components/toggle-list.scss diff --git a/client/src/app-components/toggle-list.js b/client/src/app-components/toggle-list.js new file mode 100644 index 00000000..6df36dbe --- /dev/null +++ b/client/src/app-components/toggle-list.js @@ -0,0 +1,52 @@ +import React from 'react'; +import _ from 'lodash'; +import classNames from 'classnames'; + +class ToggleList extends React.Component { + static propTypes = { + items: React.PropTypes.arrayOf(React.PropTypes.shape({ + content: React.PropTypes.node + })) + }; + + state = { + selected: [1, 3] + }; + + render() { + return ( +
+ {this.props.items.map(this.renderItem.bind(this))} +
+ ); + } + + renderItem(obj, index) { + + return ( +
+ {obj.content} +
+ ); + } + + getItemClass(index) { + let classes = { + 'toggle-list__item': true, + 'toggle-list__first-item': (index === 0), + 'toggle-list__selected': (_.includes(this.state.selected, index)) + }; + + return classNames(classes); + } + + selectItem(index) { + let actual = _.clone(this.state.selected); + (_.includes(this.state.selected, index)) ? (_.remove(actual, t => t == index)) : (actual.push(index)); + this.setState({ + selected: actual + }); + } +} + +export default ToggleList; diff --git a/client/src/app-components/toggle-list.scss b/client/src/app-components/toggle-list.scss new file mode 100644 index 00000000..b9d73082 --- /dev/null +++ b/client/src/app-components/toggle-list.scss @@ -0,0 +1,20 @@ +@import "../scss/vars"; + +.toggle-list { + + &__item { + border: 1px $light-grey solid; + border-left: none; + width: 120px; + height: 120px; + display: inline-block; + } + + &__selected { + background-color: $light-grey; + } + + &__first-item { + border: 1px $light-grey solid; + } +} \ No newline at end of file From 6fc460d4b6c866fa909d3d4e023bb2bd118cfcc3 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 10 Jan 2017 18:27:53 -0300 Subject: [PATCH 02/84] Max Red - Modified some things, I don't know which [skip ci] --- client/src/app-components/toggle-list.js | 16 ++++++++++++++-- client/src/app-components/toggle-list.scss | 5 +++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/client/src/app-components/toggle-list.js b/client/src/app-components/toggle-list.js index 6df36dbe..f90a26ae 100644 --- a/client/src/app-components/toggle-list.js +++ b/client/src/app-components/toggle-list.js @@ -6,7 +6,8 @@ class ToggleList extends React.Component { static propTypes = { items: React.PropTypes.arrayOf(React.PropTypes.shape({ content: React.PropTypes.node - })) + })), + onChange: React.PropTypes.func }; state = { @@ -42,10 +43,21 @@ class ToggleList extends React.Component { selectItem(index) { let actual = _.clone(this.state.selected); - (_.includes(this.state.selected, index)) ? (_.remove(actual, t => t == index)) : (actual.push(index)); + + _.includes(this.state.selected, index) ? _.remove(actual, t => t == index) : actual.push(index); + + console.log(actual); this.setState({ selected: actual }); + + if (this.props.onChange) { + this.props.onChange({ + target: { + value: actual + } + }); + } } } diff --git a/client/src/app-components/toggle-list.scss b/client/src/app-components/toggle-list.scss index b9d73082..7bf244cb 100644 --- a/client/src/app-components/toggle-list.scss +++ b/client/src/app-components/toggle-list.scss @@ -5,9 +5,10 @@ &__item { border: 1px $light-grey solid; border-left: none; - width: 120px; + width: 180px; height: 120px; display: inline-block; + transition: background-color 0.4s ease; } &__selected { @@ -17,4 +18,4 @@ &__first-item { border: 1px $light-grey solid; } -} \ No newline at end of file +} From 845939f08981154810ee5bcea042530ea03ac94d Mon Sep 17 00:00:00 2001 From: AntonyAntonio Date: Wed, 11 Jan 2017 04:25:26 -0300 Subject: [PATCH 03/84] Guillermo - stats architecture [skip ci] --- server/controllers/system.php | 2 ++ server/controllers/system/edit-settings.php | 1 - server/controllers/system/get-stats.php | 34 +++++++++++++++++++++ server/controllers/system/init-settings.php | 3 +- server/models/Log.php | 9 ++++-- server/models/Staff.php | 3 +- server/models/Stat.php | 17 +++++++++++ 7 files changed, 63 insertions(+), 6 deletions(-) create mode 100644 server/controllers/system/get-stats.php create mode 100644 server/models/Stat.php diff --git a/server/controllers/system.php b/server/controllers/system.php index 2cde4fe2..534f556e 100644 --- a/server/controllers/system.php +++ b/server/controllers/system.php @@ -9,6 +9,7 @@ require_once 'system/get-logs.php'; require_once 'system/get-mail-templates.php'; require_once 'system/edit-mail-template.php'; require_once 'system/recover-mail-template.php'; +require_once 'system/get-stats.php'; $systemControllerGroup = new ControllerGroup(); $systemControllerGroup->setGroupPath('/system'); @@ -23,5 +24,6 @@ $systemControllerGroup->addController(new GetLogsController); $systemControllerGroup->addController(new GetMailTemplatesController); $systemControllerGroup->addController(new EditMailTemplateController); $systemControllerGroup->addController(new RecoverMailTemplateController); +$systemControllerGroup->addController(new GetStatsController); $systemControllerGroup->finalize(); \ No newline at end of file diff --git a/server/controllers/system/edit-settings.php b/server/controllers/system/edit-settings.php index c78f1f97..22454e62 100644 --- a/server/controllers/system/edit-settings.php +++ b/server/controllers/system/edit-settings.php @@ -1,5 +1,4 @@ 'staff_1', + 'requestData' => [] + ]; + } + + public function handler() { + $begin = new DateTime(Setting::getSetting('last-stat-day')->value); + $end = new DateTime(Date::getCurrentDate()); + + $interval = new DateInterval('P1D'); + $dateRange = new DatePeriod($begin, $interval ,$end); + + foreach($dateRange as $date){ + $numberOfTickets = Log::count('type=? AND date LIKE ?',['CREATE_TICKET', $date->format('Ymd') . '%']); + $stat = new Stat(); + + $stat->setProperties([ + 'date' => $date->format('Ymd'), + 'type' => 'CREATE_TICKET', + 'general' => 1, + 'value' => $numberOfTickets, + ]); + $stat->store(); + } + + Response::respondSuccess(); + } +} \ No newline at end of file diff --git a/server/controllers/system/init-settings.php b/server/controllers/system/init-settings.php index 98fce211..89842b5c 100644 --- a/server/controllers/system/init-settings.php +++ b/server/controllers/system/init-settings.php @@ -40,7 +40,8 @@ class InitSettingsController extends Controller { 'allow-attachments' => 0, 'max-size' => 0, 'title' => 'Support Center', - 'url' => 'http://www.opensupports.com/support' + 'url' => 'http://www.opensupports.com/support', + 'last-stat-day' => '20170101'//TODO: get current date ]); } diff --git a/server/models/Log.php b/server/models/Log.php index ebe24469..966f3b3a 100644 --- a/server/models/Log.php +++ b/server/models/Log.php @@ -9,7 +9,8 @@ class Log extends DataStore { 'type', 'authorUser', 'authorStaff', - 'to' + 'to', + 'date' ]; } @@ -22,7 +23,8 @@ class Log extends DataStore { $log->setProperties(array( 'type' => $type, - 'to' => $to + 'to' => $to, + 'date' => Date::getCurrentDate() )); if($author instanceof User) { @@ -44,7 +46,8 @@ class Log extends DataStore { 'name' => $author->name, 'id' => $author->id, 'staff' => $author instanceof Staff - ] + ], + 'date' => $this->date ]; } } \ No newline at end of file diff --git a/server/models/Staff.php b/server/models/Staff.php index cca0bc4c..9ec69341 100644 --- a/server/models/Staff.php +++ b/server/models/Staff.php @@ -18,7 +18,8 @@ class Staff extends DataStore { 'level', 'sharedDepartmentList', 'sharedTicketList', - 'lastLogin' + 'lastLogin', + 'sharedStatList' ]; } diff --git a/server/models/Stat.php b/server/models/Stat.php new file mode 100644 index 00000000..08e90572 --- /dev/null +++ b/server/models/Stat.php @@ -0,0 +1,17 @@ + Date: Thu, 12 Jan 2017 02:50:45 -0300 Subject: [PATCH 04/84] Guillermo - stats architecture [skip ci] --- server/controllers/system/get-stats.php | 138 +++++++++++++++++++++--- server/data/ERRORS.php | 1 + server/models/Staff.php | 5 +- server/models/Stat.php | 8 ++ 4 files changed, 134 insertions(+), 18 deletions(-) diff --git a/server/controllers/system/get-stats.php b/server/controllers/system/get-stats.php index d8349663..5c83c8d7 100644 --- a/server/controllers/system/get-stats.php +++ b/server/controllers/system/get-stats.php @@ -1,34 +1,140 @@ 'staff_1', - 'requestData' => [] + 'requestData' => [ + 'period' => [ + 'validation' => DataValidator::in(['week', 'month', 'quarter', 'year']), + 'error' => ERRORS::INVALID_PERIOD + ] + ] ]; } public function handler() { - $begin = new DateTime(Setting::getSetting('last-stat-day')->value); - $end = new DateTime(Date::getCurrentDate()); + $this->generationNewStats(); - $interval = new DateInterval('P1D'); - $dateRange = new DatePeriod($begin, $interval ,$end); + $staffId = Controller::request('staffId'); - foreach($dateRange as $date){ - $numberOfTickets = Log::count('type=? AND date LIKE ?',['CREATE_TICKET', $date->format('Ymd') . '%']); - $stat = new Stat(); + if($staffId) { + if($staffId !== Controller::getLoggedUser()->id && !Controller::isStaffLogged(3)) { + Response::respondError(ERRORS::NO_PERMISSION); + return; + } - $stat->setProperties([ - 'date' => $date->format('Ymd'), - 'type' => 'CREATE_TICKET', - 'general' => 1, - 'value' => $numberOfTickets, - ]); - $stat->store(); + $this->getStaffStat(); + } else { + $this->getGeneralStat(); + } + } + + public function generationNewStats() { + $lastStatDay = Setting::getSetting('last-stat-day'); + $previousCurrentDate = floor(Date::getCurrentDate()/10000)-1; + + if($lastStatDay->value !== $previousCurrentDate) { + + $begin = new DateTime($lastStatDay->value); + $end = new DateTime($previousCurrentDate); + + $interval = new DateInterval('P1D'); + $dateRange = new DatePeriod($begin, $interval ,$end); + + $staffList = Staff::getAll(); + + foreach($dateRange as $date) { + $this->generateGeneralStat('CREATE_TICKET', $date); + $this->generateGeneralStat('CLOSE', $date); + $this->generateGeneralStat('SIGNUP', $date); + $this->generateGeneralStat('COMMENT', $date); + + foreach($staffList as $staff) { + $assignments = Ticketevent::count('type=? AND author_staff_id=? AND date LIKE ?',['ASSIGN',$staff->id, $date->format('Ymd') . '%']); + $closed = Ticketevent::count('type=? AND author_staff_id=? AND date LIKE ?',['CLOSE',$staff->id, $date->format('Ymd') . '%']); + + $statAssign = new Stat(); + $statAssign->setProperties([ + 'date' => $date->format('Ymd'), + 'type' => 'ASSIGN', + 'general' => 0, + 'value' => $assignments, + ]); + + $statClose = new Stat(); + $statClose->setProperties([ + 'date' => $date->format('Ymd'), + 'type' => 'CLOSE', + 'general' => 0, + 'value' => $closed, + ]); + + $staff->ownStatList->add($statAssign); + $staff->ownStatList->add($statClose); + + $staff->store(); + } + } + + $lastStatDay->value = $previousCurrentDate; + $lastStatDay->store(); + } + } + + public function generateGeneralStat($type, $date) { + $value = Log::count('type=? AND date LIKE ?',[$type, $date->format('Ymd') . '%']); + $stat = new Stat(); + + $stat->setProperties([ + 'date' => $date->format('Ymd'), + 'type' => $type, + 'general' => 1, + 'value' => $value, + ]); + + $stat->store(); + } + + public function getGeneralStat() { + $daysToRetrieve = $this->getDaysToRetrieve(); + + $statList = Stat::find('general=\'1\' ORDER BY id desc LIMIT ? ', [4 * $daysToRetrieve]); + + Response::respondSuccess($statList->toArray()); + } + + public function getStaffStat() { + $staffId = Controller::request('staffId'); + $daysToRetrieve = $this->getDaysToRetrieve(); + + $statList = Stat::find('general=\'0\' AND staff_id=? ORDER BY id desc LIMIT ? ', [$staffId, 4 * $daysToRetrieve]); + + Response::respondSuccess($statList->toArray()); + } + + public function getDaysToRetrieve() { + $period = Controller::request('period'); + $daysToRetrieve = 0; + + switch ($period) { + case 'week': + $daysToRetrieve = 7; + break; + case 'month': + $daysToRetrieve = 30; + break; + case 'quarter': + $daysToRetrieve = 90; + break; + case 'year': + $daysToRetrieve = 365; + break; } - Response::respondSuccess(); + return $daysToRetrieve; } } \ No newline at end of file diff --git a/server/data/ERRORS.php b/server/data/ERRORS.php index e0052543..4b7507cf 100644 --- a/server/data/ERRORS.php +++ b/server/data/ERRORS.php @@ -35,4 +35,5 @@ class ERRORS { const INVALID_TEMPLATE = 'INVALID_TEMPLATE'; const INVALID_SUBJECT = 'INVALID_SUBJECT'; const INVALID_BODY = 'INVALID_BODY'; + const INVALID_PERIOD = 'INVALID_PERIOD'; } diff --git a/server/models/Staff.php b/server/models/Staff.php index 9ec69341..13c3d7a8 100644 --- a/server/models/Staff.php +++ b/server/models/Staff.php @@ -19,13 +19,14 @@ class Staff extends DataStore { 'sharedDepartmentList', 'sharedTicketList', 'lastLogin', - 'sharedStatList' + 'ownStatList' ]; } public function getDefaultProps() { return [ - 'level' => 1 + 'level' => 1, + 'ownStatList' => new DataStoreList() ]; } diff --git a/server/models/Stat.php b/server/models/Stat.php index 08e90572..97f85649 100644 --- a/server/models/Stat.php +++ b/server/models/Stat.php @@ -14,4 +14,12 @@ class Stat extends DataStore { public function getDefaultProps() { return array(); } + public function toArray() { + return [ + 'date' => $this->date, + 'type' => $this->type, + 'general' => $this->general, + 'value' => $this->value + ]; + } } \ No newline at end of file From be4999009184e8c88f2d106ecf86d8d75e930ecd Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 12 Jan 2017 03:02:56 -0300 Subject: [PATCH 05/84] Ivan - Add files folder [skip ci] --- server/files/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 server/files/.gitkeep diff --git a/server/files/.gitkeep b/server/files/.gitkeep new file mode 100644 index 00000000..e69de29b From b8d24b601dc2986dec74034a6d8cb59ccf0137b7 Mon Sep 17 00:00:00 2001 From: AntonyAntonio Date: Thu, 12 Jan 2017 16:30:58 -0300 Subject: [PATCH 06/84] Guillermo - stats architecture [skip ci] --- server/controllers/system/get-stats.php | 7 +- server/libs/Date.php | 4 + tests/init.rb | 2 + tests/libs.rb | 4 + tests/system/get-stats.rb | 250 ++++++++++++++++++++++++ 5 files changed, 264 insertions(+), 3 deletions(-) create mode 100644 tests/system/get-stats.rb diff --git a/server/controllers/system/get-stats.php b/server/controllers/system/get-stats.php index 5c83c8d7..ff1fdf3a 100644 --- a/server/controllers/system/get-stats.php +++ b/server/controllers/system/get-stats.php @@ -35,12 +35,13 @@ class GetStatsController extends Controller { public function generationNewStats() { $lastStatDay = Setting::getSetting('last-stat-day'); - $previousCurrentDate = floor(Date::getCurrentDate()/10000)-1; + $previousCurrentDate = floor(Date::getPreviousDate() / 10000); + $currentDate = floor(Date::getCurrentDate() / 10000); if($lastStatDay->value !== $previousCurrentDate) { $begin = new DateTime($lastStatDay->value); - $end = new DateTime($previousCurrentDate); + $end = new DateTime($currentDate); $interval = new DateInterval('P1D'); $dateRange = new DatePeriod($begin, $interval ,$end); @@ -80,7 +81,7 @@ class GetStatsController extends Controller { } } - $lastStatDay->value = $previousCurrentDate; + $lastStatDay->value = $currentDate; $lastStatDay->store(); } } diff --git a/server/libs/Date.php b/server/libs/Date.php index c3e8ba0c..6921789f 100644 --- a/server/libs/Date.php +++ b/server/libs/Date.php @@ -3,4 +3,8 @@ class Date { public static function getCurrentDate() { return date('YmdHi'); } + + public static function getPreviousDate() { + return date('YmdHi', strtotime(' -1 day ')); + } } diff --git a/tests/init.rb b/tests/init.rb index 3eb51877..b017ab09 100644 --- a/tests/init.rb +++ b/tests/init.rb @@ -5,6 +5,7 @@ require 'uri' require 'mysql' require 'json' require 'mechanize' +require 'date' require './libs.rb' require './scripts.rb' @@ -51,3 +52,4 @@ require './staff/last-events.rb' require './system/get-mail-templates.rb' require './system/edit-mail-template.rb' require './system/recover-mail-template.rb' +require './system/get-stats.rb' diff --git a/tests/libs.rb b/tests/libs.rb index f5496d48..8b832429 100644 --- a/tests/libs.rb +++ b/tests/libs.rb @@ -29,6 +29,10 @@ class Database return queryResponse.fetch_hash end + + def query(query_string) + return @connection.query(query_string); + end end $database = Database.new diff --git a/tests/system/get-stats.rb b/tests/system/get-stats.rb new file mode 100644 index 00000000..28f79541 --- /dev/null +++ b/tests/system/get-stats.rb @@ -0,0 +1,250 @@ +describe'/system/get-stats' do + request('/user/logout') + Scripts.login($staff[:email], $staff[:password], true) + + it 'should get stats' do + + d = Date.today.prev_day + yesterday = d.strftime("%Y%m%d%H%M") + d = Date.today.prev_day.prev_day + yesterday2 = d.strftime("%Y%m%d%H%M") + d = Date.today.prev_day.prev_day.prev_day + yesterday3 = d.strftime("%Y%m%d%H%M") + + #day 1 + for i in 0..5 + $database.query("INSERT INTO log VALUES('', 'SIGNUP', NULL, " + yesterday3 + ", NULL, NULL);") + end + for i in 0..0 + $database.query("INSERT INTO log VALUES('', 'CREATE_TICKET', NULL, " + yesterday3 + ", NULL, NULL);") + end + for i in 0..1 + $database.query("INSERT INTO log VALUES('', 'CLOSE', NULL, " + yesterday3 + ", NULL, NULL);") + end + for i in 0..2 + $database.query("INSERT INTO log VALUES('', 'COMMENT', NULL, " + yesterday3 + ", NULL, NULL);") + end + for i in 0..8 + $database.query("INSERT INTO ticketevent VALUES('', 'CLOSE', NULL, " + yesterday3 + ", NULL, NULL, 1);") + end + for i in 0..4 + $database.query("INSERT INTO ticketevent VALUES('', 'ASSIGN', NULL, " + yesterday3 + ", NULL, NULL, 1);") + end + + #day 2 + for i in 0..7 + $database.query("INSERT INTO log VALUES('', 'SIGNUP', NULL, " + yesterday2 + ", NULL, NULL);") + end + for i in 0..2 + $database.query("INSERT INTO log VALUES('', 'CREATE_TICKET', NULL, " + yesterday2 + ", NULL, NULL);") + end + for i in 0..9 + $database.query("INSERT INTO log VALUES('', 'CLOSE', NULL, " + yesterday2 + ", NULL, NULL);") + end + for i in 0..2 + $database.query("INSERT INTO log VALUES('', 'COMMENT', NULL, " + yesterday2 + ", NULL, NULL);") + end + for i in 0..10 + $database.query("INSERT INTO ticketevent VALUES('', 'CLOSE', NULL, " + yesterday2 + ", NULL, NULL, 1);") + end + for i in 0..2 + $database.query("INSERT INTO ticketevent VALUES('', 'ASSIGN', NULL, " + yesterday2 + ", NULL, NULL, 1);") + end + + #day 3 + for i in 0..0 + $database.query("INSERT INTO log VALUES('', 'SIGNUP', NULL, " + yesterday + ", NULL, NULL);") + end + for i in 0..1 + $database.query("INSERT INTO log VALUES('', 'CREATE_TICKET', NULL, " + yesterday + ", NULL, NULL);") + end + for i in 0..4 + $database.query("INSERT INTO log VALUES('', 'CLOSE', NULL, " + yesterday + ", NULL, NULL);") + end + for i in 0..7 + $database.query("INSERT INTO log VALUES('', 'COMMENT', NULL, " + yesterday + ", NULL, NULL);") + end + for i in 0..3 + $database.query("INSERT INTO ticketevent VALUES('', 'CLOSE', NULL, " + yesterday + ", NULL, NULL, 1);") + end + for i in 0..7 + $database.query("INSERT INTO ticketevent VALUES('', 'ASSIGN', NULL, " + yesterday + ", NULL, NULL, 1);") + end + + result= request('/system/get-stats', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + period: 'week' + }) + + (result['status']).should.equal('success') + + row = $database.getRow('stat', 65, 'id') + + (row['date']).should.equal('20170109') + (row['type']).should.equal('CREATE_TICKET') + (row['general']).should.equal('1') + (row['value']).should.equal('1') + + row = $database.getRow('stat', 66, 'id') + + (row['date']).should.equal('20170109') + (row['type']).should.equal('CLOSE') + (row['general']).should.equal('1') + (row['value']).should.equal('2') + + row = $database.getRow('stat', 67, 'id') + + (row['date']).should.equal('20170109') + (row['type']).should.equal('SIGNUP') + (row['general']).should.equal('1') + (row['value']).should.equal('6') + + row = $database.getRow('stat', 68, 'id') + + (row['date']).should.equal('20170109') + (row['type']).should.equal('COMMENT') + (row['general']).should.equal('1') + (row['value']).should.equal('3') + + row = $database.getRow('stat', 69, 'id') + + (row['date']).should.equal('20170109') + (row['type']).should.equal('ASSIGN') + (row['general']).should.equal('0') + (row['value']).should.equal('5') + + row = $database.getRow('stat', 70, 'id') + + (row['date']).should.equal('20170109') + (row['type']).should.equal('CLOSE') + (row['general']).should.equal('0') + (row['value']).should.equal('9') + + row = $database.getRow('stat', 71, 'id') + + (row['date']).should.equal('20170109') + (row['type']).should.equal('ASSIGN') + (row['general']).should.equal('0') + (row['value']).should.equal('0') + + row = $database.getRow('stat', 72, 'id') + + (row['date']).should.equal('20170109') + (row['type']).should.equal('CLOSE') + (row['general']).should.equal('0') + (row['value']).should.equal('0') + + row = $database.getRow('stat', 73, 'id') + + (row['date']).should.equal('20170110') + (row['type']).should.equal('CREATE_TICKET') + (row['general']).should.equal('1') + (row['value']).should.equal('3') + + row = $database.getRow('stat', 74, 'id') + + (row['date']).should.equal('20170110') + (row['type']).should.equal('CLOSE') + (row['general']).should.equal('1') + (row['value']).should.equal('10') + + row = $database.getRow('stat', 75, 'id') + + (row['date']).should.equal('20170110') + (row['type']).should.equal('SIGNUP') + (row['general']).should.equal('1') + (row['value']).should.equal('8') + + row = $database.getRow('stat', 76, 'id') + + (row['date']).should.equal('20170110') + (row['type']).should.equal('COMMENT') + (row['general']).should.equal('1') + (row['value']).should.equal('3') + + row = $database.getRow('stat', 77, 'id') + + (row['date']).should.equal('20170110') + (row['type']).should.equal('ASSIGN') + (row['general']).should.equal('0') + (row['value']).should.equal('3') + + row = $database.getRow('stat', 78, 'id') + + (row['date']).should.equal('20170110') + (row['type']).should.equal('CLOSE') + (row['general']).should.equal('0') + (row['value']).should.equal('11') + + row = $database.getRow('stat', 79, 'id') + + (row['date']).should.equal('20170110') + (row['type']).should.equal('ASSIGN') + (row['general']).should.equal('0') + (row['value']).should.equal('0') + + row = $database.getRow('stat', 80, 'id') + + (row['date']).should.equal('20170110') + (row['type']).should.equal('CLOSE') + (row['general']).should.equal('0') + (row['value']).should.equal('0') + + row = $database.getRow('stat', 81, 'id') + + (row['date']).should.equal('20170111') + (row['type']).should.equal('CREATE_TICKET') + (row['general']).should.equal('1') + (row['value']).should.equal('2') + + row = $database.getRow('stat', 82, 'id') + + (row['date']).should.equal('20170111') + (row['type']).should.equal('CLOSE') + (row['general']).should.equal('1') + (row['value']).should.equal('5') + + row = $database.getRow('stat', 83, 'id') + + (row['date']).should.equal('20170111') + (row['type']).should.equal('SIGNUP') + (row['general']).should.equal('1') + (row['value']).should.equal('1') + + row = $database.getRow('stat', 84, 'id') + + (row['date']).should.equal('20170111') + (row['type']).should.equal('COMMENT') + (row['general']).should.equal('1') + (row['value']).should.equal('8') + + row = $database.getRow('stat', 85, 'id') + + (row['date']).should.equal('20170111') + (row['type']).should.equal('ASSIGN') + (row['general']).should.equal('0') + (row['value']).should.equal('8') + + row = $database.getRow('stat', 86, 'id') + + (row['date']).should.equal('20170111') + (row['type']).should.equal('CLOSE') + (row['general']).should.equal('0') + (row['value']).should.equal('4') + + row = $database.getRow('stat', 87, 'id') + + (row['date']).should.equal('20170111') + (row['type']).should.equal('ASSIGN') + (row['general']).should.equal('0') + (row['value']).should.equal('0') + + row = $database.getRow('stat', 88, 'id') + + (row['date']).should.equal('20170111') + (row['type']).should.equal('CLOSE') + (row['general']).should.equal('0') + (row['value']).should.equal('0') + end +end From 134540fed957efa2e6e03fb216fbfcb48691f1f0 Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 12 Jan 2017 16:45:01 -0300 Subject: [PATCH 07/84] Ivan - Add Database Backup, FileDownloader, FileUploader and LinearCongruentialGenerator classes [skip ci] --- server/composer.json | 3 +- server/controllers/system.php | 4 ++ server/controllers/system/backup-database.php | 30 +++++++++++++ server/controllers/system/download.php | 24 ++++++++++ server/controllers/system/init-settings.php | 5 ++- server/data/ERRORS.php | 1 + server/index.php | 4 ++ server/libs/FileDownloader.php | 40 +++++++++++++++++ server/libs/FileManager.php | 26 +++++++++++ server/libs/FileUploader.php | 44 +++++++++++++++++-- server/libs/Hashing.php | 30 ++++++++++++- server/libs/LinearCongruentialGenerator.php | 30 +++++++++++++ server/models/Ticket.php | 15 +++---- tests/ticket/create.rb | 8 ++-- 14 files changed, 246 insertions(+), 18 deletions(-) create mode 100644 server/controllers/system/backup-database.php create mode 100644 server/controllers/system/download.php create mode 100644 server/libs/FileDownloader.php create mode 100644 server/libs/FileManager.php create mode 100644 server/libs/LinearCongruentialGenerator.php diff --git a/server/composer.json b/server/composer.json index 71e09ba2..a506cdee 100644 --- a/server/composer.json +++ b/server/composer.json @@ -4,7 +4,8 @@ "respect/validation": "^1.1", "phpmailer/phpmailer": "^5.2", "google/recaptcha": "~1.1", - "gabordemooij/redbean": "^4.3" + "gabordemooij/redbean": "^4.3", + "ifsnop/mysqldump-php": "2.*" }, "require-dev": { "phpunit/phpunit": "5.0.*" diff --git a/server/controllers/system.php b/server/controllers/system.php index 2cde4fe2..e66ecc5d 100644 --- a/server/controllers/system.php +++ b/server/controllers/system.php @@ -9,6 +9,8 @@ require_once 'system/get-logs.php'; require_once 'system/get-mail-templates.php'; require_once 'system/edit-mail-template.php'; require_once 'system/recover-mail-template.php'; +require_once 'system/backup-database.php'; +require_once 'system/download.php'; $systemControllerGroup = new ControllerGroup(); $systemControllerGroup->setGroupPath('/system'); @@ -23,5 +25,7 @@ $systemControllerGroup->addController(new GetLogsController); $systemControllerGroup->addController(new GetMailTemplatesController); $systemControllerGroup->addController(new EditMailTemplateController); $systemControllerGroup->addController(new RecoverMailTemplateController); +$systemControllerGroup->addController(new BackupDatabaseController); +$systemControllerGroup->addController(new DownloadController); $systemControllerGroup->finalize(); \ No newline at end of file diff --git a/server/controllers/system/backup-database.php b/server/controllers/system/backup-database.php new file mode 100644 index 00000000..82b1fccf --- /dev/null +++ b/server/controllers/system/backup-database.php @@ -0,0 +1,30 @@ + 'staff_3', + 'requestData' => [] + ]; + } + + public function handler() { + global $mysql_host; + global $mysql_database; + global $mysql_user; + global $mysql_password; + + $fileDownloader = FileDownloader::getInstance(); + $fileDownloader->setFileName('backup.sql'); + + $mysqlDump = new IMysqldump\Mysqldump('mysql:host='. $mysql_host .';dbname=' . $mysql_database, $mysql_user, $mysql_password); + $mysqlDump->start($fileDownloader->getFullFilePath()); + + if($fileDownloader->download()) { + $fileDownloader->eraseFile(); + } + } +} \ No newline at end of file diff --git a/server/controllers/system/download.php b/server/controllers/system/download.php new file mode 100644 index 00000000..0b481bf8 --- /dev/null +++ b/server/controllers/system/download.php @@ -0,0 +1,24 @@ + 'staff_1', + 'requestData' => [ + 'file' => [ + 'validation' => DataValidator::alnum('_.')->noWhitespace() + ] + ] + ]; + } + + public function handler() { + $fileDownloader = FileDownloader::getInstance(); + $fileDownloader->setFileName(Controller::request('file')); + $fileDownloader->download(); + } +} \ No newline at end of file diff --git a/server/controllers/system/init-settings.php b/server/controllers/system/init-settings.php index 98fce211..6613b17a 100644 --- a/server/controllers/system/init-settings.php +++ b/server/controllers/system/init-settings.php @@ -40,7 +40,10 @@ class InitSettingsController extends Controller { 'allow-attachments' => 0, 'max-size' => 0, 'title' => 'Support Center', - 'url' => 'http://www.opensupports.com/support' + 'url' => 'http://www.opensupports.com/support', + 'ticket-gap' => Hashing::generateRandomPrime(100000, 999999), + 'file-gap' => Hashing::generateRandomPrime(100000, 999999), + 'file-first-number' => Hashing::generateRandomNumber(100000, 999999), ]); } diff --git a/server/data/ERRORS.php b/server/data/ERRORS.php index e0052543..bdd16d22 100644 --- a/server/data/ERRORS.php +++ b/server/data/ERRORS.php @@ -35,4 +35,5 @@ class ERRORS { const INVALID_TEMPLATE = 'INVALID_TEMPLATE'; const INVALID_SUBJECT = 'INVALID_SUBJECT'; const INVALID_BODY = 'INVALID_BODY'; + const INVALID_FILE = 'INVALID_FILE'; } diff --git a/server/index.php b/server/index.php index a9056e1e..d8508ba3 100644 --- a/server/index.php +++ b/server/index.php @@ -18,6 +18,10 @@ include_once 'libs/Hashing.php'; include_once 'libs/MailSender.php'; include_once 'libs/Date.php'; include_once 'libs/DataStoreList.php'; +include_once 'libs/LinearCongruentialGenerator.php'; +include_once 'libs/FileManager.php'; +include_once 'libs/FileDownloader.php'; +include_once 'libs/FileUploader.php'; // LOAD DATA spl_autoload_register(function ($class) { diff --git a/server/libs/FileDownloader.php b/server/libs/FileDownloader.php new file mode 100644 index 00000000..6f49ca64 --- /dev/null +++ b/server/libs/FileDownloader.php @@ -0,0 +1,40 @@ +getFullFilePath(); + + if(file_exists($fullFilePath) && is_file($fullFilePath)) { + header('Cache-control: private'); + header('Content-Type: application/octet-stream'); + header('Content-Length: '.filesize($fullFilePath)); + header('Content-Disposition: filename='. $this->getFileName()); + + flush(); + $file = fopen($fullFilePath, 'r'); + print fread($file, filesize($fullFilePath)); + fclose($file); + + return true; + } else { + return false; + } + } + + public function eraseFile() { + unlink($this->getLocalPath() . $this->getFileName()); + } +} \ No newline at end of file diff --git a/server/libs/FileManager.php b/server/libs/FileManager.php new file mode 100644 index 00000000..fd05bb13 --- /dev/null +++ b/server/libs/FileManager.php @@ -0,0 +1,26 @@ +localPath = $localPath; + } + + public function setFileName($fileName) { + $this->fileName = $fileName; + } + + public function getLocalPath() { + return $this->localPath; + } + + 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 55eb9bbc..dfc9c09b 100644 --- a/server/libs/FileUploader.php +++ b/server/libs/FileUploader.php @@ -1,5 +1,10 @@ generateNewName($file['name']); + + if($file['size'] > (1024 * $this->maxSize)) { + return false; + } + + move_uploaded_file($file['tmp_name'], $this->getLocalPath() . $newFileName); + + return true; } + + private function generateNewName($fileName) { + $newName = $fileName; + $newName = strtolower($newName); + $newName = preg_replace('/\s+/', '_', $newName); + + if ($this->linearCongruentialGenerator instanceof LinearCongruentialGenerator) { + $newName = $this->linearCongruentialGenerator->generate($this->linearCongruentialGeneratorOffset) . '_' . $newName; + } + + return $newName; + } + + public function setGeneratorValues($gap, $first, $offset) { + $this->linearCongruentialGenerator = new LinearCongruentialGenerator(); + $this->linearCongruentialGeneratorOffset = $offset; + + $this->linearCongruentialGenerator->setGap($gap); + $this->linearCongruentialGenerator->setFirst($first); + } + + public function setMaxSize($maxSize) { + $this->maxSize = $maxSize; + } + } \ No newline at end of file diff --git a/server/libs/Hashing.php b/server/libs/Hashing.php index aa402cf5..da076181 100644 --- a/server/libs/Hashing.php +++ b/server/libs/Hashing.php @@ -7,10 +7,36 @@ class Hashing { public static function verifyPassword($password, $hash) { return password_verify($password, $hash); } + public static function generateRandomToken() { return md5(uniqid(rand())); } - public static function getRandomTicketNumber($min,$max) { - return rand($min,$max); + + public static function generateRandomNumber($min, $max) { + return rand($min, $max); + } + + public static function generateRandomPrime($min, $max) { + $number = Hashing::generateRandomNumber($min, $max); + + while(!Hashing::isPrime($number)) { + $number = Hashing::generateRandomNumber($min, $max); + } + + return $number; + } + + public static function isPrime($number) { + $sqrt = sqrt($number); + $prime = true; + + for($i = 0; $i < $sqrt; $i++) { + if($sqrt % 2 === 0) { + $prime = false; + break; + } + } + + return $prime; } } \ No newline at end of file diff --git a/server/libs/LinearCongruentialGenerator.php b/server/libs/LinearCongruentialGenerator.php new file mode 100644 index 00000000..aafddb16 --- /dev/null +++ b/server/libs/LinearCongruentialGenerator.php @@ -0,0 +1,30 @@ +min = $min; + $this->max = $max; + } + + public function setGap($gap) { + if(!Hashing::isPrime($gap)) throw new Exception('LinearCongruentialGenerator: gap must be prime'); + + $this->gap = $gap; + } + + public function setFirst($first) { + $this->first = $first; + } + + public function generate($offset) { + return ($this->first - $this->min + $offset * $this->gap) % ($this->max - $this->min + 1) + $this->min; + } + + public function generateFirst() { + return Hashing::generateRandomNumber($this->min, $this->max); + } +} \ No newline at end of file diff --git a/server/models/Ticket.php b/server/models/Ticket.php index 315434e8..88351ea6 100644 --- a/server/models/Ticket.php +++ b/server/models/Ticket.php @@ -46,17 +46,16 @@ class Ticket extends DataStore { } public function generateUniqueTicketNumber() { + $linearCongruentialGenerator = new LinearCongruentialGenerator(); $ticketQuantity = Ticket::count(); - $minValue = 100000; - $maxValue = 999999; - + if ($ticketQuantity === 0) { - $ticketNumber = Hashing::getRandomTicketNumber($minValue, $maxValue); + $ticketNumber = $linearCongruentialGenerator->generateFirst(); } else { - $firstTicketNumber = Ticket::getTicket(1)->ticketNumber; - $gap = 176611; //TODO: USE RANDOM PRIME INSTEAD - - $ticketNumber = ($firstTicketNumber - $minValue + $ticketQuantity * $gap) % ($maxValue - $minValue + 1) + $minValue; + $linearCongruentialGenerator->setGap(Setting::getSetting('ticket-gap')->value); + $linearCongruentialGenerator->setFirst(Ticket::getTicket(1)->ticketNumber); + + $ticketNumber = $linearCongruentialGenerator->generate($ticketQuantity); } return $ticketNumber; diff --git a/tests/ticket/create.rb b/tests/ticket/create.rb index 481e0b50..fbc6be44 100644 --- a/tests/ticket/create.rb +++ b/tests/ticket/create.rb @@ -147,13 +147,15 @@ describe '/ticket/create' do csrf_token: $csrf_token }) + ticket_number_gap = $database.getRow('setting', 'ticket-gap', 'name')['value'].to_i + ticket0 = $database.getRow('ticket','Winter is coming','title')['ticket_number'].to_i ticket1 = $database.getRow('ticket','Winter is coming1','title')['ticket_number'].to_i ticket2 = $database.getRow('ticket','Winter is coming2','title')['ticket_number'].to_i ticket3 = $database.getRow('ticket','Winter is coming3','title')['ticket_number'].to_i - (ticket1).should.equal((ticket0 - 100000 + 1 * 176611) % 900000 + 100000) - (ticket2).should.equal((ticket0 - 100000 + 2 * 176611) % 900000 + 100000) - (ticket3).should.equal((ticket0 - 100000 + 3 * 176611) % 900000 + 100000) + (ticket1).should.equal((ticket0 - 100000 + 1 * ticket_number_gap) % 900000 + 100000) + (ticket2).should.equal((ticket0 - 100000 + 2 * ticket_number_gap) % 900000 + 100000) + (ticket3).should.equal((ticket0 - 100000 + 3 * ticket_number_gap) % 900000 + 100000) end end From 1d514dda580be4efe78983c4ca0629347f00330c Mon Sep 17 00:00:00 2001 From: AntonyAntonio Date: Thu, 12 Jan 2017 17:06:41 -0300 Subject: [PATCH 08/84] Guillermo - path-delete-all-users [skip ci] --- server/controllers/system.php | 2 ++ .../controllers/system/delete-all-users.php | 32 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 server/controllers/system/delete-all-users.php diff --git a/server/controllers/system.php b/server/controllers/system.php index e5423a5a..4a908bc1 100644 --- a/server/controllers/system.php +++ b/server/controllers/system.php @@ -11,6 +11,7 @@ require_once 'system/edit-mail-template.php'; require_once 'system/recover-mail-template.php'; require_once 'system/disable-registration.php'; require_once 'system/enable-registration.php'; +require_once 'system/delete-all-users.php'; $systemControllerGroup = new ControllerGroup(); $systemControllerGroup->setGroupPath('/system'); @@ -27,5 +28,6 @@ $systemControllerGroup->addController(new EditMailTemplateController); $systemControllerGroup->addController(new RecoverMailTemplateController); $systemControllerGroup->addController(new DisableRegistrationController); $systemControllerGroup->addController(new EnableRegistrationController); +$systemControllerGroup->addController(new DeleteAllUsersController); $systemControllerGroup->finalize(); \ No newline at end of file diff --git a/server/controllers/system/delete-all-users.php b/server/controllers/system/delete-all-users.php new file mode 100644 index 00000000..63749e59 --- /dev/null +++ b/server/controllers/system/delete-all-users.php @@ -0,0 +1,32 @@ + 'staff_3', + 'requestData' => [] + ]; + } + + public function handler() { + $password = Controller::request('password'); + + if(!Hashing::verifyPassword($password, Controller::getLoggedUser()->password)) { + Response::respondError(ERRORS::INVALID_PASSWORD); + return; + } + + Redbean::exec('SET FOREIGN_KEY_CHECKS = 0;'); + RedBean::wipe(SessionCookie::TABLE); + RedBean::wipe(User::TABLE); + RedBean::wipe(Ticket::TABLE); + RedBean::wipe(Ticketevent::TABLE); + RedBean::wipe('ticket_user'); + Redbean::exec('SET FOREIGN_KEY_CHECKS = 1;'); + + Response::respondSuccess(); + } +} \ No newline at end of file From 5f5a2be76beae00f7d93b2b3b26648be9cbc3228 Mon Sep 17 00:00:00 2001 From: AntonyAntonio Date: Thu, 12 Jan 2017 18:26:06 -0300 Subject: [PATCH 09/84] Guillermo - stast architecture [skip ci] --- tests/system/get-stats.rb | 205 +++++++++----------------------------- 1 file changed, 46 insertions(+), 159 deletions(-) diff --git a/tests/system/get-stats.rb b/tests/system/get-stats.rb index 28f79541..a86531f0 100644 --- a/tests/system/get-stats.rb +++ b/tests/system/get-stats.rb @@ -71,180 +71,67 @@ describe'/system/get-stats' do $database.query("INSERT INTO ticketevent VALUES('', 'ASSIGN', NULL, " + yesterday + ", NULL, NULL, 1);") end - result= request('/system/get-stats', { + @result = request('/system/get-stats', { csrf_userid: $csrf_userid, csrf_token: $csrf_token, period: 'week' }) - (result['status']).should.equal('success') + def assertData(position, date, type, value) + (@result['data'][position]['date']).should.equal(date) + (@result['data'][position]['type']).should.equal(type) + (@result['data'][position]['value']).should.equal(value) + end - row = $database.getRow('stat', 65, 'id') + assertData(11, '20170109', 'CREATE_TICKET', '1') + assertData(10, '20170109', 'CLOSE', '2') + assertData(9, '20170109', 'SIGNUP', '6') + assertData(8, '20170109', 'COMMENT', '3') - (row['date']).should.equal('20170109') - (row['type']).should.equal('CREATE_TICKET') - (row['general']).should.equal('1') - (row['value']).should.equal('1') - row = $database.getRow('stat', 66, 'id') + assertData(7, '20170110', 'CREATE_TICKET', '3') + assertData(6, '20170110', 'CLOSE', '10') + assertData(5, '20170110', 'SIGNUP', '8') + assertData(4, '20170110', 'COMMENT', '3') - (row['date']).should.equal('20170109') - (row['type']).should.equal('CLOSE') - (row['general']).should.equal('1') - (row['value']).should.equal('2') + assertData(3, '20170111', 'CREATE_TICKET', '2') + assertData(2, '20170111', 'CLOSE', '5') + assertData(1, '20170111', 'SIGNUP', '1') + assertData(0, '20170111', 'COMMENT', '8') - row = $database.getRow('stat', 67, 'id') - (row['date']).should.equal('20170109') - (row['type']).should.equal('SIGNUP') - (row['general']).should.equal('1') - (row['value']).should.equal('6') + @result = request('/system/get-stats', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + period: 'week', + staffId: '1' + }) + assertData(0, '20170111', 'CLOSE', '4') + assertData(1, '20170111', 'ASSIGN', '8') + assertData(2, '20170110', 'CLOSE', '11') + assertData(3, '20170110', 'ASSIGN', '3') - row = $database.getRow('stat', 68, 'id') + assertData(4, '20170109', 'CLOSE', '9') + assertData(5, '20170109', 'ASSIGN', '5') + assertData(6, '20170108', 'CLOSE', '0') + assertData(7, '20170108', 'ASSIGN', '0') - (row['date']).should.equal('20170109') - (row['type']).should.equal('COMMENT') - (row['general']).should.equal('1') - (row['value']).should.equal('3') + assertData(8, '20170107', 'CLOSE', '0') + assertData(9, '20170107', 'ASSIGN', '0') + assertData(10, '20170106', 'CLOSE', '0') + assertData(11, '20170106', 'ASSIGN', '0') - row = $database.getRow('stat', 69, 'id') + assertData(12, '20170105', 'CLOSE', '0') + assertData(13, '20170105', 'ASSIGN', '0') + assertData(14, '20170104', 'CLOSE', '0') + assertData(15, '20170104', 'ASSIGN', '0') - (row['date']).should.equal('20170109') - (row['type']).should.equal('ASSIGN') - (row['general']).should.equal('0') - (row['value']).should.equal('5') + assertData(16, '20170103', 'CLOSE', '0') + assertData(17, '20170103', 'ASSIGN', '0') + assertData(18, '20170102', 'CLOSE', '0') + assertData(19, '20170102', 'ASSIGN', '0') - row = $database.getRow('stat', 70, 'id') - - (row['date']).should.equal('20170109') - (row['type']).should.equal('CLOSE') - (row['general']).should.equal('0') - (row['value']).should.equal('9') - - row = $database.getRow('stat', 71, 'id') - - (row['date']).should.equal('20170109') - (row['type']).should.equal('ASSIGN') - (row['general']).should.equal('0') - (row['value']).should.equal('0') - - row = $database.getRow('stat', 72, 'id') - - (row['date']).should.equal('20170109') - (row['type']).should.equal('CLOSE') - (row['general']).should.equal('0') - (row['value']).should.equal('0') - - row = $database.getRow('stat', 73, 'id') - - (row['date']).should.equal('20170110') - (row['type']).should.equal('CREATE_TICKET') - (row['general']).should.equal('1') - (row['value']).should.equal('3') - - row = $database.getRow('stat', 74, 'id') - - (row['date']).should.equal('20170110') - (row['type']).should.equal('CLOSE') - (row['general']).should.equal('1') - (row['value']).should.equal('10') - - row = $database.getRow('stat', 75, 'id') - - (row['date']).should.equal('20170110') - (row['type']).should.equal('SIGNUP') - (row['general']).should.equal('1') - (row['value']).should.equal('8') - - row = $database.getRow('stat', 76, 'id') - - (row['date']).should.equal('20170110') - (row['type']).should.equal('COMMENT') - (row['general']).should.equal('1') - (row['value']).should.equal('3') - - row = $database.getRow('stat', 77, 'id') - - (row['date']).should.equal('20170110') - (row['type']).should.equal('ASSIGN') - (row['general']).should.equal('0') - (row['value']).should.equal('3') - - row = $database.getRow('stat', 78, 'id') - - (row['date']).should.equal('20170110') - (row['type']).should.equal('CLOSE') - (row['general']).should.equal('0') - (row['value']).should.equal('11') - - row = $database.getRow('stat', 79, 'id') - - (row['date']).should.equal('20170110') - (row['type']).should.equal('ASSIGN') - (row['general']).should.equal('0') - (row['value']).should.equal('0') - - row = $database.getRow('stat', 80, 'id') - - (row['date']).should.equal('20170110') - (row['type']).should.equal('CLOSE') - (row['general']).should.equal('0') - (row['value']).should.equal('0') - - row = $database.getRow('stat', 81, 'id') - - (row['date']).should.equal('20170111') - (row['type']).should.equal('CREATE_TICKET') - (row['general']).should.equal('1') - (row['value']).should.equal('2') - - row = $database.getRow('stat', 82, 'id') - - (row['date']).should.equal('20170111') - (row['type']).should.equal('CLOSE') - (row['general']).should.equal('1') - (row['value']).should.equal('5') - - row = $database.getRow('stat', 83, 'id') - - (row['date']).should.equal('20170111') - (row['type']).should.equal('SIGNUP') - (row['general']).should.equal('1') - (row['value']).should.equal('1') - - row = $database.getRow('stat', 84, 'id') - - (row['date']).should.equal('20170111') - (row['type']).should.equal('COMMENT') - (row['general']).should.equal('1') - (row['value']).should.equal('8') - - row = $database.getRow('stat', 85, 'id') - - (row['date']).should.equal('20170111') - (row['type']).should.equal('ASSIGN') - (row['general']).should.equal('0') - (row['value']).should.equal('8') - - row = $database.getRow('stat', 86, 'id') - - (row['date']).should.equal('20170111') - (row['type']).should.equal('CLOSE') - (row['general']).should.equal('0') - (row['value']).should.equal('4') - - row = $database.getRow('stat', 87, 'id') - - (row['date']).should.equal('20170111') - (row['type']).should.equal('ASSIGN') - (row['general']).should.equal('0') - (row['value']).should.equal('0') - - row = $database.getRow('stat', 88, 'id') - - (row['date']).should.equal('20170111') - (row['type']).should.equal('CLOSE') - (row['general']).should.equal('0') - (row['value']).should.equal('0') + assertData(20, '20170101', 'CLOSE', '0') + assertData(21, '20170101', 'ASSIGN', '0') end end From f2401dcec718b09c44f02d8c644357c8b8c33aa6 Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 12 Jan 2017 18:29:50 -0300 Subject: [PATCH 10/84] Ivan - Fix file uploader issues, add file upload in ticket creation [skip ci] --- server/controllers/system/init-settings.php | 3 ++- server/controllers/ticket/create.php | 24 ++++++++++++++++++++- server/libs/FileUploader.php | 13 +++++++---- server/libs/LinearCongruentialGenerator.php | 3 ++- tests/system/edit-settings.rb | 4 ++-- 5 files changed, 38 insertions(+), 9 deletions(-) diff --git a/server/controllers/system/init-settings.php b/server/controllers/system/init-settings.php index 6613b17a..a78a6c51 100644 --- a/server/controllers/system/init-settings.php +++ b/server/controllers/system/init-settings.php @@ -38,12 +38,13 @@ class InitSettingsController extends Controller { 'maintenance-mode' => 0, 'layout' => 'boxed', 'allow-attachments' => 0, - 'max-size' => 0, + 'max-size' => 1024, 'title' => 'Support Center', 'url' => 'http://www.opensupports.com/support', 'ticket-gap' => Hashing::generateRandomPrime(100000, 999999), 'file-gap' => Hashing::generateRandomPrime(100000, 999999), 'file-first-number' => Hashing::generateRandomNumber(100000, 999999), + 'file-quantity' => 0 ]); } diff --git a/server/controllers/ticket/create.php b/server/controllers/ticket/create.php index ac9f4c53..b9409361 100644 --- a/server/controllers/ticket/create.php +++ b/server/controllers/ticket/create.php @@ -60,7 +60,7 @@ class CreateController extends Controller { 'language' => $this->language, 'author' => $author, 'department' => $department, - 'file' => '', + 'file' => $this->uploadFile(), 'date' => Date::getCurrentDate(), 'unread' => false, 'unreadStaff' => true, @@ -75,4 +75,26 @@ class CreateController extends Controller { $this->ticketNumber = $ticket->ticketNumber; } + + private function uploadFile() { + if(!isset($_FILES['file'])) 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); + $fileUploader->setGeneratorValues($fileGap, $fileFirst, $fileQuantity->getValue()); + + if($fileUploader->upload($_FILES['file'])) { + $fileQuantity->value++; + $fileQuantity->store(); + + return $fileUploader->getFileName(); + } else { + throw new Exception(ERRORS::INVALID_FILE); + } + } } diff --git a/server/libs/FileUploader.php b/server/libs/FileUploader.php index dfc9c09b..8e01e089 100644 --- a/server/libs/FileUploader.php +++ b/server/libs/FileUploader.php @@ -4,6 +4,7 @@ class FileUploader extends FileManager { private $maxSize = 1024; private $linearCongruentialGenerator; private $linearCongruentialGeneratorOffset; + private $fileName; private static $instance = null; @@ -18,18 +19,18 @@ class FileUploader extends FileManager { private function __construct() {} public function upload($file) { - $newFileName = $this->generateNewName($file['name']); + $this->setNewName($file['name']); if($file['size'] > (1024 * $this->maxSize)) { return false; } - move_uploaded_file($file['tmp_name'], $this->getLocalPath() . $newFileName); + move_uploaded_file($file['tmp_name'], $this->getLocalPath() . $this->getFileName()); return true; } - private function generateNewName($fileName) { + private function setNewName($fileName) { $newName = $fileName; $newName = strtolower($newName); $newName = preg_replace('/\s+/', '_', $newName); @@ -38,7 +39,7 @@ class FileUploader extends FileManager { $newName = $this->linearCongruentialGenerator->generate($this->linearCongruentialGeneratorOffset) . '_' . $newName; } - return $newName; + $this->fileName = $newName; } public function setGeneratorValues($gap, $first, $offset) { @@ -52,5 +53,9 @@ class FileUploader extends FileManager { public function setMaxSize($maxSize) { $this->maxSize = $maxSize; } + + public function getFileName() { + return $this->fileName; + } } \ No newline at end of file diff --git a/server/libs/LinearCongruentialGenerator.php b/server/libs/LinearCongruentialGenerator.php index aafddb16..88df4141 100644 --- a/server/libs/LinearCongruentialGenerator.php +++ b/server/libs/LinearCongruentialGenerator.php @@ -21,7 +21,8 @@ class LinearCongruentialGenerator { } public function generate($offset) { - return ($this->first - $this->min + $offset * $this->gap) % ($this->max - $this->min + 1) + $this->min; + if($offset) return ($this->first - $this->min + $offset * $this->gap) % ($this->max - $this->min + 1) + $this->min; + else return $this->generateFirst(); } public function generateFirst() { diff --git a/tests/system/edit-settings.rb b/tests/system/edit-settings.rb index 0b2b77aa..69223599 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" => 2, + "max-size" => 2048, "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('2') + (row['value']).should.equal('2048') row = $database.getRow('setting', 'language', 'name') (row['value']).should.equal('en') From 71984384ccddee35723f2966e7057dbd27b673bf Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 12 Jan 2017 20:30:44 -0300 Subject: [PATCH 11/84] Ivan - Add validations before download and upload on comment [skip ci] --- server/controllers/system/download.php | 36 +++++++++++++++++++++++--- server/controllers/ticket/comment.php | 1 + server/controllers/ticket/create.php | 22 ---------------- server/libs/Controller.php | 22 ++++++++++++++++ 4 files changed, 56 insertions(+), 25 deletions(-) diff --git a/server/controllers/system/download.php b/server/controllers/system/download.php index 0b481bf8..8c6699b3 100644 --- a/server/controllers/system/download.php +++ b/server/controllers/system/download.php @@ -7,18 +7,48 @@ class DownloadController extends Controller { public function validations() { return [ - 'permission' => 'staff_1', + 'permission' => 'user', 'requestData' => [ 'file' => [ - 'validation' => DataValidator::alnum('_.')->noWhitespace() + 'validation' => DataValidator::alnum('_.')->noWhitespace(), + 'error' => ERRORS::INVALID_FILE ] ] ]; } public function handler() { + $fileName = Controller::request('file'); + + $loggedUser = Controller::getLoggedUser(); + $ticket = Ticket::getTicket($fileName, 'file'); + + if($ticket->isNull() || ($this->isNotAuthor($ticket, $loggedUser) && $this->isNotOwner($ticket, $loggedUser))) { + $ticketEvent = Ticketevent::getDataStore($fileName, 'file'); + + if($ticketEvent->isNull()) { + print ''; + return; + } + + $ticket = $ticketEvent->ticket; + + if($this->isNotAuthor($ticket, $loggedUser) && $this->isNotOwner($ticket, $loggedUser)) { + print ''; + return; + } + } + $fileDownloader = FileDownloader::getInstance(); - $fileDownloader->setFileName(Controller::request('file')); + $fileDownloader->setFileName($fileName); $fileDownloader->download(); } + + private function isNotAuthor($ticket, $loggedUser) { + return Controller::isStaffLogged() || $ticket->author->id !== $loggedUser->id; + } + + private function isNotOwner($ticket, $loggedUser) { + return !Controller::isStaffLogged() || !$ticket->owner || $ticket->owner->id !== $loggedUser->id; + } } \ No newline at end of file diff --git a/server/controllers/ticket/comment.php b/server/controllers/ticket/comment.php index b51414c2..6a043757 100644 --- a/server/controllers/ticket/comment.php +++ b/server/controllers/ticket/comment.php @@ -50,6 +50,7 @@ class CommentController extends Controller { $comment = Ticketevent::getEvent(Ticketevent::COMMENT); $comment->setProperties(array( 'content' => $this->content, + 'file' => $this->uploadFile(), 'date' => Date::getCurrentDate() )); diff --git a/server/controllers/ticket/create.php b/server/controllers/ticket/create.php index b9409361..fbcd9203 100644 --- a/server/controllers/ticket/create.php +++ b/server/controllers/ticket/create.php @@ -75,26 +75,4 @@ class CreateController extends Controller { $this->ticketNumber = $ticket->ticketNumber; } - - private function uploadFile() { - if(!isset($_FILES['file'])) 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); - $fileUploader->setGeneratorValues($fileGap, $fileFirst, $fileQuantity->getValue()); - - if($fileUploader->upload($_FILES['file'])) { - $fileQuantity->value++; - $fileQuantity->store(); - - return $fileUploader->getFileName(); - } else { - throw new Exception(ERRORS::INVALID_FILE); - } - } } diff --git a/server/libs/Controller.php b/server/libs/Controller.php index 3c8a3ca9..b82bdb0f 100644 --- a/server/libs/Controller.php +++ b/server/libs/Controller.php @@ -60,4 +60,26 @@ abstract class Controller { public static function getAppInstance() { return \Slim\Slim::getInstance(); } + + public function uploadFile() { + if(!isset($_FILES['file'])) 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); + $fileUploader->setGeneratorValues($fileGap, $fileFirst, $fileQuantity->getValue()); + + if($fileUploader->upload($_FILES['file'])) { + $fileQuantity->value++; + $fileQuantity->store(); + + return $fileUploader->getFileName(); + } else { + throw new Exception(ERRORS::INVALID_FILE); + } + } } \ No newline at end of file From 139a474693bc855a84fdfeba0814030380648657 Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 13 Jan 2017 10:33:17 -0300 Subject: [PATCH 12/84] Max Red - beautify code and set default selected indices to an empty array [skip ci] --- .../toggle-list.js | 13 ++++++------- .../toggle-list.scss | 0 2 files changed, 6 insertions(+), 7 deletions(-) rename client/src/{app-components => core-components}/toggle-list.js (77%) rename client/src/{app-components => core-components}/toggle-list.scss (100%) diff --git a/client/src/app-components/toggle-list.js b/client/src/core-components/toggle-list.js similarity index 77% rename from client/src/app-components/toggle-list.js rename to client/src/core-components/toggle-list.js index f90a26ae..8dba39a7 100644 --- a/client/src/app-components/toggle-list.js +++ b/client/src/core-components/toggle-list.js @@ -11,7 +11,7 @@ class ToggleList extends React.Component { }; state = { - selected: [1, 3] + selected: [] }; render() { @@ -35,26 +35,25 @@ class ToggleList extends React.Component { let classes = { 'toggle-list__item': true, 'toggle-list__first-item': (index === 0), - 'toggle-list__selected': (_.includes(this.state.selected, index)) + 'toggle-list__selected': _.includes(this.state.selected, index) }; return classNames(classes); } selectItem(index) { - let actual = _.clone(this.state.selected); + let newSelected = _.clone(this.state.selected); - _.includes(this.state.selected, index) ? _.remove(actual, t => t == index) : actual.push(index); + _.includes(this.state.selected, index) ? _.remove(newSelected, _index => _index == index) : newSelected.push(index); - console.log(actual); this.setState({ - selected: actual + selected: newSelected }); if (this.props.onChange) { this.props.onChange({ target: { - value: actual + value: newSelected } }); } diff --git a/client/src/app-components/toggle-list.scss b/client/src/core-components/toggle-list.scss similarity index 100% rename from client/src/app-components/toggle-list.scss rename to client/src/core-components/toggle-list.scss From 087a24c75c30ff4d75a9d9cd0e9db2ae5c55181d Mon Sep 17 00:00:00 2001 From: AntonyAntonio Date: Fri, 13 Jan 2017 13:46:57 -0300 Subject: [PATCH 13/84] Guillermo - stast architecture [skip ci] --- tests/system/get-stats.rb | 91 ++++++++++++++++++++++++--------------- 1 file changed, 57 insertions(+), 34 deletions(-) diff --git a/tests/system/get-stats.rb b/tests/system/get-stats.rb index a86531f0..406c4516 100644 --- a/tests/system/get-stats.rb +++ b/tests/system/get-stats.rb @@ -83,21 +83,44 @@ describe'/system/get-stats' do (@result['data'][position]['value']).should.equal(value) end - assertData(11, '20170109', 'CREATE_TICKET', '1') - assertData(10, '20170109', 'CLOSE', '2') - assertData(9, '20170109', 'SIGNUP', '6') - assertData(8, '20170109', 'COMMENT', '3') + d = Date.today.prev_day + yesterday = d.strftime("%Y%m%d") + d = Date.today.prev_day.prev_day + yesterday2 = d.strftime("%Y%m%d") + d = Date.today.prev_day.prev_day.prev_day + yesterday3 = d.strftime("%Y%m%d") + d = Date.today.prev_day.prev_day.prev_day.prev_day + yesterday4 = d.strftime("%Y%m%d") + d = Date.today.prev_day.prev_day.prev_day.prev_day.prev_day + yesterday5 = d.strftime("%Y%m%d") + d = Date.today.prev_day.prev_day.prev_day.prev_day.prev_day.prev_day + yesterday6 = d.strftime("%Y%m%d") + d = Date.today.prev_day.prev_day.prev_day.prev_day.prev_day.prev_day.prev_day + yesterday7 = d.strftime("%Y%m%d") + d = Date.today.prev_day.prev_day.prev_day.prev_day.prev_day.prev_day.prev_day.prev_day + yesterday8 = d.strftime("%Y%m%d") + d = Date.today.prev_day.prev_day.prev_day.prev_day.prev_day.prev_day.prev_day.prev_day.prev_day + yesterday9 = d.strftime("%Y%m%d") + d = Date.today.prev_day.prev_day.prev_day.prev_day.prev_day.prev_day.prev_day.prev_day.prev_day.prev_day + yesterday10 = d.strftime("%Y%m%d") + d = Date.today.prev_day.prev_day.prev_day.prev_day.prev_day.prev_day.prev_day.prev_day.prev_day.prev_day.prev_day + yesterday11 = d.strftime("%Y%m%d") + + assertData(11, yesterday3, 'CREATE_TICKET', '1') + assertData(10, yesterday3, 'CLOSE', '2') + assertData(9, yesterday3, 'SIGNUP', '6') + assertData(8, yesterday3, 'COMMENT', '3') - assertData(7, '20170110', 'CREATE_TICKET', '3') - assertData(6, '20170110', 'CLOSE', '10') - assertData(5, '20170110', 'SIGNUP', '8') - assertData(4, '20170110', 'COMMENT', '3') + assertData(7, yesterday2, 'CREATE_TICKET', '3') + assertData(6, yesterday2, 'CLOSE', '10') + assertData(5, yesterday2, 'SIGNUP', '8') + assertData(4, yesterday2, 'COMMENT', '3') - assertData(3, '20170111', 'CREATE_TICKET', '2') - assertData(2, '20170111', 'CLOSE', '5') - assertData(1, '20170111', 'SIGNUP', '1') - assertData(0, '20170111', 'COMMENT', '8') + assertData(3, yesterday, 'CREATE_TICKET', '2') + assertData(2, yesterday, 'CLOSE', '5') + assertData(1, yesterday, 'SIGNUP', '1') + assertData(0, yesterday, 'COMMENT', '8') @result = request('/system/get-stats', { @@ -106,32 +129,32 @@ describe'/system/get-stats' do period: 'week', staffId: '1' }) - assertData(0, '20170111', 'CLOSE', '4') - assertData(1, '20170111', 'ASSIGN', '8') - assertData(2, '20170110', 'CLOSE', '11') - assertData(3, '20170110', 'ASSIGN', '3') + assertData(0, yesterday, 'CLOSE', '4') + assertData(1, yesterday, 'ASSIGN', '8') + assertData(2, yesterday2, 'CLOSE', '11') + assertData(3, yesterday2, 'ASSIGN', '3') - assertData(4, '20170109', 'CLOSE', '9') - assertData(5, '20170109', 'ASSIGN', '5') - assertData(6, '20170108', 'CLOSE', '0') - assertData(7, '20170108', 'ASSIGN', '0') + assertData(4, yesterday3, 'CLOSE', '9') + assertData(5, yesterday3, 'ASSIGN', '5') + assertData(6, yesterday4, 'CLOSE', '0') + assertData(7, yesterday4, 'ASSIGN', '0') - assertData(8, '20170107', 'CLOSE', '0') - assertData(9, '20170107', 'ASSIGN', '0') - assertData(10, '20170106', 'CLOSE', '0') - assertData(11, '20170106', 'ASSIGN', '0') + assertData(8, yesterday5, 'CLOSE', '0') + assertData(9, yesterday5, 'ASSIGN', '0') + assertData(10, yesterday6, 'CLOSE', '0') + assertData(11, yesterday6, 'ASSIGN', '0') - assertData(12, '20170105', 'CLOSE', '0') - assertData(13, '20170105', 'ASSIGN', '0') - assertData(14, '20170104', 'CLOSE', '0') - assertData(15, '20170104', 'ASSIGN', '0') + assertData(12, yesterday7, 'CLOSE', '0') + assertData(13, yesterday7, 'ASSIGN', '0') + assertData(14, yesterday8, 'CLOSE', '0') + assertData(15, yesterday8, 'ASSIGN', '0') - assertData(16, '20170103', 'CLOSE', '0') - assertData(17, '20170103', 'ASSIGN', '0') - assertData(18, '20170102', 'CLOSE', '0') - assertData(19, '20170102', 'ASSIGN', '0') + assertData(16, yesterday9, 'CLOSE', '0') + assertData(17, yesterday9, 'ASSIGN', '0') + assertData(18, yesterday10, 'CLOSE', '0') + assertData(19, yesterday10, 'ASSIGN', '0') - assertData(20, '20170101', 'CLOSE', '0') - assertData(21, '20170101', 'ASSIGN', '0') + assertData(20, yesterday11, 'CLOSE', '0') + assertData(21, yesterday11, 'ASSIGN', '0') end end From db63948db700e5fd6a257d3afc663b5617cee49c Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Fri, 13 Jan 2017 14:40:21 -0300 Subject: [PATCH 14/84] Ivan - Add file upload test [skip ci] --- tests/system/fiile-upload-download.rb | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 tests/system/fiile-upload-download.rb diff --git a/tests/system/fiile-upload-download.rb b/tests/system/fiile-upload-download.rb new file mode 100644 index 00000000..ebaa8345 --- /dev/null +++ b/tests/system/fiile-upload-download.rb @@ -0,0 +1,24 @@ +describe 'File Upload and Download' do + request('/user/logout') + Scripts.login("creator@os4.com", "creator") + + it 'should upload file when creating ticket' do + file = File.new('upload.txt', 'w') + file.puts('file content') + + result = request('/ticket/create', { + 'csrf_userid' => $csrf_userid, + 'csrf_token' => $csrf_token, + 'title' => 'Ticket with file', + 'content' => 'this is a ticket that contains a file', + 'language' => 'en', + 'file' => file + }) + (result['status']).should.equal('success'); + + ticket = $database.getLastRow('ticket'); + + (ticket['file'].include? 'upload.txt').should.equal(true) + (File.exist?('../server/files' + ticket['file'])).should.equal(true) + end +end From 6a22ba711ecc9cbb24dc615231cfd36705a35549 Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 13 Jan 2017 15:17:43 -0300 Subject: [PATCH 15/84] Max Red - WIP first layout [skip ci] --- client/package.json | 2 + .../dashboard/admin-panel-stats-chart.js | 18 ++++++++ .../panel/dashboard/admin-panel-stats.js | 33 ++++++++++++++- client/src/app/demo/components-demo-page.js | 42 ++++++++++++++++++- client/src/data/fixtures/system-fixtures.js | 9 ++++ client/src/data/languages/en.js | 1 + 6 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js diff --git a/client/package.json b/client/package.json index 21e3f053..3caab38d 100644 --- a/client/package.json +++ b/client/package.json @@ -54,6 +54,7 @@ }, "dependencies": { "app-module-path": "^1.0.3", + "chart.js": "^1.1.1", "classnames": "^2.1.3", "draft-js": "^0.8.1", "draft-js-export-html": "^0.4.0", @@ -63,6 +64,7 @@ "lodash": "^3.10.0", "messageformat": "^0.2.2", "react": "^15.0.1", + "react-chartjs": "^0.8.0", "react-document-title": "^1.0.2", "react-dom": "^15.0.1", "react-google-recaptcha": "^0.5.2", diff --git a/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js b/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js new file mode 100644 index 00000000..d4dfabfa --- /dev/null +++ b/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js @@ -0,0 +1,18 @@ +import React from 'react'; + +class StatsChart extends React.Component { + + static propTypes = { + strokes: React.PropTypes.arrayOf(React.PropTypes.shape({ + + })) + }; + + render() { + return ( +
Shit go home!
+ ); + } +} + +export default StatsChart; \ No newline at end of file diff --git a/client/src/app/admin/panel/dashboard/admin-panel-stats.js b/client/src/app/admin/panel/dashboard/admin-panel-stats.js index 020264e4..76fd68d6 100644 --- a/client/src/app/admin/panel/dashboard/admin-panel-stats.js +++ b/client/src/app/admin/panel/dashboard/admin-panel-stats.js @@ -1,14 +1,45 @@ import React from 'react'; +import i18n from 'lib-app/i18n'; + +import Header from 'core-components/header'; +import DropDown from 'core-components/drop-down'; +import StatsChart from 'app/admin/panel/dashboard/admin-panel-stats-chart'; + class AdminPanelStats extends React.Component { render() { return (
- /admin/panel/stats +
+ +
); } + + getDropDownProps() { + return { + items: [ + { + content: 'Last 7 days', + icon: '' + }, + { + content: 'Last 30 days', + icon: '' + }, + { + content: 'Last 90 days', + icon: '' + }, + { + content: 'Last 365 days', + icon: '' + } + ] + } + } } export default AdminPanelStats; \ No newline at end of file diff --git a/client/src/app/demo/components-demo-page.js b/client/src/app/demo/components-demo-page.js index 5244975c..4a69a807 100644 --- a/client/src/app/demo/components-demo-page.js +++ b/client/src/app/demo/components-demo-page.js @@ -1,6 +1,7 @@ 'use strict'; const React = require('react'); +const LineChart = require("react-chartjs").Line; const _ = require('lodash'); const DocumentTitle = require('react-document-title'); @@ -16,8 +17,41 @@ const Menu = require('core-components/menu'); const Tooltip = require('core-components/tooltip'); const Table = require('core-components/table'); const InfoTooltip = require('core-components/info-tooltip'); -const ToggleButton = require('app-components/toggle-button'); +function rand(min, max, num) { + var rtn = []; + while (rtn.length < num) { + rtn.push((Math.random() * (max - min)) + min); + } + return rtn; +} + +let chartData = { + labels: ["January", "February", "March", "April", "", "May", "June", "July"], + datasets: [ + { + label: "My First dataset", + fillColor: "rgba(0,0,0,0)", + strokeColor: "rgba(1,2,3,1)", + pointColor: "rgba(3,2,1,1)", + pointStrokeColor: "#333", + pointHighlightFill: "#999", + pointHighlightStroke: "rgba(220,220,220,1)", + data: rand(32, 100, 8) + }, + { + label: "My Second dataset", + fillColor: "rgba(0,0,0,0)", + strokeColor: "rgba(151,187,205,1)", + pointColor: "rgba(151,187,205,1)", + pointStrokeColor: "#fff", + pointHighlightFill: "#fff", + pointHighlightStroke: "rgba(151,187,205,1)", + data: rand(32, 100, 8) + } + ] +}; +let chartOptions = {}; let dropDownItems = [{content: 'English'}, {content: 'Spanish'}, {content: 'German'}, {content: 'Portuguese'}, {content: 'Japanese'}]; let secondaryMenuItems = [ {content: 'My Tickets', icon: 'file-text'}, @@ -176,6 +210,12 @@ let DemoPage = React.createClass({ render: ( ) + }, + { + title: 'LineChart', + render: ( + + ) } ], diff --git a/client/src/data/fixtures/system-fixtures.js b/client/src/data/fixtures/system-fixtures.js index b67d450f..8626a24b 100644 --- a/client/src/data/fixtures/system-fixtures.js +++ b/client/src/data/fixtures/system-fixtures.js @@ -157,6 +157,15 @@ module.exports = [ }; } }, + { + path: '/system/get-stats', + time: 200, + response: function() { + return { + + }; + } + }, { path: '/system/get-logs', time: 300, diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js index 67a36e64..98b136a9 100644 --- a/client/src/data/languages/en.js +++ b/client/src/data/languages/en.js @@ -150,6 +150,7 @@ export default { 'LOAD_MORE': 'Load More', 'MY_NOTIFICATIONS': 'My notifications', 'ALL_NOTIFICATIONS': 'All notifications', + 'TICKET_ACTIVITY': 'Ticket Activity', //ACTIVITIES 'ACTIVITY_COMMENT': 'commented ticket', From f79913de975f2418dca3be8330e6c8785ad60330 Mon Sep 17 00:00:00 2001 From: AntonyAntonio Date: Fri, 13 Jan 2017 15:50:35 -0300 Subject: [PATCH 16/84] Guillermo - registration api keys [skip ci] --- server/controllers/system.php | 6 +++ server/controllers/system/add-api-key.php | 41 ++++++++++++++++++++ server/controllers/system/delete-api-key.php | 32 +++++++++++++++ server/controllers/system/get-all-keys.php | 19 +++++++++ server/data/ERRORS.php | 1 + server/models/APIKey.php | 18 +++++++++ 6 files changed, 117 insertions(+) create mode 100644 server/controllers/system/add-api-key.php create mode 100644 server/controllers/system/delete-api-key.php create mode 100644 server/controllers/system/get-all-keys.php create mode 100644 server/models/APIKey.php diff --git a/server/controllers/system.php b/server/controllers/system.php index 8bc393cb..1d8fa889 100644 --- a/server/controllers/system.php +++ b/server/controllers/system.php @@ -12,6 +12,9 @@ require_once 'system/recover-mail-template.php'; require_once 'system/get-stats.php'; require_once 'system/disable-registration.php'; require_once 'system/enable-registration.php'; +require_once 'system/add-api-key.php'; +require_once 'system/delete-api-key.php'; +require_once 'system/get-all-keys.php'; $systemControllerGroup = new ControllerGroup(); $systemControllerGroup->setGroupPath('/system'); @@ -29,5 +32,8 @@ $systemControllerGroup->addController(new RecoverMailTemplateController); $systemControllerGroup->addController(new DisableRegistrationController); $systemControllerGroup->addController(new EnableRegistrationController); $systemControllerGroup->addController(new GetStatsController); +$systemControllerGroup->addController(new AddAPIKeyController); +$systemControllerGroup->addController(new DeleteAPIKeyController); +$systemControllerGroup->addController(new GetAllKeyController); $systemControllerGroup->finalize(); \ No newline at end of file diff --git a/server/controllers/system/add-api-key.php b/server/controllers/system/add-api-key.php new file mode 100644 index 00000000..8bbb4b78 --- /dev/null +++ b/server/controllers/system/add-api-key.php @@ -0,0 +1,41 @@ + 'staff_3', + 'requestData' => [ + 'name' => [ + 'validation' => DataValidator::length(2, 55)->alpha(), + 'error' => ERRORS::INVALID_NAME + ] + ] + ]; + } + + public function handler() { + $apiInstance = new APIKey(); + + $name = Controller::request('name'); + + $keyInstance = APIKey::getDataStore($name, 'name'); + + if($keyInstance->isNull()){ + $token = Hashing::generateRandomToken(); + + $apiInstance->setProperties([ + 'name' => $name, + 'key' => $token + ]); + + $apiInstance->store(); + Response::respondSuccess($token); + } else { + Response::respondError(ERRORS::NAME_ALREADY_USED); + } + + } +} \ No newline at end of file diff --git a/server/controllers/system/delete-api-key.php b/server/controllers/system/delete-api-key.php new file mode 100644 index 00000000..8ee03152 --- /dev/null +++ b/server/controllers/system/delete-api-key.php @@ -0,0 +1,32 @@ + 'staff_3', + 'requestData' => [ + 'name' => [ + 'validation' => DataValidator::length(2, 55)->alpha(), + 'error' => ERRORS::INVALID_NAME + ] + ] + ]; + } + + public function handler() { + $name = Controller::request('name'); + + $keyInstance = APIKey::getDataStore($name, 'name'); + + if($keyInstance->isNull()) { + Response::respondError(ERRORS::INVALID_NAME); + return; + } + + $keyInstance->delete(); + Response::respondSuccess(); + } +} \ No newline at end of file diff --git a/server/controllers/system/get-all-keys.php b/server/controllers/system/get-all-keys.php new file mode 100644 index 00000000..35206374 --- /dev/null +++ b/server/controllers/system/get-all-keys.php @@ -0,0 +1,19 @@ + 'staff_3', + 'requestData' => [] + ]; + } + + public function handler() { + $apiList = APIKey::getAll(); + + Response::respondSuccess($apiList->toArray()); + } +} \ No newline at end of file diff --git a/server/data/ERRORS.php b/server/data/ERRORS.php index 4b7507cf..06211649 100644 --- a/server/data/ERRORS.php +++ b/server/data/ERRORS.php @@ -36,4 +36,5 @@ class ERRORS { const INVALID_SUBJECT = 'INVALID_SUBJECT'; const INVALID_BODY = 'INVALID_BODY'; const INVALID_PERIOD = 'INVALID_PERIOD'; + const NAME_ALREADY_USED = 'NAME_ALREADY_USED'; } diff --git a/server/models/APIKey.php b/server/models/APIKey.php new file mode 100644 index 00000000..c0b751fa --- /dev/null +++ b/server/models/APIKey.php @@ -0,0 +1,18 @@ + $this->name, + 'key' => $this->key + ]; + } +} \ No newline at end of file From 0108414a707904732efe9a9f86967a7fd5504b6d Mon Sep 17 00:00:00 2001 From: AntonyAntonio Date: Fri, 13 Jan 2017 17:06:49 -0300 Subject: [PATCH 17/84] Guillermo - registration api keys [skip ci] --- server/controllers/system/add-api-key.php | 4 +-- server/controllers/user/signup.php | 3 ++- server/libs/validations/captcha.php | 3 ++- server/models/APIKey.php | 4 +-- tests/init.rb | 3 +++ tests/scripts.rb | 8 ++++++ tests/system/add-api-key.rb | 30 +++++++++++++++++++++++ tests/system/delete-api-key.rb | 30 +++++++++++++++++++++++ tests/system/get-all-keys.rb | 26 ++++++++++++++++++++ 9 files changed, 105 insertions(+), 6 deletions(-) create mode 100644 tests/system/add-api-key.rb create mode 100644 tests/system/delete-api-key.rb create mode 100644 tests/system/get-all-keys.rb diff --git a/server/controllers/system/add-api-key.php b/server/controllers/system/add-api-key.php index 8bbb4b78..2f32d66d 100644 --- a/server/controllers/system/add-api-key.php +++ b/server/controllers/system/add-api-key.php @@ -9,7 +9,7 @@ class AddAPIKeyController extends Controller { 'permission' => 'staff_3', 'requestData' => [ 'name' => [ - 'validation' => DataValidator::length(2, 55)->alpha(), + 'validation' => DataValidator::length(2, 55)->alnum(), 'error' => ERRORS::INVALID_NAME ] ] @@ -28,7 +28,7 @@ class AddAPIKeyController extends Controller { $apiInstance->setProperties([ 'name' => $name, - 'key' => $token + 'token' => $token ]); $apiInstance->store(); diff --git a/server/controllers/user/signup.php b/server/controllers/user/signup.php index 48e6e1c6..cee72f1b 100644 --- a/server/controllers/user/signup.php +++ b/server/controllers/user/signup.php @@ -37,6 +37,7 @@ class SignUpController extends Controller { public function handler() { $this->storeRequestData(); + $apiKey = APIKey::getDataStore(Controller::request('apiKey'), 'token'); $existentUser = User::getUser($this->userEmail, 'email'); @@ -51,7 +52,7 @@ class SignUpController extends Controller { return; } - if (!Setting::getSetting('registration')->value) { + if (!Setting::getSetting('registration')->value && $apiKey->isNull() ) { Response::respondError(ERRORS::NO_PERMISSION); return; } diff --git a/server/libs/validations/captcha.php b/server/libs/validations/captcha.php index 437d92d8..7ac805c2 100644 --- a/server/libs/validations/captcha.php +++ b/server/libs/validations/captcha.php @@ -8,8 +8,9 @@ class Captcha extends AbstractRule { public function validate($reCaptchaResponse) { $reCaptchaPrivateKey = \Setting::getSetting('recaptcha-private')->getValue(); + $apiKey = \APIKey::getDataStore(\Controller::request('apiKey'), 'token'); - if (!$reCaptchaPrivateKey) return true; + if (!$reCaptchaPrivateKey || !$apiKey->isNull()) return true; $reCaptcha = new \ReCaptcha\ReCaptcha($reCaptchaPrivateKey); $reCaptchaValidation = $reCaptcha->verify($reCaptchaResponse, $_SERVER['REMOTE_ADDR']); diff --git a/server/models/APIKey.php b/server/models/APIKey.php index c0b751fa..2cfc3783 100644 --- a/server/models/APIKey.php +++ b/server/models/APIKey.php @@ -6,13 +6,13 @@ class APIKey extends DataStore { public static function getProps() { return [ 'name', - 'key' + 'token' ]; } public function toArray() { return [ 'name' => $this->name, - 'key' => $this->key + 'token' => $this->token ]; } } \ No newline at end of file diff --git a/tests/init.rb b/tests/init.rb index cae53d63..aaf24e28 100644 --- a/tests/init.rb +++ b/tests/init.rb @@ -55,3 +55,6 @@ require './system/recover-mail-template.rb' require './system/disable-registration.rb' require './system/enable-registration.rb' require './system/get-stats.rb' +require './system/add-api-key.rb' +require './system/delete-api-key.rb' +require './system/get-all-keys.rb' diff --git a/tests/scripts.rb b/tests/scripts.rb index 4cf57fcf..9b5eb892 100644 --- a/tests/scripts.rb +++ b/tests/scripts.rb @@ -44,4 +44,12 @@ class Scripts result['data'] end + + def self.createAPIKey(name) + result = request('/system/add-api-key', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + name: name + }) + end end diff --git a/tests/system/add-api-key.rb b/tests/system/add-api-key.rb new file mode 100644 index 00000000..cf8c86d5 --- /dev/null +++ b/tests/system/add-api-key.rb @@ -0,0 +1,30 @@ +describe'system/add-api-key' do + request('/user/logout') + Scripts.login($staff[:email], $staff[:password], true) + + it 'should add API key' do + result= request('/system/add-api-key', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + name: 'new API' + }) + + (result['status']).should.equal('success') + + row = $database.getRow('apikey', 1, 'id') + + (row['name']).should.equal('new API') + (result['data']).should.equal(row['token']) + + end + it 'should not add API key' do + result= request('/system/add-api-key', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + name: 'new API' + }) + + (result['status']).should.equal('fail') + (result['message']).should.equal('NAME_ALREADY_USED') + end +end diff --git a/tests/system/delete-api-key.rb b/tests/system/delete-api-key.rb new file mode 100644 index 00000000..21553cfb --- /dev/null +++ b/tests/system/delete-api-key.rb @@ -0,0 +1,30 @@ +describe'system/delete-api-key' do + request('/user/logout') + Scripts.login($staff[:email], $staff[:password], true) + + it 'should not delete API key' do + result= request('/system/delete-api-key', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + name: 'new PIA' + }) + + (result['status']).should.equal('fail') + (result['message']).should.equal('INVALID_NAME') + end + + it 'should delete API key' do + result= request('/system/delete-api-key', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + name: 'new API' + }) + + (result['status']).should.equal('success') + + row = $database.getRow('apikey', 1, 'id') + + (row).should.equal(nil) + end + +end diff --git a/tests/system/get-all-keys.rb b/tests/system/get-all-keys.rb new file mode 100644 index 00000000..a604af3d --- /dev/null +++ b/tests/system/get-all-keys.rb @@ -0,0 +1,26 @@ +describe'system/get-all-keys' do + request('/user/logout') + Scripts.login($staff[:email], $staff[:password], true) + + it 'should get all API keys' do + Scripts.createAPIKey('namekey1') + Scripts.createAPIKey('namekey2') + Scripts.createAPIKey('namekey3') + Scripts.createAPIKey('namekey4') + Scripts.createAPIKey('namekey5') + + result= request('/system/get-all-keys', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + }) + + (result['status']).should.equal('success') + (result['data'][0]['name']).should.equal('namekey1') + (result['data'][1]['name']).should.equal('namekey2') + (result['data'][2]['name']).should.equal('namekey3') + (result['data'][3]['name']).should.equal('namekey4') + (result['data'][4]['name']).should.equal('namekey5') + + end + +end From 8221a06048174f02523aa44399fd088301aaa88f Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 13 Jan 2017 17:06:52 -0300 Subject: [PATCH 18/84] Max Red - WIP second layout [skip ci] --- .../dashboard/admin-panel-stats-chart.js | 68 ++++++- .../panel/dashboard/admin-panel-stats.js | 76 +++++++- client/src/data/fixtures/system-fixtures.js | 172 +++++++++++++++++- 3 files changed, 311 insertions(+), 5 deletions(-) diff --git a/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js b/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js index d4dfabfa..21758266 100644 --- a/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js +++ b/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js @@ -1,18 +1,80 @@ import React from 'react'; +import {Line} from 'react-chartjs'; class StatsChart extends React.Component { static propTypes = { strokes: React.PropTypes.arrayOf(React.PropTypes.shape({ - - })) + name: React.PropTypes.string, + values: React.PropTypes.arrayOf(React.PropTypes.shape({ + date: React.PropTypes.number, + value: React.PropTypes.number + })) + })), + display: React.PropTypes.number }; render() { return ( -
Shit go home!
+
+ +
); } + + shouldBeDeleted(min, max, num) { + var rtn = []; + while (rtn.length < num) { + rtn.push((Math.random() * (max - min)) + min + ((Math.random() > 0.95) ? 1 : 0)); + } + return rtn; + } + + getChartData() { + let months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; + + let labels = [], i; + for (i = 0; i < this.props.display; i++) { + console.log(this.props.strokes[0].values[i].date); + let idx = this.props.strokes[0].values[i].date.slice(4, 6) - 1; + labels.push( this.props.strokes[0].values[i].date.slice(6, 8) + ' ' + months[idx]); + } + console.log(labels); + + return { + labels: labels, + datasets: [ + { + label: "My First dataset", + fillColor: "rgba(0,0,0,0)", + strokeColor: "rgba(1,2,3,1)", + pointColor: "rgba(3,2,1,1)", + pointStrokeColor: "#333", + pointHighlightFill: "#999", + pointHighlightStroke: "rgba(220,220,220,1)", + data: this.shouldBeDeleted(32, 36, 365) + }, + { + label: "My Second dataset", + fillColor: "rgba(0,0,0,0)", + strokeColor: "rgba(151,187,205,1)", + pointColor: "rgba(151,187,205,1)", + pointStrokeColor: "#fff", + pointHighlightFill: "#fff", + pointHighlightStroke: "rgba(151,187,205,1)", + data: this.shouldBeDeleted(32, 36, 365) + } + ] + }; + } + + getChartOptions() { + return { + + }; + } + } + export default StatsChart; \ No newline at end of file diff --git a/client/src/app/admin/panel/dashboard/admin-panel-stats.js b/client/src/app/admin/panel/dashboard/admin-panel-stats.js index 76fd68d6..e861e6fd 100644 --- a/client/src/app/admin/panel/dashboard/admin-panel-stats.js +++ b/client/src/app/admin/panel/dashboard/admin-panel-stats.js @@ -13,7 +13,7 @@ class AdminPanelStats extends React.Component {
- +
); } @@ -40,6 +40,80 @@ class AdminPanelStats extends React.Component { ] } } + + getStatsChartProps() { + return { + display: 7, + strokes: [ + { + name: 'new-tickets', + values: [ + { + date: "20160420", + value: 17 + }, + { + date: "20160421", + value: 15 + }, + { + date: "20160422", + value: 12 + }, + { + date: "20160423", + value: 19 + }, + { + date: "20160424", + value: 14 + }, + { + date: "20160425", + value: 13 + }, + { + date: "20160426", + value: 19 + } + ] + }, + { + name: 'closed-tickets', + values: [ + { + date: "20160420", + value: 20 + }, + { + date: "20160421", + value: 15 + }, + { + date: "20160422", + value: 13 + }, + { + date: "20160423", + value: 15 + }, + { + date: "20160424", + value: 12 + }, + { + date: "20160425", + value: 19 + }, + { + date: "20160426", + value: 23 + } + ] + } + ] + } + } } export default AdminPanelStats; \ No newline at end of file diff --git a/client/src/data/fixtures/system-fixtures.js b/client/src/data/fixtures/system-fixtures.js index 8626a24b..57db8e0a 100644 --- a/client/src/data/fixtures/system-fixtures.js +++ b/client/src/data/fixtures/system-fixtures.js @@ -162,7 +162,177 @@ module.exports = [ time: 200, response: function() { return { - + status: "success", + data: [ + { + "date": "20170112", + "type": "COMMENT", + "general": "1", + "value": "8" + }, + { + "date": "20170112", + "type": "SIGNUP", + "general": "1", + "value": "1" + }, + { + "date": "20170112", + "type": "CLOSE", + "general": "1", + "value": "5" + }, + { + "date": "20170112", + "type": "CREATE_TICKET", + "general": "1", + "value": "2" + }, + { + "date": "20170111", + "type": "COMMENT", + "general": "1", + "value": "3" + }, + { + "date": "20170111", + "type": "SIGNUP", + "general": "1", + "value": "8" + }, + { + "date": "20170111", + "type": "CLOSE", + "general": "1", + "value": "10" + }, + { + "date": "20170111", + "type": "CREATE_TICKET", + "general": "1", + "value": "3" + }, + { + "date": "20170110", + "type": "COMMENT", + "general": "1", + "value": "3" + }, + { + "date": "20170110", + "type": "SIGNUP", + "general": "1", + "value": "6" + }, + { + "date": "20170110", + "type": "CLOSE", + "general": "1", + "value": "2" + }, + { + "date": "20170110", + "type": "CREATE_TICKET", + "general": "1", + "value": "1" + }, + { + "date": "20170109", + "type": "COMMENT", + "general": "1", + "value": "0" + }, + { + "date": "20170109", + "type": "SIGNUP", + "general": "1", + "value": "0" + }, + { + "date": "20170109", + "type": "CLOSE", + "general": "1", + "value": "0" + }, + { + "date": "20170109", + "type": "CREATE_TICKET", + "general": "1", + "value": "0" + }, + { + "date": "20170108", + "type": "COMMENT", + "general": "1", + "value": "0" + }, + { + "date": "20170108", + "type": "SIGNUP", + "general": "1", + "value": "0" + }, + { + "date": "20170108", + "type": "CLOSE", + "general": "1", + "value": "0" + }, + { + "date": "20170108", + "type": "CREATE_TICKET", + "general": "1", + "value": "0" + }, + { + "date": "20170107", + "type": "COMMENT", + "general": "1", + "value": "0" + }, + { + "date": "20170107", + "type": "SIGNUP", + "general": "1", + "value": "0" + }, + { + "date": "20170107", + "type": "CLOSE", + "general": "1", + "value": "0" + }, + { + "date": "20170107", + "type": "CREATE_TICKET", + "general": "1", + "value": "0" + }, + { + "date": "20170106", + "type": "COMMENT", + "general": "1", + "value": "0" + }, + { + "date": "20170106", + "type": "SIGNUP", + "general": "1", + "value": "0" + }, + { + "date": "20170106", + "type": "CLOSE", + "general": "1", + "value": "0" + }, + { + "date": "20170106", + "type": "CREATE_TICKET", + "general": "1", + "value": "0" + } + ] }; } }, From dffe4a87a0b0062085b4fdeee5b209998688f333 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Fri, 13 Jan 2017 21:58:59 -0300 Subject: [PATCH 19/84] Ivan - Add file upload and download test [skip ci] --- server/controllers/system/init-settings.php | 2 +- tests/init.rb | 1 + tests/libs.rb | 7 ++ tests/system/fiile-upload-download.rb | 24 ------- tests/system/file-upload-download.rb | 74 +++++++++++++++++++++ tests/system/get-stats.rb | 12 ++-- 6 files changed, 89 insertions(+), 31 deletions(-) delete mode 100644 tests/system/fiile-upload-download.rb create mode 100644 tests/system/file-upload-download.rb diff --git a/server/controllers/system/init-settings.php b/server/controllers/system/init-settings.php index 31536cba..b5d7c6d3 100644 --- a/server/controllers/system/init-settings.php +++ b/server/controllers/system/init-settings.php @@ -42,7 +42,7 @@ class InitSettingsController extends Controller { 'title' => 'Support Center', 'url' => 'http://www.opensupports.com/support', 'registration' => true, - 'last-stat-day' => '20170101' //TODO: get current date + 'last-stat-day' => '20170101', //TODO: get current date 'ticket-gap' => Hashing::generateRandomPrime(100000, 999999), 'file-gap' => Hashing::generateRandomPrime(100000, 999999), 'file-first-number' => Hashing::generateRandomNumber(100000, 999999), diff --git a/tests/init.rb b/tests/init.rb index cae53d63..f98e9cda 100644 --- a/tests/init.rb +++ b/tests/init.rb @@ -55,3 +55,4 @@ require './system/recover-mail-template.rb' require './system/disable-registration.rb' require './system/enable-registration.rb' require './system/get-stats.rb' +require './system/file-upload-download.rb' diff --git a/tests/libs.rb b/tests/libs.rb index 8b832429..fef8e646 100644 --- a/tests/libs.rb +++ b/tests/libs.rb @@ -1,5 +1,12 @@ $agent = Mechanize.new +def plainRequest(path, data = {}) + uri = 'http://localhost:8080' + path + response = $agent.post(uri, data) + + return response +end + def request(path, data = {}) uri = 'http://localhost:8080' + path response = $agent.post(uri, data) diff --git a/tests/system/fiile-upload-download.rb b/tests/system/fiile-upload-download.rb deleted file mode 100644 index ebaa8345..00000000 --- a/tests/system/fiile-upload-download.rb +++ /dev/null @@ -1,24 +0,0 @@ -describe 'File Upload and Download' do - request('/user/logout') - Scripts.login("creator@os4.com", "creator") - - it 'should upload file when creating ticket' do - file = File.new('upload.txt', 'w') - file.puts('file content') - - result = request('/ticket/create', { - 'csrf_userid' => $csrf_userid, - 'csrf_token' => $csrf_token, - 'title' => 'Ticket with file', - 'content' => 'this is a ticket that contains a file', - 'language' => 'en', - 'file' => file - }) - (result['status']).should.equal('success'); - - ticket = $database.getLastRow('ticket'); - - (ticket['file'].include? 'upload.txt').should.equal(true) - (File.exist?('../server/files' + ticket['file'])).should.equal(true) - end -end diff --git a/tests/system/file-upload-download.rb b/tests/system/file-upload-download.rb new file mode 100644 index 00000000..44bc3c37 --- /dev/null +++ b/tests/system/file-upload-download.rb @@ -0,0 +1,74 @@ +describe 'File Upload and Download' do + request('/user/logout') + Scripts.login('creator@os4.com', 'creator') + + it 'should upload file when creating ticket' do + file = File.new('../server/files/upload.txt', 'w+') + file.puts('file content') + file.close + + result = request('/ticket/create', { + 'csrf_userid' => $csrf_userid, + 'csrf_token' => $csrf_token, + 'title' => 'Ticket with file', + 'content' => 'this is a ticket that contains a file', + 'language' => 'en', + 'departmentId' => 1, + 'file' => File.open( "../server/files/upload.txt") + }) + (result['status']).should.equal('success') + + ticket = $database.getLastRow('ticket') + + (ticket['file'].include? 'upload.txt').should.equal(true) + (File.exist? ('../server/files/' + ticket['file'])).should.equal(true) + end + + it 'should download file if author is logged' do + ticket = $database.getLastRow('ticket') + file = File.open("../server/files/" + ticket['file']) + + result = plainRequest('/system/download', { + 'csrf_userid' => $csrf_userid, + 'csrf_token' => $csrf_token, + 'file' => ticket['file'] + }) + + (result.body).should.equal(file.read) + end + + it 'should not download if author is not logged' do + request('/user/logout') + Scripts.login('staff@opensupports.com', 'staff', true) + + ticket = $database.getLastRow('ticket') + + result = plainRequest('/system/download', { + 'csrf_userid' => $csrf_userid, + 'csrf_token' => $csrf_token, + 'file' => ticket['file'] + }) + + (result.body).should.equal('') + end + + it 'should download if owner is logged' do + ticket = $database.getLastRow('ticket') + file = File.open("../server/files/" + ticket['file']) + + request('/staff/assign-ticket', { + 'csrf_userid' => $csrf_userid, + 'csrf_token' => $csrf_token, + 'ticketNumber' => ticket['ticket_number'] + }) + + result = plainRequest('/system/download', { + 'csrf_userid' => $csrf_userid, + 'csrf_token' => $csrf_token, + 'file' => ticket['file'] + }) + + (result.body).should.equal(file.read) + end + +end diff --git a/tests/system/get-stats.rb b/tests/system/get-stats.rb index 406c4516..04d31e83 100644 --- a/tests/system/get-stats.rb +++ b/tests/system/get-stats.rb @@ -25,10 +25,10 @@ describe'/system/get-stats' do $database.query("INSERT INTO log VALUES('', 'COMMENT', NULL, " + yesterday3 + ", NULL, NULL);") end for i in 0..8 - $database.query("INSERT INTO ticketevent VALUES('', 'CLOSE', NULL, " + yesterday3 + ", NULL, NULL, 1);") + $database.query("INSERT INTO ticketevent VALUES('', 'CLOSE', NULL, NULL, " + yesterday3 + ", NULL, NULL, 1);") end for i in 0..4 - $database.query("INSERT INTO ticketevent VALUES('', 'ASSIGN', NULL, " + yesterday3 + ", NULL, NULL, 1);") + $database.query("INSERT INTO ticketevent VALUES('', 'ASSIGN', NULL, NULL, " + yesterday3 + ", NULL, NULL, 1);") end #day 2 @@ -45,10 +45,10 @@ describe'/system/get-stats' do $database.query("INSERT INTO log VALUES('', 'COMMENT', NULL, " + yesterday2 + ", NULL, NULL);") end for i in 0..10 - $database.query("INSERT INTO ticketevent VALUES('', 'CLOSE', NULL, " + yesterday2 + ", NULL, NULL, 1);") + $database.query("INSERT INTO ticketevent VALUES('', 'CLOSE', NULL, NULL, " + yesterday2 + ", NULL, NULL, 1);") end for i in 0..2 - $database.query("INSERT INTO ticketevent VALUES('', 'ASSIGN', NULL, " + yesterday2 + ", NULL, NULL, 1);") + $database.query("INSERT INTO ticketevent VALUES('', 'ASSIGN', NULL, NULL, " + yesterday2 + ", NULL, NULL, 1);") end #day 3 @@ -65,10 +65,10 @@ describe'/system/get-stats' do $database.query("INSERT INTO log VALUES('', 'COMMENT', NULL, " + yesterday + ", NULL, NULL);") end for i in 0..3 - $database.query("INSERT INTO ticketevent VALUES('', 'CLOSE', NULL, " + yesterday + ", NULL, NULL, 1);") + $database.query("INSERT INTO ticketevent VALUES('', 'CLOSE', NULL, NULL, " + yesterday + ", NULL, NULL, 1);") end for i in 0..7 - $database.query("INSERT INTO ticketevent VALUES('', 'ASSIGN', NULL, " + yesterday + ", NULL, NULL, 1);") + $database.query("INSERT INTO ticketevent VALUES('', 'ASSIGN', NULL, NULL, " + yesterday + ", NULL, NULL, 1);") end @result = request('/system/get-stats', { From 4f7118c2e5bff0df05b6935d97ee5931ac2ddcde Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 14 Jan 2017 01:45:21 -0300 Subject: [PATCH 20/84] Max Red - Abstracting StatsChart, modified demo page [skip ci] --- client/package.json | 4 +- .../dashboard/admin-panel-stats-chart.js | 92 ++++++++++++------- .../panel/dashboard/admin-panel-stats.js | 51 ++++++++-- client/src/app/demo/components-demo-page.js | 31 ++++--- 4 files changed, 120 insertions(+), 58 deletions(-) diff --git a/client/package.json b/client/package.json index 3caab38d..0033b6df 100644 --- a/client/package.json +++ b/client/package.json @@ -54,7 +54,7 @@ }, "dependencies": { "app-module-path": "^1.0.3", - "chart.js": "^1.1.1", + "chart.js": "^2.4.0", "classnames": "^2.1.3", "draft-js": "^0.8.1", "draft-js-export-html": "^0.4.0", @@ -64,7 +64,7 @@ "lodash": "^3.10.0", "messageformat": "^0.2.2", "react": "^15.0.1", - "react-chartjs": "^0.8.0", + "react-chartjs-2": "^2.0.0", "react-document-title": "^1.0.2", "react-dom": "^15.0.1", "react-google-recaptcha": "^0.5.2", diff --git a/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js b/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js index 21758266..2ff937b3 100644 --- a/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js +++ b/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js @@ -1,5 +1,5 @@ import React from 'react'; -import {Line} from 'react-chartjs'; +import {Line} from 'react-chartjs-2'; class StatsChart extends React.Component { @@ -7,7 +7,7 @@ class StatsChart extends React.Component { strokes: React.PropTypes.arrayOf(React.PropTypes.shape({ name: React.PropTypes.string, values: React.PropTypes.arrayOf(React.PropTypes.shape({ - date: React.PropTypes.number, + date: React.PropTypes.string, value: React.PropTypes.number })) })), @@ -22,10 +22,10 @@ class StatsChart extends React.Component { ); } - shouldBeDeleted(min, max, num) { + shouldBeDeleted(min, max, num, type) { var rtn = []; while (rtn.length < num) { - rtn.push((Math.random() * (max - min)) + min + ((Math.random() > 0.95) ? 1 : 0)); + rtn.push(Math.floor((Math.random() * (max - min)) + min + ((Math.random() > 0.1) ? type * 3 : 0))); } return rtn; } @@ -33,44 +33,70 @@ class StatsChart extends React.Component { getChartData() { let months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; - let labels = [], i; - for (i = 0; i < this.props.display; i++) { - console.log(this.props.strokes[0].values[i].date); - let idx = this.props.strokes[0].values[i].date.slice(4, 6) - 1; - labels.push( this.props.strokes[0].values[i].date.slice(6, 8) + ' ' + months[idx]); + let labels = []; + for (let i = 0; i < this.props.display; i++) { + if(i % 2 == 0 && this.props.display > 20){ + labels.push(''); + continue; + } + let firstList = this.props.strokes[0]; + let idx = firstList.values[i].date.slice(4, 6) - 1; + labels.push( firstList.values[i].date.slice(6, 8) + ' ' + months[idx]); + } + + let color = { + 'CREATE_TICKET': 'rgba(150, 20, 20)', + 'CLOSE': 'rgba(20, 150, 20)', + 'SIGNUP': 'rgba(20, 20, 150)', + 'COMMENT': 'rgba(150, 150, 20)' + }; + + let datasets = []; + + for (let i = 0; i < this.props.strokes.length; i++) { + let stroke = this.props.strokes[i]; + + let dataset = {}; + dataset.label = stroke.name; + dataset.data = []; + dataset.fill = false; + + console.log('FUCK THIS PITCH BEF ' + stroke.values.length); + for (let j = 0; j < stroke.values.length; j++) { + console.log('OH YEAH: ' + stroke.values[j].value); + dataset.data.push(stroke.values[j].value); + console.log('OH YEAH x2'); + } + console.log('FUCK THIS PITCH AFT'); + + dataset.borderWidth = 4; + dataset.borderColor = color[stroke.name]; + dataset.pointRadius = 0; + dataset.lineTension = 0.2; + dataset.hitRadius = this.hitRadius(); + + datasets.push(dataset); } - console.log(labels); return { labels: labels, - datasets: [ - { - label: "My First dataset", - fillColor: "rgba(0,0,0,0)", - strokeColor: "rgba(1,2,3,1)", - pointColor: "rgba(3,2,1,1)", - pointStrokeColor: "#333", - pointHighlightFill: "#999", - pointHighlightStroke: "rgba(220,220,220,1)", - data: this.shouldBeDeleted(32, 36, 365) - }, - { - label: "My Second dataset", - fillColor: "rgba(0,0,0,0)", - strokeColor: "rgba(151,187,205,1)", - pointColor: "rgba(151,187,205,1)", - pointStrokeColor: "#fff", - pointHighlightFill: "#fff", - pointHighlightStroke: "rgba(151,187,205,1)", - data: this.shouldBeDeleted(32, 36, 365) - } - ] + datasets: datasets }; } + hitRadius(name) { + /// SHOULD AJUSTAR THIS VALUES + if (this.props.display === 7) return 20; + if (this.props.display === 30) return 15; + if (this.props.display === 90) return 10; + return 3; + } + getChartOptions() { return { - + legend: { + display: false + } }; } diff --git a/client/src/app/admin/panel/dashboard/admin-panel-stats.js b/client/src/app/admin/panel/dashboard/admin-panel-stats.js index e861e6fd..992fda02 100644 --- a/client/src/app/admin/panel/dashboard/admin-panel-stats.js +++ b/client/src/app/admin/panel/dashboard/admin-panel-stats.js @@ -46,40 +46,40 @@ class AdminPanelStats extends React.Component { display: 7, strokes: [ { - name: 'new-tickets', + name: 'CREATE_TICKET', values: [ { date: "20160420", - value: 17 + value: 71 }, { date: "20160421", - value: 15 + value: 21 }, { date: "20160422", - value: 12 + value: 4 }, { date: "20160423", - value: 19 + value: 9 }, { date: "20160424", - value: 14 + value: 12 }, { date: "20160425", - value: 13 + value: 14 }, { date: "20160426", - value: 19 + value: 22 } ] }, { - name: 'closed-tickets', + name: 'CLOSE', values: [ { date: "20160420", @@ -110,6 +110,39 @@ class AdminPanelStats extends React.Component { value: 23 } ] + }, + { + name: 'SIGNUP', + values: [ + { + date: "20160420", + value: 3 + }, + { + date: "20160421", + value: 5 + }, + { + date: "20160422", + value: 3 + }, + { + date: "20160423", + value: 4 + }, + { + date: "20160424", + value: 5 + }, + { + date: "20160425", + value: 5 + }, + { + date: "20160426", + value: 6 + } + ] } ] } diff --git a/client/src/app/demo/components-demo-page.js b/client/src/app/demo/components-demo-page.js index 4a69a807..0a367022 100644 --- a/client/src/app/demo/components-demo-page.js +++ b/client/src/app/demo/components-demo-page.js @@ -1,7 +1,7 @@ 'use strict'; const React = require('react'); -const LineChart = require("react-chartjs").Line; +const LineChart = require("react-chartjs-2").Line; const _ = require('lodash'); const DocumentTitle = require('react-document-title'); @@ -27,27 +27,30 @@ function rand(min, max, num) { } let chartData = { - labels: ["January", "February", "March", "April", "", "May", "June", "July"], + labels: ["January", "February", "March", "April", "May", "June"], datasets: [ - { - label: "My First dataset", - fillColor: "rgba(0,0,0,0)", - strokeColor: "rgba(1,2,3,1)", - pointColor: "rgba(3,2,1,1)", - pointStrokeColor: "#333", - pointHighlightFill: "#999", - pointHighlightStroke: "rgba(220,220,220,1)", - data: rand(32, 100, 8) - }, { label: "My Second dataset", - fillColor: "rgba(0,0,0,0)", + fill: false, strokeColor: "rgba(151,187,205,1)", pointColor: "rgba(151,187,205,1)", pointStrokeColor: "#fff", pointHighlightFill: "#fff", pointHighlightStroke: "rgba(151,187,205,1)", - data: rand(32, 100, 8) + borderWidth: 3, + data: rand(32, 100, 6), + pointRadius: 0 + }, + { + label: "My Second dataset", + fill: false, + strokeColor: "rgba(151,187,205,1)", + pointColor: "rgba(151,187,205,1)", + pointStrokeColor: "#fff", + pointHighlightFill: "#fff", + pointHighlightStroke: "rgba(151,187,205,1)", + borderWidth: 3, + data: rand(32, 100, 6) } ] }; From d12194cd34ece2a1df3510d57c39b0f9a3458dbe Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 14 Jan 2017 14:00:02 -0300 Subject: [PATCH 21/84] Max Red - beautify code and add functionality [skip ci] --- .../dashboard/admin-panel-stats-chart.js | 85 ++++++++++--------- .../panel/dashboard/admin-panel-stats.js | 3 + client/src/app/demo/components-demo-page.js | 2 - client/src/data/languages/en.js | 5 ++ 4 files changed, 53 insertions(+), 42 deletions(-) diff --git a/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js b/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js index 2ff937b3..6f36e39c 100644 --- a/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js +++ b/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js @@ -1,6 +1,8 @@ import React from 'react'; import {Line} from 'react-chartjs-2'; +import i18n from 'lib-app/i18n'; + class StatsChart extends React.Component { static propTypes = { @@ -8,6 +10,7 @@ class StatsChart extends React.Component { name: React.PropTypes.string, values: React.PropTypes.arrayOf(React.PropTypes.shape({ date: React.PropTypes.string, + show: React.PropTypes.bool, value: React.PropTypes.number })) })), @@ -17,7 +20,7 @@ class StatsChart extends React.Component { render() { return (
- +
); } @@ -31,9 +34,48 @@ class StatsChart extends React.Component { } getChartData() { - let months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; + let labels = this.getLabels(); + let color = { + 'CREATE_TICKET': 'rgba(150, 20, 20, 0.8)', + 'CLOSE': 'rgba(20, 150, 20, 0.8)', + 'SIGNUP': 'rgba(20, 20, 150, 0.8)', + 'COMMENT': 'rgba(150, 150, 20, 0.8)' + }; + + let datasets = []; + + for (let i = 0; i < this.props.strokes.length; i++) { + let stroke = this.props.strokes[i]; + console.log(color[stroke.name]); + + let dataset = { + label: i18n('CHART_' + stroke.name), + data: stroke.values.map((val) => val.value), + fill: false, + borderWidth: 4, + borderColor: color[stroke.name], + pointBorderColor: color[stroke.name], + pointRadius: 0, + lineTension: 0.2, + pointHoverBackgroundColor: color[stroke.name], + hitRadius: this.hitRadius(), + showLine: stroke.show + }; + + datasets.push(dataset); + } + + return { + labels: labels, + datasets: datasets + }; + } + + getLabels() { + let months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; let labels = []; + for (let i = 0; i < this.props.display; i++) { if(i % 2 == 0 && this.props.display > 20){ labels.push(''); @@ -44,44 +86,7 @@ class StatsChart extends React.Component { labels.push( firstList.values[i].date.slice(6, 8) + ' ' + months[idx]); } - let color = { - 'CREATE_TICKET': 'rgba(150, 20, 20)', - 'CLOSE': 'rgba(20, 150, 20)', - 'SIGNUP': 'rgba(20, 20, 150)', - 'COMMENT': 'rgba(150, 150, 20)' - }; - - let datasets = []; - - for (let i = 0; i < this.props.strokes.length; i++) { - let stroke = this.props.strokes[i]; - - let dataset = {}; - dataset.label = stroke.name; - dataset.data = []; - dataset.fill = false; - - console.log('FUCK THIS PITCH BEF ' + stroke.values.length); - for (let j = 0; j < stroke.values.length; j++) { - console.log('OH YEAH: ' + stroke.values[j].value); - dataset.data.push(stroke.values[j].value); - console.log('OH YEAH x2'); - } - console.log('FUCK THIS PITCH AFT'); - - dataset.borderWidth = 4; - dataset.borderColor = color[stroke.name]; - dataset.pointRadius = 0; - dataset.lineTension = 0.2; - dataset.hitRadius = this.hitRadius(); - - datasets.push(dataset); - } - - return { - labels: labels, - datasets: datasets - }; + return labels; } hitRadius(name) { diff --git a/client/src/app/admin/panel/dashboard/admin-panel-stats.js b/client/src/app/admin/panel/dashboard/admin-panel-stats.js index 992fda02..2feb50f7 100644 --- a/client/src/app/admin/panel/dashboard/admin-panel-stats.js +++ b/client/src/app/admin/panel/dashboard/admin-panel-stats.js @@ -47,6 +47,7 @@ class AdminPanelStats extends React.Component { strokes: [ { name: 'CREATE_TICKET', + show: true, values: [ { date: "20160420", @@ -80,6 +81,7 @@ class AdminPanelStats extends React.Component { }, { name: 'CLOSE', + show: true, values: [ { date: "20160420", @@ -113,6 +115,7 @@ class AdminPanelStats extends React.Component { }, { name: 'SIGNUP', + show: true, values: [ { date: "20160420", diff --git a/client/src/app/demo/components-demo-page.js b/client/src/app/demo/components-demo-page.js index 0a367022..68042fd4 100644 --- a/client/src/app/demo/components-demo-page.js +++ b/client/src/app/demo/components-demo-page.js @@ -32,7 +32,6 @@ let chartData = { { label: "My Second dataset", fill: false, - strokeColor: "rgba(151,187,205,1)", pointColor: "rgba(151,187,205,1)", pointStrokeColor: "#fff", pointHighlightFill: "#fff", @@ -44,7 +43,6 @@ let chartData = { { label: "My Second dataset", fill: false, - strokeColor: "rgba(151,187,205,1)", pointColor: "rgba(151,187,205,1)", pointStrokeColor: "#fff", pointHighlightFill: "#fff", diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js index 61e8ec37..ceda9f35 100644 --- a/client/src/data/languages/en.js +++ b/client/src/data/languages/en.js @@ -154,6 +154,11 @@ export default { 'VERIFY_FAILED': 'Could not verify', 'TICKET_ACTIVITY': 'Ticket Activity', + 'CHART_CREATE_TICKET': 'Tickets created', + 'CHART_CLOSE': 'Tickets closed', + 'CHART_SIGNUP': 'Signups', + 'CHART_COMMENT': 'Replies', + //ACTIVITIES 'ACTIVITY_COMMENT': 'commented ticket', 'ACTIVITY_ASSIGN': 'assigned ticket', From 1e69e6f4f85e3ee9ff21b7f8b414024463ec258a Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 14 Jan 2017 14:17:35 -0300 Subject: [PATCH 22/84] Max Red - Finished StatsChart component, started full component [skip ci] --- .../dashboard/admin-panel-stats-chart.js | 16 +-- .../panel/dashboard/admin-panel-stats.js | 102 +++++++++++------- 2 files changed, 63 insertions(+), 55 deletions(-) diff --git a/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js b/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js index 6f36e39c..b5582017 100644 --- a/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js +++ b/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js @@ -25,14 +25,6 @@ class StatsChart extends React.Component { ); } - shouldBeDeleted(min, max, num, type) { - var rtn = []; - while (rtn.length < num) { - rtn.push(Math.floor((Math.random() * (max - min)) + min + ((Math.random() > 0.1) ? type * 3 : 0))); - } - return rtn; - } - getChartData() { let labels = this.getLabels(); @@ -47,7 +39,6 @@ class StatsChart extends React.Component { for (let i = 0; i < this.props.strokes.length; i++) { let stroke = this.props.strokes[i]; - console.log(color[stroke.name]); let dataset = { label: i18n('CHART_' + stroke.name), @@ -77,10 +68,6 @@ class StatsChart extends React.Component { let labels = []; for (let i = 0; i < this.props.display; i++) { - if(i % 2 == 0 && this.props.display > 20){ - labels.push(''); - continue; - } let firstList = this.props.strokes[0]; let idx = firstList.values[i].date.slice(4, 6) - 1; labels.push( firstList.values[i].date.slice(6, 8) + ' ' + months[idx]); @@ -89,8 +76,7 @@ class StatsChart extends React.Component { return labels; } - hitRadius(name) { - /// SHOULD AJUSTAR THIS VALUES + hitRadius() { if (this.props.display === 7) return 20; if (this.props.display === 30) return 15; if (this.props.display === 90) return 10; diff --git a/client/src/app/admin/panel/dashboard/admin-panel-stats.js b/client/src/app/admin/panel/dashboard/admin-panel-stats.js index 2feb50f7..a7ae93dc 100644 --- a/client/src/app/admin/panel/dashboard/admin-panel-stats.js +++ b/client/src/app/admin/panel/dashboard/admin-panel-stats.js @@ -4,6 +4,8 @@ import i18n from 'lib-app/i18n'; import Header from 'core-components/header'; import DropDown from 'core-components/drop-down'; +import ToggleList from 'core-components/toggle-list'; + import StatsChart from 'app/admin/panel/dashboard/admin-panel-stats-chart'; class AdminPanelStats extends React.Component { @@ -13,11 +15,31 @@ class AdminPanelStats extends React.Component {
+
); } + getToggleListProps() { + return { + items: [ + { + content:
+ }, + { + content:
+ }, + { + content:
+ }, + { + content:
+ } + ] + }; + } + getDropDownProps() { return { items: [ @@ -51,15 +73,15 @@ class AdminPanelStats extends React.Component { values: [ { date: "20160420", - value: 71 + value: 17 }, { date: "20160421", - value: 21 + value: 15 }, { date: "20160422", - value: 4 + value: 12 }, { date: "20160423", @@ -67,49 +89,15 @@ class AdminPanelStats extends React.Component { }, { date: "20160424", - value: 12 + value: 10 }, { date: "20160425", - value: 14 + value: 7 }, { date: "20160426", - value: 22 - } - ] - }, - { - name: 'CLOSE', - show: true, - values: [ - { - date: "20160420", - value: 20 - }, - { - date: "20160421", - value: 15 - }, - { - date: "20160422", - value: 13 - }, - { - date: "20160423", - value: 15 - }, - { - date: "20160424", - value: 12 - }, - { - date: "20160425", - value: 19 - }, - { - date: "20160426", - value: 23 + value: 5 } ] }, @@ -146,6 +134,40 @@ class AdminPanelStats extends React.Component { value: 6 } ] + }, + { + name: 'CLOSE', + show: true, + values: [ + { + date: "20160420", + value: 4 + }, + { + date: "20160421", + value: 7 + }, + { + date: "20160422", + value: 4 + }, + { + date: "20160423", + value: 7 + }, + { + date: "20160424", + value: 9 + }, + { + date: "20160425", + value: 11 + }, + { + date: "20160426", + value: 13 + } + ] } ] } From 8c50cc97c91f04ba3fee33d00fed15388e9d78b9 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 14 Jan 2017 15:15:26 -0300 Subject: [PATCH 23/84] Max Red - Create stats state, and display correct values in the toggle list [skip ci] --- .../dashboard/admin-panel-stats-chart.js | 6 +- .../panel/dashboard/admin-panel-stats.js | 61 +++++++++++++++++-- client/src/data/languages/en.js | 1 + 3 files changed, 60 insertions(+), 8 deletions(-) diff --git a/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js b/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js index b5582017..d62cc729 100644 --- a/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js +++ b/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js @@ -29,10 +29,10 @@ class StatsChart extends React.Component { let labels = this.getLabels(); let color = { - 'CREATE_TICKET': 'rgba(150, 20, 20, 0.8)', - 'CLOSE': 'rgba(20, 150, 20, 0.8)', + 'CLOSE': 'rgba(150, 20, 20, 0.8)', + 'CREATE_TICKET': 'rgba(20, 150, 20, 0.8)', 'SIGNUP': 'rgba(20, 20, 150, 0.8)', - 'COMMENT': 'rgba(150, 150, 20, 0.8)' + 'COMMENT': 'rgba(20, 200, 200, 0.8)' }; let datasets = []; diff --git a/client/src/app/admin/panel/dashboard/admin-panel-stats.js b/client/src/app/admin/panel/dashboard/admin-panel-stats.js index a7ae93dc..5b24047a 100644 --- a/client/src/app/admin/panel/dashboard/admin-panel-stats.js +++ b/client/src/app/admin/panel/dashboard/admin-panel-stats.js @@ -1,6 +1,7 @@ import React from 'react'; import i18n from 'lib-app/i18n'; +import API from 'lib-app/api-call'; import Header from 'core-components/header'; import DropDown from 'core-components/drop-down'; @@ -10,6 +11,19 @@ import StatsChart from 'app/admin/panel/dashboard/admin-panel-stats-chart'; class AdminPanelStats extends React.Component { + state = { + stats: { + 'CLOSE': 0, + 'CREATE_TICKET': 0, + 'SIGNUP': 0, + 'COMMENT': 0 + } + }; + + componentDidMount() { + this.retrieve(); + } + render() { return (
@@ -22,19 +36,36 @@ class AdminPanelStats extends React.Component { } getToggleListProps() { + console.log('LALA: ' + this.state.stats); return { items: [ { - content:
+ content: +
+ {this.state.stats['CREATE_TICKET']} +
{i18n('CHART_CREATE_TICKET')}
+
}, { - content:
+ content: +
+ {this.state.stats['CLOSE']} +
{i18n('CHART_CLOSE')}
+
}, { - content:
+ content: +
+ {this.state.stats['SIGNUP']} +
{i18n('CHART_SIGNUP')}
+
}, { - content:
+ content: +
+ {this.state.stats['COMMENT']} +
{i18n('CHART_COMMENT')}
+
} ] }; @@ -68,7 +99,7 @@ class AdminPanelStats extends React.Component { display: 7, strokes: [ { - name: 'CREATE_TICKET', + name: 'COMMENT', show: true, values: [ { @@ -172,6 +203,26 @@ class AdminPanelStats extends React.Component { ] } } + + retrieve() { + API.call({ + path: '/system/get-stats', + data: {} + }).then(this.onRetrieveSuccess.bind(this)); + } + + onRetrieveSuccess(result) { + let newState = { + 'CLOSE': 0, + 'CREATE_TICKET': 0, + 'SIGNUP': 0, + 'COMMENT': 0 + }; + for (let i = 0; i < result.data.length; i++) { + newState[result.data[i].type] += result.data[i].value * 1; + } + this.setState({stats: newState}); + } } export default AdminPanelStats; \ No newline at end of file diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js index ceda9f35..cb576806 100644 --- a/client/src/data/languages/en.js +++ b/client/src/data/languages/en.js @@ -154,6 +154,7 @@ export default { 'VERIFY_FAILED': 'Could not verify', 'TICKET_ACTIVITY': 'Ticket Activity', + 'CHART_CREATE_TICKET': 'Tickets created', 'CHART_CLOSE': 'Tickets closed', 'CHART_SIGNUP': 'Signups', From d575882bf2b2009ea3cde94067cf0fae4616bd52 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Sat, 14 Jan 2017 16:39:22 -0300 Subject: [PATCH 24/84] Ivan - Add file uploader component [skip ci] --- .../create-ticket-form.js | 3 ++ .../create-ticket-form.scss | 4 ++ client/src/core-components/file-uploader.js | 40 +++++++++++++++++++ client/src/core-components/file-uploader.scss | 31 ++++++++++++++ client/src/core-components/form-field.js | 9 +++-- client/src/lib-core/APIUtils.js | 3 +- 6 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 client/src/core-components/file-uploader.js create mode 100644 client/src/core-components/file-uploader.scss 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 83b012bc..f8898b8f 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 @@ -56,6 +56,9 @@ class CreateTicketForm extends React.Component { }}/>
+
+ +
{(!this.props.userLogged) ? this.renderCaptcha() : null} Create Ticket diff --git a/client/src/app/main/dashboard/dashboard-create-ticket/create-ticket-form.scss b/client/src/app/main/dashboard/dashboard-create-ticket/create-ticket-form.scss index 045c290c..bc7d906e 100644 --- a/client/src/app/main/dashboard/dashboard-create-ticket/create-ticket-form.scss +++ b/client/src/app/main/dashboard/dashboard-create-ticket/create-ticket-form.scss @@ -1,5 +1,9 @@ .create-ticket-form { + &__file { + text-align: left; + } + &__message { margin-top: 20px; } diff --git a/client/src/core-components/file-uploader.js b/client/src/core-components/file-uploader.js new file mode 100644 index 00000000..c18771ad --- /dev/null +++ b/client/src/core-components/file-uploader.js @@ -0,0 +1,40 @@ +import React from 'react'; + +import Button from 'core-components/button'; +import Icon from 'core-components/icon'; + +class FileUploader extends React.Component { + static propTypes = { + text: React.PropTypes.string, + value: React.PropTypes.object, + onChange: React.PropTypes.func + }; + + static defaultProps = { + text: 'Upload file' + }; + + render() { + return ( + + ); + } + + onChange(event) { + if(this.props.onChange) { + this.props.onChange({ + target: { + value: event.target.files[0] + } + }); + } + } +} + +export default FileUploader; \ No newline at end of file diff --git a/client/src/core-components/file-uploader.scss b/client/src/core-components/file-uploader.scss new file mode 100644 index 00000000..b6c766e7 --- /dev/null +++ b/client/src/core-components/file-uploader.scss @@ -0,0 +1,31 @@ +@import "../scss/vars"; + +.file-uploader { + + &__input { + width: 0.1px; + height: 0.1px; + opacity: 0; + overflow: hidden; + position: absolute; + z-index: -1; + } + + &__custom { + display: inline-block; + cursor: pointer; + color: white; + background-color: $primary-red; + line-height: 35px; + padding: 0 15px; + } + + &__icon { + margin-right: 15px; + } + + &__value { + margin-left: 10px; + color: $dark-grey; + } +} \ No newline at end of file diff --git a/client/src/core-components/form-field.js b/client/src/core-components/form-field.js index c913e959..d12dbe47 100644 --- a/client/src/core-components/form-field.js +++ b/client/src/core-components/form-field.js @@ -9,6 +9,7 @@ import Checkbox from 'core-components/checkbox'; import CheckboxGroup from 'core-components/checkbox-group'; import TextEditor from 'core-components/text-editor'; import InfoTooltip from 'core-components/info-tooltip'; +import FileUploader from 'core-components/file-uploader'; class FormField extends React.Component { static contextTypes = { @@ -24,7 +25,7 @@ class FormField extends React.Component { error: React.PropTypes.string, infoMessage: React.PropTypes.node, value: React.PropTypes.any, - field: React.PropTypes.oneOf(['input', 'textarea', 'select', 'checkbox', 'checkbox-group']), + field: React.PropTypes.oneOf(['input', 'textarea', 'select', 'checkbox', 'checkbox-group', 'file']), fieldProps: React.PropTypes.object }; @@ -84,7 +85,8 @@ class FormField extends React.Component { 'textarea': TextEditor, 'select': DropDown, 'checkbox': Checkbox, - 'checkbox-group': CheckboxGroup + 'checkbox-group': CheckboxGroup, + 'file': FileUploader }[this.props.field]; if(this.props.decorator) { @@ -142,7 +144,8 @@ class FormField extends React.Component { getDivTypes() { return [ 'textarea', - 'checkbox-group' + 'checkbox-group', + 'file' ]; } diff --git a/client/src/lib-core/APIUtils.js b/client/src/lib-core/APIUtils.js index 2ba05eea..65b52ae6 100644 --- a/client/src/lib-core/APIUtils.js +++ b/client/src/lib-core/APIUtils.js @@ -9,7 +9,8 @@ const APIUtils = { url: path, method: method, data: data, - dataType: 'json' + processData: false, + contentType: false }) .done(resolve) .fail((jqXHR, textStatus) => { From 7022dfeabfa0eabe1995cf0c28e4326e26964e12 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 14 Jan 2017 17:20:04 -0300 Subject: [PATCH 25/84] Max Red - Showing real data in graph taken from fixtures [skip ci] --- .../dashboard/admin-panel-stats-chart.js | 14 ++-- .../panel/dashboard/admin-panel-stats.js | 78 +++++++++++++++++-- client/src/data/fixtures/system-fixtures.js | 28 +++---- 3 files changed, 93 insertions(+), 27 deletions(-) diff --git a/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js b/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js index d62cc729..3e6c582b 100644 --- a/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js +++ b/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js @@ -8,13 +8,13 @@ class StatsChart extends React.Component { static propTypes = { strokes: React.PropTypes.arrayOf(React.PropTypes.shape({ name: React.PropTypes.string, + show: React.PropTypes.bool, values: React.PropTypes.arrayOf(React.PropTypes.shape({ date: React.PropTypes.string, - show: React.PropTypes.bool, value: React.PropTypes.number })) })), - display: React.PropTypes.number + period: React.PropTypes.number }; render() { @@ -56,7 +56,7 @@ class StatsChart extends React.Component { datasets.push(dataset); } - + return { labels: labels, datasets: datasets @@ -67,7 +67,7 @@ class StatsChart extends React.Component { let months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; let labels = []; - for (let i = 0; i < this.props.display; i++) { + for (let i = 0; i < this.props.period; i++) { let firstList = this.props.strokes[0]; let idx = firstList.values[i].date.slice(4, 6) - 1; labels.push( firstList.values[i].date.slice(6, 8) + ' ' + months[idx]); @@ -77,9 +77,9 @@ class StatsChart extends React.Component { } hitRadius() { - if (this.props.display === 7) return 20; - if (this.props.display === 30) return 15; - if (this.props.display === 90) return 10; + if (this.props.period === 7) return 20; + if (this.props.period === 30) return 15; + if (this.props.period === 90) return 10; return 3; } diff --git a/client/src/app/admin/panel/dashboard/admin-panel-stats.js b/client/src/app/admin/panel/dashboard/admin-panel-stats.js index 5b24047a..74843f6a 100644 --- a/client/src/app/admin/panel/dashboard/admin-panel-stats.js +++ b/client/src/app/admin/panel/dashboard/admin-panel-stats.js @@ -1,4 +1,5 @@ import React from 'react'; +import _ from 'lodash'; import i18n from 'lib-app/i18n'; import API from 'lib-app/api-call'; @@ -17,7 +18,30 @@ class AdminPanelStats extends React.Component { 'CREATE_TICKET': 0, 'SIGNUP': 0, 'COMMENT': 0 - } + }, + strokes: [ + { + name: 'CLOSE', + show: true, + values: [] + }, + { + name: 'CREATE_TICKET', + show: true, + values: [] + }, + { + name: 'SIGNUP', + show: true, + values: [] + }, + { + name: 'COMMENT', + show: true, + values: [] + } + ], + period: 0 }; componentDidMount() { @@ -36,7 +60,6 @@ class AdminPanelStats extends React.Component { } getToggleListProps() { - console.log('LALA: ' + this.state.stats); return { items: [ { @@ -95,9 +118,14 @@ class AdminPanelStats extends React.Component { } getStatsChartProps() { + + console.log('This is the shit'); + console.log(this.state.strokes); + return { - display: 7, - strokes: [ + period: this.state.period, + strokes: this.state.strokes + /*strokes: [ { name: 'COMMENT', show: true, @@ -200,7 +228,7 @@ class AdminPanelStats extends React.Component { } ] } - ] + ]*/ } } @@ -212,16 +240,54 @@ class AdminPanelStats extends React.Component { } onRetrieveSuccess(result) { + let newState = { 'CLOSE': 0, 'CREATE_TICKET': 0, 'SIGNUP': 0, 'COMMENT': 0 }; + + let ID = { + 'CLOSE': 0, + 'CREATE_TICKET': 1, + 'SIGNUP': 2, + 'COMMENT': 3 + }; + + let newStrokes = [ + { + name: 'CLOSE', + show: true, + values: [] + }, + { + name: 'CREATE_TICKET', + show: true, + values: [] + }, + { + name: 'SIGNUP', + show: true, + values: [] + }, + { + name: 'COMMENT', + show: true, + values: [] + } + ]; + for (let i = 0; i < result.data.length; i++) { newState[result.data[i].type] += result.data[i].value * 1; + + newStrokes[ ID[result.data[i].type] ].values.push({ + date: result.data[i].date, + value: result.data[i].value * 1 + }); } - this.setState({stats: newState}); + + this.setState({stats: newState, strokes: newStrokes, period: 7}); } } diff --git a/client/src/data/fixtures/system-fixtures.js b/client/src/data/fixtures/system-fixtures.js index 57db8e0a..76200c6c 100644 --- a/client/src/data/fixtures/system-fixtures.js +++ b/client/src/data/fixtures/system-fixtures.js @@ -246,55 +246,55 @@ module.exports = [ "date": "20170109", "type": "SIGNUP", "general": "1", - "value": "0" + "value": "7" }, { "date": "20170109", "type": "CLOSE", "general": "1", - "value": "0" + "value": "4" }, { "date": "20170109", "type": "CREATE_TICKET", "general": "1", - "value": "0" + "value": "9" }, { "date": "20170108", "type": "COMMENT", "general": "1", - "value": "0" + "value": "8" }, { "date": "20170108", "type": "SIGNUP", "general": "1", - "value": "0" + "value": "4" }, { "date": "20170108", "type": "CLOSE", "general": "1", - "value": "0" + "value": "5" }, { "date": "20170108", "type": "CREATE_TICKET", "general": "1", - "value": "0" + "value": "6" }, { "date": "20170107", "type": "COMMENT", "general": "1", - "value": "0" + "value": "4" }, { "date": "20170107", "type": "SIGNUP", "general": "1", - "value": "0" + "value": "1" }, { "date": "20170107", @@ -306,31 +306,31 @@ module.exports = [ "date": "20170107", "type": "CREATE_TICKET", "general": "1", - "value": "0" + "value": "2" }, { "date": "20170106", "type": "COMMENT", "general": "1", - "value": "0" + "value": "7" }, { "date": "20170106", "type": "SIGNUP", "general": "1", - "value": "0" + "value": "4" }, { "date": "20170106", "type": "CLOSE", "general": "1", - "value": "0" + "value": "5" }, { "date": "20170106", "type": "CREATE_TICKET", "general": "1", - "value": "0" + "value": "5" } ] }; From 6eae5f929989032fce606f048b52cac559845269 Mon Sep 17 00:00:00 2001 From: AntonyAntonio Date: Sat, 14 Jan 2017 18:19:21 -0300 Subject: [PATCH 26/84] Guillermo - csv import [skip ci] --- server/controllers/system.php | 2 ++ server/controllers/system/csv-import.php | 46 ++++++++++++++++++++++++ server/controllers/user/signup.php | 31 +++++++++------- server/index.php | 2 ++ server/libs/Controller.php | 17 +++++++-- 5 files changed, 83 insertions(+), 15 deletions(-) create mode 100644 server/controllers/system/csv-import.php diff --git a/server/controllers/system.php b/server/controllers/system.php index 2f2c65c6..78163f11 100644 --- a/server/controllers/system.php +++ b/server/controllers/system.php @@ -16,6 +16,7 @@ require_once 'system/add-api-key.php'; require_once 'system/delete-api-key.php'; require_once 'system/get-all-keys.php'; require_once 'system/delete-all-users.php'; +require_once 'system/csv-import.php'; $systemControllerGroup = new ControllerGroup(); $systemControllerGroup->setGroupPath('/system'); @@ -37,5 +38,6 @@ $systemControllerGroup->addController(new AddAPIKeyController); $systemControllerGroup->addController(new DeleteAPIKeyController); $systemControllerGroup->addController(new GetAllKeyController); $systemControllerGroup->addController(new DeleteAllUsersController); +$systemControllerGroup->addController(new CSVImportController); $systemControllerGroup->finalize(); \ No newline at end of file diff --git a/server/controllers/system/csv-import.php b/server/controllers/system/csv-import.php new file mode 100644 index 00000000..daa0a99a --- /dev/null +++ b/server/controllers/system/csv-import.php @@ -0,0 +1,46 @@ + 'staff_3', + 'requestData' => [] + ]; + } + + public function handler() { + $file = fopen("Hoja1.csv","r"); + $errors = []; + + while(!feof($file)) { + $userList = fgetcsv($file); + + Controller::setDataRequester(function ($key) use ($userList) { + switch ($key) { + case 'email': + return $userList[0]; + case 'password': + return $userList[1]; + case 'name': + return $userList[2]; + } + + return null; + }); + + $signupController = new SignUpController(true); + + try { + $signupController->validate(); + $signupController->handler(); + } catch (\Exception $exception) { + $errors[] = $exception->getMessage() . ' in email ' . $userList[0]; + } + } + + fclose($file); + Response::respondSuccess($errors); + } +} \ No newline at end of file diff --git a/server/controllers/user/signup.php b/server/controllers/user/signup.php index cee72f1b..567c7b21 100644 --- a/server/controllers/user/signup.php +++ b/server/controllers/user/signup.php @@ -10,9 +10,14 @@ class SignUpController extends Controller { private $userName; private $userPassword; private $verificationToken; + private $csvImported; + + public function __construct($csvImported = false) { + $this->csvImported = $csvImported; + } public function validations() { - return [ + $validations = [ 'permission' => 'any', 'requestData' => [ 'name' => [ @@ -26,13 +31,18 @@ class SignUpController extends Controller { 'password' => [ 'validation' => DataValidator::length(5, 200), 'error' => ERRORS::INVALID_PASSWORD - ], - 'captcha' => [ - 'validation' => DataValidator::captcha(), - 'error' => ERRORS::INVALID_CAPTCHA ] ] ]; + + if(!$this->csvImported) { + $validations['requestData']['captcha'] = [ + 'validation' => DataValidator::captcha(), + 'error' => ERRORS::INVALID_CAPTCHA + ]; + } + + return $validations; } public function handler() { @@ -42,19 +52,16 @@ class SignUpController extends Controller { $existentUser = User::getUser($this->userEmail, 'email'); if (!$existentUser->isNull()) { - Response::respondError(ERRORS::USER_EXISTS); - return; + throw new Exception(ERRORS::USER_EXISTS); } $banRow = Ban::getDataStore($this->userEmail,'email'); if (!$banRow->isNull()) { - Response::respondError(ERRORS::ALREADY_BANNED); - return; + throw new Exception(ERRORS::ALREADY_BANNED); } - if (!Setting::getSetting('registration')->value && $apiKey->isNull() ) { - Response::respondError(ERRORS::NO_PERMISSION); - return; + if (!Setting::getSetting('registration')->value && $apiKey->isNull() && !$this->csvImported) { + throw new Exception(ERRORS::NO_PERMISSION); } $userId = $this->createNewUserAndRetrieveId(); diff --git a/server/index.php b/server/index.php index a9056e1e..040d3680 100644 --- a/server/index.php +++ b/server/index.php @@ -19,6 +19,8 @@ include_once 'libs/MailSender.php'; include_once 'libs/Date.php'; include_once 'libs/DataStoreList.php'; +Controller::init(); + // LOAD DATA spl_autoload_register(function ($class) { $classPath = "data/{$class}.php"; diff --git a/server/libs/Controller.php b/server/libs/Controller.php index 3c8a3ca9..b3bfdef8 100644 --- a/server/libs/Controller.php +++ b/server/libs/Controller.php @@ -3,6 +3,7 @@ require_once 'libs/Validator.php'; require_once 'models/Session.php'; abstract class Controller { + private static $dataRequester; /** * Instance-related stuff @@ -28,10 +29,20 @@ abstract class Controller { $validator->validate($this->validations()); } - public static function request($key) { - $app = self::getAppInstance(); + public static function init() { + self::$dataRequester = function ($key) { + $app = self::getAppInstance(); - return $app->request()->post($key); + return $app->request()->post($key); + }; + } + + public static function setDataRequester($dataRequester) { + self::$dataRequester = $dataRequester; + } + + public static function request($key) { + return call_user_func(self::$dataRequester, $key); } public static function getLoggedUser() { From 9861bfb0234f1b74ebfa22d35ac765228667158a Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 14 Jan 2017 18:41:19 -0300 Subject: [PATCH 27/84] Max Red - Added functionality to dropdown [skip ci] --- .../dashboard/admin-panel-stats-chart.js | 4 +- .../panel/dashboard/admin-panel-stats.js | 162 +++++------------- client/src/data/fixtures/system-fixtures.js | 48 +++++- 3 files changed, 93 insertions(+), 121 deletions(-) diff --git a/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js b/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js index 3e6c582b..52d25748 100644 --- a/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js +++ b/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js @@ -44,7 +44,7 @@ class StatsChart extends React.Component { label: i18n('CHART_' + stroke.name), data: stroke.values.map((val) => val.value), fill: false, - borderWidth: 4, + borderWidth: 4, // ESTO PODRIA CAMBIAR DEPENDIENDO DEL PERIOD, MIENTRA MAS HALLA, DEBERIA SER MAS FINO borderColor: color[stroke.name], pointBorderColor: color[stroke.name], pointRadius: 0, @@ -80,7 +80,7 @@ class StatsChart extends React.Component { if (this.props.period === 7) return 20; if (this.props.period === 30) return 15; if (this.props.period === 90) return 10; - return 3; + return 1; } getChartOptions() { diff --git a/client/src/app/admin/panel/dashboard/admin-panel-stats.js b/client/src/app/admin/panel/dashboard/admin-panel-stats.js index 74843f6a..f84956a2 100644 --- a/client/src/app/admin/panel/dashboard/admin-panel-stats.js +++ b/client/src/app/admin/panel/dashboard/admin-panel-stats.js @@ -45,7 +45,7 @@ class AdminPanelStats extends React.Component { }; componentDidMount() { - this.retrieve(); + this.retrieve(7); } render() { @@ -90,10 +90,15 @@ class AdminPanelStats extends React.Component {
{i18n('CHART_COMMENT')}
} - ] + ], + onChange: this.onToggleListChange.bind(this) }; } + onToggleListChange(data) { + + } + getDropDownProps() { return { items: [ @@ -113,133 +118,58 @@ class AdminPanelStats extends React.Component { content: 'Last 365 days', icon: '' } - ] + ], + onChange: this.onDropDownChange.bind(this) } } + onDropDownChange(event) { + console.log('DROP DOWN HAS CHANGED'); + let val = [7, 30, 90, 365]; + + this.retrieve(val[event.index]); + } + getStatsChartProps() { - - console.log('This is the shit'); - console.log(this.state.strokes); - return { period: this.state.period, strokes: this.state.strokes - /*strokes: [ - { - name: 'COMMENT', - show: true, - values: [ - { - date: "20160420", - value: 17 - }, - { - date: "20160421", - value: 15 - }, - { - date: "20160422", - value: 12 - }, - { - date: "20160423", - value: 9 - }, - { - date: "20160424", - value: 10 - }, - { - date: "20160425", - value: 7 - }, - { - date: "20160426", - value: 5 - } - ] - }, - { - name: 'SIGNUP', - show: true, - values: [ - { - date: "20160420", - value: 3 - }, - { - date: "20160421", - value: 5 - }, - { - date: "20160422", - value: 3 - }, - { - date: "20160423", - value: 4 - }, - { - date: "20160424", - value: 5 - }, - { - date: "20160425", - value: 5 - }, - { - date: "20160426", - value: 6 - } - ] - }, - { - name: 'CLOSE', - show: true, - values: [ - { - date: "20160420", - value: 4 - }, - { - date: "20160421", - value: 7 - }, - { - date: "20160422", - value: 4 - }, - { - date: "20160423", - value: 7 - }, - { - date: "20160424", - value: 9 - }, - { - date: "20160425", - value: 11 - }, - { - date: "20160426", - value: 13 - } - ] - } - ]*/ } } - retrieve() { + retrieve(period) { + console.log('THIS SHOULD NOT BE DISPLAYED'); + + let periodName; + switch (period) { + case 30: + periodName = 'MONTH'; + break; + case 90: + periodName = 'QUARTER'; + break; + case 365: + periodName = 'YEAR'; + break; + default: + periodName = 'WEEK'; + } + + console.log('--------------------------------------------period: ' + this.state.period); + console.log('--------------------------------------------PERIOD NAME: ' + periodName); + API.call({ path: '/system/get-stats', - data: {} - }).then(this.onRetrieveSuccess.bind(this)); + data: { + period: periodName + } + }).then(this.onRetrieveSuccess.bind(this, period)); } - onRetrieveSuccess(result) { + onRetrieveSuccess(period, result) { + + console.log('This is the shit you SHOULD look at!'); + console.log(result); let newState = { 'CLOSE': 0, @@ -287,7 +217,7 @@ class AdminPanelStats extends React.Component { }); } - this.setState({stats: newState, strokes: newStrokes, period: 7}); + this.setState({stats: newState, strokes: newStrokes, period: period}); } } diff --git a/client/src/data/fixtures/system-fixtures.js b/client/src/data/fixtures/system-fixtures.js index 76200c6c..06b087fd 100644 --- a/client/src/data/fixtures/system-fixtures.js +++ b/client/src/data/fixtures/system-fixtures.js @@ -160,10 +160,52 @@ module.exports = [ { path: '/system/get-stats', time: 200, - response: function() { + response: function(_data) { + let ID = { + 'WEEK': 7, + 'MONTH': 30, + 'QUARTER': 90, + 'YEAR': 365 + }; + + let k = ID[_data.period]; + let DATA = []; + + for (let i = 0; i < k; i++) { + DATA.push({ + date: '201701' + (i + 10) % 100, + type: 'COMMENT', + general: 1, + value: (4 + i + Math.floor(Math.random() * 2)).toString() + }); + DATA.push({ + date: '201701' + (i + 10) % 100, + type: 'SIGNUP', + general: 1, + value: (9 + i + Math.floor(Math.random() * (i / 15))).toString() + }); + DATA.push({ + date: '201701' + (i + 10) % 100, + type: 'CLOSE', + general: 1, + value: (8 + i + Math.floor(Math.random() * i)).toString() + }); + DATA.push({ + date: '201701' + (i + 10) % 100, + type: 'CREATE_TICKET', + general: 1, + value: (10 + Math.floor(Math.random() * 4)).toString() + }); + } + + console.log('DATA:'); + console.log(DATA); + console.log(k); + return { status: "success", - data: [ + data: DATA + /*data: [ { "date": "20170112", "type": "COMMENT", @@ -332,7 +374,7 @@ module.exports = [ "general": "1", "value": "5" } - ] + ]*/ }; } }, From 19f25657ef324ea6b85f43d32103ba7a859f930b Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 14 Jan 2017 18:47:04 -0300 Subject: [PATCH 28/84] Max Red - Corrected to work even if the response of system/get-stats is not the full week/month/year etc.. [skip ci] --- .../admin/panel/dashboard/admin-panel-stats-chart.js | 12 ++++++++---- .../app/admin/panel/dashboard/admin-panel-stats.js | 4 +++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js b/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js index 52d25748..64b0df74 100644 --- a/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js +++ b/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js @@ -44,7 +44,7 @@ class StatsChart extends React.Component { label: i18n('CHART_' + stroke.name), data: stroke.values.map((val) => val.value), fill: false, - borderWidth: 4, // ESTO PODRIA CAMBIAR DEPENDIENDO DEL PERIOD, MIENTRA MAS HALLA, DEBERIA SER MAS FINO + borderWidth: this.getBorderWidth(), borderColor: color[stroke.name], pointBorderColor: color[stroke.name], pointRadius: 0, @@ -63,6 +63,10 @@ class StatsChart extends React.Component { }; } + getBorderWidth() { + return (this.props.period <= 90) ? 4 : 2; + } + getLabels() { let months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; let labels = []; @@ -77,9 +81,9 @@ class StatsChart extends React.Component { } hitRadius() { - if (this.props.period === 7) return 20; - if (this.props.period === 30) return 15; - if (this.props.period === 90) return 10; + if (this.props.period <= 7) return 20; + if (this.props.period <= 30) return 15; + if (this.props.period <= 90) return 10; return 1; } diff --git a/client/src/app/admin/panel/dashboard/admin-panel-stats.js b/client/src/app/admin/panel/dashboard/admin-panel-stats.js index f84956a2..ab5d1d5f 100644 --- a/client/src/app/admin/panel/dashboard/admin-panel-stats.js +++ b/client/src/app/admin/panel/dashboard/admin-panel-stats.js @@ -208,6 +208,8 @@ class AdminPanelStats extends React.Component { } ]; + let realPeriod = result.data.length / 4; + for (let i = 0; i < result.data.length; i++) { newState[result.data[i].type] += result.data[i].value * 1; @@ -217,7 +219,7 @@ class AdminPanelStats extends React.Component { }); } - this.setState({stats: newState, strokes: newStrokes, period: period}); + this.setState({stats: newState, strokes: newStrokes, period: realPeriod}); } } From fd2c20ac9fccbbaf3c9403141e6d1672b0de9b90 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 14 Jan 2017 21:31:02 -0300 Subject: [PATCH 29/84] Max Red - Added all functionality to the component [skip ci] --- .../dashboard/admin-panel-stats-chart.js | 17 ++++-- .../panel/dashboard/admin-panel-stats.js | 59 ++++++++++--------- client/src/core-components/toggle-list.js | 10 +++- client/src/data/fixtures/system-fixtures.js | 4 +- 4 files changed, 50 insertions(+), 40 deletions(-) diff --git a/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js b/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js index 64b0df74..8ff25b1f 100644 --- a/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js +++ b/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js @@ -8,19 +8,19 @@ class StatsChart extends React.Component { static propTypes = { strokes: React.PropTypes.arrayOf(React.PropTypes.shape({ name: React.PropTypes.string, - show: React.PropTypes.bool, values: React.PropTypes.arrayOf(React.PropTypes.shape({ date: React.PropTypes.string, value: React.PropTypes.number })) })), + //showed: React.PropTypes.arrayOf(React.PropTypes.bool), period: React.PropTypes.number }; render() { return (
- +
); } @@ -48,10 +48,10 @@ class StatsChart extends React.Component { borderColor: color[stroke.name], pointBorderColor: color[stroke.name], pointRadius: 0, + pointHoverRadius: 3, lineTension: 0.2, pointHoverBackgroundColor: color[stroke.name], - hitRadius: this.hitRadius(), - showLine: stroke.show + hitRadius: this.hitRadius(i) }; datasets.push(dataset); @@ -72,6 +72,10 @@ class StatsChart extends React.Component { let labels = []; for (let i = 0; i < this.props.period; i++) { + if (!this.props.strokes.length){ + labels.push(''); + continue; + } let firstList = this.props.strokes[0]; let idx = firstList.values[i].date.slice(4, 6) - 1; labels.push( firstList.values[i].date.slice(6, 8) + ' ' + months[idx]); @@ -80,11 +84,12 @@ class StatsChart extends React.Component { return labels; } - hitRadius() { + hitRadius(index) { + //if (!this.props.showed[index]) return 0; if (this.props.period <= 7) return 20; if (this.props.period <= 30) return 15; if (this.props.period <= 90) return 10; - return 1; + return 3; } getChartOptions() { diff --git a/client/src/app/admin/panel/dashboard/admin-panel-stats.js b/client/src/app/admin/panel/dashboard/admin-panel-stats.js index ab5d1d5f..16a97c5b 100644 --- a/client/src/app/admin/panel/dashboard/admin-panel-stats.js +++ b/client/src/app/admin/panel/dashboard/admin-panel-stats.js @@ -14,33 +14,30 @@ class AdminPanelStats extends React.Component { state = { stats: { - 'CLOSE': 0, 'CREATE_TICKET': 0, + 'CLOSE': 0, 'SIGNUP': 0, 'COMMENT': 0 }, strokes: [ { - name: 'CLOSE', - show: true, + name: 'CREATE_TICKET', values: [] }, { - name: 'CREATE_TICKET', - show: true, + name: 'CLOSE', values: [] }, { name: 'SIGNUP', - show: true, values: [] }, { name: 'COMMENT', - show: true, values: [] } ], + showed: [0], period: 0 }; @@ -61,6 +58,7 @@ class AdminPanelStats extends React.Component { getToggleListProps() { return { + values: this.state.showed, items: [ { content: @@ -95,8 +93,10 @@ class AdminPanelStats extends React.Component { }; } - onToggleListChange(data) { - + onToggleListChange(event) { + this.setState({ + showed: event.target.value + }); } getDropDownProps() { @@ -124,22 +124,23 @@ class AdminPanelStats extends React.Component { } onDropDownChange(event) { - console.log('DROP DOWN HAS CHANGED'); let val = [7, 30, 90, 365]; this.retrieve(val[event.index]); } getStatsChartProps() { + let showed = this.getShowedArray(); + return { period: this.state.period, - strokes: this.state.strokes - } + strokes: _.filter(this.state.strokes, (s, i) => showed[i]) + //strokes: this.state.strokes, + //showed: this.getShowedArray() + }; } retrieve(period) { - console.log('THIS SHOULD NOT BE DISPLAYED'); - let periodName; switch (period) { case 30: @@ -155,9 +156,6 @@ class AdminPanelStats extends React.Component { periodName = 'WEEK'; } - console.log('--------------------------------------------period: ' + this.state.period); - console.log('--------------------------------------------PERIOD NAME: ' + periodName); - API.call({ path: '/system/get-stats', data: { @@ -168,42 +166,35 @@ class AdminPanelStats extends React.Component { onRetrieveSuccess(period, result) { - console.log('This is the shit you SHOULD look at!'); - console.log(result); - let newState = { - 'CLOSE': 0, 'CREATE_TICKET': 0, + 'CLOSE': 0, 'SIGNUP': 0, 'COMMENT': 0 }; let ID = { - 'CLOSE': 0, - 'CREATE_TICKET': 1, + 'CREATE_TICKET': 0, + 'CLOSE': 1, 'SIGNUP': 2, 'COMMENT': 3 }; let newStrokes = [ { - name: 'CLOSE', - show: true, + name: 'CREATE_TICKET', values: [] }, { - name: 'CREATE_TICKET', - show: true, + name: 'CLOSE', values: [] }, { name: 'SIGNUP', - show: true, values: [] }, { name: 'COMMENT', - show: true, values: [] } ]; @@ -221,6 +212,16 @@ class AdminPanelStats extends React.Component { this.setState({stats: newState, strokes: newStrokes, period: realPeriod}); } + + getShowedArray() { + let showed = [false, false, false, false]; + + for (let i = 0; i < showed.length; i++) { + showed[this.state.showed[i]] = true; + } + + return showed; + } } export default AdminPanelStats; \ No newline at end of file diff --git a/client/src/core-components/toggle-list.js b/client/src/core-components/toggle-list.js index 8dba39a7..b38defe0 100644 --- a/client/src/core-components/toggle-list.js +++ b/client/src/core-components/toggle-list.js @@ -35,16 +35,16 @@ class ToggleList extends React.Component { let classes = { 'toggle-list__item': true, 'toggle-list__first-item': (index === 0), - 'toggle-list__selected': _.includes(this.state.selected, index) + 'toggle-list__selected': _.includes(this.getSelectedList(), index) }; return classNames(classes); } selectItem(index) { - let newSelected = _.clone(this.state.selected); + let newSelected = _.clone(this.getSelectedList()); - _.includes(this.state.selected, index) ? _.remove(newSelected, _index => _index == index) : newSelected.push(index); + _.includes(this.getSelectedList(), index) ? _.remove(newSelected, _index => _index == index) : newSelected.push(index); this.setState({ selected: newSelected @@ -58,6 +58,10 @@ class ToggleList extends React.Component { }); } } + + getSelectedList() { + return (this.props.values === undefined) ? this.state.selected : this.props.values; + } } export default ToggleList; diff --git a/client/src/data/fixtures/system-fixtures.js b/client/src/data/fixtures/system-fixtures.js index 06b087fd..9d329319 100644 --- a/client/src/data/fixtures/system-fixtures.js +++ b/client/src/data/fixtures/system-fixtures.js @@ -182,13 +182,13 @@ module.exports = [ date: '201701' + (i + 10) % 100, type: 'SIGNUP', general: 1, - value: (9 + i + Math.floor(Math.random() * (i / 15))).toString() + value: (9 + i + Math.floor(Math.random() * (i * 15))).toString() }); DATA.push({ date: '201701' + (i + 10) % 100, type: 'CLOSE', general: 1, - value: (8 + i + Math.floor(Math.random() * i)).toString() + value: (8 + i + Math.floor(Math.random() * i * i * i * i)).toString() }); DATA.push({ date: '201701' + (i + 10) % 100, From 35d9a166cfbe28c212e9873f97cb6f356686d4d9 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Sat, 14 Jan 2017 21:44:20 -0300 Subject: [PATCH 30/84] Ivan - Add file download component [skip ci] --- client/src/app-components/ticket-event.js | 22 ++++++++++++++++++-- client/src/app-components/ticket-event.scss | 8 +++++++ client/src/app-components/ticket-viewer.js | 5 ++++- client/src/app-components/ticket-viewer.scss | 7 ------- client/src/data/fixtures/system-fixtures.js | 8 +++++++ client/src/data/fixtures/user-fixtures.js | 8 +++---- client/src/lib-app/api-call.js | 4 ++-- client/src/lib-app/fixtures-loader.js | 2 +- server/controllers/system/download.php | 2 +- 9 files changed, 48 insertions(+), 18 deletions(-) diff --git a/client/src/app-components/ticket-event.js b/client/src/app-components/ticket-event.js index bdcd9b2e..719f417d 100644 --- a/client/src/app-components/ticket-event.js +++ b/client/src/app-components/ticket-event.js @@ -2,6 +2,7 @@ import React from 'react'; import classNames from 'classnames'; import i18n from 'lib-app/i18n'; +import API from 'lib-app/api-call'; import DateTransformer from 'lib-core/date-transformer'; import Icon from 'core-components/icon'; @@ -161,7 +162,7 @@ class TicketEvent extends React.Component { } return ( -
+
{node}
) @@ -222,9 +223,26 @@ class TicketEvent extends React.Component { const fileName = filePath.replace(/^.*[\\\/]/, ''); return ( - {fileName} + {fileName} ) } + + onFileClick(filePath) { + API.call({ + path: '/system/download', + plain: true, + data: { + file: filePath + } + }).then((result) => { + let contentType = 'application/octet-stream'; + let link = document.createElement('a'); + let blob = new Blob([result], {'type': contentType}); + link.href = window.URL.createObjectURL(blob); + link.download = filePath; + link.click(); + }); + } } export default TicketEvent; diff --git a/client/src/app-components/ticket-event.scss b/client/src/app-components/ticket-event.scss index 50105bbe..328d16e1 100644 --- a/client/src/app-components/ticket-event.scss +++ b/client/src/app-components/ticket-event.scss @@ -91,6 +91,14 @@ } } + &__file { + background-color: $very-light-grey; + cursor: pointer; + text-align: right; + padding: 5px 10px; + font-size: 12px; + } + &_staff { .ticket-event__icon { background-color: $primary-blue; diff --git a/client/src/app-components/ticket-viewer.js b/client/src/app-components/ticket-viewer.js index 6b6f1362..c00b875a 100644 --- a/client/src/app-components/ticket-viewer.js +++ b/client/src/app-components/ticket-viewer.js @@ -190,6 +190,7 @@ class TicketViewer extends React.Component {
+ {i18n('RESPOND_TICKET')}
@@ -234,10 +235,12 @@ class TicketViewer extends React.Component { loading: this.state.loading, onChange: (formState) => {this.setState({ commentValue: formState.content, + commentFile: formState.file, commentEdited: true })}, values: { - 'content': this.state.commentValue + 'content': this.state.commentValue, + 'file': this.state.commentFile } }; } diff --git a/client/src/app-components/ticket-viewer.scss b/client/src/app-components/ticket-viewer.scss index 9f03fbf7..2a6658ed 100644 --- a/client/src/app-components/ticket-viewer.scss +++ b/client/src/app-components/ticket-viewer.scss @@ -48,13 +48,6 @@ margin-top: 10px; } - &__file { - background-color: $very-light-grey; - text-align: right; - padding: 5px 10px; - font-size: 12px; - } - &__comments { position: relative; } diff --git a/client/src/data/fixtures/system-fixtures.js b/client/src/data/fixtures/system-fixtures.js index b67d450f..ac2a5bbd 100644 --- a/client/src/data/fixtures/system-fixtures.js +++ b/client/src/data/fixtures/system-fixtures.js @@ -110,6 +110,14 @@ module.exports = [ }; } }, + { + path: '/system/download', + time: 100, + contentType: 'application/octet-stream', + response: function () { + return 'text content'; + } + }, { path: '/system/get-mail-templates', time: 100, diff --git a/client/src/data/fixtures/user-fixtures.js b/client/src/data/fixtures/user-fixtures.js index 484d7c95..2ff9801b 100644 --- a/client/src/data/fixtures/user-fixtures.js +++ b/client/src/data/fixtures/user-fixtures.js @@ -166,7 +166,7 @@ module.exports = [ name: 'Sales Support' }, date: '201504090001', - file: 'http://www.opensupports.com/some_file.zip', + file: 'some_file.txt', language: 'en', unread: false, closed: false, @@ -385,7 +385,7 @@ module.exports = [ name: 'Technical Issues' }, date: '201604161427', - file: 'http://www.opensupports.com/some_file.zip', + file: 'some_file.txt', language: 'en', unread: true, closed: false, @@ -504,7 +504,7 @@ module.exports = [ name: 'Sales Support' }, date: '201604150849', - file: 'http://www.opensupports.com/some_file.zip', + file: 'some_file.txt', language: 'en', unread: false, closed: false, @@ -607,7 +607,7 @@ module.exports = [ name: 'Sales Support' }, date: '201504091032', - file: 'http://www.opensupports.com/some_file.zip', + file: 'some_file.txt', language: 'en', unread: false, closed: false, diff --git a/client/src/lib-app/api-call.js b/client/src/lib-app/api-call.js index f65ba752..032c5bc0 100644 --- a/client/src/lib-app/api-call.js +++ b/client/src/lib-app/api-call.js @@ -12,13 +12,13 @@ function processData (data) { } module.exports = { - call: function ({path, data}) { + call: function ({path, data, plain}) { return new Promise(function (resolve, reject) { APIUtils.post(root + path, processData(data)) .then(function (result) { console.log(result); - if (result.status === 'success') { + if (plain || result.status === 'success') { resolve(result); } else if (reject) { reject(result); diff --git a/client/src/lib-app/fixtures-loader.js b/client/src/lib-app/fixtures-loader.js index 1850cb34..dc02c382 100644 --- a/client/src/lib-app/fixtures-loader.js +++ b/client/src/lib-app/fixtures-loader.js @@ -24,7 +24,7 @@ fixtures.add(require('data/fixtures/article-fixtures')); _.each(fixtures.getAll(), function (fixture) { mockjax({ - contentType: 'application/json', + contentType: fixture.contentType || 'application/json', url: 'http://localhost:3000/api' + fixture.path, responseTime: fixture.time || 500, response: function (settings) { diff --git a/server/controllers/system/download.php b/server/controllers/system/download.php index 8c6699b3..278ddc1b 100644 --- a/server/controllers/system/download.php +++ b/server/controllers/system/download.php @@ -10,7 +10,7 @@ class DownloadController extends Controller { 'permission' => 'user', 'requestData' => [ 'file' => [ - 'validation' => DataValidator::alnum('_.')->noWhitespace(), + 'validation' => DataValidator::alnum('_.-')->noWhitespace(), 'error' => ERRORS::INVALID_FILE ] ] From 575f34256aa6e7e77849e4acd53951a6b1db868d Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Sat, 14 Jan 2017 23:51:31 -0300 Subject: [PATCH 31/84] Ivan - Fix unit testing backend --- server/tests/__mocks__/APIKeyMock.php | 12 ++++++++++++ server/tests/__mocks__/UserMock.php | 2 ++ server/tests/libs/validations/captchaTest.php | 4 ++++ 3 files changed, 18 insertions(+) create mode 100644 server/tests/__mocks__/APIKeyMock.php diff --git a/server/tests/__mocks__/APIKeyMock.php b/server/tests/__mocks__/APIKeyMock.php new file mode 100644 index 00000000..7ef32d77 --- /dev/null +++ b/server/tests/__mocks__/APIKeyMock.php @@ -0,0 +1,12 @@ + parent::stub()->returns(new NullDataStore()), + )); + } +} \ No newline at end of file diff --git a/server/tests/__mocks__/UserMock.php b/server/tests/__mocks__/UserMock.php index c8edb25a..d7913a23 100644 --- a/server/tests/__mocks__/UserMock.php +++ b/server/tests/__mocks__/UserMock.php @@ -5,6 +5,7 @@ class User extends \Mock { public static function initStubs() { parent::setStatics(array( 'authenticate' => parent::stub()->returns(self::getUserInstanceMock()), + 'getDataStore' => parent::stub()->returns(self::getUserInstanceMock()) )); } @@ -18,6 +19,7 @@ class User extends \Mock { $mockUserInstance->id = 'MOCK_ID'; $mockUserInstance->email = 'MOCK_EMAIL'; $mockUserInstance->password = 'MOCK_PASSWORD'; + $mockUserInstance->verificationToken = null; return $mockUserInstance; } diff --git a/server/tests/libs/validations/captchaTest.php b/server/tests/libs/validations/captchaTest.php index e2e86eaf..c85bfcf7 100644 --- a/server/tests/libs/validations/captchaTest.php +++ b/server/tests/libs/validations/captchaTest.php @@ -2,6 +2,8 @@ include_once 'tests/__lib__/Mock.php'; include_once 'tests/__mocks__/RespectMock.php'; include_once 'tests/__mocks__/SettingMock.php'; +include_once 'tests/__mocks__/APIKeyMock.php'; +include_once 'tests/__mocks__/ControllerMock.php'; include_once 'tests/__mocks__/ReCaptchaMock.php'; include_once 'libs/validations/captcha.php'; @@ -10,6 +12,8 @@ class CaptchaValidationTest extends PHPUnit_Framework_TestCase { protected function setUp() { Setting::initStubs(); + Controller::initStubs(); + APIKey::initStubs(); \ReCaptcha\ReCaptcha::initVerify(); $_SERVER['REMOTE_ADDR'] = 'MOCK_REMOTE'; From 1f6e3ae0286a02a84529bc84e86703c02072c462 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 15 Jan 2017 00:07:02 -0300 Subject: [PATCH 32/84] Max Red - Added basic scss [skip ci] --- .../app/admin/panel/dashboard/admin-panel-stats.js | 10 ++++++---- .../app/admin/panel/dashboard/admin-panel-stats.scss | 11 +++++++++++ client/src/core-components/toggle-list.js | 11 ++++++++++- client/src/data/fixtures/system-fixtures.js | 8 ++++---- 4 files changed, 31 insertions(+), 9 deletions(-) create mode 100644 client/src/app/admin/panel/dashboard/admin-panel-stats.scss diff --git a/client/src/app/admin/panel/dashboard/admin-panel-stats.js b/client/src/app/admin/panel/dashboard/admin-panel-stats.js index 16a97c5b..84790d04 100644 --- a/client/src/app/admin/panel/dashboard/admin-panel-stats.js +++ b/client/src/app/admin/panel/dashboard/admin-panel-stats.js @@ -47,7 +47,7 @@ class AdminPanelStats extends React.Component { render() { return ( -
+
@@ -59,6 +59,8 @@ class AdminPanelStats extends React.Component { getToggleListProps() { return { values: this.state.showed, + className: 'admin-panel-stats__toggle-list', + onChange: this.onToggleListChange.bind(this), items: [ { content: @@ -88,8 +90,7 @@ class AdminPanelStats extends React.Component {
{i18n('CHART_COMMENT')}
} - ], - onChange: this.onToggleListChange.bind(this) + ] }; } @@ -119,7 +120,8 @@ class AdminPanelStats extends React.Component { icon: '' } ], - onChange: this.onDropDownChange.bind(this) + onChange: this.onDropDownChange.bind(this), + className: 'admin-panel-stats__dropdown' } } diff --git a/client/src/app/admin/panel/dashboard/admin-panel-stats.scss b/client/src/app/admin/panel/dashboard/admin-panel-stats.scss new file mode 100644 index 00000000..d020a3a5 --- /dev/null +++ b/client/src/app/admin/panel/dashboard/admin-panel-stats.scss @@ -0,0 +1,11 @@ +.admin-panel-stats { + + &__dropdown { + margin-left: auto; + margin-bottom: 20px; + } + + &__toggle-list { + margin-bottom: 20px; + } +} \ No newline at end of file diff --git a/client/src/core-components/toggle-list.js b/client/src/core-components/toggle-list.js index b38defe0..e5e70fbc 100644 --- a/client/src/core-components/toggle-list.js +++ b/client/src/core-components/toggle-list.js @@ -16,12 +16,21 @@ class ToggleList extends React.Component { render() { return ( -
+
{this.props.items.map(this.renderItem.bind(this))}
); } + getClass() { + let classes = { + 'toggle-list': true, + [this.props.className]: (this.props.className) + }; + + return classNames(classes); + } + renderItem(obj, index) { return ( diff --git a/client/src/data/fixtures/system-fixtures.js b/client/src/data/fixtures/system-fixtures.js index 9d329319..38ff3062 100644 --- a/client/src/data/fixtures/system-fixtures.js +++ b/client/src/data/fixtures/system-fixtures.js @@ -176,25 +176,25 @@ module.exports = [ date: '201701' + (i + 10) % 100, type: 'COMMENT', general: 1, - value: (4 + i + Math.floor(Math.random() * 2)).toString() + value: (Math.floor(Math.random() * i)).toString() }); DATA.push({ date: '201701' + (i + 10) % 100, type: 'SIGNUP', general: 1, - value: (9 + i + Math.floor(Math.random() * (i * 15))).toString() + value: (Math.floor(Math.random() * i * i / 365)).toString() }); DATA.push({ date: '201701' + (i + 10) % 100, type: 'CLOSE', general: 1, - value: (8 + i + Math.floor(Math.random() * i * i * i * i)).toString() + value: (Math.floor(Math.random() * i * i * i / 365 / 365)).toString() }); DATA.push({ date: '201701' + (i + 10) % 100, type: 'CREATE_TICKET', general: 1, - value: (10 + Math.floor(Math.random() * 4)).toString() + value: (Math.floor(Math.random()*Math.random()*Math.random()*Math.random()*Math.random()*1.05**i)).toString() }); } From e8e29d8701ff06228291fdd6bd95cca8cd5ef3ea Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Sun, 15 Jan 2017 01:36:04 -0300 Subject: [PATCH 33/84] Ivan - Fix static ticketevent --- server/models/APIKey.php | 1 + server/models/Ticketevent.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/server/models/APIKey.php b/server/models/APIKey.php index 2cfc3783..91218cac 100644 --- a/server/models/APIKey.php +++ b/server/models/APIKey.php @@ -9,6 +9,7 @@ class APIKey extends DataStore { 'token' ]; } + public function toArray() { return [ 'name' => $this->name, diff --git a/server/models/Ticketevent.php b/server/models/Ticketevent.php index 4bd7ebb1..a8a23fed 100644 --- a/server/models/Ticketevent.php +++ b/server/models/Ticketevent.php @@ -36,7 +36,7 @@ class Ticketevent extends DataStore { return $ticketEvent; } - public function getProps() { + public static function getProps() { return [ 'type', 'content', From 0500666174a4a30f6111a5fd3810f5492941121e Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 15 Jan 2017 15:07:07 -0300 Subject: [PATCH 34/84] Max Red - Added even more basic scss [skip ci] --- .../admin/panel/dashboard/admin-panel-stats.js | 13 +++++++++++-- .../admin/panel/dashboard/admin-panel-stats.scss | 16 ++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/client/src/app/admin/panel/dashboard/admin-panel-stats.js b/client/src/app/admin/panel/dashboard/admin-panel-stats.js index 84790d04..2252dc37 100644 --- a/client/src/app/admin/panel/dashboard/admin-panel-stats.js +++ b/client/src/app/admin/panel/dashboard/admin-panel-stats.js @@ -61,7 +61,16 @@ class AdminPanelStats extends React.Component { values: this.state.showed, className: 'admin-panel-stats__toggle-list', onChange: this.onToggleListChange.bind(this), - items: [ + items: ['CREATE_TICKET', 'CLOSE', 'SIGNUP', 'COMMENT'].map((name) => { + return { + content: +
+
{this.state.stats[name]}
+
{i18n('CHART_' + name)}
+
+ } + }) + /*sitems: [ { content:
@@ -90,7 +99,7 @@ class AdminPanelStats extends React.Component {
{i18n('CHART_COMMENT')}
} - ] + ]*/ }; } diff --git a/client/src/app/admin/panel/dashboard/admin-panel-stats.scss b/client/src/app/admin/panel/dashboard/admin-panel-stats.scss index d020a3a5..2a20db81 100644 --- a/client/src/app/admin/panel/dashboard/admin-panel-stats.scss +++ b/client/src/app/admin/panel/dashboard/admin-panel-stats.scss @@ -1,3 +1,5 @@ +@import "../../../../scss/vars"; + .admin-panel-stats { &__dropdown { @@ -7,5 +9,19 @@ &__toggle-list { margin-bottom: 20px; + + &-item { + + &-value { + font-size: $font-size--lg; + line-height: 80px; + } + + &-name { + font-size: $font-size--md; + line-height: 20px; + } + } } + } \ No newline at end of file From 30f1526f1ccb4e53406b96739e26a0f627ba40cf Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 15 Jan 2017 15:47:13 -0300 Subject: [PATCH 35/84] Max Red - Added even even more more basic scss [skip ci] --- client/src/core-components/toggle-list.js | 1 + client/src/core-components/toggle-list.scss | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/client/src/core-components/toggle-list.js b/client/src/core-components/toggle-list.js index e5e70fbc..d057a6f1 100644 --- a/client/src/core-components/toggle-list.js +++ b/client/src/core-components/toggle-list.js @@ -44,6 +44,7 @@ class ToggleList extends React.Component { let classes = { 'toggle-list__item': true, 'toggle-list__first-item': (index === 0), + 'toggle-list__last-item': (index === this.props.items.length - 1), 'toggle-list__selected': _.includes(this.getSelectedList(), index) }; diff --git a/client/src/core-components/toggle-list.scss b/client/src/core-components/toggle-list.scss index 7bf244cb..a016f8a3 100644 --- a/client/src/core-components/toggle-list.scss +++ b/client/src/core-components/toggle-list.scss @@ -8,14 +8,19 @@ width: 180px; height: 120px; display: inline-block; - transition: background-color 0.4s ease; + transition: box-shadow 0.2s ease-in-out; } &__selected { - background-color: $light-grey; + box-shadow: inset 0 -5px 40px 10px rgba(0, 0, 0, 0.05); } &__first-item { border: 1px $light-grey solid; + border-radius: 4px 0 0 4px; + } + + &__last-item { + border-radius: 0 4px 4px 0; } } From ebb3516df370135c153b63a31ac2cbaa4170e578 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 15 Jan 2017 17:20:48 -0300 Subject: [PATCH 36/84] Max Red - Starting refactoring of component stats [skip ci] --- .../stats-chart.js} | 2 - client/src/app-components/stats.js | 211 +++++++++++++++++ client/src/app-components/stats.scss | 0 .../panel/dashboard/admin-panel-stats.js | 224 +----------------- client/src/data/fixtures/system-fixtures.js | 174 +------------- 5 files changed, 216 insertions(+), 395 deletions(-) rename client/src/{app/admin/panel/dashboard/admin-panel-stats-chart.js => app-components/stats-chart.js} (96%) create mode 100644 client/src/app-components/stats.js create mode 100644 client/src/app-components/stats.scss diff --git a/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js b/client/src/app-components/stats-chart.js similarity index 96% rename from client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js rename to client/src/app-components/stats-chart.js index 8ff25b1f..18604cae 100644 --- a/client/src/app/admin/panel/dashboard/admin-panel-stats-chart.js +++ b/client/src/app-components/stats-chart.js @@ -13,7 +13,6 @@ class StatsChart extends React.Component { value: React.PropTypes.number })) })), - //showed: React.PropTypes.arrayOf(React.PropTypes.bool), period: React.PropTypes.number }; @@ -85,7 +84,6 @@ class StatsChart extends React.Component { } hitRadius(index) { - //if (!this.props.showed[index]) return 0; if (this.props.period <= 7) return 20; if (this.props.period <= 30) return 15; if (this.props.period <= 90) return 10; diff --git a/client/src/app-components/stats.js b/client/src/app-components/stats.js new file mode 100644 index 00000000..9283e22b --- /dev/null +++ b/client/src/app-components/stats.js @@ -0,0 +1,211 @@ +import React from 'react'; +import _ from 'lodash'; + +import i18n from 'lib-app/i18n'; +import API from 'lib-app/api-call'; + +import DropDown from 'core-components/drop-down'; +import ToggleList from 'core-components/toggle-list'; + +import StatsChart from 'app-components/stats-chart'; + +const generalStrokes = ['CREATE_TICKET', 'CLOSE', 'SIGNUP', 'COMMENT']; +const staffStrokes = ['ASSIGN', 'CLOSE']; + +class Stats extends React.Component { + + static propTypes = { + type: React.PropTypes.string + }; + + state = { + stats: { + 'CREATE_TICKET': 0, + 'CLOSE': 0, + 'SIGNUP': 0, + 'COMMENT': 0 + }, + strokes: [ + { + name: 'CREATE_TICKET', + values: [] + }, + { + name: 'CLOSE', + values: [] + }, + { + name: 'SIGNUP', + values: [] + }, + { + name: 'COMMENT', + values: [] + } + ], + showed: [0], + period: 0 + }; + + componentDidMount() { + this.retrieve(7); + } + + render() { + return ( +
+ + + +
+ ); + } + + getToggleListProps() { + return { + values: this.state.showed, + className: 'admin-panel-stats__toggle-list', + onChange: this.onToggleListChange.bind(this), + items: ['CREATE_TICKET', 'CLOSE', 'SIGNUP', 'COMMENT'].map((name) => { + return { + content: +
+
{this.state.stats[name]}
+
{i18n('CHART_' + name)}
+
+ } + }) + }; + } + + onToggleListChange(event) { + this.setState({ + showed: event.target.value + }); + } + + getDropDownProps() { + return { + items: [ + { + content: 'Last 7 days', + icon: '' + }, + { + content: 'Last 30 days', + icon: '' + }, + { + content: 'Last 90 days', + icon: '' + }, + { + content: 'Last 365 days', + icon: '' + } + ], + onChange: this.onDropDownChange.bind(this), + className: 'admin-panel-stats__dropdown' + } + } + + onDropDownChange(event) { + let val = [7, 30, 90, 3 65]; + + this.retrieve(val[event.index]); + } + + getStatsChartProps() { + let showed = this.getShowedArray(); + + return { + period: this.state.period, + strokes: _.filter(this.state.strokes, (s, i) => showed[i]) + }; + } + + retrieve(period) { + let periodName; + switch (period) { + case 30: + periodName = 'MONTH'; + break; + case 90: + periodName = 'QUARTER'; + break; + case 365: + periodName = 'YEAR'; + break; + default: + periodName = 'WEEK'; + } + + API.call({ + path: '/system/get-stats', + data: { + period: periodName + } + }).then(this.onRetrieveSuccess.bind(this, period)); + } + + onRetrieveSuccess(period, result) { + + let newStats = { + 'CREATE_TICKET': 0, + 'CLOSE': 0, + 'SIGNUP': 0, + 'COMMENT': 0 + }; + + let ID = { + 'CREATE_TICKET': 0, + 'CLOSE': 1, + 'SIGNUP': 2, + 'COMMENT': 3 + }; + + let newStrokes = [ + { + name: 'CREATE_TICKET', + values: [] + }, + { + name: 'CLOSE', + values: [] + }, + { + name: 'SIGNUP', + values: [] + }, + { + name: 'COMMENT', + values: [] + } + ]; + + let realPeriod = result.data.length / 4; + + for (let i = 0; i < result.data.length; i++) { + newStats[result.data[i].type] += result.data[i].value * 1; + + newStrokes[ ID[result.data[i].type] ].values.push({ + date: result.data[i].date, + value: result.data[i].value * 1 + }); + } + + this.setState({stats: newStats, strokes: newStrokes, period: realPeriod}); + } + + getShowedArray() { + let showed = [false, false, false, false]; + + for (let i = 0; i < showed.length; i++) { + showed[this.state.showed[i]] = true; + } + + return showed; + } +} + +export default Stats; \ No newline at end of file diff --git a/client/src/app-components/stats.scss b/client/src/app-components/stats.scss new file mode 100644 index 00000000..e69de29b diff --git a/client/src/app/admin/panel/dashboard/admin-panel-stats.js b/client/src/app/admin/panel/dashboard/admin-panel-stats.js index 2252dc37..5e992ffb 100644 --- a/client/src/app/admin/panel/dashboard/admin-panel-stats.js +++ b/client/src/app/admin/panel/dashboard/admin-panel-stats.js @@ -1,238 +1,20 @@ import React from 'react'; -import _ from 'lodash'; import i18n from 'lib-app/i18n'; -import API from 'lib-app/api-call'; - +import Stats from 'app-components/stats'; import Header from 'core-components/header'; -import DropDown from 'core-components/drop-down'; -import ToggleList from 'core-components/toggle-list'; - -import StatsChart from 'app/admin/panel/dashboard/admin-panel-stats-chart'; class AdminPanelStats extends React.Component { - state = { - stats: { - 'CREATE_TICKET': 0, - 'CLOSE': 0, - 'SIGNUP': 0, - 'COMMENT': 0 - }, - strokes: [ - { - name: 'CREATE_TICKET', - values: [] - }, - { - name: 'CLOSE', - values: [] - }, - { - name: 'SIGNUP', - values: [] - }, - { - name: 'COMMENT', - values: [] - } - ], - showed: [0], - period: 0 - }; - - componentDidMount() { - this.retrieve(7); - } - render() { return (
- - - +
); } - - getToggleListProps() { - return { - values: this.state.showed, - className: 'admin-panel-stats__toggle-list', - onChange: this.onToggleListChange.bind(this), - items: ['CREATE_TICKET', 'CLOSE', 'SIGNUP', 'COMMENT'].map((name) => { - return { - content: -
-
{this.state.stats[name]}
-
{i18n('CHART_' + name)}
-
- } - }) - /*sitems: [ - { - content: -
- {this.state.stats['CREATE_TICKET']} -
{i18n('CHART_CREATE_TICKET')}
-
- }, - { - content: -
- {this.state.stats['CLOSE']} -
{i18n('CHART_CLOSE')}
-
- }, - { - content: -
- {this.state.stats['SIGNUP']} -
{i18n('CHART_SIGNUP')}
-
- }, - { - content: -
- {this.state.stats['COMMENT']} -
{i18n('CHART_COMMENT')}
-
- } - ]*/ - }; - } - - onToggleListChange(event) { - this.setState({ - showed: event.target.value - }); - } - - getDropDownProps() { - return { - items: [ - { - content: 'Last 7 days', - icon: '' - }, - { - content: 'Last 30 days', - icon: '' - }, - { - content: 'Last 90 days', - icon: '' - }, - { - content: 'Last 365 days', - icon: '' - } - ], - onChange: this.onDropDownChange.bind(this), - className: 'admin-panel-stats__dropdown' - } - } - - onDropDownChange(event) { - let val = [7, 30, 90, 365]; - - this.retrieve(val[event.index]); - } - - getStatsChartProps() { - let showed = this.getShowedArray(); - - return { - period: this.state.period, - strokes: _.filter(this.state.strokes, (s, i) => showed[i]) - //strokes: this.state.strokes, - //showed: this.getShowedArray() - }; - } - - retrieve(period) { - let periodName; - switch (period) { - case 30: - periodName = 'MONTH'; - break; - case 90: - periodName = 'QUARTER'; - break; - case 365: - periodName = 'YEAR'; - break; - default: - periodName = 'WEEK'; - } - - API.call({ - path: '/system/get-stats', - data: { - period: periodName - } - }).then(this.onRetrieveSuccess.bind(this, period)); - } - - onRetrieveSuccess(period, result) { - - let newState = { - 'CREATE_TICKET': 0, - 'CLOSE': 0, - 'SIGNUP': 0, - 'COMMENT': 0 - }; - - let ID = { - 'CREATE_TICKET': 0, - 'CLOSE': 1, - 'SIGNUP': 2, - 'COMMENT': 3 - }; - - let newStrokes = [ - { - name: 'CREATE_TICKET', - values: [] - }, - { - name: 'CLOSE', - values: [] - }, - { - name: 'SIGNUP', - values: [] - }, - { - name: 'COMMENT', - values: [] - } - ]; - - let realPeriod = result.data.length / 4; - - for (let i = 0; i < result.data.length; i++) { - newState[result.data[i].type] += result.data[i].value * 1; - - newStrokes[ ID[result.data[i].type] ].values.push({ - date: result.data[i].date, - value: result.data[i].value * 1 - }); - } - - this.setState({stats: newState, strokes: newStrokes, period: realPeriod}); - } - - getShowedArray() { - let showed = [false, false, false, false]; - - for (let i = 0; i < showed.length; i++) { - showed[this.state.showed[i]] = true; - } - - return showed; - } + } export default AdminPanelStats; \ No newline at end of file diff --git a/client/src/data/fixtures/system-fixtures.js b/client/src/data/fixtures/system-fixtures.js index 38ff3062..797398bd 100644 --- a/client/src/data/fixtures/system-fixtures.js +++ b/client/src/data/fixtures/system-fixtures.js @@ -182,7 +182,7 @@ module.exports = [ date: '201701' + (i + 10) % 100, type: 'SIGNUP', general: 1, - value: (Math.floor(Math.random() * i * i / 365)).toString() + value: (Math.floor(Math.random() * (i - 180) * (i - 185) / (1.027**i) )).toString() }); DATA.push({ date: '201701' + (i + 10) % 100, @@ -194,7 +194,7 @@ module.exports = [ date: '201701' + (i + 10) % 100, type: 'CREATE_TICKET', general: 1, - value: (Math.floor(Math.random()*Math.random()*Math.random()*Math.random()*Math.random()*1.05**i)).toString() + value: (Math.floor(Math.random()*Math.random()*Math.random()*Math.random()*Math.random()*1.027**i)).toString() }); } @@ -205,176 +205,6 @@ module.exports = [ return { status: "success", data: DATA - /*data: [ - { - "date": "20170112", - "type": "COMMENT", - "general": "1", - "value": "8" - }, - { - "date": "20170112", - "type": "SIGNUP", - "general": "1", - "value": "1" - }, - { - "date": "20170112", - "type": "CLOSE", - "general": "1", - "value": "5" - }, - { - "date": "20170112", - "type": "CREATE_TICKET", - "general": "1", - "value": "2" - }, - { - "date": "20170111", - "type": "COMMENT", - "general": "1", - "value": "3" - }, - { - "date": "20170111", - "type": "SIGNUP", - "general": "1", - "value": "8" - }, - { - "date": "20170111", - "type": "CLOSE", - "general": "1", - "value": "10" - }, - { - "date": "20170111", - "type": "CREATE_TICKET", - "general": "1", - "value": "3" - }, - { - "date": "20170110", - "type": "COMMENT", - "general": "1", - "value": "3" - }, - { - "date": "20170110", - "type": "SIGNUP", - "general": "1", - "value": "6" - }, - { - "date": "20170110", - "type": "CLOSE", - "general": "1", - "value": "2" - }, - { - "date": "20170110", - "type": "CREATE_TICKET", - "general": "1", - "value": "1" - }, - { - "date": "20170109", - "type": "COMMENT", - "general": "1", - "value": "0" - }, - { - "date": "20170109", - "type": "SIGNUP", - "general": "1", - "value": "7" - }, - { - "date": "20170109", - "type": "CLOSE", - "general": "1", - "value": "4" - }, - { - "date": "20170109", - "type": "CREATE_TICKET", - "general": "1", - "value": "9" - }, - { - "date": "20170108", - "type": "COMMENT", - "general": "1", - "value": "8" - }, - { - "date": "20170108", - "type": "SIGNUP", - "general": "1", - "value": "4" - }, - { - "date": "20170108", - "type": "CLOSE", - "general": "1", - "value": "5" - }, - { - "date": "20170108", - "type": "CREATE_TICKET", - "general": "1", - "value": "6" - }, - { - "date": "20170107", - "type": "COMMENT", - "general": "1", - "value": "4" - }, - { - "date": "20170107", - "type": "SIGNUP", - "general": "1", - "value": "1" - }, - { - "date": "20170107", - "type": "CLOSE", - "general": "1", - "value": "0" - }, - { - "date": "20170107", - "type": "CREATE_TICKET", - "general": "1", - "value": "2" - }, - { - "date": "20170106", - "type": "COMMENT", - "general": "1", - "value": "7" - }, - { - "date": "20170106", - "type": "SIGNUP", - "general": "1", - "value": "4" - }, - { - "date": "20170106", - "type": "CLOSE", - "general": "1", - "value": "5" - }, - { - "date": "20170106", - "type": "CREATE_TICKET", - "general": "1", - "value": "5" - } - ]*/ }; } }, From 565c60c1988ee8c6e384580a79c10bf00b682176 Mon Sep 17 00:00:00 2001 From: AntonyAntonio Date: Sun, 15 Jan 2017 17:33:33 -0300 Subject: [PATCH 37/84] Guillermo - csv import [skip ci] --- server/controllers/system/csv-import.php | 7 ++++++- server/controllers/ticket/comment.php | 2 +- server/controllers/ticket/create.php | 2 +- server/libs/Controller.php | 2 +- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/server/controllers/system/csv-import.php b/server/controllers/system/csv-import.php index daa0a99a..e415c6f1 100644 --- a/server/controllers/system/csv-import.php +++ b/server/controllers/system/csv-import.php @@ -11,7 +11,9 @@ class CSVImportController extends Controller { } public function handler() { - $file = fopen("Hoja1.csv","r"); + $fileUploader = $this->uploadFile(); + + $file = fopen($fileUploader->getFullFilePath(),'r'); $errors = []; while(!feof($file)) { @@ -41,6 +43,9 @@ class CSVImportController extends Controller { } fclose($file); + + unlink($fileUploader->getFullFilePath()); + Response::respondSuccess($errors); } } \ No newline at end of file diff --git a/server/controllers/ticket/comment.php b/server/controllers/ticket/comment.php index 6a043757..2b5c90b9 100644 --- a/server/controllers/ticket/comment.php +++ b/server/controllers/ticket/comment.php @@ -50,7 +50,7 @@ class CommentController extends Controller { $comment = Ticketevent::getEvent(Ticketevent::COMMENT); $comment->setProperties(array( 'content' => $this->content, - 'file' => $this->uploadFile(), + 'file' => $this->uploadFile()->getFileName(), 'date' => Date::getCurrentDate() )); diff --git a/server/controllers/ticket/create.php b/server/controllers/ticket/create.php index fbcd9203..1a07a0cb 100644 --- a/server/controllers/ticket/create.php +++ b/server/controllers/ticket/create.php @@ -60,7 +60,7 @@ class CreateController extends Controller { 'language' => $this->language, 'author' => $author, 'department' => $department, - 'file' => $this->uploadFile(), + 'file' => $this->uploadFile()->getFileName(), 'date' => Date::getCurrentDate(), 'unread' => false, 'unreadStaff' => true, diff --git a/server/libs/Controller.php b/server/libs/Controller.php index d24cb1af..632d758d 100644 --- a/server/libs/Controller.php +++ b/server/libs/Controller.php @@ -88,7 +88,7 @@ abstract class Controller { $fileQuantity->value++; $fileQuantity->store(); - return $fileUploader->getFileName(); + return $fileUploader; } else { throw new Exception(ERRORS::INVALID_FILE); } From da928f9b6f022a46521191047c6454bd696eca76 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 15 Jan 2017 18:33:00 -0300 Subject: [PATCH 38/84] Max Red - Added abstraction to the component in order to work in view-staff page [skip ci] --- client/src/app-components/stats-chart.js | 3 +- client/src/app-components/stats.js | 128 ++++++++++---------- client/src/data/fixtures/system-fixtures.js | 66 ++++++---- client/src/data/languages/en.js | 1 + 4 files changed, 106 insertions(+), 92 deletions(-) diff --git a/client/src/app-components/stats-chart.js b/client/src/app-components/stats-chart.js index 18604cae..ca6ddb1c 100644 --- a/client/src/app-components/stats-chart.js +++ b/client/src/app-components/stats-chart.js @@ -31,7 +31,8 @@ class StatsChart extends React.Component { 'CLOSE': 'rgba(150, 20, 20, 0.8)', 'CREATE_TICKET': 'rgba(20, 150, 20, 0.8)', 'SIGNUP': 'rgba(20, 20, 150, 0.8)', - 'COMMENT': 'rgba(20, 200, 200, 0.8)' + 'COMMENT': 'rgba(20, 200, 200, 0.8)', + 'ASSIGN': 'rgba(200, 200, 20, 0.8)' }; let datasets = []; diff --git a/client/src/app-components/stats.js b/client/src/app-components/stats.js index 9283e22b..408376a1 100644 --- a/client/src/app-components/stats.js +++ b/client/src/app-components/stats.js @@ -11,38 +11,29 @@ import StatsChart from 'app-components/stats-chart'; const generalStrokes = ['CREATE_TICKET', 'CLOSE', 'SIGNUP', 'COMMENT']; const staffStrokes = ['ASSIGN', 'CLOSE']; +const ID = { + 'CREATE_TICKET': 0, + 'ASSIGN': 0, + 'CLOSE': 1, + 'SIGNUP': 2, + 'COMMENT': 3 +}; class Stats extends React.Component { static propTypes = { - type: React.PropTypes.string + type: React.PropTypes.string, + staffId: React.PropTypes.number }; state = { - stats: { - 'CREATE_TICKET': 0, - 'CLOSE': 0, - 'SIGNUP': 0, - 'COMMENT': 0 - }, - strokes: [ - { - name: 'CREATE_TICKET', + stats: this.getDefaultStats(), + strokes: this.getStrokes().map((name) => { + return { + name: name, values: [] - }, - { - name: 'CLOSE', - values: [] - }, - { - name: 'SIGNUP', - values: [] - }, - { - name: 'COMMENT', - values: [] - } - ], + } + }), showed: [0], period: 0 }; @@ -64,14 +55,14 @@ class Stats extends React.Component { getToggleListProps() { return { values: this.state.showed, - className: 'admin-panel-stats__toggle-list', + className: this.getClassPrefix() + '__toggle-list', onChange: this.onToggleListChange.bind(this), - items: ['CREATE_TICKET', 'CLOSE', 'SIGNUP', 'COMMENT'].map((name) => { + items: this.getStrokes().map((name) => { return { content: -
-
{this.state.stats[name]}
-
{i18n('CHART_' + name)}
+
+
{this.state.stats[name]}
+
{i18n('CHART_' + name)}
} }) @@ -105,12 +96,12 @@ class Stats extends React.Component { } ], onChange: this.onDropDownChange.bind(this), - className: 'admin-panel-stats__dropdown' + className: this.getClassPrefix() + '__dropdown' } } onDropDownChange(event) { - let val = [7, 30, 90, 3 65]; + let val = [7, 30, 90, 365]; this.retrieve(val[event.index]); } @@ -126,6 +117,7 @@ class Stats extends React.Component { retrieve(period) { let periodName; + switch (period) { case 30: periodName = 'MONTH'; @@ -142,48 +134,24 @@ class Stats extends React.Component { API.call({ path: '/system/get-stats', - data: { + data: this.getApiCallData(periodName) + /*data: { period: periodName - } + }*/ }).then(this.onRetrieveSuccess.bind(this, period)); } onRetrieveSuccess(period, result) { + let newStats = this.getDefaultStats(); - let newStats = { - 'CREATE_TICKET': 0, - 'CLOSE': 0, - 'SIGNUP': 0, - 'COMMENT': 0 - }; + let newStrokes = this.getStrokes().map((name) => { + return { + name: name, + values: [] + }; + }); - let ID = { - 'CREATE_TICKET': 0, - 'CLOSE': 1, - 'SIGNUP': 2, - 'COMMENT': 3 - }; - - let newStrokes = [ - { - name: 'CREATE_TICKET', - values: [] - }, - { - name: 'CLOSE', - values: [] - }, - { - name: 'SIGNUP', - values: [] - }, - { - name: 'COMMENT', - values: [] - } - ]; - - let realPeriod = result.data.length / 4; + let realPeriod = result.data.length / this.getStrokes().length; for (let i = 0; i < result.data.length; i++) { newStats[result.data[i].type] += result.data[i].value * 1; @@ -198,7 +166,7 @@ class Stats extends React.Component { } getShowedArray() { - let showed = [false, false, false, false]; + let showed = this.getStrokes().map(() => false); for (let i = 0; i < showed.length; i++) { showed[this.state.showed[i]] = true; @@ -206,6 +174,32 @@ class Stats extends React.Component { return showed; } + + getStrokes() { + return this.props.type === 'general' ? generalStrokes : staffStrokes; + } + + getDefaultStats() { + return this.props.type === 'general' ? + { + 'CREATE_TICKET': 0, + 'CLOSE': 0, + 'SIGNUP': 0, + 'COMMENT': 0 + } : + { + 'ASSIGN': 0, + 'CLOSE': 0 + }; + } + + getClassPrefix() { + return this.props.type === 'general' ? 'admin-panel-stats' : 'ANOTHER_ONE'; /// IMPORTANTE... + } + + getApiCallData(periodName) { + return this.props.type === 'general' ? {period: periodName} : {period: periodName, staffId: this.props.staffId}; + } } export default Stats; \ No newline at end of file diff --git a/client/src/data/fixtures/system-fixtures.js b/client/src/data/fixtures/system-fixtures.js index 797398bd..bf5b7c3d 100644 --- a/client/src/data/fixtures/system-fixtures.js +++ b/client/src/data/fixtures/system-fixtures.js @@ -161,6 +161,8 @@ module.exports = [ path: '/system/get-stats', time: 200, response: function(_data) { + let generalVal = _data.staffId; + let ID = { 'WEEK': 7, 'MONTH': 30, @@ -172,30 +174,46 @@ module.exports = [ let DATA = []; for (let i = 0; i < k; i++) { - DATA.push({ - date: '201701' + (i + 10) % 100, - type: 'COMMENT', - general: 1, - value: (Math.floor(Math.random() * i)).toString() - }); - DATA.push({ - date: '201701' + (i + 10) % 100, - type: 'SIGNUP', - general: 1, - value: (Math.floor(Math.random() * (i - 180) * (i - 185) / (1.027**i) )).toString() - }); - DATA.push({ - date: '201701' + (i + 10) % 100, - type: 'CLOSE', - general: 1, - value: (Math.floor(Math.random() * i * i * i / 365 / 365)).toString() - }); - DATA.push({ - date: '201701' + (i + 10) % 100, - type: 'CREATE_TICKET', - general: 1, - value: (Math.floor(Math.random()*Math.random()*Math.random()*Math.random()*Math.random()*1.027**i)).toString() - }); + if(generalVal){ + DATA.push({ + date: '201701' + (i + 10) % 100, + type: 'ASSIGN', + general: generalVal, + value: (Math.floor((Math.random() + 17) * i)).toString() + }); + DATA.push({ + date: '201701' + (i + 10) % 100, + type: 'CLOSE', + general: generalVal, + value: (Math.floor((Math.random() + 12) * i )).toString() + }); + } + else { + DATA.push({ + date: '201701' + (i + 10) % 100, + type: 'COMMENT', + general: generalVal, + value: (Math.floor((Math.random() + 5) * i)).toString() + }); + DATA.push({ + date: '201701' + (i + 10) % 100, + type: 'SIGNUP', + general: generalVal, + value: (Math.floor(Math.random() * (i - 180) * (i - 185) / 400)).toString() + }); + DATA.push({ + date: '201701' + (i + 10) % 100, + type: 'CLOSE', + general: generalVal, + value: (Math.floor((Math.random() + 12) * i )).toString() + }); + DATA.push({ + date: '201701' + (i + 10) % 100, + type: 'CREATE_TICKET', + general: generalVal, + value: (Math.floor((Math.random() + 7) * i)).toString() + }); + } } console.log('DATA:'); diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js index cb576806..94a18a34 100644 --- a/client/src/data/languages/en.js +++ b/client/src/data/languages/en.js @@ -159,6 +159,7 @@ export default { 'CHART_CLOSE': 'Tickets closed', 'CHART_SIGNUP': 'Signups', 'CHART_COMMENT': 'Replies', + 'CHART_ASSIGN': 'Assigned', //ACTIVITIES 'ACTIVITY_COMMENT': 'commented ticket', From 371b7973b21fc1ea9b90d4d668c56919f138d367 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 15 Jan 2017 19:46:08 -0300 Subject: [PATCH 39/84] Max Red - Ivan changed some things (problems with userId in my-account) and I kept abstacting the component, and applied it to staff-editor [skip ci] --- client/src/app-components/stats-chart.js | 2 +- client/src/app-components/stats.js | 27 ++++++---- client/src/app-components/stats.scss | 53 +++++++++++++++++++ .../panel/dashboard/admin-panel-my-account.js | 1 + .../src/app/admin/panel/staff/staff-editor.js | 4 +- .../app/admin/panel/staff/staff-editor.scss | 9 ++++ client/src/core-components/toggle-list.js | 4 +- client/src/core-components/toggle-list.scss | 9 +++- client/src/data/fixtures/system-fixtures.js | 12 ++--- client/src/data/languages/en.js | 1 + client/src/reducers/session-reducer.js | 6 ++- 11 files changed, 106 insertions(+), 22 deletions(-) diff --git a/client/src/app-components/stats-chart.js b/client/src/app-components/stats-chart.js index ca6ddb1c..9b0d9111 100644 --- a/client/src/app-components/stats-chart.js +++ b/client/src/app-components/stats-chart.js @@ -64,7 +64,7 @@ class StatsChart extends React.Component { } getBorderWidth() { - return (this.props.period <= 90) ? 4 : 2; + return (this.props.period <= 90) ? 3 : 2; } getLabels() { diff --git a/client/src/app-components/stats.js b/client/src/app-components/stats.js index 408376a1..c112cd7f 100644 --- a/client/src/app-components/stats.js +++ b/client/src/app-components/stats.js @@ -1,5 +1,6 @@ import React from 'react'; import _ from 'lodash'; +import classNames from 'classnames'; import i18n from 'lib-app/i18n'; import API from 'lib-app/api-call'; @@ -44,7 +45,7 @@ class Stats extends React.Component { render() { return ( -
+
@@ -52,17 +53,27 @@ class Stats extends React.Component { ); } + getClass() { + let classes = { + 'stats': true, + 'stats_staff': this.props.type === 'staff' + }; + + return classNames(classes); + } + getToggleListProps() { return { values: this.state.showed, - className: this.getClassPrefix() + '__toggle-list', + className: 'stats__toggle-list', onChange: this.onToggleListChange.bind(this), + type: this.props.type === 'general' ? 'default' : 'small', items: this.getStrokes().map((name) => { return { content: -
-
{this.state.stats[name]}
-
{i18n('CHART_' + name)}
+
+
{this.state.stats[name]}
+
{i18n('CHART_' + name)}
} }) @@ -96,7 +107,7 @@ class Stats extends React.Component { } ], onChange: this.onDropDownChange.bind(this), - className: this.getClassPrefix() + '__dropdown' + className: 'stats__dropdown' } } @@ -193,10 +204,6 @@ class Stats extends React.Component { }; } - getClassPrefix() { - return this.props.type === 'general' ? 'admin-panel-stats' : 'ANOTHER_ONE'; /// IMPORTANTE... - } - getApiCallData(periodName) { return this.props.type === 'general' ? {period: periodName} : {period: periodName, staffId: this.props.staffId}; } diff --git a/client/src/app-components/stats.scss b/client/src/app-components/stats.scss index e69de29b..f7539577 100644 --- a/client/src/app-components/stats.scss +++ b/client/src/app-components/stats.scss @@ -0,0 +1,53 @@ +@import '../scss/vars'; + +.stats { + + &__dropdown { + margin-left: auto; + margin-bottom: 20px; + } + + &__toggle-list { + margin-bottom: 20px; + + &-item { + + &-value { + font-size: $font-size--lg; + line-height: 80px; + } + + &-name { + font-size: $font-size--md; + line-height: 20px; + } + } + } + + &_staff { + .stats__dropdown { + margin-left: auto; + margin-bottom: 20px; + float: left; + } + + .stats__toggle-list { + margin-bottom: 20px; + float: right; + + &-item { + + &-value { + font-size: $font-size--md; + line-height: 40px; + } + + &-name { + font-size: $font-size--sm; + line-height: 20px; + } + } + } + } + +} \ No newline at end of file diff --git a/client/src/app/admin/panel/dashboard/admin-panel-my-account.js b/client/src/app/admin/panel/dashboard/admin-panel-my-account.js index 0cd165e3..165db779 100644 --- a/client/src/app/admin/panel/dashboard/admin-panel-my-account.js +++ b/client/src/app/admin/panel/dashboard/admin-panel-my-account.js @@ -23,6 +23,7 @@ class AdminPanelMyAccount extends React.Component { getEditorProps() { return { myAccount: true, + staffId: this.props.userId, name: this.props.userName, email: this.props.userEmail, profilePic: this.props.userProfilePic, diff --git a/client/src/app/admin/panel/staff/staff-editor.js b/client/src/app/admin/panel/staff/staff-editor.js index fdca49f0..1581698f 100644 --- a/client/src/app/admin/panel/staff/staff-editor.js +++ b/client/src/app/admin/panel/staff/staff-editor.js @@ -6,6 +6,7 @@ import API from 'lib-app/api-call'; import SessionStore from 'lib-app/session-store'; import TicketList from 'app-components/ticket-list'; import AreYouSure from 'app-components/are-you-sure'; +import Stats from 'app-components/stats'; import Form from 'core-components/form'; import FormField from 'core-components/form-field'; @@ -97,7 +98,8 @@ class StaffEditor extends React.Component {
- ACTIVITY +
{i18n('ACTIVITY')}
+
diff --git a/client/src/app/admin/panel/staff/staff-editor.scss b/client/src/app/admin/panel/staff/staff-editor.scss index 8e29ab3c..2f601ddd 100644 --- a/client/src/app/admin/panel/staff/staff-editor.scss +++ b/client/src/app/admin/panel/staff/staff-editor.scss @@ -156,4 +156,13 @@ color: $dark-grey; } } + + &__activity { + + &-title { + margin-bottom: 10px; + text-align: left; + } + } + } \ No newline at end of file diff --git a/client/src/core-components/toggle-list.js b/client/src/core-components/toggle-list.js index d057a6f1..edf16ada 100644 --- a/client/src/core-components/toggle-list.js +++ b/client/src/core-components/toggle-list.js @@ -7,7 +7,8 @@ class ToggleList extends React.Component { items: React.PropTypes.arrayOf(React.PropTypes.shape({ content: React.PropTypes.node })), - onChange: React.PropTypes.func + onChange: React.PropTypes.func, + type: React.PropTypes.oneOf(['default', 'small']) }; state = { @@ -25,6 +26,7 @@ class ToggleList extends React.Component { getClass() { let classes = { 'toggle-list': true, + 'toggle-list_small': this.props.type == 'small', [this.props.className]: (this.props.className) }; diff --git a/client/src/core-components/toggle-list.scss b/client/src/core-components/toggle-list.scss index a016f8a3..1fdd82e5 100644 --- a/client/src/core-components/toggle-list.scss +++ b/client/src/core-components/toggle-list.scss @@ -12,7 +12,7 @@ } &__selected { - box-shadow: inset 0 -5px 40px 10px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 -5px 40px 10px rgba(0, 0, 0, 0.08); } &__first-item { @@ -23,4 +23,11 @@ &__last-item { border-radius: 0 4px 4px 0; } + + &_small { + .toggle-list__item { + height: 80px; + width: 120px; + } + } } diff --git a/client/src/data/fixtures/system-fixtures.js b/client/src/data/fixtures/system-fixtures.js index bf5b7c3d..658e4ad7 100644 --- a/client/src/data/fixtures/system-fixtures.js +++ b/client/src/data/fixtures/system-fixtures.js @@ -176,13 +176,13 @@ module.exports = [ for (let i = 0; i < k; i++) { if(generalVal){ DATA.push({ - date: '201701' + (i + 10) % 100, + date: '201701' + (i + 103) % 100, type: 'ASSIGN', general: generalVal, value: (Math.floor((Math.random() + 17) * i)).toString() }); DATA.push({ - date: '201701' + (i + 10) % 100, + date: '201701' + (i + 109) % 100, type: 'CLOSE', general: generalVal, value: (Math.floor((Math.random() + 12) * i )).toString() @@ -190,25 +190,25 @@ module.exports = [ } else { DATA.push({ - date: '201701' + (i + 10) % 100, + date: '201701' + (i + 107) % 100, type: 'COMMENT', general: generalVal, value: (Math.floor((Math.random() + 5) * i)).toString() }); DATA.push({ - date: '201701' + (i + 10) % 100, + date: '201701' + (i + 104) % 100, type: 'SIGNUP', general: generalVal, value: (Math.floor(Math.random() * (i - 180) * (i - 185) / 400)).toString() }); DATA.push({ - date: '201701' + (i + 10) % 100, + date: '201701' + (i + 103) % 100, type: 'CLOSE', general: generalVal, value: (Math.floor((Math.random() + 12) * i )).toString() }); DATA.push({ - date: '201701' + (i + 10) % 100, + date: '201701' + (i + 99) % 100, type: 'CREATE_TICKET', general: generalVal, value: (Math.floor((Math.random() + 7) * i)).toString() diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js index 94a18a34..c79a2ae8 100644 --- a/client/src/data/languages/en.js +++ b/client/src/data/languages/en.js @@ -153,6 +153,7 @@ export default { 'VERIFY_SUCCESS': 'User verified', 'VERIFY_FAILED': 'Could not verify', 'TICKET_ACTIVITY': 'Ticket Activity', + 'ACTIVITY': 'Activity', 'CHART_CREATE_TICKET': 'Tickets created', diff --git a/client/src/reducers/session-reducer.js b/client/src/reducers/session-reducer.js index be4323cc..c1eca34f 100644 --- a/client/src/reducers/session-reducer.js +++ b/client/src/reducers/session-reducer.js @@ -44,7 +44,8 @@ class SessionReducer extends Reducer { logged: true, pending: false, failed: false, - staff: payload.data.staff + staff: payload.data.staff, + userId: payload.data.userId }); } @@ -75,7 +76,8 @@ class SessionReducer extends Reducer { initDone: true, logged: true, pending: false, - failed: false + failed: false, + userId: payload.data.userId }); } From 8584be092441b6d16460f8e95c82d5f4fa228a0f Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 15 Jan 2017 20:10:02 -0300 Subject: [PATCH 40/84] Max Red - Changed colors [skip ci] --- client/src/app-components/stats-chart.js | 10 +++++----- client/src/app-components/stats.js | 3 --- client/src/app-components/stats.scss | 1 + 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/client/src/app-components/stats-chart.js b/client/src/app-components/stats-chart.js index 9b0d9111..f50d2d71 100644 --- a/client/src/app-components/stats-chart.js +++ b/client/src/app-components/stats-chart.js @@ -28,11 +28,11 @@ class StatsChart extends React.Component { let labels = this.getLabels(); let color = { - 'CLOSE': 'rgba(150, 20, 20, 0.8)', - 'CREATE_TICKET': 'rgba(20, 150, 20, 0.8)', - 'SIGNUP': 'rgba(20, 20, 150, 0.8)', - 'COMMENT': 'rgba(20, 200, 200, 0.8)', - 'ASSIGN': 'rgba(200, 200, 20, 0.8)' + 'CLOSE': 'rgba(150, 20, 20, 0.6)', + 'CREATE_TICKET': 'rgba(20, 150, 20, 0.6)', + 'SIGNUP': 'rgba(20, 20, 150, 0.6)', + 'COMMENT': 'rgba(20, 200, 200, 0.6)', + 'ASSIGN': 'rgba(20, 150, 20, 0.6)' }; let datasets = []; diff --git a/client/src/app-components/stats.js b/client/src/app-components/stats.js index c112cd7f..e0b84f42 100644 --- a/client/src/app-components/stats.js +++ b/client/src/app-components/stats.js @@ -146,9 +146,6 @@ class Stats extends React.Component { API.call({ path: '/system/get-stats', data: this.getApiCallData(periodName) - /*data: { - period: periodName - }*/ }).then(this.onRetrieveSuccess.bind(this, period)); } diff --git a/client/src/app-components/stats.scss b/client/src/app-components/stats.scss index f7539577..c1557e9e 100644 --- a/client/src/app-components/stats.scss +++ b/client/src/app-components/stats.scss @@ -9,6 +9,7 @@ &__toggle-list { margin-bottom: 20px; + user-select: none; &-item { From 7c19ef17165adcef939220f835a819271546fd77 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 16 Jan 2017 12:04:47 -0300 Subject: [PATCH 41/84] Max Red - Beautify code, replacing a for using .map [skip ci] --- client/src/app-components/stats-chart.js | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/client/src/app-components/stats-chart.js b/client/src/app-components/stats-chart.js index f50d2d71..5e4704b7 100644 --- a/client/src/app-components/stats-chart.js +++ b/client/src/app-components/stats-chart.js @@ -35,12 +35,9 @@ class StatsChart extends React.Component { 'ASSIGN': 'rgba(20, 150, 20, 0.6)' }; - let datasets = []; - - for (let i = 0; i < this.props.strokes.length; i++) { - let stroke = this.props.strokes[i]; - - let dataset = { + let strokes = this.props.strokes.slice(); + let datasets = strokes.map((stroke, index) => { + return { label: i18n('CHART_' + stroke.name), data: stroke.values.map((val) => val.value), fill: false, @@ -51,12 +48,10 @@ class StatsChart extends React.Component { pointHoverRadius: 3, lineTension: 0.2, pointHoverBackgroundColor: color[stroke.name], - hitRadius: this.hitRadius(i) - }; + hitRadius: this.hitRadius(index) + } + }); - datasets.push(dataset); - } - return { labels: labels, datasets: datasets From 9fbf53d586f2c36a6ff4f1dc52793a95fa8f4fba Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 16 Jan 2017 12:20:22 -0300 Subject: [PATCH 42/84] Max Red - Beautify code, replacing another for using .map [skip ci] --- client/src/app-components/stats.js | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/client/src/app-components/stats.js b/client/src/app-components/stats.js index e0b84f42..337bf446 100644 --- a/client/src/app-components/stats.js +++ b/client/src/app-components/stats.js @@ -88,24 +88,12 @@ class Stats extends React.Component { getDropDownProps() { return { - items: [ - { - content: 'Last 7 days', + items: ['Last 7 days', 'Last 30 days', 'Last 90 days', 'Last 365 days'].map((name) => { + return { + content: name, icon: '' - }, - { - content: 'Last 30 days', - icon: '' - }, - { - content: 'Last 90 days', - icon: '' - }, - { - content: 'Last 365 days', - icon: '' - } - ], + }; + }), onChange: this.onDropDownChange.bind(this), className: 'stats__dropdown' } From 1019b4ff967ec8477611d2a7ad567617b2c41dc1 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 16 Jan 2017 12:39:07 -0300 Subject: [PATCH 43/84] Max Red - Delete redundant css [skip ci] --- .../panel/dashboard/admin-panel-stats.scss | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/client/src/app/admin/panel/dashboard/admin-panel-stats.scss b/client/src/app/admin/panel/dashboard/admin-panel-stats.scss index 2a20db81..e69de29b 100644 --- a/client/src/app/admin/panel/dashboard/admin-panel-stats.scss +++ b/client/src/app/admin/panel/dashboard/admin-panel-stats.scss @@ -1,27 +0,0 @@ -@import "../../../../scss/vars"; - -.admin-panel-stats { - - &__dropdown { - margin-left: auto; - margin-bottom: 20px; - } - - &__toggle-list { - margin-bottom: 20px; - - &-item { - - &-value { - font-size: $font-size--lg; - line-height: 80px; - } - - &-name { - font-size: $font-size--md; - line-height: 20px; - } - } - } - -} \ No newline at end of file From a70778db9cd4ae07e949beacfb8dc13f8944a826 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 16 Jan 2017 16:06:19 -0300 Subject: [PATCH 44/84] Max Red - disable registration and fixed a message in en.js[skip ci] --- client/src/app/App.js | 16 ++++++++++------ client/src/app/main/main-layout-header.js | 2 +- client/src/data/fixtures/system-fixtures.js | 1 + client/src/data/languages/en.js | 2 +- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/client/src/app/App.js b/client/src/app/App.js index d52ea248..6d327fa8 100644 --- a/client/src/app/App.js +++ b/client/src/app/App.js @@ -86,20 +86,24 @@ class App extends React.Component { browserHistory.push('/admin/panel'); } - if (this.props.session.userLevel && !this.isPathAvailableForStaff()) { + if (props.session.userLevel && !this.isPathAvailableForStaff(props)) { browserHistory.push('/admin/panel'); } + + if (!props.config.registration && _.includes(props.location.pathname, 'signup')) { + browserHistory.push('/'); + } } - isPathAvailableForStaff() { - let pathForLevel2 = _.findIndex(level2Paths, path => _.includes(this.props.location.pathname, path)) !== -1; - let pathForLevel3 = _.findIndex(level3Paths, path => _.includes(this.props.location.pathname, path)) !== -1; + isPathAvailableForStaff(props) { + let pathForLevel2 = _.findIndex(level2Paths, path => _.includes(props.location.pathname, path)) !== -1; + let pathForLevel3 = _.findIndex(level3Paths, path => _.includes(props.location.pathname, path)) !== -1; - if (this.props.session.userLevel === 1) { + if (props.session.userLevel === 1) { return !pathForLevel2 && !pathForLevel3; } - if (this.props.session.userLevel === 2) { + if (props.session.userLevel === 2) { return !pathForLevel3; } diff --git a/client/src/app/main/main-layout-header.js b/client/src/app/main/main-layout-header.js index dd031535..2254590c 100644 --- a/client/src/app/main/main-layout-header.js +++ b/client/src/app/main/main-layout-header.js @@ -32,7 +32,7 @@ class MainLayoutHeader extends React.Component { result = (
- + {this.props.config === true ? : null}
); } diff --git a/client/src/data/fixtures/system-fixtures.js b/client/src/data/fixtures/system-fixtures.js index ac2a5bbd..ecf3916e 100644 --- a/client/src/data/fixtures/system-fixtures.js +++ b/client/src/data/fixtures/system-fixtures.js @@ -20,6 +20,7 @@ module.exports = [ 'smtp-user': 'Wesa', 'maintenance-mode': false, 'allow-attachments': true, + 'registration': false, 'max-size': 500, 'departments': [ {id: 1, name: 'Sales Support', owners: 2}, diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js index 8e69269c..a7ec1983 100644 --- a/client/src/data/languages/en.js +++ b/client/src/data/languages/en.js @@ -186,7 +186,7 @@ export default { 'TICKET_LIST_DESCRIPTION': 'Here you can find a list of all tickets you have sent to our support team.', 'TICKETS_DESCRIPTION': 'Send ticket through our support center and get response of your doubts, suggestions and issues.', 'ARTICLES_DESCRIPTION': 'Take a look to our articles about common issues, guides and documentation.', - 'ACCOUNT_DESCRIPTION': 'All your tickets are stored in your accounts\'s profile. Keep track off all your tickets you send to our staff team.', + 'ACCOUNT_DESCRIPTION': 'All your tickets are stored in your account\'s profile. Keep track of all your tickets you send to our staff team.', 'SUPPORT_CENTER_DESCRIPTION': 'Welcome to our support center. You can contact us through a tickets system. Your tickets will be answered by our staff.', 'CUSTOM_RESPONSES_DESCRIPTION': 'Custom responses are automated responses for common problems', 'MY_TICKETS_DESCRIPTION': 'Here you can view the tickets you are responsible for.', From fdd35ed2c17d8e23536c2829fddadc958418df69 Mon Sep 17 00:00:00 2001 From: AntonyAntonio Date: Mon, 16 Jan 2017 16:07:53 -0300 Subject: [PATCH 45/84] Guillermo - disable-user-system [skip ci] --- server/controllers/article/get-all.php | 2 +- server/controllers/system.php | 4 + .../system/disable-user-system.php | 57 ++++++++++++++ .../system/enabled-user-system.php | 74 +++++++++++++++++++ server/controllers/system/get-settings.php | 3 +- server/controllers/system/init-settings.php | 3 +- server/controllers/ticket/comment.php | 22 +++++- server/controllers/ticket/create.php | 27 ++++++- server/controllers/ticket/get.php | 31 +++++++- server/controllers/user/delete.php | 4 + server/controllers/user/get-user.php | 5 ++ server/controllers/user/get-users.php | 4 + server/controllers/user/login.php | 7 +- server/controllers/user/recover-password.php | 4 + .../user/send-recover-password.php | 4 + server/controllers/user/signup.php | 4 + server/controllers/user/verify.php | 4 + server/data/ERRORS.php | 3 + server/data/InitialMails.php | 20 +++++ .../user-system-disabled-en.html | 3 + .../user-system-disabled-es.html | 3 + .../user-system-enabled-en.html | 4 + .../user-system-enabled-es.html | 3 + server/libs/Controller.php | 4 + server/models/MailTemplate.php | 2 + server/models/Ticket.php | 8 +- tests/init.rb | 1 + tests/system/get-mail-templates.rb | 2 +- 28 files changed, 293 insertions(+), 19 deletions(-) create mode 100644 server/controllers/system/disable-user-system.php create mode 100644 server/controllers/system/enabled-user-system.php create mode 100644 server/data/mail-templates/user-system-disabled-en.html create mode 100644 server/data/mail-templates/user-system-disabled-es.html create mode 100644 server/data/mail-templates/user-system-enabled-en.html create mode 100644 server/data/mail-templates/user-system-enabled-es.html diff --git a/server/controllers/article/get-all.php b/server/controllers/article/get-all.php index 9d90e152..40a49efc 100644 --- a/server/controllers/article/get-all.php +++ b/server/controllers/article/get-all.php @@ -7,7 +7,7 @@ class GetAllArticlesController extends Controller { public function validations() { return [ - 'permission' => 'user', + 'permission' => (Controller::isUserSystemEnabled()) ? 'user' : 'any', 'requestData' => [] ]; } diff --git a/server/controllers/system.php b/server/controllers/system.php index e5423a5a..e1250709 100644 --- a/server/controllers/system.php +++ b/server/controllers/system.php @@ -11,6 +11,8 @@ require_once 'system/edit-mail-template.php'; require_once 'system/recover-mail-template.php'; require_once 'system/disable-registration.php'; require_once 'system/enable-registration.php'; +require_once 'system/disable-user-system.php'; +require_once 'system/enabled-user-system.php'; $systemControllerGroup = new ControllerGroup(); $systemControllerGroup->setGroupPath('/system'); @@ -27,5 +29,7 @@ $systemControllerGroup->addController(new EditMailTemplateController); $systemControllerGroup->addController(new RecoverMailTemplateController); $systemControllerGroup->addController(new DisableRegistrationController); $systemControllerGroup->addController(new EnableRegistrationController); +$systemControllerGroup->addController(new DisableUserSystemController); +$systemControllerGroup->addController(new EnabledUserSystemController); $systemControllerGroup->finalize(); \ No newline at end of file diff --git a/server/controllers/system/disable-user-system.php b/server/controllers/system/disable-user-system.php new file mode 100644 index 00000000..cc1eee83 --- /dev/null +++ b/server/controllers/system/disable-user-system.php @@ -0,0 +1,57 @@ + 'staff_3', + 'requestData' => [] + ]; + } + + public function handler() { + $password = Controller::request('password'); + + if(!Hashing::verifyPassword($password, Controller::getLoggedUser()->password)) { + throw new Exception(ERRORS::INVALID_PASSWORD); + + } + + if(!Controller::isUserSystemEnabled()) { + throw new Exception(ERRORS::SYSTEM_USER_IS_ALREADY_DISABLED); + } + + $userSystemEnabled = Setting::getSetting('user-system-enabled'); + $userSystemEnabled->value = 0 ; + $userSystemEnabled->store(); + + $userList = User::getAll(); + + foreach($userList as $user) { + $ticketNumberList = []; + + foreach($user->sharedTicketList as $ticket) { + $ticket->authorEmail = $user->email; + $ticket->authorName = $user->name; + $ticket->author = null; + + $ticketNumberList[] = $ticket->ticketNumber; + $ticket->store(); + } + + $mailSender = new MailSender(); + + $mailSender->setTemplate(MailTemplate::USER_SYSTEM_DISABLED, [ + 'to' => $user->email, + 'name' => $user->name, + 'tickets' => json_encode($ticketNumberList) + ]); + + $mailSender->send(); + + $user->delete(); + } + Response::respondSuccess(); + } +} \ No newline at end of file diff --git a/server/controllers/system/enabled-user-system.php b/server/controllers/system/enabled-user-system.php new file mode 100644 index 00000000..fb6b2d3a --- /dev/null +++ b/server/controllers/system/enabled-user-system.php @@ -0,0 +1,74 @@ + 'staff_3', + 'requestData' => [] + ]; + } + + public function handler() { + $password = Controller::request('password'); + + if(!Hashing::verifyPassword($password, Controller::getLoggedUser()->password)) { + throw new Exception(ERRORS::INVALID_PASSWORD); + + } + + if(Controller::isUserSystemEnabled()) { + throw new Exception(ERRORS::SYSTEM_USER_IS_ALREADY_ENABLED); + } + + $userSystemEnabled = Setting::getSetting('user-system-enabled'); + $userSystemEnabled->value = 1 ; + $userSystemEnabled->store(); + + $ticketList = Ticket::getAll(); + + foreach($ticketList as $ticket) { + + $userRow = User::getDataStore($ticket->authorEmail, 'email'); + + if($userRow->isNull()) { + $userInstance = new User(); + + $password = Hashing::generateRandomToken(); + + $userInstance->setProperties([ + 'name' => $ticket->authorName, + 'signupDate' => Date::getCurrentDate(), + 'tickets' => 1, + 'email' => $ticket->authorEmail, + 'password' => Hashing::hashPassword($password), + 'verificationToken' => null + ]); + + $userInstance->store(); + + $mailSender = new MailSender(); + $mailSender->setTemplate(MailTemplate::USER_SYSTEM_ENABLED, [ + 'to' => $ticket->authorEmail, + 'name' => $ticket->authorName, + 'password' => $password + ]); + $mailSender->send(); + + } else { + $userRow->tickets = $userRow->tickets + 1; + $userRow->sharedTicketList->add($ticket); + $userRow->store(); + } + + $actualUserRow = User::getDataStore($ticket->authorEmail,'email'); + $ticket->author = $actualUserRow; + $ticket->authorName = null; + $ticket->authorEmail = null; + $ticket->store(); + } + + Response::respondSuccess(); + } +} \ No newline at end of file diff --git a/server/controllers/system/get-settings.php b/server/controllers/system/get-settings.php index 9cddb302..41e2299d 100644 --- a/server/controllers/system/get-settings.php +++ b/server/controllers/system/get-settings.php @@ -46,7 +46,8 @@ class GetSettingsController extends Controller { 'registration' => Setting::getSetting('registration')->getValue(), 'departments' => Department::getDepartmentNames(), 'supportedLanguages' => Language::getSupportedLanguages(), - 'allowedLanguages' => Language::getAllowedLanguages() + 'allowedLanguages' => Language::getAllowedLanguages(), + 'user-system-enabled' => Setting::getSetting('user-system-enabled')->getValue() ]; } diff --git a/server/controllers/system/init-settings.php b/server/controllers/system/init-settings.php index 47f83893..67d0df5f 100644 --- a/server/controllers/system/init-settings.php +++ b/server/controllers/system/init-settings.php @@ -41,7 +41,8 @@ class InitSettingsController extends Controller { 'max-size' => 0, 'title' => 'Support Center', 'url' => 'http://www.opensupports.com/support', - 'registration' => true + 'registration' => true, + 'user-system-enabled' => true ]); } diff --git a/server/controllers/ticket/comment.php b/server/controllers/ticket/comment.php index b51414c2..72f9dc94 100644 --- a/server/controllers/ticket/comment.php +++ b/server/controllers/ticket/comment.php @@ -9,7 +9,7 @@ class CommentController extends Controller { private $content; public function validations() { - return [ + $validations = [ 'permission' => 'user', 'requestData' => [ 'content' => [ @@ -22,13 +22,23 @@ class CommentController extends Controller { ] ] ]; + + if(!Controller::isUserSystemEnabled()) { + $validations['permission'] = 'any'; + $validations['requestData']['email'] = [ + 'validation' => DataValidator::email(), + 'error' => ERRORS::INVALID_EMAIL + ]; + } + + return $validations; } public function handler() { $session = Session::getInstance(); $this->requestData(); - if ($session->isLoggedWithId($this->ticket->author->id) || Controller::isStaffLogged()) { + if (!Controller::isUserSystemEnabled() || $session->isLoggedWithId($this->ticket->author->id) || Controller::isStaffLogged()) { $this->storeComment(); Log::createLog('COMMENT', $this->ticket->ticketNumber); @@ -41,9 +51,13 @@ class CommentController extends Controller { private function requestData() { $ticketNumber = Controller::request('ticketNumber'); - + $email = Controller::request('email'); $this->ticket = Ticket::getByTicketNumber($ticketNumber); $this->content = Controller::request('content'); + + if(!Controller::isUserSystemEnabled() && $this->ticket->authorEmail !== $email && !Controller::isStaffLogged()) { + throw new Exception(ERRORS::NO_PERMISSION); + } } private function storeComment() { @@ -56,7 +70,7 @@ class CommentController extends Controller { if(Controller::isStaffLogged()) { $this->ticket->unread = true; $comment->authorStaff = Controller::getLoggedUser(); - } else { + } else if(Controller::isUserSystemEnabled()) { $this->ticket->unreadStaff = true; $comment->authorUser = Controller::getLoggedUser(); } diff --git a/server/controllers/ticket/create.php b/server/controllers/ticket/create.php index ac9f4c53..c1f0e077 100644 --- a/server/controllers/ticket/create.php +++ b/server/controllers/ticket/create.php @@ -10,9 +10,11 @@ class CreateController extends Controller { private $departmentId; private $language; private $ticketNumber; + private $email; + private $name; public function validations() { - return [ + $validations = [ 'permission' => 'user', 'requestData' => [ 'title' => [ @@ -33,6 +35,16 @@ class CreateController extends Controller { ] ] ]; + + if(!Controller::isUserSystemEnabled()) { + $validations['permission'] = 'any'; + $validations['requestData']['captcha'] = [ + 'validation' => DataValidator::captcha(), + 'error' => ERRORS::INVALID_CAPTCHA + ]; + } + + return $validations; } public function handler() { @@ -40,6 +52,8 @@ class CreateController extends Controller { $this->content = Controller::request('content'); $this->departmentId = Controller::request('departmentId'); $this->language = Controller::request('language'); + $this->email = Controller::request('email'); + $this->name = Controller::request('name'); $this->storeTicket(); @@ -65,12 +79,17 @@ class CreateController extends Controller { 'unread' => false, 'unreadStaff' => true, 'closed' => false, + 'authorName' => $this->name, + 'authorEmail' => $this->email )); - $author->sharedTicketList->add($ticket); - $author->tickets++; + if(Controller::isUserSystemEnabled()) { + $author->sharedTicketList->add($ticket); + $author->tickets++; + + $author->store(); + } - $author->store(); $ticket->store(); $this->ticketNumber = $ticket->ticketNumber; diff --git a/server/controllers/ticket/get.php b/server/controllers/ticket/get.php index 36ef3f8b..6e2a6758 100644 --- a/server/controllers/ticket/get.php +++ b/server/controllers/ticket/get.php @@ -8,7 +8,7 @@ class TicketGetController extends Controller { private $ticket; public function validations() { - return [ + $validations = [ 'permission' => 'user', 'requestData' => [ 'ticketNumber' => [ @@ -17,13 +17,38 @@ class TicketGetController extends Controller { ] ] ]; + + if(!Controller::isUserSystemEnabled() && !Controller::isStaffLogged()) { + $validations['permission'] = 'any'; + $validations['requestData']['email'] = [ + 'validation' => DataValidator::email(), + 'error' => ERRORS::INVALID_EMAIL + ]; + $validations['requestData']['captcha'] = [ + 'validation' => DataValidator::captcha(), + 'error' => ERRORS::INVALID_CAPTCHA + ]; + } + + return $validations; } public function handler() { + $email = Controller::request('email'); + $this->ticket = Ticket::getByTicketNumber(Controller::request('ticketNumber')); + if(!Controller::isUserSystemEnabled() && !Controller::isStaffLogged()) { + if($this->ticket->authorEmail === $email) { + Response::respondSuccess($this->ticket->toArray()); + return; + } else { + throw new Exception(ERRORS::NO_PERMISSION); + } + } + if ($this->shouldDenyPermission()) { - Response::respondError(ERRORS::NO_PERMISSION); + throw new Exception(ERRORS::NO_PERMISSION); } else { Response::respondSuccess($this->ticket->toArray()); } @@ -32,7 +57,7 @@ class TicketGetController extends Controller { private function shouldDenyPermission() { $user = Controller::getLoggedUser(); - return (!Controller::isStaffLogged() && $this->ticket->author->id !== $user->id) || + return (!Controller::isStaffLogged() && (Controller::isUserSystemEnabled() && $this->ticket->author->id !== $user->id)) || (Controller::isStaffLogged() && $this->ticket->owner && $this->ticket->owner->id !== $user->id); } } \ No newline at end of file diff --git a/server/controllers/user/delete.php b/server/controllers/user/delete.php index 75cf7dfc..b17ed8a4 100644 --- a/server/controllers/user/delete.php +++ b/server/controllers/user/delete.php @@ -20,6 +20,10 @@ class DeleteUserController extends Controller { } public function handler() { + if(!Controller::isUserSystemEnabled()) { + throw new Exception(ERRORS::USER_SYSTEM_DISABLED); + } + $userId = Controller::request('userId'); $user = User::getDataStore($userId); diff --git a/server/controllers/user/get-user.php b/server/controllers/user/get-user.php index 8ea55c09..ae9b4f9e 100644 --- a/server/controllers/user/get-user.php +++ b/server/controllers/user/get-user.php @@ -18,6 +18,11 @@ class GetUserByIdController extends Controller { } public function handler() { + + if(!Controller::isUserSystemEnabled()) { + throw new Exception(ERRORS::USER_SYSTEM_DISABLED); + } + $userId = Controller::request('userId'); $user = User::getDataStore($userId); $staff = Controller::getLoggedUser(); diff --git a/server/controllers/user/get-users.php b/server/controllers/user/get-users.php index eadd6922..5d8daf28 100644 --- a/server/controllers/user/get-users.php +++ b/server/controllers/user/get-users.php @@ -21,6 +21,10 @@ class GetUsersController extends Controller { } public function handler() { + if(!Controller::isUserSystemEnabled()) { + throw new Exception(ERRORS::USER_SYSTEM_DISABLED); + } + $userList = $this->getUserList(); $userListArray = []; diff --git a/server/controllers/user/login.php b/server/controllers/user/login.php index 7eada075..ebd55c30 100644 --- a/server/controllers/user/login.php +++ b/server/controllers/user/login.php @@ -14,9 +14,12 @@ class LoginController extends Controller { } public function handler() { + if(!Controller::isUserSystemEnabled() && !Controller::request('staff')) { + throw new Exception(ERRORS::USER_SYSTEM_DISABLED); + } + if ($this->isAlreadyLoggedIn()) { - Response::respondError(ERRORS::SESSION_EXISTS); - return; + throw new Exception(ERRORS::SESSION_EXISTS); } if ($this->checkInputCredentials() || $this->checkRememberToken()) { diff --git a/server/controllers/user/recover-password.php b/server/controllers/user/recover-password.php index c5cec698..ac3ceef2 100644 --- a/server/controllers/user/recover-password.php +++ b/server/controllers/user/recover-password.php @@ -27,6 +27,10 @@ class RecoverPasswordController extends Controller { } public function handler() { + if(!Controller::isUserSystemEnabled()) { + throw new Exception(ERRORS::USER_SYSTEM_DISABLED); + } + $this->requestData(); $this->changePassword(); } diff --git a/server/controllers/user/send-recover-password.php b/server/controllers/user/send-recover-password.php index e92d1ae6..c59eebb1 100644 --- a/server/controllers/user/send-recover-password.php +++ b/server/controllers/user/send-recover-password.php @@ -21,6 +21,10 @@ class SendRecoverPasswordController extends Controller { } public function handler() { + if(!Controller::isUserSystemEnabled()) { + throw new Exception(ERRORS::USER_SYSTEM_DISABLED); + } + $email = Controller::request('email'); $this->user = User::getUser($email,'email'); diff --git a/server/controllers/user/signup.php b/server/controllers/user/signup.php index 48e6e1c6..8b4937ca 100644 --- a/server/controllers/user/signup.php +++ b/server/controllers/user/signup.php @@ -36,6 +36,10 @@ class SignUpController extends Controller { } public function handler() { + if(!Controller::isUserSystemEnabled()) { + throw new Exception(ERRORS::USER_SYSTEM_DISABLED); + } + $this->storeRequestData(); $existentUser = User::getUser($this->userEmail, 'email'); diff --git a/server/controllers/user/verify.php b/server/controllers/user/verify.php index 616d3b92..aa2dd31d 100644 --- a/server/controllers/user/verify.php +++ b/server/controllers/user/verify.php @@ -17,6 +17,10 @@ class VerifyController extends Controller{ } public function handler() { + if(!Controller::isUserSystemEnabled()) { + throw new Exception(ERRORS::USER_SYSTEM_DISABLED); + } + $email = Controller::request('email'); $token = Controller::request('token'); diff --git a/server/data/ERRORS.php b/server/data/ERRORS.php index e0052543..b6b86d63 100644 --- a/server/data/ERRORS.php +++ b/server/data/ERRORS.php @@ -35,4 +35,7 @@ class ERRORS { const INVALID_TEMPLATE = 'INVALID_TEMPLATE'; const INVALID_SUBJECT = 'INVALID_SUBJECT'; const INVALID_BODY = 'INVALID_BODY'; + const USER_SYSTEM_DISABLED= 'USER_SYSTEM_DISABLED'; + const SYSTEM_USER_IS_ALREADY_DISABLED= 'SYSTEM_USER_IS_ALREADY_DISABLED'; + const SYSTEM_USER_IS_ALREADY_ENABLED= 'SYSTEM_USER_IS_ALREADY_ENABLED'; } diff --git a/server/data/InitialMails.php b/server/data/InitialMails.php index 899d9af3..7be66192 100644 --- a/server/data/InitialMails.php +++ b/server/data/InitialMails.php @@ -53,6 +53,26 @@ class InitialMails { 'body' => file_get_contents('data/mail-templates/user-recovered-password-es.html') ] ], + 'USER_SYSTEM_DISABLED' => [ + 'en' => [ + 'subject' => 'Account has been deleted - OpenSupports', + 'body' => file_get_contents('data/mail-templates/user-system-disabled-en.html') + ], + 'es' => [ + 'subject' => 'cuanta borrada - OpenSupports', + 'body' => file_get_contents('data/mail-templates/user-system-disabled-es.html') + ] + ], + 'USER_SYSTEM_ENABLED' => [ + 'en' => [ + 'subject' => 'account has been created - OpenSupports', + 'body' => file_get_contents('data/mail-templates/user-system-enabled-en.html') + ], + 'es' => [ + 'subject' => 'se te ha creado una cuenta - OpenSupports', + 'body' => file_get_contents('data/mail-templates/user-system-enabled-es.html') + ] + ] ]; } } \ No newline at end of file diff --git a/server/data/mail-templates/user-system-disabled-en.html b/server/data/mail-templates/user-system-disabled-en.html new file mode 100644 index 00000000..d42819c1 --- /dev/null +++ b/server/data/mail-templates/user-system-disabled-en.html @@ -0,0 +1,3 @@ +
+ Hi {{name}} the system user has been deleted this is the list of your tickets {{tickets}} +
\ No newline at end of file diff --git a/server/data/mail-templates/user-system-disabled-es.html b/server/data/mail-templates/user-system-disabled-es.html new file mode 100644 index 00000000..fb4f3603 --- /dev/null +++ b/server/data/mail-templates/user-system-disabled-es.html @@ -0,0 +1,3 @@ +
+ hoola {{name}} the system user has been deleted this is the list of your tickets {{tickets}} +
\ No newline at end of file diff --git a/server/data/mail-templates/user-system-enabled-en.html b/server/data/mail-templates/user-system-enabled-en.html new file mode 100644 index 00000000..5b2bd906 --- /dev/null +++ b/server/data/mail-templates/user-system-enabled-en.html @@ -0,0 +1,4 @@ +
+ hi {{name}} the system user has been Created this is your new password {{password}} , you can change it if you want + maxi puto +
\ No newline at end of file diff --git a/server/data/mail-templates/user-system-enabled-es.html b/server/data/mail-templates/user-system-enabled-es.html new file mode 100644 index 00000000..a1081984 --- /dev/null +++ b/server/data/mail-templates/user-system-enabled-es.html @@ -0,0 +1,3 @@ +
+ hoola {{name}} el sistema de usuarios se ha creado este es tu contra {{password}} , puedes cambairla si quieres +
\ No newline at end of file diff --git a/server/libs/Controller.php b/server/libs/Controller.php index 3c8a3ca9..f58a93e4 100644 --- a/server/libs/Controller.php +++ b/server/libs/Controller.php @@ -60,4 +60,8 @@ abstract class Controller { public static function getAppInstance() { return \Slim\Slim::getInstance(); } + + public static function isUserSystemEnabled() { + return Setting::getSetting('user-system-enabled')->getValue(); + } } \ No newline at end of file diff --git a/server/models/MailTemplate.php b/server/models/MailTemplate.php index a2931061..0379693b 100644 --- a/server/models/MailTemplate.php +++ b/server/models/MailTemplate.php @@ -8,6 +8,8 @@ class MailTemplate extends DataStore { const USER_PASSWORD = 'USER_PASSWORD'; const PASSWORD_FORGOT = 'PASSWORD_FORGOT'; const PASSWORD_RECOVERED = 'PASSWORD_RECOVERED'; + const USER_SYSTEM_DISABLED = 'USER_SYSTEM_DISABLED'; + const USER_SYSTEM_ENABLED = 'USER_SYSTEM_ENABLED'; public static function getTemplate($type) { $globalLanguage = Setting::getSetting('language')->value; diff --git a/server/models/Ticket.php b/server/models/Ticket.php index 315434e8..0c743bec 100644 --- a/server/models/Ticket.php +++ b/server/models/Ticket.php @@ -20,7 +20,9 @@ class Ticket extends DataStore { 'owner', 'ownTicketeventList', 'unreadStaff', - 'language' + 'language', + 'authorEmail', + 'authorName' ); } @@ -80,7 +82,9 @@ class Ticket extends DataStore { 'priority' => $this->priority, 'author' => $this->authorToArray(), 'owner' => $this->ownerToArray(), - 'events' => $this->eventsToArray() + 'events' => $this->eventsToArray(), + 'authorEmail' => $this->authorEmail, + 'authorName' => $this->authorName ]; } diff --git a/tests/init.rb b/tests/init.rb index bb1cdbaa..14646c99 100644 --- a/tests/init.rb +++ b/tests/init.rb @@ -53,3 +53,4 @@ require './system/edit-mail-template.rb' require './system/recover-mail-template.rb' require './system/disable-registration.rb' require './system/enable-registration.rb' +require './system/disable-user-system.rb' diff --git a/tests/system/get-mail-templates.rb b/tests/system/get-mail-templates.rb index 8e067655..f6b4ab10 100644 --- a/tests/system/get-mail-templates.rb +++ b/tests/system/get-mail-templates.rb @@ -10,6 +10,6 @@ describe'system/get-mail-templates' do (result['status']).should.equal('success') - (result['data'].size).should.equal(10) + (result['data'].size).should.equal(14) end end From 73c8d94626d9a7c332716494a639ecdf35b2aa41 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 16 Jan 2017 16:58:46 -0300 Subject: [PATCH 46/84] Max Red - renamed user-system to advanced-settings [skip ci] --- client/src/app/Routes.js | 4 ++-- client/src/app/admin/panel/admin-panel-menu.js | 4 ++-- .../settings/admin-panel-advanced-settings.js | 14 ++++++++++++++ .../panel/settings/admin-panel-user-system.js | 14 -------------- client/src/data/languages/en.js | 2 +- 5 files changed, 19 insertions(+), 19 deletions(-) create mode 100644 client/src/app/admin/panel/settings/admin-panel-advanced-settings.js delete mode 100644 client/src/app/admin/panel/settings/admin-panel-user-system.js diff --git a/client/src/app/Routes.js b/client/src/app/Routes.js index 2a137332..678a7e1c 100644 --- a/client/src/app/Routes.js +++ b/client/src/app/Routes.js @@ -48,7 +48,7 @@ import AdminPanelDepartments from 'app/admin/panel/staff/admin-panel-departments import AdminPanelViewStaff from 'app/admin/panel/staff/admin-panel-view-staff'; import AdminPanelSystemPreferences from 'app/admin/panel/settings/admin-panel-system-preferences'; -import AdminPanelUserSystem from 'app/admin/panel/settings/admin-panel-user-system'; +import AdminPanelAdvancedSettings from 'app/admin/panel/settings/admin-panel-advanced-settings'; import AdminPanelEmailTemplates from 'app/admin/panel/settings/admin-panel-email-templates'; import AdminPanelCustomFields from 'app/admin/panel/settings/admin-panel-custom-fields'; @@ -114,7 +114,7 @@ export default ( - + diff --git a/client/src/app/admin/panel/admin-panel-menu.js b/client/src/app/admin/panel/admin-panel-menu.js index 7112320d..711a095f 100644 --- a/client/src/app/admin/panel/admin-panel-menu.js +++ b/client/src/app/admin/panel/admin-panel-menu.js @@ -201,8 +201,8 @@ class AdminPanelMenu extends React.Component { level: 3 }, { - name: i18n('USER_SYSTEM'), - path: '/admin/panel/settings/user-system', + name: i18n('ADVANCED_SETTINGS'), + path: '/admin/panel/settings/advanced-settings', level: 3 }, { diff --git a/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js b/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js new file mode 100644 index 00000000..25012844 --- /dev/null +++ b/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js @@ -0,0 +1,14 @@ +import React from 'react'; + +class AdminPanelAdvancedSettings extends React.Component { + + render() { + return ( +
+ /admin/panel/settings/advanced-settings +
+ ); + } +} + +export default AdminPanelAdvancedSettings; \ No newline at end of file diff --git a/client/src/app/admin/panel/settings/admin-panel-user-system.js b/client/src/app/admin/panel/settings/admin-panel-user-system.js deleted file mode 100644 index 671bd69b..00000000 --- a/client/src/app/admin/panel/settings/admin-panel-user-system.js +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; - -class AdminPanelUserSystem extends React.Component { - - render() { - return ( -
- /admin/panel/settings/user-system -
- ); - } -} - -export default AdminPanelUserSystem; \ No newline at end of file diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js index 8e69269c..ef3d610f 100644 --- a/client/src/data/languages/en.js +++ b/client/src/data/languages/en.js @@ -48,7 +48,7 @@ export default { 'STAFF_MEMBERS': 'Staff Members', 'DEPARTMENTS': 'Departments', 'SYSTEM_PREFERENCES': 'System Preferences', - 'USER_SYSTEM': 'User System', + 'ADVANCED_SETTINGS': 'Advanced Settings', 'EMAIL_TEMPLATES': 'Email Templates', 'FILTERS_CUSTOM_FIELDS': 'Filters and Custom Fields', 'PRIORITY': 'Priority', From bcb9b5b7ac4428772af5644c2308683e8ec9e79e Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 16 Jan 2017 17:00:48 -0300 Subject: [PATCH 47/84] Max Red - deleted filters and custom fields [skip ci] --- client/src/app/Routes.js | 2 -- client/src/app/admin/panel/admin-panel-menu.js | 5 ----- .../panel/settings/admin-panel-custom-fields.js | 14 -------------- 3 files changed, 21 deletions(-) delete mode 100644 client/src/app/admin/panel/settings/admin-panel-custom-fields.js diff --git a/client/src/app/Routes.js b/client/src/app/Routes.js index 678a7e1c..f293eded 100644 --- a/client/src/app/Routes.js +++ b/client/src/app/Routes.js @@ -50,7 +50,6 @@ import AdminPanelViewStaff from 'app/admin/panel/staff/admin-panel-view-staff'; import AdminPanelSystemPreferences from 'app/admin/panel/settings/admin-panel-system-preferences'; import AdminPanelAdvancedSettings from 'app/admin/panel/settings/admin-panel-advanced-settings'; import AdminPanelEmailTemplates from 'app/admin/panel/settings/admin-panel-email-templates'; -import AdminPanelCustomFields from 'app/admin/panel/settings/admin-panel-custom-fields'; const history = syncHistoryWithStore(browserHistory, store); @@ -116,7 +115,6 @@ export default ( - diff --git a/client/src/app/admin/panel/admin-panel-menu.js b/client/src/app/admin/panel/admin-panel-menu.js index 711a095f..92d325d3 100644 --- a/client/src/app/admin/panel/admin-panel-menu.js +++ b/client/src/app/admin/panel/admin-panel-menu.js @@ -209,11 +209,6 @@ class AdminPanelMenu extends React.Component { name: i18n('EMAIL_TEMPLATES'), path: '/admin/panel/settings/email-templates', level: 3 - }, - { - name: i18n('FILTERS_CUSTOM_FIELDS'), - path: '/admin/panel/settings/custom-fields', - level: 3 } ]) } diff --git a/client/src/app/admin/panel/settings/admin-panel-custom-fields.js b/client/src/app/admin/panel/settings/admin-panel-custom-fields.js deleted file mode 100644 index 8ffce603..00000000 --- a/client/src/app/admin/panel/settings/admin-panel-custom-fields.js +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; - -class AdminPanelCustomFields extends React.Component { - - render() { - return ( -
- /admin/panel/settings/custom-fields -
- ); - } -} - -export default AdminPanelCustomFields; \ No newline at end of file From 8ce33a2e4091c4da25996ee79228d073d203a5f5 Mon Sep 17 00:00:00 2001 From: AntonyAntonio Date: Mon, 16 Jan 2017 17:11:45 -0300 Subject: [PATCH 48/84] Guillermo - disable-user-system [skip ci] --- server/controllers/system.php | 1 + server/controllers/system/init-settings.php | 3 +-- server/data/ERRORS.php | 4 ++-- tests/init.rb | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/server/controllers/system.php b/server/controllers/system.php index 18f96ccc..99ae4d82 100644 --- a/server/controllers/system.php +++ b/server/controllers/system.php @@ -16,6 +16,7 @@ require_once 'system/enabled-user-system.php'; require_once 'system/add-api-key.php'; require_once 'system/delete-api-key.php'; require_once 'system/get-all-keys.php'; +require_once 'system/get-stats.php'; require_once 'system/delete-all-users.php'; require_once 'system/backup-database.php'; require_once 'system/download.php'; diff --git a/server/controllers/system/init-settings.php b/server/controllers/system/init-settings.php index 3ce00b75..808fafd5 100644 --- a/server/controllers/system/init-settings.php +++ b/server/controllers/system/init-settings.php @@ -42,8 +42,7 @@ class InitSettingsController extends Controller { 'title' => 'Support Center', 'url' => 'http://www.opensupports.com/support', 'registration' => true, - 'user-system-enabled' => true - 'registration' => true, + 'user-system-enabled' => true, 'last-stat-day' => '20170101', //TODO: get current date 'ticket-gap' => Hashing::generateRandomPrime(100000, 999999), 'file-gap' => Hashing::generateRandomPrime(100000, 999999), diff --git a/server/data/ERRORS.php b/server/data/ERRORS.php index 6e2921b8..1f49d6de 100644 --- a/server/data/ERRORS.php +++ b/server/data/ERRORS.php @@ -36,8 +36,8 @@ class ERRORS { const INVALID_SUBJECT = 'INVALID_SUBJECT'; const INVALID_BODY = 'INVALID_BODY'; const USER_SYSTEM_DISABLED= 'USER_SYSTEM_DISABLED'; - const SYSTEM_USER_IS_ALREADY_DISABLED= 'SYSTEM_USER_IS_ALREADY_DISABLED'; - const SYSTEM_USER_IS_ALREADY_ENABLED= 'SYSTEM_USER_IS_ALREADY_ENABLED'; + const SYSTEM_USER_IS_ALREADY_DISABLED = 'SYSTEM_USER_IS_ALREADY_DISABLED'; + const SYSTEM_USER_IS_ALREADY_ENABLED = 'SYSTEM_USER_IS_ALREADY_ENABLED'; const INVALID_PERIOD = 'INVALID_PERIOD'; const NAME_ALREADY_USED = 'NAME_ALREADY_USED'; const INVALID_FILE = 'INVALID_FILE'; diff --git a/tests/init.rb b/tests/init.rb index 75c8b75e..90a63e4b 100644 --- a/tests/init.rb +++ b/tests/init.rb @@ -53,9 +53,9 @@ require './system/edit-mail-template.rb' require './system/recover-mail-template.rb' require './system/disable-registration.rb' require './system/enable-registration.rb' -require './system/disable-user-system.rb' require './system/get-stats.rb' require './system/add-api-key.rb' require './system/delete-api-key.rb' require './system/get-all-keys.rb' require './system/file-upload-download.rb' +require './system/disable-user-system.rb' From c4b63aab4347bc026069fd27189b23a5a7217073 Mon Sep 17 00:00:00 2001 From: AntonyAntonio Date: Mon, 16 Jan 2017 18:04:26 -0300 Subject: [PATCH 49/84] Guillermo - disable-user-system [skip ci] --- server/controllers/system/csv-import.php | 4 ++++ server/controllers/ticket/comment.php | 4 +++- server/controllers/ticket/create.php | 4 +++- tests/init.rb | 1 + 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/server/controllers/system/csv-import.php b/server/controllers/system/csv-import.php index e415c6f1..ea3093b8 100644 --- a/server/controllers/system/csv-import.php +++ b/server/controllers/system/csv-import.php @@ -13,6 +13,10 @@ class CSVImportController extends Controller { public function handler() { $fileUploader = $this->uploadFile(); + if(!$fileUploader instanceof FileUploader) { + throw new Exception(ERRORS::INVALID_FILE); + } + $file = fopen($fileUploader->getFullFilePath(),'r'); $errors = []; diff --git a/server/controllers/ticket/comment.php b/server/controllers/ticket/comment.php index 2b5c90b9..9c27dc17 100644 --- a/server/controllers/ticket/comment.php +++ b/server/controllers/ticket/comment.php @@ -47,10 +47,12 @@ class CommentController extends Controller { } private function storeComment() { + $fileUploader = $this->uploadFile(); + $comment = Ticketevent::getEvent(Ticketevent::COMMENT); $comment->setProperties(array( 'content' => $this->content, - 'file' => $this->uploadFile()->getFileName(), + '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 1a07a0cb..4b761dc5 100644 --- a/server/controllers/ticket/create.php +++ b/server/controllers/ticket/create.php @@ -53,6 +53,8 @@ class CreateController extends Controller { $department = Department::getDataStore($this->departmentId); $author = Controller::getLoggedUser(); + $fileUploader = $this->uploadFile(); + $ticket = new Ticket(); $ticket->setProperties(array( 'title' => $this->title, @@ -60,7 +62,7 @@ class CreateController extends Controller { 'language' => $this->language, 'author' => $author, 'department' => $department, - 'file' => $this->uploadFile()->getFileName(), + 'file' => ($fileUploader instanceof FileUploader) ? $fileUploader->getFileName() : null, 'date' => Date::getCurrentDate(), 'unread' => false, 'unreadStaff' => true, diff --git a/tests/init.rb b/tests/init.rb index 1ecc936f..dad08d9a 100644 --- a/tests/init.rb +++ b/tests/init.rb @@ -59,3 +59,4 @@ require './system/add-api-key.rb' require './system/delete-api-key.rb' require './system/get-all-keys.rb' require './system/file-upload-download.rb' +require './system/csv-import.rb' From e32717a1a648744447decdde5496322dddd9061d Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 16 Jan 2017 18:05:07 -0300 Subject: [PATCH 50/84] Max Red - Added toggle buttons [skip ci] --- .../settings/admin-panel-advanced-settings.js | 46 +++++++++++++++++-- .../admin-panel-advanced-settings.scss | 3 ++ client/src/data/fixtures/system-fixtures.js | 10 ++-- client/src/data/languages/en.js | 3 ++ 4 files changed, 56 insertions(+), 6 deletions(-) create mode 100644 client/src/app/admin/panel/settings/admin-panel-advanced-settings.scss diff --git a/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js b/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js index 25012844..5a38038b 100644 --- a/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js +++ b/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js @@ -1,14 +1,54 @@ import React from 'react'; +import {connect} from 'react-redux'; + +import ConfigActions from 'actions/config-actions'; +import i18n from 'lib-app/i18n'; +import API from 'lib-app/api-call'; +import ToggleButton from 'app-components/toggle-button'; + +import Header from 'core-components/header'; class AdminPanelAdvancedSettings extends React.Component { + state = { + loading: true, + values: { + + } + }; + render() { return ( -
- /admin/panel/settings/advanced-settings +
+
+
+
+
+
+ + {i18n('USER_SYSTEM_ENABLED')} +
+
+
+
+ + {i18n('REGISTRATION')} +
+
+
+
+ +
+
); } + } -export default AdminPanelAdvancedSettings; \ No newline at end of file + +export default connect((store) => { + return { + config: store.config + }; +})(AdminPanelAdvancedSettings); diff --git a/client/src/app/admin/panel/settings/admin-panel-advanced-settings.scss b/client/src/app/admin/panel/settings/admin-panel-advanced-settings.scss new file mode 100644 index 00000000..b7ac1dcd --- /dev/null +++ b/client/src/app/admin/panel/settings/admin-panel-advanced-settings.scss @@ -0,0 +1,3 @@ +.admin-panel-system-settings { + +} \ No newline at end of file diff --git a/client/src/data/fixtures/system-fixtures.js b/client/src/data/fixtures/system-fixtures.js index ac2a5bbd..8b6e0e19 100644 --- a/client/src/data/fixtures/system-fixtures.js +++ b/client/src/data/fixtures/system-fixtures.js @@ -1,7 +1,7 @@ module.exports = [ { path: '/system/get-settings', - time: 1000, + time: 850, response: function (params) { if(params && params.allSettings) { return { @@ -27,7 +27,9 @@ module.exports = [ {id: 3, name: 'System and Administration', owners: 0} ], 'allowedLanguages': ['en', 'es', 'de', 'fr', 'pt', 'jp', 'ru', 'cn', 'in', 'tr'], - 'supportedLanguages': ['en', 'es', 'de'] + 'supportedLanguages': ['en', 'es', 'de'], + 'registration': true, + 'user-system-enabled': true } }; @@ -44,7 +46,9 @@ module.exports = [ {id: 3, name: 'System and Administration', owners: 0} ], 'allowedLanguages': ['en', 'es', 'de', 'fr', 'pt', 'jp', 'ru', 'cn', 'in', 'tr'], - 'supportedLanguages': ['en', 'es', 'de'] + 'supportedLanguages': ['en', 'es', 'de'], + 'registration': true, + 'user-system-enabled': true } }; } diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js index ef3d610f..457784da 100644 --- a/client/src/data/languages/en.js +++ b/client/src/data/languages/en.js @@ -152,6 +152,8 @@ export default { 'ALL_NOTIFICATIONS': 'All notifications', 'VERIFY_SUCCESS': 'User verified', 'VERIFY_FAILED': 'Could not verify', + 'USER_SYSTEM_ENABLED': 'Use user system for customers', + 'REGISTRATION': 'Enable user registration', //ACTIVITIES 'ACTIVITY_COMMENT': 'commented ticket', @@ -213,6 +215,7 @@ export default { 'SYSTEM_PREFERENCES_DESCRIPTION': 'Here you can edit the preferences of the system.', 'VERIFY_SUCCESS_DESCRIPTION': 'You user has been verified correctly. You can log in now.', 'VERIFY_FAILED_DESCRIPTION': 'The verification could not be done.', + 'ADVANCED_SETTINGS_DESCRIPTION': 'Advanced settings description should go here!', //ERRORS 'EMAIL_OR_PASSWORD': 'Email or password invalid', From 78a98b9d0e3823e968f580ec91572792a7b40df2 Mon Sep 17 00:00:00 2001 From: AntonyAntonio Date: Mon, 16 Jan 2017 18:15:28 -0300 Subject: [PATCH 51/84] Guillermo - disable-user-system [skip ci] --- .../system/disable-user-system.php | 1 + .../system/enabled-user-system.php | 48 ++++++++++--------- server/controllers/system/init-settings.php | 2 +- server/data/ERRORS.php | 2 +- 4 files changed, 29 insertions(+), 24 deletions(-) diff --git a/server/controllers/system/disable-user-system.php b/server/controllers/system/disable-user-system.php index cc1eee83..fc1cc0a1 100644 --- a/server/controllers/system/disable-user-system.php +++ b/server/controllers/system/disable-user-system.php @@ -52,6 +52,7 @@ class DisableUserSystemController extends Controller { $user->delete(); } + Response::respondSuccess(); } } \ No newline at end of file diff --git a/server/controllers/system/enabled-user-system.php b/server/controllers/system/enabled-user-system.php index fb6b2d3a..0139608a 100644 --- a/server/controllers/system/enabled-user-system.php +++ b/server/controllers/system/enabled-user-system.php @@ -33,28 +33,7 @@ class EnabledUserSystemController extends Controller { $userRow = User::getDataStore($ticket->authorEmail, 'email'); if($userRow->isNull()) { - $userInstance = new User(); - - $password = Hashing::generateRandomToken(); - - $userInstance->setProperties([ - 'name' => $ticket->authorName, - 'signupDate' => Date::getCurrentDate(), - 'tickets' => 1, - 'email' => $ticket->authorEmail, - 'password' => Hashing::hashPassword($password), - 'verificationToken' => null - ]); - - $userInstance->store(); - - $mailSender = new MailSender(); - $mailSender->setTemplate(MailTemplate::USER_SYSTEM_ENABLED, [ - 'to' => $ticket->authorEmail, - 'name' => $ticket->authorName, - 'password' => $password - ]); - $mailSender->send(); + $this->createUser($ticket->authorEmail,$ticket->authorName); } else { $userRow->tickets = $userRow->tickets + 1; @@ -71,4 +50,29 @@ class EnabledUserSystemController extends Controller { Response::respondSuccess(); } + public function createUser($email,$name) { + $userInstance = new User(); + + $password = Hashing::generateRandomToken(); + + $userInstance->setProperties([ + 'name' => $name, + 'signupDate' => Date::getCurrentDate(), + 'tickets' => 1, + 'email' => $email, + 'password' => Hashing::hashPassword($password), + 'verificationToken' => null + ]); + + $userInstance->store(); + + $mailSender = new MailSender(); + $mailSender->setTemplate(MailTemplate::USER_SYSTEM_ENABLED, [ + 'to' => $email, + 'name' => $name, + 'password' => $password + ]); + $mailSender->send(); + + } } \ No newline at end of file diff --git a/server/controllers/system/init-settings.php b/server/controllers/system/init-settings.php index 808fafd5..4106797b 100644 --- a/server/controllers/system/init-settings.php +++ b/server/controllers/system/init-settings.php @@ -38,7 +38,7 @@ class InitSettingsController extends Controller { 'maintenance-mode' => 0, 'layout' => 'boxed', 'allow-attachments' => 0, - 'max-size' => 0, + 'max-size' => 1024, 'title' => 'Support Center', 'url' => 'http://www.opensupports.com/support', 'registration' => true, diff --git a/server/data/ERRORS.php b/server/data/ERRORS.php index 1f49d6de..d75c7e2b 100644 --- a/server/data/ERRORS.php +++ b/server/data/ERRORS.php @@ -35,7 +35,7 @@ class ERRORS { const INVALID_TEMPLATE = 'INVALID_TEMPLATE'; const INVALID_SUBJECT = 'INVALID_SUBJECT'; const INVALID_BODY = 'INVALID_BODY'; - const USER_SYSTEM_DISABLED= 'USER_SYSTEM_DISABLED'; + const USER_SYSTEM_DISABLED = 'USER_SYSTEM_DISABLED'; const SYSTEM_USER_IS_ALREADY_DISABLED = 'SYSTEM_USER_IS_ALREADY_DISABLED'; const SYSTEM_USER_IS_ALREADY_ENABLED = 'SYSTEM_USER_IS_ALREADY_ENABLED'; const INVALID_PERIOD = 'INVALID_PERIOD'; From e44792c3de5cb723bfe4cf14176e9f02d837674b Mon Sep 17 00:00:00 2001 From: AntonyAntonio Date: Mon, 16 Jan 2017 20:06:08 -0300 Subject: [PATCH 52/84] Ivan - Add csv file [skip ci] --- tests/system/csv-import.rb | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tests/system/csv-import.rb diff --git a/tests/system/csv-import.rb b/tests/system/csv-import.rb new file mode 100644 index 00000000..61ac34ba --- /dev/null +++ b/tests/system/csv-import.rb @@ -0,0 +1,28 @@ +describe'system/csv-import' do + request('/user/logout') + Scripts.login($staff[:email], $staff[:password], true) + + it 'should create user with csv-import' do + + file = File.new('../server/files/test.csv', 'w+') + file.puts('prueba1@hotmail.com, contrasena1,ma') + file.puts('prueba2@hotmail.com,contrasena2,max') + file.puts('prueba3@hotmail.com,contrasena3,maxi') + file.close + result= request('/system/csv-import', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + file: File.open( "../server/files/test.csv") + }) + + (result['status']).should.equal('success') + row = $database.getRow('user', 'prueba1@hotmail.com', 'email') + (row['name']).should.equal('ma') + + row = $database.getRow('user', 'prueba2@hotmail.com', 'email') + (row['name']).should.equal('max') + + row = $database.getRow('user', 'prueba3@hotmail.com', 'email') + (row['name']).should.equal('maxi') + end +end From 577ce49d6f3e11a5e629759e7304640697300f04 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 16 Jan 2017 20:07:41 -0300 Subject: [PATCH 53/84] Max Red - Created top bars [skip ci] --- client/src/app-components/toggle-button.js | 13 +++++++- .../settings/admin-panel-advanced-settings.js | 32 ++++++++++++++++--- .../admin-panel-advanced-settings.scss | 17 +++++++++- client/src/data/languages/en.js | 4 +++ 4 files changed, 59 insertions(+), 7 deletions(-) diff --git a/client/src/app-components/toggle-button.js b/client/src/app-components/toggle-button.js index dda2a00d..ee32845b 100644 --- a/client/src/app-components/toggle-button.js +++ b/client/src/app-components/toggle-button.js @@ -1,5 +1,6 @@ import React from 'react'; +import classNames from 'classnames'; import i18n from 'lib-app/i18n'; class ToggleButton extends React.Component { @@ -12,12 +13,22 @@ class ToggleButton extends React.Component { render() { return ( -
+
{this.props.value ? i18n('ON') : i18n('OFF')}
); } + getClass() { + let classes = { + 'toggle-button': true, + [this.props.className]: (this.props.className) + }; + + return classNames(classes); + } + + onClick() { if (this.props.onChange) { this.props.onChange({ diff --git a/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js b/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js index 5a38038b..63b9e522 100644 --- a/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js +++ b/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js @@ -3,9 +3,10 @@ import {connect} from 'react-redux'; import ConfigActions from 'actions/config-actions'; import i18n from 'lib-app/i18n'; -import API from 'lib-app/api-call'; import ToggleButton from 'app-components/toggle-button'; +import Button from 'core-components/button'; +import FileUploader from 'core-components/file-uploader'; import Header from 'core-components/header'; class AdminPanelAdvancedSettings extends React.Component { @@ -25,20 +26,41 @@ class AdminPanelAdvancedSettings extends React.Component {
- - {i18n('USER_SYSTEM_ENABLED')} + {i18n('USER_SYSTEM_ENABLED')} +
- - {i18n('REGISTRATION')} + {i18n('REGISTRATION')} +
+
+
+
{i18n('INCLUDE_USERS_VIA_CSV')}
+ +
+
+
{i18n('INCLUDE_DATABASE_VIA_SQL')}
+ +
+
+
{i18n('BACKUP_DATABASE')}
+ +
+
+
{i18n('DELETE_ALL_USERS')}
+ +
+
+
+ +
); diff --git a/client/src/app/admin/panel/settings/admin-panel-advanced-settings.scss b/client/src/app/admin/panel/settings/admin-panel-advanced-settings.scss index b7ac1dcd..cc27227e 100644 --- a/client/src/app/admin/panel/settings/admin-panel-advanced-settings.scss +++ b/client/src/app/admin/panel/settings/admin-panel-advanced-settings.scss @@ -1,3 +1,18 @@ .admin-panel-system-settings { + &__user-system-enabled { -} \ No newline at end of file + } + + &__registration { + + } + + &__toggle-button { + display: inline-block; + margin-left: 20px; + } + + &__text { + margin-bottom: 20px; + } +} diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js index 457784da..53f6018a 100644 --- a/client/src/data/languages/en.js +++ b/client/src/data/languages/en.js @@ -154,6 +154,10 @@ export default { 'VERIFY_FAILED': 'Could not verify', 'USER_SYSTEM_ENABLED': 'Use user system for customers', 'REGISTRATION': 'Enable user registration', + 'INCLUDE_USERS_VIA_CSV': 'Include users via CSV file', + 'INCLUDE_DATABASE_VIA_SQL': 'Include database via SQL file', + 'BACKUP_DATABASE': 'Backup database', + 'DELETE_ALL_USERS': 'Delete all users', //ACTIVITIES 'ACTIVITY_COMMENT': 'commented ticket', From 6ff0dbdf6b995b17deb4f69d4b959d77aece9818 Mon Sep 17 00:00:00 2001 From: AntonyAntonio Date: Mon, 16 Jan 2017 21:05:11 -0300 Subject: [PATCH 54/84] Guillermo - Add user system test [skip ci] --- tests/system/disable-user-system.rb | 89 +++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 tests/system/disable-user-system.rb diff --git a/tests/system/disable-user-system.rb b/tests/system/disable-user-system.rb new file mode 100644 index 00000000..076fdb23 --- /dev/null +++ b/tests/system/disable-user-system.rb @@ -0,0 +1,89 @@ +describe'system/disable-user-system' do + request('/user/logout') + Scripts.login($staff[:email], $staff[:password], true) + + it 'should disable the user system' do + result = request('/system/disable-user-system', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + password:$staff[:password] + }) + + puts result['message'] + (result['status']).should.equal('success') + + row = $database.getRow('setting', 'user-system-enabled', 'name') + + (row['value']).should.equal('0') + row = $database.getRow('user', 1, 'id') + (row).should.equal(nil) + + numberOftickets= $database.query("SELECT * FROM ticket WHERE author_id IS NULL AND author_email IS NOT NULL AND author_name IS NOT NULL") + + (numberOftickets.num_rows).should.equal(35) + + request('/user/logout') + + result = request('/user/signup', { + :name => 'test name', + :email => 'steve@mail.com', + :password => 'customm' + }) + + (result['status']).should.equal('fail') + (result['message']).should.equal('USER_SYSTEM_DISABLED') + + result = request('/user/login', { + email: @loginEmail, + password: @loginPass + }) + + (result['status']).should.equal('fail') + (result['message']).should.equal('USER_SYSTEM_DISABLED') + end + + it 'should not disable the user system if it is already disabled 'do + request('/user/logout') + Scripts.login($staff[:email], $staff[:password], true) + + result = request('/system/disable-user-system', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + password:$staff[:password] + }) + + (result['status']).should.equal('fail') + (result['message']).should.equal('SYSTEM_USER_IS_ALREADY_DISABLED') + end + + it 'should enabled the user system' do + result = request('/system/enabled-user-system', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + password:$staff[:password] + }) + + puts result['message'] + (result['status']).should.equal('success') + + row = $database.getRow('setting', 'user-system-enabled', 'name') + (row['value']).should.equal('1') + + numberOftickets= $database.query("SELECT * FROM ticket WHERE author_email IS NULL AND author_name IS NULL AND author_id IS NOT NULL" ) + + (numberOftickets.num_rows).should.equal(35) + + end + + it 'should not enabled the user system' do + result = request('/system/enabled-user-system', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + password:$staff[:password] + }) + + (result['status']).should.equal('fail') + (result['message']).should.equal('SYSTEM_USER_IS_ALREADY_ENABLED') + + end +end From ee5ba9dfad06b66dd3c645d0d84b193946e6680f Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 17 Jan 2017 14:55:00 -0300 Subject: [PATCH 55/84] Max Red - WIP [skip ci] --- client/src/app-components/are-you-sure.js | 45 +++++++++++++++---- client/src/app-components/are-you-sure.scss | 6 +++ .../settings/admin-panel-advanced-settings.js | 9 +++- client/src/data/languages/en.js | 1 + 4 files changed, 50 insertions(+), 11 deletions(-) diff --git a/client/src/app-components/are-you-sure.js b/client/src/app-components/are-you-sure.js index 82b569c0..71c8cdd8 100644 --- a/client/src/app-components/are-you-sure.js +++ b/client/src/app-components/are-you-sure.js @@ -2,21 +2,27 @@ import React from 'react'; import i18n from 'lib-app/i18n'; import Button from 'core-components/button'; +import Input from 'core-components/input'; import ModalContainer from 'app-components/modal-container'; class AreYouSure extends React.Component { static propTypes = { description: React.PropTypes.node, - onYes: React.PropTypes.func + onYes: React.PropTypes.func, + type: React.PropTypes.string }; static contextTypes = { closeModal: React.PropTypes.func }; - - static openModal(description, onYes) { + + state = { + password: '' + }; + + static openModal(description, onYes, type) { ModalContainer.openModal( - + ); } @@ -33,6 +39,7 @@ class AreYouSure extends React.Component {
{this.props.description}
+ {this.props.type === 'secure' ? this.renderPassword() : null}
-
@@ -49,11 +56,31 @@ class AreYouSure extends React.Component { ); } - onYes() { - this.closeModal(); + renderPassword() { + return ( + + ); + } - if (this.props.onYes) { - this.props.onYes(); + onPasswordChange(event) { + this.setState({ + password: event.target.value + }); + } + + onInputKeyDown(event) { + if (event.keyCode == 13) { + this.onYes(); + } + } + + onYes() { + if (this.state.password){ + this.closeModal(); + + if (this.props.onYes) { + this.props.onYes(); + } } } diff --git a/client/src/app-components/are-you-sure.scss b/client/src/app-components/are-you-sure.scss index 04f4c40e..9bb1964a 100644 --- a/client/src/app-components/are-you-sure.scss +++ b/client/src/app-components/are-you-sure.scss @@ -27,4 +27,10 @@ display: inline-block; margin-right: 10px; } + + &__password { + margin: 0 auto; + margin-top: -30px; + margin-bottom: 20px; + } } \ No newline at end of file diff --git a/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js b/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js index 63b9e522..08867d35 100644 --- a/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js +++ b/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js @@ -4,6 +4,7 @@ import {connect} from 'react-redux'; import ConfigActions from 'actions/config-actions'; import i18n from 'lib-app/i18n'; import ToggleButton from 'app-components/toggle-button'; +import AreYouSure from 'app-components/are-you-sure'; import Button from 'core-components/button'; import FileUploader from 'core-components/file-uploader'; @@ -27,13 +28,13 @@ class AdminPanelAdvancedSettings extends React.Component {
{i18n('USER_SYSTEM_ENABLED')} - +
{i18n('REGISTRATION')} - +
@@ -66,6 +67,10 @@ class AdminPanelAdvancedSettings extends React.Component { ); } + onToggleButtonChange() { + AreYouSure.openModal(
{i18n('PLEASE_CONFIRM_PASSWORD')}
, (a) => a, 'secure'); + } + } diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js index 53f6018a..0c934834 100644 --- a/client/src/data/languages/en.js +++ b/client/src/data/languages/en.js @@ -158,6 +158,7 @@ export default { 'INCLUDE_DATABASE_VIA_SQL': 'Include database via SQL file', 'BACKUP_DATABASE': 'Backup database', 'DELETE_ALL_USERS': 'Delete all users', + 'PLEASE_CONFIRM_PASSWORD': 'Please confirm your password to make these changes', //ACTIVITIES 'ACTIVITY_COMMENT': 'commented ticket', From a40121111efdaac2322cfe7230b1dc9a90a9749e Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 17 Jan 2017 14:58:28 -0300 Subject: [PATCH 56/84] Max Red - modified registration setting in fixtures [skip ci] --- client/src/data/fixtures/system-fixtures.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/data/fixtures/system-fixtures.js b/client/src/data/fixtures/system-fixtures.js index ecf3916e..ddff91bd 100644 --- a/client/src/data/fixtures/system-fixtures.js +++ b/client/src/data/fixtures/system-fixtures.js @@ -20,7 +20,7 @@ module.exports = [ 'smtp-user': 'Wesa', 'maintenance-mode': false, 'allow-attachments': true, - 'registration': false, + 'registration': true, 'max-size': 500, 'departments': [ {id: 1, name: 'Sales Support', owners: 2}, From 4fb1c32cbca114f2c515c340efdb49abaa0c4a86 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 17 Jan 2017 15:09:00 -0300 Subject: [PATCH 57/84] Max Red - beautified code by replacing a for for a map (: [skip ci] --- client/src/app-components/stats-chart.js | 1 - client/src/app-components/stats.js | 12 ++++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/client/src/app-components/stats-chart.js b/client/src/app-components/stats-chart.js index 5e4704b7..1ed7480e 100644 --- a/client/src/app-components/stats-chart.js +++ b/client/src/app-components/stats-chart.js @@ -93,7 +93,6 @@ class StatsChart extends React.Component { } }; } - } diff --git a/client/src/app-components/stats.js b/client/src/app-components/stats.js index 337bf446..a93e67dd 100644 --- a/client/src/app-components/stats.js +++ b/client/src/app-components/stats.js @@ -149,14 +149,14 @@ class Stats extends React.Component { let realPeriod = result.data.length / this.getStrokes().length; - for (let i = 0; i < result.data.length; i++) { - newStats[result.data[i].type] += result.data[i].value * 1; + result.data.map((item) => { + newStats[item.type] += item.value * 1; - newStrokes[ ID[result.data[i].type] ].values.push({ - date: result.data[i].date, - value: result.data[i].value * 1 + newStrokes[ ID[item.type] ].values.push({ + date: item.date, + value: item.value * 1 }); - } + }); this.setState({stats: newStats, strokes: newStrokes, period: realPeriod}); } From fda6e798a027682d93a6e6e7f541edfd7487386b Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 17 Jan 2017 15:26:18 -0300 Subject: [PATCH 58/84] Max Red - problems with displaying stats in admin-panel-my-account view, Ivan fixed it [skip ci] --- client/src/app/admin/panel/dashboard/admin-panel-stats.js | 2 +- client/src/data/languages/en.js | 1 + client/src/reducers/session-reducer.js | 4 +++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/client/src/app/admin/panel/dashboard/admin-panel-stats.js b/client/src/app/admin/panel/dashboard/admin-panel-stats.js index 5e992ffb..fbbd9f7e 100644 --- a/client/src/app/admin/panel/dashboard/admin-panel-stats.js +++ b/client/src/app/admin/panel/dashboard/admin-panel-stats.js @@ -9,7 +9,7 @@ class AdminPanelStats extends React.Component { render() { return (
-
+
); diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js index c79a2ae8..3c086c8a 100644 --- a/client/src/data/languages/en.js +++ b/client/src/data/languages/en.js @@ -222,6 +222,7 @@ export default { 'SYSTEM_PREFERENCES_DESCRIPTION': 'Here you can edit the preferences of the system.', 'VERIFY_SUCCESS_DESCRIPTION': 'You user has been verified correctly. You can log in now.', 'VERIFY_FAILED_DESCRIPTION': 'The verification could not be done.', + 'TICKET_ACTIVITY_DESCRIPTION': 'Here you can view ', //ERRORS 'EMAIL_OR_PASSWORD': 'Email or password invalid', diff --git a/client/src/reducers/session-reducer.js b/client/src/reducers/session-reducer.js index c1eca34f..a51d7e67 100644 --- a/client/src/reducers/session-reducer.js +++ b/client/src/reducers/session-reducer.js @@ -119,6 +119,7 @@ class SessionReducer extends Reducer { onSessionChecked(state) { let userData = sessionStore.getUserData(); + let userId = sessionStore.getSessionData().userId; return _.extend({}, state, { initDone: true, @@ -129,7 +130,8 @@ class SessionReducer extends Reducer { userProfilePic: userData.profilePic, userLevel: userData.level, userDepartments: userData.departments, - userTickets: userData.tickets + userTickets: userData.tickets, + userId: userId }); } From f1c82dc38445915b1bd17c168376453959ead179 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 17 Jan 2017 15:50:33 -0300 Subject: [PATCH 59/84] Max Red - beautified code a little bit more replacing another for for another map [skip ci] --- client/src/app-components/stats-chart.js | 17 +++++++++-------- client/src/app/admin/panel/admin-panel-menu.js | 2 +- .../admin/panel/dashboard/admin-panel-stats.js | 2 +- client/src/data/languages/en.js | 8 ++++---- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/client/src/app-components/stats-chart.js b/client/src/app-components/stats-chart.js index 1ed7480e..ca1a2d49 100644 --- a/client/src/app-components/stats-chart.js +++ b/client/src/app-components/stats-chart.js @@ -66,14 +66,15 @@ class StatsChart extends React.Component { let months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; let labels = []; - for (let i = 0; i < this.props.period; i++) { - if (!this.props.strokes.length){ - labels.push(''); - continue; - } - let firstList = this.props.strokes[0]; - let idx = firstList.values[i].date.slice(4, 6) - 1; - labels.push( firstList.values[i].date.slice(6, 8) + ' ' + months[idx]); + if (!this.props.strokes.length) { + labels = Array.from('x'.repeat(this.props.period)); + } + else { + labels = this.props.strokes[0].values.map((item) => { + let idx = item.date.slice(4, 6) - 1; + + return item.date.slice(6, 8) + ' ' + months[idx]; + }); } return labels; diff --git a/client/src/app/admin/panel/admin-panel-menu.js b/client/src/app/admin/panel/admin-panel-menu.js index 7112320d..976d7c96 100644 --- a/client/src/app/admin/panel/admin-panel-menu.js +++ b/client/src/app/admin/panel/admin-panel-menu.js @@ -99,7 +99,7 @@ class AdminPanelMenu extends React.Component { level: 1, items: this.getItemsByFilteredByLevel([ { - name: i18n('TICKET_STATS'), + name: i18n('STATISTICS'), path: '/admin/panel/stats', level: 1 }, diff --git a/client/src/app/admin/panel/dashboard/admin-panel-stats.js b/client/src/app/admin/panel/dashboard/admin-panel-stats.js index fbbd9f7e..c5452e50 100644 --- a/client/src/app/admin/panel/dashboard/admin-panel-stats.js +++ b/client/src/app/admin/panel/dashboard/admin-panel-stats.js @@ -9,7 +9,7 @@ class AdminPanelStats extends React.Component { render() { return (
-
+
); diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js index 3c086c8a..b72a8e69 100644 --- a/client/src/data/languages/en.js +++ b/client/src/data/languages/en.js @@ -36,7 +36,7 @@ export default { 'DASHBOARD': 'Dashboard', 'USERS': 'Users', 'SETTINGS': 'Settings', - 'TICKET_STATS': 'Ticket Stats', + 'STATISTICS': 'Statistics', 'LAST_ACTIVITY': 'Last Activity', 'MY_TICKETS': 'My Tickets', 'NEW_TICKETS': 'New Tickets', @@ -152,7 +152,7 @@ export default { 'ALL_NOTIFICATIONS': 'All notifications', 'VERIFY_SUCCESS': 'User verified', 'VERIFY_FAILED': 'Could not verify', - 'TICKET_ACTIVITY': 'Ticket Activity', + 'STATISTICS': 'Statistics', 'ACTIVITY': 'Activity', @@ -211,7 +211,7 @@ export default { 'ADD_ARTICLE_DESCRIPTION': 'Here you can add an article that will be available for every user. It will be added inside the category {category}.', 'LIST_ARTICLES_DESCRIPTION': 'This is a list of articles that includes information about our services.', 'ADD_TOPIC_DESCRIPTION': 'Here you can add a topic that works as a category for articles.', - 'DELETE_ARTICLE_DESCRIPTION': 'You\'re going to delete this article for ever.', + 'DELETE_ARTICLE_DESCRIPTION': 'You\'re going to delete this article forever.', 'STAFF_MEMBERS_DESCRIPTION': 'Here you can see who are your staff members.', 'ADD_STAFF_DESCRIPTION': 'Here you can add staff members to your teams.', 'EDIT_STAFF_DESCRIPTION': 'Here you can edit information about a staff member.', @@ -222,7 +222,7 @@ export default { 'SYSTEM_PREFERENCES_DESCRIPTION': 'Here you can edit the preferences of the system.', 'VERIFY_SUCCESS_DESCRIPTION': 'You user has been verified correctly. You can log in now.', 'VERIFY_FAILED_DESCRIPTION': 'The verification could not be done.', - 'TICKET_ACTIVITY_DESCRIPTION': 'Here you can view ', + 'STATISTICS_DESCRIPTION': 'Here you can view statistics related to tickets and signups.', //ERRORS 'EMAIL_OR_PASSWORD': 'Email or password invalid', From 26d26320c927a26b426caf2c0bbd2c36069d8c8c Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 17 Jan 2017 15:52:12 -0300 Subject: [PATCH 60/84] Max Red - deleted console.logs from system-fixtures [skip ci] --- client/src/data/fixtures/system-fixtures.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/client/src/data/fixtures/system-fixtures.js b/client/src/data/fixtures/system-fixtures.js index 658e4ad7..51f64179 100644 --- a/client/src/data/fixtures/system-fixtures.js +++ b/client/src/data/fixtures/system-fixtures.js @@ -216,10 +216,6 @@ module.exports = [ } } - console.log('DATA:'); - console.log(DATA); - console.log(k); - return { status: "success", data: DATA From bce56d7b0503c6df80804b7993dc7818b1dff467 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 17 Jan 2017 15:53:43 -0300 Subject: [PATCH 61/84] Max Red - make toggle list unselectable and not able to change cursor view [skip ci] --- client/src/core-components/toggle-list.scss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/src/core-components/toggle-list.scss b/client/src/core-components/toggle-list.scss index 1fdd82e5..1ba34f67 100644 --- a/client/src/core-components/toggle-list.scss +++ b/client/src/core-components/toggle-list.scss @@ -9,6 +9,8 @@ height: 120px; display: inline-block; transition: box-shadow 0.2s ease-in-out; + user-select: none; + cursor: default; } &__selected { From e04d967c14c33cd126af067612d6511635c95636 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 17 Jan 2017 16:12:49 -0300 Subject: [PATCH 62/84] Max Red - space things up adding some css [skip ci] --- .../admin/panel/settings/admin-panel-advanced-settings.js | 8 ++++---- .../panel/settings/admin-panel-advanced-settings.scss | 7 +++++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js b/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js index 08867d35..e0151063 100644 --- a/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js +++ b/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js @@ -44,19 +44,19 @@ class AdminPanelAdvancedSettings extends React.Component {
{i18n('INCLUDE_USERS_VIA_CSV')}
- +
{i18n('INCLUDE_DATABASE_VIA_SQL')}
- +
{i18n('BACKUP_DATABASE')}
- +
{i18n('DELETE_ALL_USERS')}
- +
diff --git a/client/src/app/admin/panel/settings/admin-panel-advanced-settings.scss b/client/src/app/admin/panel/settings/admin-panel-advanced-settings.scss index cc27227e..3e836b97 100644 --- a/client/src/app/admin/panel/settings/admin-panel-advanced-settings.scss +++ b/client/src/app/admin/panel/settings/admin-panel-advanced-settings.scss @@ -10,9 +10,16 @@ &__toggle-button { display: inline-block; margin-left: 20px; + margin-top: 20px; + margin-bottom: 20px; } &__text { + margin-top: 30px; margin-bottom: 20px; } + + &__button { + margin-bottom: 30px; + } } From e20760e8bba0a9b2b42e9059b75c160ce78595d0 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Tue, 17 Jan 2017 16:27:46 -0300 Subject: [PATCH 63/84] Ivan - Update home page for user system disabled [skip ci] --- .../main/main-home/main-home-page-portal.js | 62 +++++++++++++++++-- .../src/app/main/main-home/main-home-page.js | 21 ++++--- client/src/app/main/main-layout-header.js | 2 +- client/src/core-components/button.js | 4 +- client/src/core-components/button.scss | 31 ++++++++++ client/src/core-components/card.js | 28 ++++++++- client/src/core-components/card.scss | 8 +++ client/src/data/fixtures/system-fixtures.js | 5 +- client/src/data/languages/en.js | 2 + 9 files changed, 146 insertions(+), 17 deletions(-) diff --git a/client/src/app/main/main-home/main-home-page-portal.js b/client/src/app/main/main-home/main-home-page-portal.js index 6f63cc37..3935e0d7 100644 --- a/client/src/app/main/main-home/main-home-page-portal.js +++ b/client/src/app/main/main-home/main-home-page-portal.js @@ -1,5 +1,7 @@ import React from 'react'; import classNames from 'classnames'; +import {browserHistory} from 'react-router'; +import {connect} from 'react-redux' import Widget from 'core-components/widget'; import Card from 'core-components/card'; @@ -7,26 +9,76 @@ import i18n from 'lib-app/i18n'; import Header from 'core-components/header'; class MainHomePagePortal extends React.Component { + static propTypes = { + type: React.PropTypes.oneOf(['default', 'complete']) + }; + render() { return (
-
+
- +
- +
- +
); } + + getTicketsCardProps() { + return { + title: i18n('TICKETS'), + description: i18n('TICKETS_DESCRIPTION'), + icon: 'ticket', + color: 'red', + buttonText: (this.props.type === 'complete') ? i18n('CREATE_TICKET') : null, + onButtonClick: () => browserHistory.push('/create-ticket') + }; + } + + getAccountCardProps() { + return { + title: i18n('ACCOUNT'), + description: i18n('ACCOUNT_DESCRIPTION'), + icon: 'user', + color: 'green' + }; + } + + getArticlesCardProps() { + return { + title: i18n('ARTICLES'), + description: i18n('ARTICLES_DESCRIPTION'), + icon: 'book', + color: 'blue', + buttonText: (this.props.type === 'complete') ? i18n('VIEW_ARTICLES') : null, + onButtonClick: () => browserHistory.push('/view-articles') + }; + } + + getViewTicketCardProps() { + return { + title: i18n('VIEW_TICKET'), + description: i18n('VIEW_TICKET_DESCRIPTION'), + icon: 'check-square-o', + color: 'green', + buttonText: (this.props.type === 'complete') ? i18n('CHECK_TICKET') : null, + onButtonClick: () => browserHistory.push('/check-ticket') + }; + } } -export default MainHomePagePortal; \ No newline at end of file +export default connect((store) => { + return { + title: store.config.title + }; +})(MainHomePagePortal); \ No newline at end of file diff --git a/client/src/app/main/main-home/main-home-page.js b/client/src/app/main/main-home/main-home-page.js index 5b258354..92840276 100644 --- a/client/src/app/main/main-home/main-home-page.js +++ b/client/src/app/main/main-home/main-home-page.js @@ -1,6 +1,6 @@ import React from 'react'; +import {connect} from 'react-redux' -import {connect} from 'react-redux' import i18n from 'lib-app/i18n'; import MainHomePageLoginWidget from 'app/main/main-home/main-home-page-login-widget'; @@ -13,11 +13,9 @@ class MainHomePage extends React.Component { return (
{this.renderMessage()} -
- -
-
- + {(this.props.config['user-system-enabled']) ? this.renderLoginWidget() : null} +
+
); @@ -34,6 +32,14 @@ class MainHomePage extends React.Component { } } + renderLoginWidget() { + return ( +
+ +
+ ); + } + renderSuccess() { return ( @@ -53,6 +59,7 @@ class MainHomePage extends React.Component { export default connect((store) => { return { - session: store.session + session: store.session, + config: store.config }; })(MainHomePage); \ No newline at end of file diff --git a/client/src/app/main/main-layout-header.js b/client/src/app/main/main-layout-header.js index dd031535..6702eb0b 100644 --- a/client/src/app/main/main-layout-header.js +++ b/client/src/app/main/main-layout-header.js @@ -12,7 +12,7 @@ class MainLayoutHeader extends React.Component { render() { return (
- {this.renderAccessLinks()} + {(this.props.config['user-system-enabled']) ? this.renderAccessLinks() : null}
); diff --git a/client/src/core-components/button.js b/client/src/core-components/button.js index 2932b38c..404834ad 100644 --- a/client/src/core-components/button.js +++ b/client/src/core-components/button.js @@ -17,6 +17,7 @@ class Button extends React.Component { static propTypes = { children: React.PropTypes.node, + inverted: React.PropTypes.bool, size: React.PropTypes.oneOf([ 'extra-small', 'small', @@ -70,7 +71,8 @@ class Button extends React.Component { let classes = { 'button': true, 'button_disabled': this.props.disabled, - + 'button_inverted': this.props.inverted, + 'button_primary': (this.props.type === 'primary'), 'button_secondary': (this.props.type === 'secondary'), 'button_tertiary': (this.props.type === 'tertiary'), diff --git a/client/src/core-components/button.scss b/client/src/core-components/button.scss index 2c133d1d..2729a652 100644 --- a/client/src/core-components/button.scss +++ b/client/src/core-components/button.scss @@ -31,6 +31,10 @@ &_secondary { background-color: $primary-green; + &:focus, &:hover { + background-color: lighten($primary-green, 5%); + outline: none; + } &.button_disabled, &.button_disabled:hover { @@ -41,6 +45,11 @@ &_tertiary { background-color: $secondary-blue; + &:focus, &:hover { + background-color: lighten($secondary-blue, 5%); + outline: none; + } + &.button_disabled, &.button_disabled:hover { background-color: lighten($secondary-blue, 15%); @@ -93,4 +102,26 @@ text-decoration: underline; } } + + &_inverted { + background-color: white; + + &:focus, &:hover { + background-color: white; + opacity: 0.9; + outline: none; + } + + &.button_primary { + color: $primary-red; + } + + &.button_secondary { + color: $primary-green; + } + + &.button_tertiary { + color: $secondary-blue; + } + } } \ No newline at end of file diff --git a/client/src/core-components/card.js b/client/src/core-components/card.js index 991b0161..29dda180 100644 --- a/client/src/core-components/card.js +++ b/client/src/core-components/card.js @@ -1,5 +1,6 @@ import React from 'react'; import Icon from 'core-components/icon'; +import Button from 'core-components/button'; import classNames from 'classnames'; class Card extends React.Component{ @@ -7,7 +8,9 @@ class Card extends React.Component{ description: React.PropTypes.string, title: React.PropTypes.string, icon: React.PropTypes.string, - color: React.PropTypes.string + color: React.PropTypes.string, + buttonText: React.PropTypes.string, + onButtonClick: React.PropTypes.func }; render() { @@ -16,12 +19,23 @@ class Card extends React.Component{
{this.props.title}
{this.props.description}
+ {(this.props.buttonText) ? this.renderButton() : null} +
+ ); + } + + renderButton() { + return ( +
+
); } getClass() { - var classes = { + let classes = { 'card': true, 'card_red': (this.props.color === 'red'), 'card_blue': (this.props.color === 'blue'), @@ -32,5 +46,15 @@ class Card extends React.Component{ return classNames(classes); } + + getButtonType() { + let types = { + 'red': 'primary', + 'green': 'secondary', + 'blue': 'tertiary' + }; + + return types[this.props.color]; + } } export default Card; diff --git a/client/src/core-components/card.scss b/client/src/core-components/card.scss index 77bd29e2..1044b8b5 100644 --- a/client/src/core-components/card.scss +++ b/client/src/core-components/card.scss @@ -5,6 +5,7 @@ color: white; height: 260px; padding: 15px; + position: relative; &__title { font-variant: small-caps; @@ -16,6 +17,13 @@ font-size: $font-size--sm; } + &__button { + position: absolute; + left: 0; + right: 0; + bottom: 17px; + } + &_red { background-color: $primary-red; } diff --git a/client/src/data/fixtures/system-fixtures.js b/client/src/data/fixtures/system-fixtures.js index ac2a5bbd..b317c0b1 100644 --- a/client/src/data/fixtures/system-fixtures.js +++ b/client/src/data/fixtures/system-fixtures.js @@ -11,7 +11,7 @@ module.exports = [ 'reCaptchaKey': '6LfM5CYTAAAAAGLz6ctpf-hchX2_l0Ge-Bn-n8wS', 'reCaptchaPrivate': 'LALA', 'url': 'http://www.opensupports.com/support', - 'title': 'Very Cool', + 'title': 'OpenSupports Support Center', 'layout': 'Boxed', 'time-zone': 3, 'no-reply-email': 'shitr@post.com', @@ -36,8 +36,11 @@ module.exports = [ status: 'success', data: { 'language': 'en', + 'title': '', + 'layout': 'Boxed', 'reCaptchaKey': '6LfM5CYTAAAAAGLz6ctpf-hchX2_l0Ge-Bn-n8wS', 'maintenance-mode': false, + 'user-system-enabled': false, 'departments': [ {id: 1, name: 'Sales Support', owners: 2}, {id: 2, name: 'Technical Issues', owners: 5}, diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js index 8e69269c..882ffabf 100644 --- a/client/src/data/languages/en.js +++ b/client/src/data/languages/en.js @@ -73,6 +73,7 @@ export default { 'ASSIGN_TO_ME': 'Assign to me', 'UN_ASSIGN': 'Unassign', 'VIEW_TICKET': 'View Ticket', + 'VIEW_TICKET_DESCRIPTION': 'Check the status of your ticket using your ticket number and email.', 'SELECT_CUSTOM_RESPONSE': 'Select a custom response...', 'WARNING': 'Warning', 'INFO': 'Information', @@ -152,6 +153,7 @@ export default { 'ALL_NOTIFICATIONS': 'All notifications', 'VERIFY_SUCCESS': 'User verified', 'VERIFY_FAILED': 'Could not verify', + 'CHECK_TICKET': 'Check Ticket', //ACTIVITIES 'ACTIVITY_COMMENT': 'commented ticket', From 18b736dea784bed16fab63ad70c55335ae456ee4 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 17 Jan 2017 21:39:16 -0300 Subject: [PATCH 64/84] Max Red - add items from fixtures to registration api keys [skip ci] --- .../settings/admin-panel-advanced-settings.js | 49 ++++++++++++++++++- .../admin-panel-advanced-settings.scss | 24 +++++++++ client/src/data/fixtures/system-fixtures.js | 29 +++++++++-- client/src/data/languages/en.js | 3 ++ 4 files changed, 101 insertions(+), 4 deletions(-) diff --git a/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js b/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js index e0151063..bb8354c8 100644 --- a/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js +++ b/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js @@ -2,6 +2,7 @@ import React from 'react'; import {connect} from 'react-redux'; import ConfigActions from 'actions/config-actions'; +import API from 'lib-app/api-call'; import i18n from 'lib-app/i18n'; import ToggleButton from 'app-components/toggle-button'; import AreYouSure from 'app-components/are-you-sure'; @@ -9,16 +10,21 @@ import AreYouSure from 'app-components/are-you-sure'; import Button from 'core-components/button'; import FileUploader from 'core-components/file-uploader'; import Header from 'core-components/header'; +import Listing from 'core-components/listing'; class AdminPanelAdvancedSettings extends React.Component { state = { loading: true, values: { - + apikeys: [] } }; + componentDidMount() { + this.getAllKeys(); + } + render() { return (
@@ -62,11 +68,52 @@ class AdminPanelAdvancedSettings extends React.Component {
+
+
{i18n('REGISTRATION_API_KEYS')}
+
+ +
+
+
{i18n('NAME_OF_KEY')}
+
+
{i18n('KEY')}
+
+ +
+
); } + getListingProps() { + return { + title: i18n('REGISTRATION_API_KEYS'), + enableAddNew: true, + items: this.state.values.apikeys.map((item) => { + return { + content: item.name, + icon: '' + }; + }) + } + } + + getAllKeys() { + API.call({ + path: '/system/get-all-keys', + data: {} + }).then(this.onRetrieveSuccess.bind(this)); + } + + onRetrieveSuccess(result) { + this.setState({ + values: { + apikeys: result.data + } + }); + } + onToggleButtonChange() { AreYouSure.openModal(
{i18n('PLEASE_CONFIRM_PASSWORD')}
, (a) => a, 'secure'); } diff --git a/client/src/app/admin/panel/settings/admin-panel-advanced-settings.scss b/client/src/app/admin/panel/settings/admin-panel-advanced-settings.scss index 3e836b97..30ea3730 100644 --- a/client/src/app/admin/panel/settings/admin-panel-advanced-settings.scss +++ b/client/src/app/admin/panel/settings/admin-panel-advanced-settings.scss @@ -1,3 +1,5 @@ +@import "../../../../scss/vars"; + .admin-panel-system-settings { &__user-system-enabled { @@ -21,5 +23,27 @@ &__button { margin-bottom: 30px; + width: 150px; + } + + &__api-keys { + text-align: left; + + &-title { + font-size: $font-size--bg; + margin-bottom: 20px; + text-align: left; + } + + &-subtitle { + font-size: $font-size--md; + margin-bottom: 5px; + } + + &-button { + margin-left: 20px; + margin-right: 20px; + width: 150px; + } } } diff --git a/client/src/data/fixtures/system-fixtures.js b/client/src/data/fixtures/system-fixtures.js index 8b6e0e19..3e98c9a8 100644 --- a/client/src/data/fixtures/system-fixtures.js +++ b/client/src/data/fixtures/system-fixtures.js @@ -169,13 +169,36 @@ module.exports = [ }; } }, + { + path: '/system/get-all-keys', + time: 300, + response: function () { + return { + status: "success", + data: [ + { + name: 'Game System Registration', + token: '9as8da9s51c6a51c51a9s1c9asdf1' + }, + { + name: 'PHPbb forum', + token: 'apires1qe65fq65e1f6a5e1f6afaef2' + }, + { + name: 'How do you turn this on?', + token: 'das65d4as651age16wq6ofqwwcemcw' + } + ] + } + } + }, { path: '/system/get-logs', time: 300, - response: function() { + response: function () { return { - "status": "success", - "data": [ + status: "success", + data: [ { "type": "EDIT_SETTINGS", "to": null, diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js index 0c934834..5b9fd926 100644 --- a/client/src/data/languages/en.js +++ b/client/src/data/languages/en.js @@ -159,6 +159,9 @@ export default { 'BACKUP_DATABASE': 'Backup database', 'DELETE_ALL_USERS': 'Delete all users', 'PLEASE_CONFIRM_PASSWORD': 'Please confirm your password to make these changes', + 'REGISTRATION_API_KEYS': 'Registration API keys', + 'NAME_OF_KEY': 'Name of key', + 'KEY': 'Key', //ACTIVITIES 'ACTIVITY_COMMENT': 'commented ticket', From cf7dbffbf3dcc8df39f4fefbc9dceb42c5f5161e Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 17 Jan 2017 23:51:22 -0300 Subject: [PATCH 65/84] Max Red - WIP [skip ci] --- client/src/app-components/are-you-sure.js | 12 +- .../settings/admin-panel-advanced-settings.js | 120 ++++++++++++++++-- client/src/data/fixtures/system-fixtures.js | 60 ++++++++- 3 files changed, 179 insertions(+), 13 deletions(-) diff --git a/client/src/app-components/are-you-sure.js b/client/src/app-components/are-you-sure.js index 71c8cdd8..f2bb55d5 100644 --- a/client/src/app-components/are-you-sure.js +++ b/client/src/app-components/are-you-sure.js @@ -9,7 +9,11 @@ class AreYouSure extends React.Component { static propTypes = { description: React.PropTypes.node, onYes: React.PropTypes.func, - type: React.PropTypes.string + type: React.PropTypes.oneOf(['default', 'secure']) + }; + + static defaultProps = { + type: 'default' }; static contextTypes = { @@ -39,7 +43,7 @@ class AreYouSure extends React.Component {
{this.props.description}
- {this.props.type === 'secure' ? this.renderPassword() : null} + {(this.props.type === 'secure') ? this.renderPassword() : null}
+
{i18n('DELETE_ALL_USERS')}
- +
@@ -86,6 +92,12 @@ class AdminPanelAdvancedSettings extends React.Component { ); } + renderMessage() { + return ( + {this.state.messageContent} + ); + } + getListingProps() { return { title: i18n('REGISTRATION_API_KEYS'), @@ -114,10 +126,102 @@ class AdminPanelAdvancedSettings extends React.Component { }); } - onToggleButtonChange() { - AreYouSure.openModal(
{i18n('PLEASE_CONFIRM_PASSWORD')}
, (a) => a, 'secure'); + onToggleButtonUserSystemChange() { + AreYouSure.openModal(
{i18n('PLEASE_CONFIRM_PASSWORD')}
, this.onAreYouSureUserSystemOk.bind(this), 'secure'); } + onToggleButtonRegistrationChange() { + AreYouSure.openModal(
{i18n('PLEASE_CONFIRM_PASSWORD')}
, this.onAreYouSureRegistrationOk.bind(this), 'secure'); + } + + onAreYouSureUserSystemOk(password) { + API.call({ + path: this.props.config['user-system-enabled'] ? '/system/disable-user-system' : '/system/enable-user-system', + data: { + password: password + } + }).then(() => { + this.setState({ + messageType: 'success', + messageContent: this.props.config['user-system-enabled'] ? i18n('USER_SYSTEM_DISABLE_DESCRIPTION') : i18n('USER_SYSTEM_ENABLE_DESCRIPTION') + }); + this.props.dispatch(ConfigActions.updateData()); + }).catch(() => this.setState({messageType: 'fail', messageContent: i18n('ERROR_UPDATING_SETTINGS')})); + } + + onAreYouSureRegistrationOk(password) { + API.call({ + path: this.props.config['user-system-enabled'] ? '/system/disable-registration' : '/system/enable-registration', + data: { + password: password + } + }).then(() => { + this.setState({ + messageType: 'success', + messageContent: this.props.config['user-system-enabled'] ? i18n('REGISTRATION_DISABLE_DESCRIPTION') : i18n('REGISTRATION_ENABLE_DESCRIPTION') + }); + this.props.dispatch(ConfigActions.updateData()); + }).catch(() => this.setState({messageType: 'fail', messageContent: i18n('ERROR_UPDATING_SETTINGS')})); + } + + onImportCSV(event) { + AreYouSure.openModal(
{i18n('PLEASE_CONFIRM_PASSWORD')}
, this.onAreYouSureCSVOk.bind(this, event.target.value), 'secure'); + } + + onImportSQL(event) { + AreYouSure.openModal(
{i18n('PLEASE_CONFIRM_PASSWORD')}
, this.onAreYouSureSQLOk.bind(this, event.target.value), 'secure'); + } + + onAreYouSureCSVOk(file, password) { + API.call({ + path: '/system/import-csv', + data: { + file: file, + password: password + } + }).then(() => this.setState({messageType: 'success', messageContent: i18n('SUCCESS_IMPORTING_CSV_DESCRIPTION')} + )).catch(() => this.setState({messageType: 'fail', messageContent: i18n('ERROR_IMPORTING_CSV_DESCRIPTION')})); + } + + onAreYouSureSQLOk(file, password) { + API.call({ + path: '/system/import-sql', + data: { + file: file, + password: password + } + }).then(() => this.setState({messageType: 'success', messageContent: i18n('SUCCESS_IMPORTING_SQL_DESCRIPTION')} + )).catch(() => this.setState({messageType: 'fail', messageContent: i18n('ERROR_IMPORTING_SQL_DESCRIPTION')})); + } + + onBackupDatabase() { + API.call({ + path: '/system/backup-database', + plain: true, + data: {} + }).then((result) => { + let contentType = 'application/octet-stream'; + let link = document.createElement('a'); + let blob = new Blob([result], {'type': contentType}); + link.href = window.URL.createObjectURL(blob); + link.download = 'backup.sql'; + link.click(); + }); + } + + onDeleteAllUsers() { + AreYouSure.openModal(
{i18n('PLEASE_CONFIRM_PASSWORD')}
, this.onAreYouSureDeleteAllUsersOk.bind(this), 'secure'); + } + + onAreYouSureDeleteAllUsersOk(password) { + API.call({ + path: '/system/delete-all-users', + data: { + password: password + } + }).then(() => this.setState({messageType: 'success', messageContent: i18n('SUCCESS_DELETING_ALL_USERS')} + )).catch(() => this.setState({messageType: 'fail', messageContent: i18n('ERROR_DELETING_ALL_USERS')})); + } } diff --git a/client/src/data/fixtures/system-fixtures.js b/client/src/data/fixtures/system-fixtures.js index 3e98c9a8..f84766b7 100644 --- a/client/src/data/fixtures/system-fixtures.js +++ b/client/src/data/fixtures/system-fixtures.js @@ -122,6 +122,24 @@ module.exports = [ return 'text content'; } }, + { + path: '/system/delete-all-users', + time: 100, + response: function () { + return { + status: 'success', + data: {} + }; + } + }, + { + path: '/system/backup-database', + time: 100, + contentType: 'application/octet-stream', + response: function () { + return 'text content'; + } + }, { path: '/system/get-mail-templates', time: 100, @@ -169,12 +187,52 @@ module.exports = [ }; } }, + { + path: '/system/enable-user-system', + time: 100, + response: function () { + return { + status: 'success', + data: {} + } + } + }, + { + path: '/system/disable-user-system', + time: 100, + response: function () { + return { + status: 'success', + data: {} + } + } + }, + { + path: '/system/enable-registration', + time: 100, + response: function () { + return { + status: 'success', + data: {} + } + } + }, + { + path: '/system/disable-registration', + time: 100, + response: function () { + return { + status: 'success', + data: {} + } + } + }, { path: '/system/get-all-keys', time: 300, response: function () { return { - status: "success", + status: 'success', data: [ { name: 'Game System Registration', From 4119509cc43057e2188a25bff286412abd73d430 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Thu, 19 Jan 2017 17:37:51 -0300 Subject: [PATCH 66/84] Ivan - Add create ticket for no user system [skip ci] --- client/src/app/Routes.js | 7 ++++ .../create-ticket-form.js | 37 ++++++++++++------- .../dashboard-create-ticket-page.js | 35 ++++++++++++++++-- .../dashboard-create-ticket-page.scss | 6 +++ client/src/app/main/main-check-ticket-page.js | 13 +++++++ .../src/app/main/main-check-ticket-page.scss | 0 .../app/main/main-signup/main-signup-page.js | 4 +- 7 files changed, 84 insertions(+), 18 deletions(-) create mode 100644 client/src/app/main/dashboard/dashboard-create-ticket/dashboard-create-ticket-page.scss create mode 100644 client/src/app/main/main-check-ticket-page.js create mode 100644 client/src/app/main/main-check-ticket-page.scss diff --git a/client/src/app/Routes.js b/client/src/app/Routes.js index 2a137332..59b5f961 100644 --- a/client/src/app/Routes.js +++ b/client/src/app/Routes.js @@ -13,6 +13,7 @@ import MainSignUpPage from 'app/main/main-signup/main-signup-page'; import MainVerifyTokenPage from 'app/main/main-verify-token-page'; import MainRecoverPasswordPage from 'app/main/main-recover-password/main-recover-password-page'; import MainMaintenancePage from 'app/main/main-maintenance-page'; +import MainCheckTicketPage from 'app/main/main-check-ticket-page'; import DashboardLayout from 'app/main/dashboard/dashboard-layout'; import DashboardListTicketsPage from 'app/main/dashboard/dashboard-list-tickets/dashboard-list-tickets-page'; @@ -63,6 +64,12 @@ export default ( + + + + + + 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 f8898b8f..a4c17908 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 @@ -10,6 +10,7 @@ import SessionStore from 'lib-app/session-store'; import store from 'app/store'; import SessionActions from 'actions/session-actions'; import LanguageSelector from 'app-components/language-selector'; +import Captcha from 'app/main/captcha'; import Header from 'core-components/header'; import Form from 'core-components/form'; @@ -34,6 +35,8 @@ class CreateTicketForm extends React.Component { title: '', content: RichTextEditor.createEmptyValue(), departmentIndex: 0, + email: '', + name: '', language: 'en' } }; @@ -79,7 +82,7 @@ class CreateTicketForm extends React.Component { renderCaptcha() { return (
- +
); } @@ -105,16 +108,23 @@ class CreateTicketForm extends React.Component { } onSubmit(formState) { - this.setState({ - loading: true - }); + let captcha = this.refs.captcha && this.refs.captcha.getWrappedInstance(); - API.call({ - path: '/ticket/create', - data: _.extend({}, formState, { - departmentId: SessionStore.getDepartments()[formState.departmentIndex].id - }) - }).then(this.onTicketSuccess.bind(this)).catch(this.onTicketFail.bind(this)); + if (captcha && !captcha.getValue()) { + captcha.focus(); + } else { + this.setState({ + loading: true + }); + + API.call({ + path: '/ticket/create', + data: _.extend({}, formState, { + captcha: captcha && captcha.getValue(), + departmentId: SessionStore.getDepartments()[formState.departmentIndex].id + }) + }).then(this.onTicketSuccess.bind(this)).catch(this.onTicketFail.bind(this)); + } } onTicketSuccess() { @@ -123,9 +133,10 @@ class CreateTicketForm extends React.Component { message: 'success' }); - store.dispatch(SessionActions.getUserData()); - - setTimeout(() => {browserHistory.push('/dashboard')}, 2000); + if(this.props.userLogged) { + store.dispatch(SessionActions.getUserData()); + setTimeout(() => {browserHistory.push('/dashboard')}, 2000); + } } onTicketFail() { diff --git a/client/src/app/main/dashboard/dashboard-create-ticket/dashboard-create-ticket-page.js b/client/src/app/main/dashboard/dashboard-create-ticket/dashboard-create-ticket-page.js index 596cc4a9..cc7ad75f 100644 --- a/client/src/app/main/dashboard/dashboard-create-ticket/dashboard-create-ticket-page.js +++ b/client/src/app/main/dashboard/dashboard-create-ticket/dashboard-create-ticket-page.js @@ -1,16 +1,45 @@ import React from 'react'; +import classNames from 'classnames'; +import {connect} from 'react-redux'; +import Captcha from 'app/main/captcha'; import CreateTicketForm from 'app/main/dashboard/dashboard-create-ticket/create-ticket-form'; +import Widget from 'core-components/widget'; class DashboardCreateTicketPage extends React.Component { + static propTypes = { + userSystemEnabled: React.PropTypes.bool + }; + render() { + let Wrapper = 'div'; + + if(!this.props.userSystemEnabled) { + Wrapper = Widget; + } + return ( -
- +
+ + +
); } + + getClass() { + let classes = { + 'dashboard-create-ticket-page': true, + 'dashboard-create-ticket-page_wrapped': (!this.props.userSystemEnabled) + }; + + return classNames(classes); + } } -export default DashboardCreateTicketPage; +export default connect((store) => { + return { + userSystemEnabled: store.config['user-system-enabled'] + }; +})(DashboardCreateTicketPage); diff --git a/client/src/app/main/dashboard/dashboard-create-ticket/dashboard-create-ticket-page.scss b/client/src/app/main/dashboard/dashboard-create-ticket/dashboard-create-ticket-page.scss new file mode 100644 index 00000000..cba5b276 --- /dev/null +++ b/client/src/app/main/dashboard/dashboard-create-ticket/dashboard-create-ticket-page.scss @@ -0,0 +1,6 @@ +.dashboard-create-ticket-page { + + &_wrapped { + padding: 0 10px; + } +} \ No newline at end of file diff --git a/client/src/app/main/main-check-ticket-page.js b/client/src/app/main/main-check-ticket-page.js new file mode 100644 index 00000000..25ebb95a --- /dev/null +++ b/client/src/app/main/main-check-ticket-page.js @@ -0,0 +1,13 @@ +import React from 'react'; + +class MainCheckTicketPage extends React.Component { + render() { + return ( +
+ +
+ ) + } +} + +export default MainCheckTicketPage; \ No newline at end of file diff --git a/client/src/app/main/main-check-ticket-page.scss b/client/src/app/main/main-check-ticket-page.scss new file mode 100644 index 00000000..e69de29b 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 fa14d8f9..e5baab65 100644 --- a/client/src/app/main/main-signup/main-signup-page.js +++ b/client/src/app/main/main-signup/main-signup-page.js @@ -63,7 +63,7 @@ class MainSignUpPageWidget extends React.Component { return { loading: this.state.loading, className: 'signup-widget__form', - onSubmit: this.onLoginFormSubmit.bind(this) + onSubmit: this.onSignupFormSubmit.bind(this) }; } @@ -77,7 +77,7 @@ class MainSignUpPageWidget extends React.Component { }; } - onLoginFormSubmit(formState) { + onSignupFormSubmit(formState) { const captcha = this.refs.captcha.getWrappedInstance(); if (!captcha.getValue()) { From ec18363058928df136e13424402641a30d3e0f81 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Thu, 19 Jan 2017 19:48:55 -0300 Subject: [PATCH 67/84] Ivan - Add check ticket page [skip ci] --- client/src/app/Routes.js | 4 +- .../create-ticket-form.js | 8 +- client/src/app/main/main-check-ticket-page.js | 86 ++++++++++++++++++- .../src/app/main/main-check-ticket-page.scss | 24 ++++++ 4 files changed, 115 insertions(+), 7 deletions(-) diff --git a/client/src/app/Routes.js b/client/src/app/Routes.js index 59b5f961..c6b0b52b 100644 --- a/client/src/app/Routes.js +++ b/client/src/app/Routes.js @@ -66,8 +66,8 @@ export default ( - - + + 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 a4c17908..1ce083b3 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 @@ -2,7 +2,7 @@ import React from 'react'; import _ from 'lodash'; import ReCAPTCHA from 'react-google-recaptcha'; import { browserHistory } from 'react-router'; -import RichTextEditor from 'react-rte-browserify'; +import RichTextEditor from 'react-rte-browserify'; import i18n from 'lib-app/i18n'; import API from 'lib-app/api-call'; @@ -123,11 +123,11 @@ class CreateTicketForm extends React.Component { captcha: captcha && captcha.getValue(), departmentId: SessionStore.getDepartments()[formState.departmentIndex].id }) - }).then(this.onTicketSuccess.bind(this)).catch(this.onTicketFail.bind(this)); + }).then(this.onTicketSuccess.bind(this, formState.email)).catch(this.onTicketFail.bind(this)); } } - onTicketSuccess() { + onTicketSuccess(email, result) { this.setState({ loading: false, message: 'success' @@ -136,6 +136,8 @@ class CreateTicketForm extends React.Component { if(this.props.userLogged) { store.dispatch(SessionActions.getUserData()); setTimeout(() => {browserHistory.push('/dashboard')}, 2000); + } else { + setTimeout(() => {browserHistory.push('/check-ticket/' + email + '/' + result.data.ticketNumber)}, 2000); } } diff --git a/client/src/app/main/main-check-ticket-page.js b/client/src/app/main/main-check-ticket-page.js index 25ebb95a..4eb84a37 100644 --- a/client/src/app/main/main-check-ticket-page.js +++ b/client/src/app/main/main-check-ticket-page.js @@ -1,12 +1,94 @@ import React from 'react'; +import { browserHistory } from 'react-router'; + +import i18n from 'lib-app/i18n'; +import API from 'lib-app/api-call'; +import SessionStore from 'lib-app/session-store'; + +import Widget from 'core-components/widget'; +import Header from 'core-components/header'; +import Form from 'core-components/form'; +import FormField from 'core-components/form-field'; +import SubmitButton from 'core-components/submit-button'; +import Captcha from 'app/main/captcha'; class MainCheckTicketPage extends React.Component { + + state = { + loading: false, + form: { + email: this.props.params.email || '', + ticketNumber: this.props.params.ticketNumber || '' + }, + errors: {} + }; + render() { return (
- + +
+
+
+
+ +
+
+ +
+
+
+ +
+ {i18n('CHECK_TICKET')} +
+
- ) + ); + } + + getFormProps() { + return { + className: 'main-check-ticket-page__form', + loading: this.state.loading, + values: this.state.form, + errors: this.state.errors, + onChange: (form) => this.setState({form}), + onValidateErrors: (errors) => this.setState({errors}), + onSubmit: this.onFormSubmit.bind(this) + }; + } + + onFormSubmit(form) { + const captcha = this.refs.captcha.getWrappedInstance(); + + if (!captcha.getValue()) { + captcha.focus(); + } else { + this.setState({ + loading: true + }); + + API.call({ + path: '/ticket/get', + data: { + captcha: captcha && captcha.getValue(), + ticketNumber: form.ticketNumber, + email: form.email + } + }).then(this.onTicketGetSuccess.bind(this)).catch(() => this.setState({ + loading: false, + errors: { + email: i18n('INVALID_EMAIL_OR_TICKET_NUMBER'), + ticketNumber: i18n('INVALID_EMAIL_OR_TICKET_NUMBER') + } + })); + } + } + + onTicketGetSuccess(result) { + SessionStore.setItem('token', result.data.token); + setTimeout(() => {browserHistory.push('/view-ticket/' + this.state.form.email + '/' + this.state.form.ticketNumber)}, 2000); } } diff --git a/client/src/app/main/main-check-ticket-page.scss b/client/src/app/main/main-check-ticket-page.scss index e69de29b..935387f8 100644 --- a/client/src/app/main/main-check-ticket-page.scss +++ b/client/src/app/main/main-check-ticket-page.scss @@ -0,0 +1,24 @@ +.main-check-ticket-page { + padding: 0 15px; + + &__form { + margin: 0 auto; + max-width: 790px; + } + + &__inputs { + display: inline-block; + margin: 0 auto; + } + + &__input { + display: inline-block; + margin: 0 20px; + } + + &__captcha { + margin: 20px auto 20px; + height: 78px; + width: 304px; + } +} \ No newline at end of file From 4e0669c4ae0840248f7ce140dd146af8dd472018 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Fri, 20 Jan 2017 22:01:18 -0300 Subject: [PATCH 68/84] Ivan - WIP [skip ci] --- client/src/app/Routes.js | 2 +- client/src/app/main/main-view-ticket.js | 104 ++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 client/src/app/main/main-view-ticket.js diff --git a/client/src/app/Routes.js b/client/src/app/Routes.js index c6b0b52b..6349f569 100644 --- a/client/src/app/Routes.js +++ b/client/src/app/Routes.js @@ -67,7 +67,7 @@ export default ( - + diff --git a/client/src/app/main/main-view-ticket.js b/client/src/app/main/main-view-ticket.js new file mode 100644 index 00000000..3d093cc9 --- /dev/null +++ b/client/src/app/main/main-view-ticket.js @@ -0,0 +1,104 @@ +import React from 'react'; +import _ from 'lodash'; +import {connect} from 'react-redux'; + +import API from 'lib-app/api-call'; +import i18n from 'lib-app/i18n'; +import SessionStore from 'lib-app/session-store'; + +import TicketViewer from 'app-components/ticket-viewer'; +import Loading from 'core-components/loading'; +import Header from 'core-components/header'; + +class MainViewTicket extends React.Component { + + state = { + loading: true, + ticket: {} + }; + + componentDidMount() { + this.retrieveTicket(); + } + + render() { + return ( +
+
+ {(this.state.loading) ? this.renderLoading() : this.renderView()} +
+ ); + } + + renderLoading() { + return ( +
+ +
+ ) + }; + + renderView() { + return (_.isEmpty(this.state.ticket)) ? this.renderNoPermissionError() : this.renderTicketView(); + } + + renderNoPermissionError() { + return ( +
+ {i18n('NO_PERMISSION')} +
+ ); + } + + renderTicketView() { + return ( +
+ +
+ ); + } + + getTicketViewProps() { + return { + ticket: this.state.ticket, + onChange: this.retrieveTicket.bind(this), + assignmentAllowed: true, + customResponses: this.props.customResponses, + editable: this.state.ticket.owner && this.state.ticket.owner.id == SessionStore.getSessionData().userId + }; + } + + retrieveTicket() { + API.call({ + path: '/ticket/get', + data: { + ticketNumber: this.props.params.ticketNumber + } + }).then(this.onRetrieveSuccess.bind(this)).catch(this.onRetrieveFail.bind(this)) + } + + onRetrieveSuccess(result) { + this.setState({ + loading: false, + ticket: result.data + }); + + if(result.data.unreadStaff) { + API.call({ + path: '/ticket/seen', + data: { + ticketNumber: this.props.params.ticketNumber + } + }); + } + } + + onRetrieveFail() { + this.setState({ + loading: false, + ticket: {} + }); + } +} + +export default MainViewTicket; \ No newline at end of file From 9db530f2ddc8e0808ee7495789d7e7625dce70ea Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 21 Jan 2017 00:20:25 -0300 Subject: [PATCH 69/84] Ivan - Add ticket view page for no user system[skip ci] --- client/src/app/Routes.js | 3 +- .../panel/tickets/admin-panel-view-ticket.js | 14 ++- client/src/app/main/main-check-ticket-page.js | 2 +- client/src/app/main/main-view-ticket-page.js | 20 ++++ .../src/app/main/main-view-ticket-page.scss | 3 + client/src/app/main/main-view-ticket.js | 104 ------------------ client/src/data/fixtures/ticket-fixtures.js | 2 + 7 files changed, 40 insertions(+), 108 deletions(-) create mode 100644 client/src/app/main/main-view-ticket-page.js create mode 100644 client/src/app/main/main-view-ticket-page.scss delete mode 100644 client/src/app/main/main-view-ticket.js diff --git a/client/src/app/Routes.js b/client/src/app/Routes.js index 6349f569..70bcdcad 100644 --- a/client/src/app/Routes.js +++ b/client/src/app/Routes.js @@ -14,6 +14,7 @@ import MainVerifyTokenPage from 'app/main/main-verify-token-page'; import MainRecoverPasswordPage from 'app/main/main-recover-password/main-recover-password-page'; import MainMaintenancePage from 'app/main/main-maintenance-page'; import MainCheckTicketPage from 'app/main/main-check-ticket-page'; +import MainViewTicketPage from 'app/main/main-view-ticket-page'; import DashboardLayout from 'app/main/dashboard/dashboard-layout'; import DashboardListTicketsPage from 'app/main/dashboard/dashboard-list-tickets/dashboard-list-tickets-page'; @@ -67,7 +68,7 @@ export default ( - + diff --git a/client/src/app/admin/panel/tickets/admin-panel-view-ticket.js b/client/src/app/admin/panel/tickets/admin-panel-view-ticket.js index b0002fdc..6cf0f8c3 100644 --- a/client/src/app/admin/panel/tickets/admin-panel-view-ticket.js +++ b/client/src/app/admin/panel/tickets/admin-panel-view-ticket.js @@ -12,6 +12,16 @@ import Header from 'core-components/header'; class AdminPanelViewTicket extends React.Component { + static propTypes = { + avoidSeen: React.PropTypes.bool, + assignmentAllowed: React.PropTypes.bool + }; + + static defaultProps = { + avoidSeen: false, + assignmentAllowed: true + }; + state = { loading: true, ticket: {} @@ -62,7 +72,7 @@ class AdminPanelViewTicket extends React.Component { return { ticket: this.state.ticket, onChange: this.retrieveTicket.bind(this), - assignmentAllowed: true, + assignmentAllowed: this.props.assignmentAllowed, customResponses: this.props.customResponses, editable: this.state.ticket.owner && this.state.ticket.owner.id == SessionStore.getSessionData().userId }; @@ -83,7 +93,7 @@ class AdminPanelViewTicket extends React.Component { ticket: result.data }); - if(result.data.unreadStaff) { + if(!this.props.avoidSeen && result.data.unreadStaff) { API.call({ path: '/ticket/seen', data: { diff --git a/client/src/app/main/main-check-ticket-page.js b/client/src/app/main/main-check-ticket-page.js index 4eb84a37..f95297a3 100644 --- a/client/src/app/main/main-check-ticket-page.js +++ b/client/src/app/main/main-check-ticket-page.js @@ -88,7 +88,7 @@ class MainCheckTicketPage extends React.Component { onTicketGetSuccess(result) { SessionStore.setItem('token', result.data.token); - setTimeout(() => {browserHistory.push('/view-ticket/' + this.state.form.email + '/' + this.state.form.ticketNumber)}, 2000); + setTimeout(() => {browserHistory.push('/view-ticket/' + this.state.form.ticketNumber)}, 2000); } } diff --git a/client/src/app/main/main-view-ticket-page.js b/client/src/app/main/main-view-ticket-page.js new file mode 100644 index 00000000..b5517367 --- /dev/null +++ b/client/src/app/main/main-view-ticket-page.js @@ -0,0 +1,20 @@ +import React from 'react'; + +import AdminPanelViewTicket from 'app/admin/panel/tickets/admin-panel-view-ticket' + +import Widget from 'core-components/widget'; + +class MainViewTicketPage extends React.Component { + + render() { + return ( +
+ + + +
+ ); + } +} + +export default MainViewTicketPage; \ No newline at end of file diff --git a/client/src/app/main/main-view-ticket-page.scss b/client/src/app/main/main-view-ticket-page.scss new file mode 100644 index 00000000..4ba281a7 --- /dev/null +++ b/client/src/app/main/main-view-ticket-page.scss @@ -0,0 +1,3 @@ +.main-view-ticket-page { + padding: 0 15px; +} \ No newline at end of file diff --git a/client/src/app/main/main-view-ticket.js b/client/src/app/main/main-view-ticket.js deleted file mode 100644 index 3d093cc9..00000000 --- a/client/src/app/main/main-view-ticket.js +++ /dev/null @@ -1,104 +0,0 @@ -import React from 'react'; -import _ from 'lodash'; -import {connect} from 'react-redux'; - -import API from 'lib-app/api-call'; -import i18n from 'lib-app/i18n'; -import SessionStore from 'lib-app/session-store'; - -import TicketViewer from 'app-components/ticket-viewer'; -import Loading from 'core-components/loading'; -import Header from 'core-components/header'; - -class MainViewTicket extends React.Component { - - state = { - loading: true, - ticket: {} - }; - - componentDidMount() { - this.retrieveTicket(); - } - - render() { - return ( -
-
- {(this.state.loading) ? this.renderLoading() : this.renderView()} -
- ); - } - - renderLoading() { - return ( -
- -
- ) - }; - - renderView() { - return (_.isEmpty(this.state.ticket)) ? this.renderNoPermissionError() : this.renderTicketView(); - } - - renderNoPermissionError() { - return ( -
- {i18n('NO_PERMISSION')} -
- ); - } - - renderTicketView() { - return ( -
- -
- ); - } - - getTicketViewProps() { - return { - ticket: this.state.ticket, - onChange: this.retrieveTicket.bind(this), - assignmentAllowed: true, - customResponses: this.props.customResponses, - editable: this.state.ticket.owner && this.state.ticket.owner.id == SessionStore.getSessionData().userId - }; - } - - retrieveTicket() { - API.call({ - path: '/ticket/get', - data: { - ticketNumber: this.props.params.ticketNumber - } - }).then(this.onRetrieveSuccess.bind(this)).catch(this.onRetrieveFail.bind(this)) - } - - onRetrieveSuccess(result) { - this.setState({ - loading: false, - ticket: result.data - }); - - if(result.data.unreadStaff) { - API.call({ - path: '/ticket/seen', - data: { - ticketNumber: this.props.params.ticketNumber - } - }); - } - } - - onRetrieveFail() { - this.setState({ - loading: false, - ticket: {} - }); - } -} - -export default MainViewTicket; \ No newline at end of file diff --git a/client/src/data/fixtures/ticket-fixtures.js b/client/src/data/fixtures/ticket-fixtures.js index 1975b855..dea4ee7f 100644 --- a/client/src/data/fixtures/ticket-fixtures.js +++ b/client/src/data/fixtures/ticket-fixtures.js @@ -110,10 +110,12 @@ module.exports = [ closed: false, priority: 'medium', author: { + id: 3, name: 'Haskell Curry', email: 'haskell@lambda.com' }, owner: { + id: 1, name: 'Steve Jobs' }, events: [ From 0bd07ef211d5db93728bf11f38166312cef4a603 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 21 Jan 2017 01:17:28 -0300 Subject: [PATCH 70/84] Ivan - Add token ticket for backend [skip ci] --- server/controllers/ticket/comment.php | 12 +++++-- server/controllers/ticket/get.php | 45 +++++++++++++++++++++------ server/models/Session.php | 11 ++++++- 3 files changed, 55 insertions(+), 13 deletions(-) diff --git a/server/controllers/ticket/comment.php b/server/controllers/ticket/comment.php index cd7713e1..cc0d24ba 100644 --- a/server/controllers/ticket/comment.php +++ b/server/controllers/ticket/comment.php @@ -25,9 +25,15 @@ class CommentController extends Controller { if(!Controller::isUserSystemEnabled()) { $validations['permission'] = 'any'; - $validations['requestData']['email'] = [ - 'validation' => DataValidator::email(), - 'error' => ERRORS::INVALID_EMAIL + $session = Session::getInstance(); + + $validations['requestData']['csrf_token'] = [ + 'validation' => DataValidator::equals($session->getToken()), + 'error' => ERRORS::NO_PERMISSION + ]; + $validations['requestData']['ticketNumber'] = [ + 'validation' => DataValidator::equals($session->getTicketNumber()), + 'error' => ERRORS::INVALID_TICKET ]; } diff --git a/server/controllers/ticket/get.php b/server/controllers/ticket/get.php index 6e2a6758..61cba027 100644 --- a/server/controllers/ticket/get.php +++ b/server/controllers/ticket/get.php @@ -20,14 +20,28 @@ class TicketGetController extends Controller { if(!Controller::isUserSystemEnabled() && !Controller::isStaffLogged()) { $validations['permission'] = 'any'; - $validations['requestData']['email'] = [ - 'validation' => DataValidator::email(), - 'error' => ERRORS::INVALID_EMAIL - ]; - $validations['requestData']['captcha'] = [ - 'validation' => DataValidator::captcha(), - 'error' => ERRORS::INVALID_CAPTCHA - ]; + + if(Controller::request('token')) { + $session = Session::getInstance(); + + $validations['requestData']['csrf_token'] = [ + 'validation' => DataValidator::equals($session->getToken()), + 'error' => ERRORS::NO_PERMISSION + ]; + $validations['requestData']['ticketNumber'] = [ + 'validation' => DataValidator::equals($session->getTicketNumber()), + 'error' => ERRORS::INVALID_TICKET + ]; + } else { + $validations['requestData']['email'] = [ + 'validation' => DataValidator::email(), + 'error' => ERRORS::INVALID_EMAIL + ]; + $validations['requestData']['captcha'] = [ + 'validation' => DataValidator::captcha(), + 'error' => ERRORS::INVALID_CAPTCHA + ]; + } } return $validations; @@ -40,7 +54,11 @@ class TicketGetController extends Controller { if(!Controller::isUserSystemEnabled() && !Controller::isStaffLogged()) { if($this->ticket->authorEmail === $email) { - Response::respondSuccess($this->ticket->toArray()); + if(!Controller::request('token')) { + $this->generateSessionToken(); + } else { + Response::respondSuccess($this->ticket->toArray()); + } return; } else { throw new Exception(ERRORS::NO_PERMISSION); @@ -54,6 +72,15 @@ class TicketGetController extends Controller { } } + private function generateSessionToken() { + $session = Session::getInstance(); + $token = Hashing::generateRandomToken(); + + $session->createTicketSession($this->ticket->ticketNUmber); + + Response::respondSuccess(['token' => $token, 'ticketNumber' => $this->ticket->ticketNUmber]); + } + private function shouldDenyPermission() { $user = Controller::getLoggedUser(); diff --git a/server/models/Session.php b/server/models/Session.php index 9535876a..eceb9c13 100644 --- a/server/models/Session.php +++ b/server/models/Session.php @@ -29,6 +29,15 @@ class Session { $this->store('staff', $staff); $this->store('token', Hashing::generateRandomToken()); } + + public function createTicketSession($ticketNumber) { + $this->store('ticketNumber', $ticketNumber); + $this->store('token', Hashing::generateRandomToken()); + } + + public function getTicketNumber() { + return $this->getStoredData('ticketNumber'); + } public function getToken() { return $this->getStoredData('token'); @@ -51,7 +60,7 @@ class Session { $token === $data['token']; } - private function store($key, $value) { + public function store($key, $value) { $_SESSION[$key] = $value; } From 6109e1ac730619c44d9a7ffb1c5c9ace64678095 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 21 Jan 2017 01:42:48 -0300 Subject: [PATCH 71/84] Ivan - Add article list for no user system [skip ci] --- client/src/app-components/topic-viewer.js | 2 +- client/src/app/Routes.js | 1 + .../dashboard-article-page.js | 33 +++++++++++++++---- .../dashboard-article-page.scss | 4 +++ .../dashboard-list-articles-page.js | 33 +++++++++++++++---- .../dashboard-list-articles-page.scss | 4 +++ .../main/main-home/main-home-page-portal.js | 2 +- 7 files changed, 64 insertions(+), 15 deletions(-) diff --git a/client/src/app-components/topic-viewer.js b/client/src/app-components/topic-viewer.js index 2009da8c..d54164ff 100644 --- a/client/src/app-components/topic-viewer.js +++ b/client/src/app-components/topic-viewer.js @@ -105,7 +105,7 @@ class TopicViewer extends React.Component { {article.title} - + {(this.props.editable) ? : null} ); } diff --git a/client/src/app/Routes.js b/client/src/app/Routes.js index 70bcdcad..192fd723 100644 --- a/client/src/app/Routes.js +++ b/client/src/app/Routes.js @@ -70,6 +70,7 @@ export default ( + diff --git a/client/src/app/main/dashboard/dashboard-article/dashboard-article-page.js b/client/src/app/main/dashboard/dashboard-article/dashboard-article-page.js index f5d8b509..27062bf6 100644 --- a/client/src/app/main/dashboard/dashboard-article/dashboard-article-page.js +++ b/client/src/app/main/dashboard/dashboard-article/dashboard-article-page.js @@ -1,5 +1,6 @@ import React from 'react'; import _ from 'lodash'; +import classNames from 'classnames'; import {connect} from 'react-redux'; import ArticlesActions from 'actions/articles-actions'; @@ -10,6 +11,7 @@ import DateTransformer from 'lib-core/date-transformer'; import Header from 'core-components/header'; import Loading from 'core-components/loading'; import BreadCrumb from 'core-components/breadcrumb'; +import Widget from 'core-components/widget'; class DashboardArticlePage extends React.Component { @@ -32,12 +34,20 @@ class DashboardArticlePage extends React.Component { } render() { + let Wrapper = 'div'; + + if(_.startsWith(this.props.location.pathname, '/article/')) { + Wrapper = Widget; + } + return ( -
-
- -
- {(this.props.loading) ? : this.renderContent()} +
+ +
+ +
+ {(this.props.loading) ? : this.renderContent()} +
); } @@ -62,6 +72,15 @@ class DashboardArticlePage extends React.Component {
); } + + getClass() { + let classes = { + 'dashboard-article-page': true, + 'dashboard-article-page_wrapped': _.startsWith(this.props.location.pathname, '/article/') + }; + + return classNames(classes); + } findArticle() { let article = null; @@ -91,11 +110,11 @@ class DashboardArticlePage extends React.Component { let article = this.findArticle(); let topic = this.findTopic(); let items = [ - {content: i18n('ARTICLES'), url: '/dashboard/articles'} + {content: i18n('ARTICLES'), url: (_.startsWith(this.props.location.pathname, '/article/')) ? '/articles' : '/dashboard/articles'} ]; if(topic && topic.name) { - items.push({content: topic.name, url: '/dashboard/articles'}); + items.push({content: topic.name, url: (_.startsWith(this.props.location.pathname, '/article/')) ? '/articles' : '/dashboard/articles'}); } if(article && article.title) { diff --git a/client/src/app/main/dashboard/dashboard-article/dashboard-article-page.scss b/client/src/app/main/dashboard/dashboard-article/dashboard-article-page.scss index b165a2cd..aa91618e 100644 --- a/client/src/app/main/dashboard/dashboard-article/dashboard-article-page.scss +++ b/client/src/app/main/dashboard/dashboard-article/dashboard-article-page.scss @@ -5,4 +5,8 @@ text-align: right; margin-top: 20px; } + + &_wrapped { + padding: 0 15px; + } } \ No newline at end of file diff --git a/client/src/app/main/dashboard/dashboard-list-articles/dashboard-list-articles-page.js b/client/src/app/main/dashboard/dashboard-list-articles/dashboard-list-articles-page.js index da942c22..f7c434e8 100644 --- a/client/src/app/main/dashboard/dashboard-list-articles/dashboard-list-articles-page.js +++ b/client/src/app/main/dashboard/dashboard-list-articles/dashboard-list-articles-page.js @@ -1,4 +1,5 @@ import React from 'react'; +import classNames from 'classnames'; import {connect} from 'react-redux'; import _ from 'lodash'; import {Link} from 'react-router'; @@ -9,6 +10,7 @@ import ArticlesActions from 'actions/articles-actions'; import Header from 'core-components/header'; import SearchBox from 'core-components/search-box'; +import Widget from 'core-components/widget'; class DashboardListArticlesPage extends React.Component { @@ -22,18 +24,28 @@ class DashboardListArticlesPage extends React.Component { } render() { + let Wrapper = 'div'; + + if(this.props.location.pathname == '/articles') { + Wrapper = Widget; + } + return ( -
-
- - {(!this.state.showSearchResults) ? this.renderArticleList() : this.renderSearchResults()} +
+ +
+ + {(!this.state.showSearchResults) ? this.renderArticleList() : this.renderSearchResults()} +
); } renderArticleList() { + let articlePath = (this.props.location.pathname == '/articles') ? '/article/' : '/dashboard/article/'; + return ( - + ); } @@ -53,7 +65,7 @@ class DashboardListArticlesPage extends React.Component { return (
- {item.title} + {item.title}
{content}
{item.topic}
@@ -61,6 +73,15 @@ class DashboardListArticlesPage extends React.Component { ); } + getClass() { + let classes = { + 'dashboard-list-articles-page': true, + 'dashboard-list-articles-page_wrapped': (this.props.location.pathname == '/articles') + }; + + return classNames(classes); + } + onSearch(query) { this.setState({ results: SearchBox.searchQueryInList(this.getArticles(), query, this.isQueryInTitle.bind(this), this.isQueryInContent.bind(this)), diff --git a/client/src/app/main/dashboard/dashboard-list-articles/dashboard-list-articles-page.scss b/client/src/app/main/dashboard/dashboard-list-articles/dashboard-list-articles-page.scss index 418797af..709461c1 100644 --- a/client/src/app/main/dashboard/dashboard-list-articles/dashboard-list-articles-page.scss +++ b/client/src/app/main/dashboard/dashboard-list-articles/dashboard-list-articles-page.scss @@ -29,4 +29,8 @@ text-transform: uppercase; } } + + &_wrapped { + padding: 0 15px; + } } \ No newline at end of file diff --git a/client/src/app/main/main-home/main-home-page-portal.js b/client/src/app/main/main-home/main-home-page-portal.js index 3935e0d7..a27916de 100644 --- a/client/src/app/main/main-home/main-home-page-portal.js +++ b/client/src/app/main/main-home/main-home-page-portal.js @@ -61,7 +61,7 @@ class MainHomePagePortal extends React.Component { icon: 'book', color: 'blue', buttonText: (this.props.type === 'complete') ? i18n('VIEW_ARTICLES') : null, - onButtonClick: () => browserHistory.push('/view-articles') + onButtonClick: () => browserHistory.push('/articles') }; } From c18142f2ba9ff588c2cb7199f3bef0d7fc031856 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 21 Jan 2017 01:54:13 -0300 Subject: [PATCH 72/84] Ivan - Add home link and english keys for no user system [skip ci] --- client/src/app-components/topic-viewer.scss | 3 ++- .../dashboard-create-ticket-page.js | 14 ++++---------- client/src/app/main/main-check-ticket-page.js | 2 +- client/src/app/main/main-layout-header.js | 10 +++++++++- client/src/data/languages/en.js | 6 +++--- 5 files changed, 19 insertions(+), 16 deletions(-) diff --git a/client/src/app-components/topic-viewer.scss b/client/src/app-components/topic-viewer.scss index f674fd88..97dd43f5 100644 --- a/client/src/app-components/topic-viewer.scss +++ b/client/src/app-components/topic-viewer.scss @@ -2,10 +2,11 @@ .topic-viewer { text-align: left; + margin: 35px 0; &__header { cursor: default; - margin-bottom: 15px; + margin-bottom: 20px; font-size: $font-size--bg; &:hover { diff --git a/client/src/app/main/dashboard/dashboard-create-ticket/dashboard-create-ticket-page.js b/client/src/app/main/dashboard/dashboard-create-ticket/dashboard-create-ticket-page.js index cc7ad75f..8edc3bcc 100644 --- a/client/src/app/main/dashboard/dashboard-create-ticket/dashboard-create-ticket-page.js +++ b/client/src/app/main/dashboard/dashboard-create-ticket/dashboard-create-ticket-page.js @@ -1,8 +1,6 @@ import React from 'react'; import classNames from 'classnames'; -import {connect} from 'react-redux'; -import Captcha from 'app/main/captcha'; import CreateTicketForm from 'app/main/dashboard/dashboard-create-ticket/create-ticket-form'; import Widget from 'core-components/widget'; @@ -15,14 +13,14 @@ class DashboardCreateTicketPage extends React.Component { render() { let Wrapper = 'div'; - if(!this.props.userSystemEnabled) { + if((this.props.location.pathname === '/create-ticket')) { Wrapper = Widget; } return (
- +
); @@ -31,15 +29,11 @@ class DashboardCreateTicketPage extends React.Component { getClass() { let classes = { 'dashboard-create-ticket-page': true, - 'dashboard-create-ticket-page_wrapped': (!this.props.userSystemEnabled) + 'dashboard-create-ticket-page_wrapped': (this.props.location.pathname === '/create-ticket') }; return classNames(classes); } } -export default connect((store) => { - return { - userSystemEnabled: store.config['user-system-enabled'] - }; -})(DashboardCreateTicketPage); +export default DashboardCreateTicketPage; diff --git a/client/src/app/main/main-check-ticket-page.js b/client/src/app/main/main-check-ticket-page.js index f95297a3..e0a1df21 100644 --- a/client/src/app/main/main-check-ticket-page.js +++ b/client/src/app/main/main-check-ticket-page.js @@ -27,7 +27,7 @@ class MainCheckTicketPage extends React.Component { return (
-
+
diff --git a/client/src/app/main/main-layout-header.js b/client/src/app/main/main-layout-header.js index c42545f0..7c705740 100644 --- a/client/src/app/main/main-layout-header.js +++ b/client/src/app/main/main-layout-header.js @@ -12,7 +12,7 @@ class MainLayoutHeader extends React.Component { render() { return (
- {(this.props.config['user-system-enabled']) ? this.renderAccessLinks() : null} + {(this.props.config['user-system-enabled']) ? this.renderAccessLinks() : this.renderHomeLink()}
); @@ -40,6 +40,14 @@ class MainLayoutHeader extends React.Component { return result; } + renderHomeLink() { + return ( +
+ +
+ ); + } + getLanguageSelectorProps() { return { className: 'main-layout-header__languages', diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js index 81277ea4..74d595a1 100644 --- a/client/src/data/languages/en.js +++ b/client/src/data/languages/en.js @@ -154,10 +154,10 @@ export default { 'VERIFY_SUCCESS': 'User verified', 'VERIFY_FAILED': 'Could not verify', 'CHECK_TICKET': 'Check Ticket', - 'STATISTICS': 'Statistics', 'ACTIVITY': 'Activity', - - + 'HOME': 'Home', + 'TICKET_NUMBER': 'Ticket number', + 'CHART_CREATE_TICKET': 'Tickets created', 'CHART_CLOSE': 'Tickets closed', 'CHART_SIGNUP': 'Signups', From 09c6453d46e4326cafac8b217f7ca1b5aaeca561 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 21 Jan 2017 02:00:04 -0300 Subject: [PATCH 73/84] Ivan - Fix some issues related to no user system [skip ci] --- .../dashboard/dashboard-article/dashboard-article-page.js | 4 ++-- client/src/app/main/main-layout-header.js | 2 +- client/src/data/fixtures/system-fixtures.js | 4 +++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/client/src/app/main/dashboard/dashboard-article/dashboard-article-page.js b/client/src/app/main/dashboard/dashboard-article/dashboard-article-page.js index 27062bf6..19d17a3a 100644 --- a/client/src/app/main/dashboard/dashboard-article/dashboard-article-page.js +++ b/client/src/app/main/dashboard/dashboard-article/dashboard-article-page.js @@ -42,12 +42,12 @@ class DashboardArticlePage extends React.Component { return (
- +
{(this.props.loading) ? : this.renderContent()} -
+
); } diff --git a/client/src/app/main/main-layout-header.js b/client/src/app/main/main-layout-header.js index 7c705740..5f575136 100644 --- a/client/src/app/main/main-layout-header.js +++ b/client/src/app/main/main-layout-header.js @@ -32,7 +32,7 @@ class MainLayoutHeader extends React.Component { result = (
- {this.props.config === true ? : null} + {(this.props.config['registration'] === true) ? : null}
); } diff --git a/client/src/data/fixtures/system-fixtures.js b/client/src/data/fixtures/system-fixtures.js index d98c393a..37b65062 100644 --- a/client/src/data/fixtures/system-fixtures.js +++ b/client/src/data/fixtures/system-fixtures.js @@ -19,6 +19,7 @@ module.exports = [ 'smtp-port': '7070', 'smtp-user': 'Wesa', 'maintenance-mode': false, + 'user-system-enabled': true, 'allow-attachments': true, 'registration': true, 'max-size': 500, @@ -41,7 +42,8 @@ module.exports = [ 'layout': 'Boxed', 'reCaptchaKey': '6LfM5CYTAAAAAGLz6ctpf-hchX2_l0Ge-Bn-n8wS', 'maintenance-mode': false, - 'user-system-enabled': false, + 'user-system-enabled': true, + 'registration': true, 'departments': [ {id: 1, name: 'Sales Support', owners: 2}, {id: 2, name: 'Technical Issues', owners: 5}, From 796571c8a11bea64ca41423221280d77de2b7a92 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 21 Jan 2017 19:06:13 -0300 Subject: [PATCH 74/84] Ivan - Update some texts [skip ci] --- client/src/app-components/are-you-sure.js | 2 +- .../settings/admin-panel-advanced-settings.js | 28 +++++++++---------- client/src/data/fixtures/system-fixtures.js | 20 +++++++++++++ client/src/data/languages/en.js | 10 +++++-- 4 files changed, 42 insertions(+), 18 deletions(-) diff --git a/client/src/app-components/are-you-sure.js b/client/src/app-components/are-you-sure.js index f2bb55d5..4bff7460 100644 --- a/client/src/app-components/are-you-sure.js +++ b/client/src/app-components/are-you-sure.js @@ -41,7 +41,7 @@ class AreYouSure extends React.Component { {i18n('ARE_YOU_SURE')}
- {this.props.description} + {this.props.description || (this.props.type === 'secure' && i18n('PLEASE_CONFIRM_PASSWORD'))}
{(this.props.type === 'secure') ? this.renderPassword() : null}
diff --git a/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js b/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js index d453e030..010aa405 100644 --- a/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js +++ b/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js @@ -39,13 +39,13 @@ class AdminPanelAdvancedSettings extends React.Component {
- {i18n('USER_SYSTEM_ENABLED')} + {i18n('ENABLE_USER_SYSTEM')}
- {i18n('REGISTRATION')} + {i18n('ENABLE_USER_REGISTRATION')}
@@ -127,11 +127,11 @@ class AdminPanelAdvancedSettings extends React.Component { } onToggleButtonUserSystemChange() { - AreYouSure.openModal(
{i18n('PLEASE_CONFIRM_PASSWORD')}
, this.onAreYouSureUserSystemOk.bind(this), 'secure'); + AreYouSure.openModal(null, this.onAreYouSureUserSystemOk.bind(this), 'secure'); } onToggleButtonRegistrationChange() { - AreYouSure.openModal(
{i18n('PLEASE_CONFIRM_PASSWORD')}
, this.onAreYouSureRegistrationOk.bind(this), 'secure'); + AreYouSure.openModal(null, this.onAreYouSureRegistrationOk.bind(this), 'secure'); } onAreYouSureUserSystemOk(password) { @@ -143,10 +143,10 @@ class AdminPanelAdvancedSettings extends React.Component { }).then(() => { this.setState({ messageType: 'success', - messageContent: this.props.config['user-system-enabled'] ? i18n('USER_SYSTEM_DISABLE_DESCRIPTION') : i18n('USER_SYSTEM_ENABLE_DESCRIPTION') + messageContent: this.props.config['user-system-enabled'] ? i18n('USER_SYSTEM_DISABLED') : i18n('USER_SYSTEM_ENABLED') }); this.props.dispatch(ConfigActions.updateData()); - }).catch(() => this.setState({messageType: 'fail', messageContent: i18n('ERROR_UPDATING_SETTINGS')})); + }).catch(() => this.setState({messageType: 'error', messageContent: i18n('ERROR_UPDATING_SETTINGS')})); } onAreYouSureRegistrationOk(password) { @@ -158,18 +158,18 @@ class AdminPanelAdvancedSettings extends React.Component { }).then(() => { this.setState({ messageType: 'success', - messageContent: this.props.config['user-system-enabled'] ? i18n('REGISTRATION_DISABLE_DESCRIPTION') : i18n('REGISTRATION_ENABLE_DESCRIPTION') + messageContent: this.props.config['registration'] ? i18n('REGISTRATION_DISABLED') : i18n('REGISTRATION_ENABLED') }); this.props.dispatch(ConfigActions.updateData()); - }).catch(() => this.setState({messageType: 'fail', messageContent: i18n('ERROR_UPDATING_SETTINGS')})); + }).catch(() => this.setState({messageType: 'error', messageContent: i18n('ERROR_UPDATING_SETTINGS')})); } onImportCSV(event) { - AreYouSure.openModal(
{i18n('PLEASE_CONFIRM_PASSWORD')}
, this.onAreYouSureCSVOk.bind(this, event.target.value), 'secure'); + AreYouSure.openModal(null, this.onAreYouSureCSVOk.bind(this, event.target.value), 'secure'); } onImportSQL(event) { - AreYouSure.openModal(
{i18n('PLEASE_CONFIRM_PASSWORD')}
, this.onAreYouSureSQLOk.bind(this, event.target.value), 'secure'); + AreYouSure.openModal(null, this.onAreYouSureSQLOk.bind(this, event.target.value), 'secure'); } onAreYouSureCSVOk(file, password) { @@ -180,7 +180,7 @@ class AdminPanelAdvancedSettings extends React.Component { password: password } }).then(() => this.setState({messageType: 'success', messageContent: i18n('SUCCESS_IMPORTING_CSV_DESCRIPTION')} - )).catch(() => this.setState({messageType: 'fail', messageContent: i18n('ERROR_IMPORTING_CSV_DESCRIPTION')})); + )).catch(() => this.setState({messageType: 'error', messageContent: i18n('ERROR_IMPORTING_CSV_DESCRIPTION')})); } onAreYouSureSQLOk(file, password) { @@ -191,7 +191,7 @@ class AdminPanelAdvancedSettings extends React.Component { password: password } }).then(() => this.setState({messageType: 'success', messageContent: i18n('SUCCESS_IMPORTING_SQL_DESCRIPTION')} - )).catch(() => this.setState({messageType: 'fail', messageContent: i18n('ERROR_IMPORTING_SQL_DESCRIPTION')})); + )).catch(() => this.setState({messageType: 'error', messageContent: i18n('ERROR_IMPORTING_SQL_DESCRIPTION')})); } onBackupDatabase() { @@ -210,7 +210,7 @@ class AdminPanelAdvancedSettings extends React.Component { } onDeleteAllUsers() { - AreYouSure.openModal(
{i18n('PLEASE_CONFIRM_PASSWORD')}
, this.onAreYouSureDeleteAllUsersOk.bind(this), 'secure'); + AreYouSure.openModal(null, this.onAreYouSureDeleteAllUsersOk.bind(this), 'secure'); } onAreYouSureDeleteAllUsersOk(password) { @@ -220,7 +220,7 @@ class AdminPanelAdvancedSettings extends React.Component { password: password } }).then(() => this.setState({messageType: 'success', messageContent: i18n('SUCCESS_DELETING_ALL_USERS')} - )).catch(() => this.setState({messageType: 'fail', messageContent: i18n('ERROR_DELETING_ALL_USERS')})); + )).catch(() => this.setState({messageType: 'error', messageContent: i18n('ERROR_DELETING_ALL_USERS')})); } } diff --git a/client/src/data/fixtures/system-fixtures.js b/client/src/data/fixtures/system-fixtures.js index f84766b7..64f7d3d8 100644 --- a/client/src/data/fixtures/system-fixtures.js +++ b/client/src/data/fixtures/system-fixtures.js @@ -140,6 +140,26 @@ module.exports = [ return 'text content'; } }, + { + path: '/system/import-csv', + time: 100, + response: function () { + return { + status: 'success', + data: {} + }; + } + }, + { + path: '/system/import-sql', + time: 100, + response: function () { + return { + status: 'success', + data: {} + }; + } + }, { path: '/system/get-mail-templates', time: 100, diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js index 5b9fd926..4d2564fa 100644 --- a/client/src/data/languages/en.js +++ b/client/src/data/languages/en.js @@ -152,8 +152,8 @@ export default { 'ALL_NOTIFICATIONS': 'All notifications', 'VERIFY_SUCCESS': 'User verified', 'VERIFY_FAILED': 'Could not verify', - 'USER_SYSTEM_ENABLED': 'Use user system for customers', - 'REGISTRATION': 'Enable user registration', + 'ENABLE_USER_SYSTEM': 'Use user system for customers', + 'ENABLE_USER_REGISTRATION': 'Enable user registration', 'INCLUDE_USERS_VIA_CSV': 'Include users via CSV file', 'INCLUDE_DATABASE_VIA_SQL': 'Include database via SQL file', 'BACKUP_DATABASE': 'Backup database', @@ -223,7 +223,11 @@ export default { 'SYSTEM_PREFERENCES_DESCRIPTION': 'Here you can edit the preferences of the system.', 'VERIFY_SUCCESS_DESCRIPTION': 'You user has been verified correctly. You can log in now.', 'VERIFY_FAILED_DESCRIPTION': 'The verification could not be done.', - 'ADVANCED_SETTINGS_DESCRIPTION': 'Advanced settings description should go here!', + 'ADVANCED_SETTINGS_DESCRIPTION': 'Here you can change the advanced settings of your system. Please be careful, the changes you make can not be reversed.', + 'USER_SYSTEM_DISABLED': 'User system has been disabled', + 'USER_SYSTEM_ENABLED': 'User system has been enabled', + 'REGISTRATION_DISABLED': 'Registration has been disabled', + 'REGISTRATION_ENABLED': 'Registration has been enabled', //ERRORS 'EMAIL_OR_PASSWORD': 'Email or password invalid', From 5e51536f259bc86ea1bec7caad30c17059d1b53d Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Sun, 22 Jan 2017 06:52:03 -0300 Subject: [PATCH 75/84] Ivan - Add api keys [skip ci] --- .../settings/admin-panel-advanced-settings.js | 132 +++++++++++++----- .../admin-panel-advanced-settings.scss | 27 +++- client/src/data/fixtures/system-fixtures.js | 22 ++- client/src/data/languages/en.js | 3 + 4 files changed, 139 insertions(+), 45 deletions(-) diff --git a/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js b/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js index 010aa405..52f7245d 100644 --- a/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js +++ b/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js @@ -1,17 +1,21 @@ import React from 'react'; -import {connect} from 'react-redux'; +import {connect} from 'react-redux'; import ConfigActions from 'actions/config-actions'; import API from 'lib-app/api-call'; import i18n from 'lib-app/i18n'; import ToggleButton from 'app-components/toggle-button'; import AreYouSure from 'app-components/are-you-sure'; +import ModalContainer from 'app-components/modal-container'; import Message from 'core-components/message'; import Button from 'core-components/button'; import FileUploader from 'core-components/file-uploader'; import Header from 'core-components/header'; import Listing from 'core-components/listing'; +import Form from 'core-components/form'; +import FormField from 'core-components/form-field'; +import SubmitButton from 'core-components/submit-button'; class AdminPanelAdvancedSettings extends React.Component { @@ -21,9 +25,8 @@ class AdminPanelAdvancedSettings extends React.Component { messageContent: '', keyName: '', keyCode: '', - values: { - apikeys: [] - } + selectedAPIKey: -1, + APIKeys: [] }; componentDidMount() { @@ -32,21 +35,21 @@ class AdminPanelAdvancedSettings extends React.Component { render() { return ( -
+
{(this.state.messageType) ? this.renderMessage() : null}
-
- {i18n('ENABLE_USER_SYSTEM')} - +
+ {i18n('ENABLE_USER_SYSTEM')} +
-
- {i18n('ENABLE_USER_REGISTRATION')} - +
+ {i18n('ENABLE_USER_REGISTRATION')} +
@@ -55,36 +58,32 @@ class AdminPanelAdvancedSettings extends React.Component {
-
{i18n('INCLUDE_USERS_VIA_CSV')}
- +
{i18n('INCLUDE_USERS_VIA_CSV')}
+
-
{i18n('INCLUDE_DATABASE_VIA_SQL')}
- +
{i18n('INCLUDE_DATABASE_VIA_SQL')}
+
-
{i18n('BACKUP_DATABASE')}
- +
{i18n('BACKUP_DATABASE')}
+
-
{i18n('DELETE_ALL_USERS')}
- +
{i18n('DELETE_ALL_USERS')}
+
-
-
{i18n('REGISTRATION_API_KEYS')}
+
+
{i18n('REGISTRATION_API_KEYS')}
-
{i18n('NAME_OF_KEY')}
-
-
{i18n('KEY')}
-
- + {(this.state.selectedAPIKey === -1) ? this.renderNoKey() : this.renderKey()}
@@ -98,31 +97,86 @@ class AdminPanelAdvancedSettings extends React.Component { ); } + renderNoKey() { + return ( +
+ {i18n('NO_KEY_SELECTED')} +
+ ); + } + + renderKey() { + let currentAPIKey = this.state.APIKeys[this.state.selectedAPIKey]; + + return ( +
+
{i18n('NAME_OF_KEY')}
+
{currentAPIKey.name}
+
{i18n('KEY')}
+
{currentAPIKey.token}
+ +
+ ); + } + getListingProps() { return { title: i18n('REGISTRATION_API_KEYS'), enableAddNew: true, - items: this.state.values.apikeys.map((item) => { + items: this.state.APIKeys.map((item) => { return { content: item.name, icon: '' }; - }) - } + }), + selectedIndex: this.state.selectedAPIKey, + onChange: index => this.setState({selectedAPIKey: index}), + onAddClick: this.openAPIKeyModal.bind(this) + }; + } + + openAPIKeyModal() { + ModalContainer.openModal( + +
+ + {i18n('SUBMIT')} + + ); + } + + addAPIKey({name}) { + ModalContainer.closeModal(); + API.call({ + path: '/system/add-api-key', + data: {name} + }).then(this.getAllKeys.bind(this)); } getAllKeys() { API.call({ - path: '/system/get-all-keys', + path: '/system/get-api-keys', data: {} }).then(this.onRetrieveSuccess.bind(this)); } + onDeleteKeyClick() { + AreYouSure.openModal(null, () => { + API.call({ + path: '/system/delete-api-key', + data: { + name: this.state.APIKeys[this.state.selectedAPIKey].name + } + }).then(this.getAllKeys.bind(this)); + }); + } + onRetrieveSuccess(result) { this.setState({ - values: { - apikeys: result.data - } + APIKeys: result.data, + selectedAPIKey: -1 }); } @@ -151,7 +205,7 @@ class AdminPanelAdvancedSettings extends React.Component { onAreYouSureRegistrationOk(password) { API.call({ - path: this.props.config['user-system-enabled'] ? '/system/disable-registration' : '/system/enable-registration', + path: this.props.config['registration'] ? '/system/disable-registration' : '/system/enable-registration', data: { password: password } @@ -179,8 +233,9 @@ class AdminPanelAdvancedSettings extends React.Component { file: file, password: password } - }).then(() => this.setState({messageType: 'success', messageContent: i18n('SUCCESS_IMPORTING_CSV_DESCRIPTION')} - )).catch(() => this.setState({messageType: 'error', messageContent: i18n('ERROR_IMPORTING_CSV_DESCRIPTION')})); + }) + .then(() => this.setState({messageType: 'success', messageContent: i18n('SUCCESS_IMPORTING_CSV_DESCRIPTION')})) + .catch(() => this.setState({messageType: 'error', messageContent: i18n('ERROR_IMPORTING_CSV_DESCRIPTION')})); } onAreYouSureSQLOk(file, password) { @@ -190,8 +245,9 @@ class AdminPanelAdvancedSettings extends React.Component { file: file, password: password } - }).then(() => this.setState({messageType: 'success', messageContent: i18n('SUCCESS_IMPORTING_SQL_DESCRIPTION')} - )).catch(() => this.setState({messageType: 'error', messageContent: i18n('ERROR_IMPORTING_SQL_DESCRIPTION')})); + }) + .then(() => this.setState({messageType: 'success', messageContent: i18n('SUCCESS_IMPORTING_SQL_DESCRIPTION')})) + .catch(() => this.setState({messageType: 'error', messageContent: i18n('ERROR_IMPORTING_SQL_DESCRIPTION')})); } onBackupDatabase() { diff --git a/client/src/app/admin/panel/settings/admin-panel-advanced-settings.scss b/client/src/app/admin/panel/settings/admin-panel-advanced-settings.scss index 30ea3730..86ec9150 100644 --- a/client/src/app/admin/panel/settings/admin-panel-advanced-settings.scss +++ b/client/src/app/admin/panel/settings/admin-panel-advanced-settings.scss @@ -1,6 +1,6 @@ @import "../../../../scss/vars"; -.admin-panel-system-settings { +.admin-panel-advanced-settings { &__user-system-enabled { } @@ -27,7 +27,6 @@ } &__api-keys { - text-align: left; &-title { font-size: $font-size--bg; @@ -35,15 +34,31 @@ text-align: left; } + &-info { + text-align: left; + } + &-subtitle { font-size: $font-size--md; margin-bottom: 5px; } - &-button { - margin-left: 20px; - margin-right: 20px; - width: 150px; + &-data { + background-color: $light-grey; + border-radius: 4px; + width: 300px; + margin: 10px 0; + text-align: center; + padding: 5px 0; + } + + &-modal { + min-width: 500px; + } + + &-none { + color: $dark-grey; + font-size: $font-size--md; } } } diff --git a/client/src/data/fixtures/system-fixtures.js b/client/src/data/fixtures/system-fixtures.js index 64f7d3d8..18b94c0f 100644 --- a/client/src/data/fixtures/system-fixtures.js +++ b/client/src/data/fixtures/system-fixtures.js @@ -248,7 +248,27 @@ module.exports = [ } }, { - path: '/system/get-all-keys', + path: '/system/add-api-key', + time: 300, + response: function () { + return { + status: 'success', + data: {} + }; + } + }, + { + path: '/system/delete-api-key', + time: 300, + response: function () { + return { + status: 'success', + data: {} + }; + } + }, + { + path: '/system/get-api-keys', time: 300, response: function () { return { diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js index 4d2564fa..fbd6a4ba 100644 --- a/client/src/data/languages/en.js +++ b/client/src/data/languages/en.js @@ -162,6 +162,8 @@ export default { 'REGISTRATION_API_KEYS': 'Registration API keys', 'NAME_OF_KEY': 'Name of key', 'KEY': 'Key', + 'ADD_API_KEY': 'Add API Key', + 'NO_KEY_SELECTED': 'No Key selected', //ACTIVITIES 'ACTIVITY_COMMENT': 'commented ticket', @@ -228,6 +230,7 @@ export default { 'USER_SYSTEM_ENABLED': 'User system has been enabled', 'REGISTRATION_DISABLED': 'Registration has been disabled', 'REGISTRATION_ENABLED': 'Registration has been enabled', + 'ADD_API_KEY_DESCRIPTION': 'Insert the name and a registration api key be generated.', //ERRORS 'EMAIL_OR_PASSWORD': 'Email or password invalid', From 6f1638e5fe465d681911018d74547b1e0b8bf1ef Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 8 Feb 2017 15:09:15 -0300 Subject: [PATCH 76/84] Ivan - Update backend methods [skip ci] --- server/controllers/article/add-topic.php | 1 + server/controllers/article/add.php | 1 + server/controllers/article/delete-topic.php | 1 + server/controllers/article/delete.php | 1 + server/controllers/article/edit-topic.php | 1 + server/controllers/article/edit.php | 1 + server/controllers/article/get-all.php | 1 + server/controllers/staff/add.php | 1 + server/controllers/staff/assign-ticket.php | 2 ++ server/controllers/staff/delete.php | 1 + server/controllers/staff/edit.php | 1 + server/controllers/staff/get-all-tickets.php | 1 + server/controllers/staff/get-all.php | 1 + server/controllers/staff/get-new-tickets.php | 1 + server/controllers/staff/get-tickets.php | 1 + server/controllers/staff/get.php | 1 + server/controllers/staff/last-events.php | 1 + server/controllers/staff/search-tickets.php | 1 + server/controllers/staff/un-assign-ticket.php | 1 + server/controllers/system/add-api-key.php | 1 + server/controllers/system/add-department.php | 1 + server/controllers/system/backup-database.php | 1 + server/controllers/system/csv-import.php | 1 + server/controllers/system/delete-all-users.php | 1 + server/controllers/system/delete-api-key.php | 1 + server/controllers/system/delete-department.php | 3 ++- server/controllers/system/disable-registration.php | 1 + server/controllers/system/disable-user-system.php | 1 + server/controllers/system/download.php | 1 + server/controllers/system/edit-department.php | 1 + server/controllers/system/edit-mail-template.php | 1 + server/controllers/system/edit-settings.php | 1 + server/controllers/system/enable-registration.php | 1 + server/controllers/system/enabled-user-system.php | 1 + server/controllers/system/get-all-keys.php | 1 + server/controllers/system/get-logs.php | 1 + server/controllers/system/get-mail-templates.php | 1 + server/controllers/system/get-settings.php | 1 + server/controllers/system/get-stats.php | 1 + server/controllers/system/init-settings.php | 1 + server/controllers/system/recover-mail-template.php | 1 + server/controllers/ticket/add-custom-response.php | 1 + server/controllers/ticket/change-department.php | 1 + server/controllers/ticket/change-priority.php | 1 + server/controllers/ticket/close.php | 1 + server/controllers/ticket/comment.php | 1 + server/controllers/ticket/create.php | 1 + server/controllers/ticket/delete-custom-response.php | 1 + server/controllers/ticket/edit-custom-response.php | 1 + server/controllers/ticket/get-custom-responses.php | 1 + server/controllers/ticket/get.php | 1 + server/controllers/ticket/re-open.php | 1 + server/controllers/ticket/seen.php | 1 + server/controllers/user/ban.php | 1 + server/controllers/user/check-session.php | 1 + server/controllers/user/delete.php | 1 + server/controllers/user/edit-email.php | 1 + server/controllers/user/edit-password.php | 3 ++- server/controllers/user/get-user.php | 3 ++- server/controllers/user/get-users.php | 1 + server/controllers/user/get.php | 1 + server/controllers/user/list-ban.php | 1 + server/controllers/user/login.php | 3 ++- server/controllers/user/logout.php | 1 + server/controllers/user/recover-password.php | 1 + server/controllers/user/send-recover-password.php | 1 + server/controllers/user/signup.php | 3 ++- server/controllers/user/un-ban.php | 1 + server/controllers/user/verify.php | 1 + server/libs/ControllerGroup.php | 6 +++++- 70 files changed, 80 insertions(+), 6 deletions(-) diff --git a/server/controllers/article/add-topic.php b/server/controllers/article/add-topic.php index 9bfe8d99..71e9424b 100644 --- a/server/controllers/article/add-topic.php +++ b/server/controllers/article/add-topic.php @@ -4,6 +4,7 @@ DataValidator::with('CustomValidations', true); class AddTopicController extends Controller { const PATH = '/add-topic'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/article/add.php b/server/controllers/article/add.php index 79e6d469..c01d7ecf 100644 --- a/server/controllers/article/add.php +++ b/server/controllers/article/add.php @@ -4,6 +4,7 @@ DataValidator::with('CustomValidations', true); class AddArticleController extends Controller { const PATH = '/add'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/article/delete-topic.php b/server/controllers/article/delete-topic.php index 61f372f6..ba10905a 100644 --- a/server/controllers/article/delete-topic.php +++ b/server/controllers/article/delete-topic.php @@ -4,6 +4,7 @@ DataValidator::with('CustomValidations', true); class DeleteTopicController extends Controller { const PATH = '/delete-topic'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/article/delete.php b/server/controllers/article/delete.php index a3aafb7c..44886e16 100644 --- a/server/controllers/article/delete.php +++ b/server/controllers/article/delete.php @@ -4,6 +4,7 @@ DataValidator::with('CustomValidations', true); class DeleteArticleController extends Controller { const PATH = '/delete'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/article/edit-topic.php b/server/controllers/article/edit-topic.php index c06fef30..5717557b 100644 --- a/server/controllers/article/edit-topic.php +++ b/server/controllers/article/edit-topic.php @@ -4,6 +4,7 @@ DataValidator::with('CustomValidations', true); class EditTopicController extends Controller { const PATH = '/edit-topic'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/article/edit.php b/server/controllers/article/edit.php index 86d78a4a..60220680 100644 --- a/server/controllers/article/edit.php +++ b/server/controllers/article/edit.php @@ -4,6 +4,7 @@ DataValidator::with('CustomValidations', true); class EditArticleController extends Controller { const PATH = '/edit'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/article/get-all.php b/server/controllers/article/get-all.php index 40a49efc..3f2577be 100644 --- a/server/controllers/article/get-all.php +++ b/server/controllers/article/get-all.php @@ -4,6 +4,7 @@ DataValidator::with('CustomValidations', true); class GetAllArticlesController extends Controller { const PATH = '/get-all'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/staff/add.php b/server/controllers/staff/add.php index 7c9a2827..86f6a7cf 100644 --- a/server/controllers/staff/add.php +++ b/server/controllers/staff/add.php @@ -4,6 +4,7 @@ DataValidator::with('CustomValidations', true); class AddStaffController extends Controller { const PATH = '/add'; + const METHOD = 'POST'; private $name; private $email; diff --git a/server/controllers/staff/assign-ticket.php b/server/controllers/staff/assign-ticket.php index b92d3364..4f40d524 100644 --- a/server/controllers/staff/assign-ticket.php +++ b/server/controllers/staff/assign-ticket.php @@ -4,6 +4,8 @@ DataValidator::with('CustomValidations', true); class AssignStaffController extends Controller { const PATH = '/assign-ticket'; + const METHOD = 'POST'; + private $ticket; private $user; diff --git a/server/controllers/staff/delete.php b/server/controllers/staff/delete.php index 8aeec886..47cb461a 100644 --- a/server/controllers/staff/delete.php +++ b/server/controllers/staff/delete.php @@ -6,6 +6,7 @@ DataValidator::with('CustomValidations', true); class DeleteStaffController extends Controller { const PATH = '/delete'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/staff/edit.php b/server/controllers/staff/edit.php index fef5f0fc..d62b6fb2 100644 --- a/server/controllers/staff/edit.php +++ b/server/controllers/staff/edit.php @@ -3,6 +3,7 @@ use Respect\Validation\Validator as DataValidator; class EditStaffController extends Controller { const PATH = '/edit'; + const METHOD = 'POST'; private $staffInstance; diff --git a/server/controllers/staff/get-all-tickets.php b/server/controllers/staff/get-all-tickets.php index be7641a2..98c3f4d6 100644 --- a/server/controllers/staff/get-all-tickets.php +++ b/server/controllers/staff/get-all-tickets.php @@ -3,6 +3,7 @@ use Respect\Validation\Validator as DataValidator; class GetAllTicketsStaffController extends Controller { const PATH = '/get-all-tickets'; + const METHOD = 'POST'; public function validations() { return[ diff --git a/server/controllers/staff/get-all.php b/server/controllers/staff/get-all.php index 2c93165a..2fc903c6 100644 --- a/server/controllers/staff/get-all.php +++ b/server/controllers/staff/get-all.php @@ -4,6 +4,7 @@ use Respect\Validation\Validator as DataValidator; class GetAllStaffController extends Controller { const PATH ='/get-all'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/staff/get-new-tickets.php b/server/controllers/staff/get-new-tickets.php index de9e2504..61ee2c5f 100644 --- a/server/controllers/staff/get-new-tickets.php +++ b/server/controllers/staff/get-new-tickets.php @@ -3,6 +3,7 @@ use Respect\Validation\Validator as DataValidator; class GetNewTicketsStaffController extends Controller { const PATH = '/get-new-tickets'; + const METHOD = 'POST'; public function validations() { return[ diff --git a/server/controllers/staff/get-tickets.php b/server/controllers/staff/get-tickets.php index d9ff1289..225dacae 100644 --- a/server/controllers/staff/get-tickets.php +++ b/server/controllers/staff/get-tickets.php @@ -3,6 +3,7 @@ use Respect\Validation\Validator as DataValidator; class GetTicketStaffController extends Controller { const PATH = '/get-tickets'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/staff/get.php b/server/controllers/staff/get.php index c6dc6418..f5558c9f 100644 --- a/server/controllers/staff/get.php +++ b/server/controllers/staff/get.php @@ -4,6 +4,7 @@ DataValidator::with('CustomValidations', true); class GetStaffController extends Controller { const PATH = '/get'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/staff/last-events.php b/server/controllers/staff/last-events.php index c6de992f..aae4b470 100644 --- a/server/controllers/staff/last-events.php +++ b/server/controllers/staff/last-events.php @@ -3,6 +3,7 @@ use Respect\Validation\Validator as DataValidator; class LastEventsStaffController extends Controller { const PATH = '/last-events'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/staff/search-tickets.php b/server/controllers/staff/search-tickets.php index e7af0189..21998d9a 100644 --- a/server/controllers/staff/search-tickets.php +++ b/server/controllers/staff/search-tickets.php @@ -3,6 +3,7 @@ use Respect\Validation\Validator as DataValidator; class SearchTicketStaffController extends Controller { const PATH = '/search-tickets'; + const METHOD = 'POST'; public function validations() { return[ diff --git a/server/controllers/staff/un-assign-ticket.php b/server/controllers/staff/un-assign-ticket.php index db15b28e..19630f35 100644 --- a/server/controllers/staff/un-assign-ticket.php +++ b/server/controllers/staff/un-assign-ticket.php @@ -4,6 +4,7 @@ DataValidator::with('CustomValidations', true); class UnAssignStaffController extends Controller { const PATH = '/un-assign-ticket'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/system/add-api-key.php b/server/controllers/system/add-api-key.php index 2f32d66d..38a6d1bb 100644 --- a/server/controllers/system/add-api-key.php +++ b/server/controllers/system/add-api-key.php @@ -3,6 +3,7 @@ use Respect\Validation\Validator as DataValidator; class AddAPIKeyController extends Controller { const PATH = '/add-api-key'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/system/add-department.php b/server/controllers/system/add-department.php index 9f13e7d7..b6de596e 100644 --- a/server/controllers/system/add-department.php +++ b/server/controllers/system/add-department.php @@ -3,6 +3,7 @@ use Respect\Validation\Validator as DataValidator; class AddDepartmentController extends Controller { const PATH = '/add-department'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/system/backup-database.php b/server/controllers/system/backup-database.php index 82b1fccf..73889e71 100644 --- a/server/controllers/system/backup-database.php +++ b/server/controllers/system/backup-database.php @@ -3,6 +3,7 @@ use Ifsnop\Mysqldump as IMysqldump; class BackupDatabaseController extends Controller { const PATH = '/backup-database'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/system/csv-import.php b/server/controllers/system/csv-import.php index ea3093b8..b7f6a815 100644 --- a/server/controllers/system/csv-import.php +++ b/server/controllers/system/csv-import.php @@ -2,6 +2,7 @@ class CSVImportController extends Controller { const PATH = '/csv-import'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/system/delete-all-users.php b/server/controllers/system/delete-all-users.php index 63749e59..1ac56920 100644 --- a/server/controllers/system/delete-all-users.php +++ b/server/controllers/system/delete-all-users.php @@ -3,6 +3,7 @@ use RedBeanPHP\Facade as RedBean; class DeleteAllUsersController extends Controller { const PATH = '/delete-all-users'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/system/delete-api-key.php b/server/controllers/system/delete-api-key.php index 8ee03152..c38201be 100644 --- a/server/controllers/system/delete-api-key.php +++ b/server/controllers/system/delete-api-key.php @@ -3,6 +3,7 @@ use Respect\Validation\Validator as DataValidator; class DeleteAPIKeyController extends Controller { const PATH = '/delete-api-key'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/system/delete-department.php b/server/controllers/system/delete-department.php index 0da23a80..452266bc 100644 --- a/server/controllers/system/delete-department.php +++ b/server/controllers/system/delete-department.php @@ -4,7 +4,8 @@ DataValidator::with('CustomValidations', true); class DeleteDepartmentController extends Controller { const PATH = '/delete-department'; - + const METHOD = 'POST'; + private $departmentId; private $transferDepartmentId; diff --git a/server/controllers/system/disable-registration.php b/server/controllers/system/disable-registration.php index 4b9ab053..ab1ae2d7 100644 --- a/server/controllers/system/disable-registration.php +++ b/server/controllers/system/disable-registration.php @@ -2,6 +2,7 @@ class DisableRegistrationController extends Controller { const PATH = '/disable-registration'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/system/disable-user-system.php b/server/controllers/system/disable-user-system.php index fc1cc0a1..acdec689 100644 --- a/server/controllers/system/disable-user-system.php +++ b/server/controllers/system/disable-user-system.php @@ -2,6 +2,7 @@ class DisableUserSystemController extends Controller { const PATH = '/disable-user-system'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/system/download.php b/server/controllers/system/download.php index 278ddc1b..b0b8e639 100644 --- a/server/controllers/system/download.php +++ b/server/controllers/system/download.php @@ -4,6 +4,7 @@ use Respect\Validation\Validator as DataValidator; class DownloadController extends Controller { const PATH = '/download'; + const METHOD = 'GET'; public function validations() { return [ diff --git a/server/controllers/system/edit-department.php b/server/controllers/system/edit-department.php index 30679fbc..2ccf8b7a 100644 --- a/server/controllers/system/edit-department.php +++ b/server/controllers/system/edit-department.php @@ -5,6 +5,7 @@ DataValidator::with('CustomValidations', true); class EditDepartmentController extends Controller { const PATH = '/edit-department'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/system/edit-mail-template.php b/server/controllers/system/edit-mail-template.php index cb916a86..06ddd5e6 100644 --- a/server/controllers/system/edit-mail-template.php +++ b/server/controllers/system/edit-mail-template.php @@ -3,6 +3,7 @@ use Respect\Validation\Validator as DataValidator; class EditMailTemplateController extends Controller { const PATH = '/edit-mail-template'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/system/edit-settings.php b/server/controllers/system/edit-settings.php index 22454e62..41c86550 100644 --- a/server/controllers/system/edit-settings.php +++ b/server/controllers/system/edit-settings.php @@ -2,6 +2,7 @@ class EditSettingsController extends Controller { const PATH = '/edit-settings'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/system/enable-registration.php b/server/controllers/system/enable-registration.php index 6221daa9..3666eb09 100644 --- a/server/controllers/system/enable-registration.php +++ b/server/controllers/system/enable-registration.php @@ -3,6 +3,7 @@ use Respect\Validation\Validator as DataValidator; class EnableRegistrationController extends Controller { const PATH = '/enable-registration'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/system/enabled-user-system.php b/server/controllers/system/enabled-user-system.php index 0139608a..375593e0 100644 --- a/server/controllers/system/enabled-user-system.php +++ b/server/controllers/system/enabled-user-system.php @@ -2,6 +2,7 @@ class EnabledUserSystemController extends Controller { const PATH = '/enabled-user-system'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/system/get-all-keys.php b/server/controllers/system/get-all-keys.php index 35206374..fa896451 100644 --- a/server/controllers/system/get-all-keys.php +++ b/server/controllers/system/get-all-keys.php @@ -3,6 +3,7 @@ use Respect\Validation\Validator as DataValidator; class GetAllKeyController extends Controller { const PATH = '/get-all-keys'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/system/get-logs.php b/server/controllers/system/get-logs.php index 99217560..3caa2447 100644 --- a/server/controllers/system/get-logs.php +++ b/server/controllers/system/get-logs.php @@ -3,6 +3,7 @@ use Respect\Validation\Validator as DataValidator; class GetLogsController extends Controller { const PATH = '/get-logs'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/system/get-mail-templates.php b/server/controllers/system/get-mail-templates.php index b0d0a46a..cb4de9e0 100644 --- a/server/controllers/system/get-mail-templates.php +++ b/server/controllers/system/get-mail-templates.php @@ -3,6 +3,7 @@ use Respect\Validation\Validator as DataValidator; class GetMailTemplatesController extends Controller { const PATH = '/get-mail-templates'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/system/get-settings.php b/server/controllers/system/get-settings.php index 41e2299d..15f1df8d 100644 --- a/server/controllers/system/get-settings.php +++ b/server/controllers/system/get-settings.php @@ -2,6 +2,7 @@ class GetSettingsController extends Controller { const PATH = '/get-settings'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/system/get-stats.php b/server/controllers/system/get-stats.php index ff1fdf3a..31a4e67b 100644 --- a/server/controllers/system/get-stats.php +++ b/server/controllers/system/get-stats.php @@ -3,6 +3,7 @@ use Respect\Validation\Validator as DataValidator; class GetStatsController extends Controller { const PATH = '/get-stats'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/system/init-settings.php b/server/controllers/system/init-settings.php index 4106797b..a3bfdf65 100644 --- a/server/controllers/system/init-settings.php +++ b/server/controllers/system/init-settings.php @@ -2,6 +2,7 @@ class InitSettingsController extends Controller { const PATH = '/init-settings'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/system/recover-mail-template.php b/server/controllers/system/recover-mail-template.php index 9fdff9be..5242ad81 100644 --- a/server/controllers/system/recover-mail-template.php +++ b/server/controllers/system/recover-mail-template.php @@ -3,6 +3,7 @@ use Respect\Validation\Validator as DataValidator; class RecoverMailTemplateController extends Controller { const PATH = '/recover-mail-template'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/ticket/add-custom-response.php b/server/controllers/ticket/add-custom-response.php index 68af88f7..ac05d2d6 100644 --- a/server/controllers/ticket/add-custom-response.php +++ b/server/controllers/ticket/add-custom-response.php @@ -4,6 +4,7 @@ DataValidator::with('CustomValidations', true); class AddCustomResponseController extends Controller { const PATH = '/add-custom-response'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/ticket/change-department.php b/server/controllers/ticket/change-department.php index ac2e78da..61e99a4b 100644 --- a/server/controllers/ticket/change-department.php +++ b/server/controllers/ticket/change-department.php @@ -4,6 +4,7 @@ DataValidator::with('CustomValidations', true); class ChangeDepartmentController extends Controller { const PATH = '/change-department'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/ticket/change-priority.php b/server/controllers/ticket/change-priority.php index 2e671a57..18f5be15 100644 --- a/server/controllers/ticket/change-priority.php +++ b/server/controllers/ticket/change-priority.php @@ -3,6 +3,7 @@ use Respect\Validation\Validator as DataValidator; class ChangePriorityController extends Controller { const PATH = '/change-priority'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/ticket/close.php b/server/controllers/ticket/close.php index ed983a35..a1b6a323 100644 --- a/server/controllers/ticket/close.php +++ b/server/controllers/ticket/close.php @@ -4,6 +4,7 @@ DataValidator::with('CustomValidations', true); class CloseController extends Controller { const PATH = '/close'; + const METHOD = 'POST'; private $ticket; diff --git a/server/controllers/ticket/comment.php b/server/controllers/ticket/comment.php index cc0d24ba..c1593472 100644 --- a/server/controllers/ticket/comment.php +++ b/server/controllers/ticket/comment.php @@ -4,6 +4,7 @@ DataValidator::with('CustomValidations', true); class CommentController extends Controller { const PATH = '/comment'; + const METHOD = 'POST'; private $ticket; private $content; diff --git a/server/controllers/ticket/create.php b/server/controllers/ticket/create.php index 5b39ab47..23559205 100644 --- a/server/controllers/ticket/create.php +++ b/server/controllers/ticket/create.php @@ -4,6 +4,7 @@ DataValidator::with('CustomValidations', true); class CreateController extends Controller { const PATH = '/create'; + const METHOD = 'POST'; private $title; private $content; diff --git a/server/controllers/ticket/delete-custom-response.php b/server/controllers/ticket/delete-custom-response.php index 4ab5ca8b..d9be3c09 100644 --- a/server/controllers/ticket/delete-custom-response.php +++ b/server/controllers/ticket/delete-custom-response.php @@ -4,6 +4,7 @@ DataValidator::with('CustomValidations', true); class DeleteCustomResponseController extends Controller { const PATH = '/delete-custom-response'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/ticket/edit-custom-response.php b/server/controllers/ticket/edit-custom-response.php index 12b170a7..c4b5975c 100644 --- a/server/controllers/ticket/edit-custom-response.php +++ b/server/controllers/ticket/edit-custom-response.php @@ -4,6 +4,7 @@ DataValidator::with('CustomValidations', true); class EditCustomResponseController extends Controller { const PATH = '/edit-custom-response'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/ticket/get-custom-responses.php b/server/controllers/ticket/get-custom-responses.php index 7c2872cf..e2c0fb64 100644 --- a/server/controllers/ticket/get-custom-responses.php +++ b/server/controllers/ticket/get-custom-responses.php @@ -4,6 +4,7 @@ DataValidator::with('CustomValidations', true); class GetCustomResponsesController extends Controller { const PATH = '/get-custom-responses'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/ticket/get.php b/server/controllers/ticket/get.php index 61cba027..c1799e42 100644 --- a/server/controllers/ticket/get.php +++ b/server/controllers/ticket/get.php @@ -4,6 +4,7 @@ DataValidator::with('CustomValidations', true); class TicketGetController extends Controller { const PATH = '/get'; + const METHOD = 'POST'; private $ticket; diff --git a/server/controllers/ticket/re-open.php b/server/controllers/ticket/re-open.php index b2754256..0df85fa0 100644 --- a/server/controllers/ticket/re-open.php +++ b/server/controllers/ticket/re-open.php @@ -3,6 +3,7 @@ use Respect\Validation\Validator as DataValidator; class ReOpenController extends Controller { const PATH = '/re-open'; + const METHOD = 'POST'; private $ticket; diff --git a/server/controllers/ticket/seen.php b/server/controllers/ticket/seen.php index fa07e0c4..051b3e45 100644 --- a/server/controllers/ticket/seen.php +++ b/server/controllers/ticket/seen.php @@ -3,6 +3,7 @@ use Respect\Validation\Validator as DataValidator; class SeenController extends Controller { const PATH = '/seen'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/user/ban.php b/server/controllers/user/ban.php index 650c4a73..4cc903b7 100644 --- a/server/controllers/user/ban.php +++ b/server/controllers/user/ban.php @@ -3,6 +3,7 @@ use Respect\Validation\Validator as DataValidator; class BanUserController extends Controller { const PATH = '/ban'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/user/check-session.php b/server/controllers/user/check-session.php index 88cc8fd3..750bddcd 100644 --- a/server/controllers/user/check-session.php +++ b/server/controllers/user/check-session.php @@ -2,6 +2,7 @@ class CheckSessionController extends Controller { const PATH = '/check-session'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/user/delete.php b/server/controllers/user/delete.php index b17ed8a4..bfc86a06 100644 --- a/server/controllers/user/delete.php +++ b/server/controllers/user/delete.php @@ -6,6 +6,7 @@ DataValidator::with('CustomValidations', true); class DeleteUserController extends Controller { const PATH = '/delete'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/user/edit-email.php b/server/controllers/user/edit-email.php index 5a81ac60..a8bdbdb2 100644 --- a/server/controllers/user/edit-email.php +++ b/server/controllers/user/edit-email.php @@ -3,6 +3,7 @@ use Respect\Validation\Validator as DataValidator; class EditEmail extends Controller{ const PATH = '/edit-email'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/user/edit-password.php b/server/controllers/user/edit-password.php index de4ef6db..9083aeb5 100644 --- a/server/controllers/user/edit-password.php +++ b/server/controllers/user/edit-password.php @@ -3,7 +3,8 @@ use Respect\Validation\Validator as DataValidator; class EditPassword extends Controller { const PATH = '/edit-password'; - + const METHOD = 'POST'; + public function validations() { return [ 'permission' => 'user', diff --git a/server/controllers/user/get-user.php b/server/controllers/user/get-user.php index ae9b4f9e..6d257f7c 100644 --- a/server/controllers/user/get-user.php +++ b/server/controllers/user/get-user.php @@ -4,7 +4,8 @@ DataValidator::with('CustomValidations', true); class GetUserByIdController extends Controller { const PATH = '/get-user'; - + const METHOD = 'POST'; + public function validations() { return [ 'permission' => 'staff_1', diff --git a/server/controllers/user/get-users.php b/server/controllers/user/get-users.php index 5d8daf28..8f3c6c7a 100644 --- a/server/controllers/user/get-users.php +++ b/server/controllers/user/get-users.php @@ -3,6 +3,7 @@ use Respect\Validation\Validator as DataValidator; class GetUsersController extends Controller { const PATH = '/get-users'; + const METHOD = 'POST'; public function validations() { return[ diff --git a/server/controllers/user/get.php b/server/controllers/user/get.php index 43f189dd..cbdf931d 100644 --- a/server/controllers/user/get.php +++ b/server/controllers/user/get.php @@ -4,6 +4,7 @@ DataValidator::with('CustomValidations', true); class GetUserController extends Controller { const PATH = '/get'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/user/list-ban.php b/server/controllers/user/list-ban.php index c037eabc..794f3ffd 100644 --- a/server/controllers/user/list-ban.php +++ b/server/controllers/user/list-ban.php @@ -3,6 +3,7 @@ use Respect\Validation\Validator as DataValidator; class ListBanUserController extends Controller { const PATH = '/list-ban'; + const METHOD = 'POST'; public function validations() { return [ diff --git a/server/controllers/user/login.php b/server/controllers/user/login.php index ebd55c30..1465210b 100644 --- a/server/controllers/user/login.php +++ b/server/controllers/user/login.php @@ -2,6 +2,7 @@ class LoginController extends Controller { const PATH = '/login'; + const METHOD = 'POST'; private $userInstance; private $rememberToken; @@ -40,7 +41,7 @@ class LoginController extends Controller { Response::respondSuccess($this->getUserData()); } else { - Response::respondError(ERRORS::INVALID_CREDENTIALS); + Response::respondError(Controller::request('email')); } } diff --git a/server/controllers/user/logout.php b/server/controllers/user/logout.php index 60e51c80..5ba3b4a0 100644 --- a/server/controllers/user/logout.php +++ b/server/controllers/user/logout.php @@ -1,6 +1,7 @@ group($this->groupPath, function () use ($app, $controllers) { foreach ($controllers as $controller) { - $app->post($controller::PATH, $controller->getHandler()); + if($controller::METHOD === 'POST') { + $app->post($controller::PATH, $controller->getHandler()); + } else { + $app->get($controller::PATH, $controller->getHandler()); + } } }); } From 8f02a08018ae078dc2f1c0a9b00b674a7cb61e02 Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 9 Feb 2017 17:05:59 -0300 Subject: [PATCH 77/84] Ivan - Update profile pic upload [skip ci] --- .../src/app/admin/panel/staff/staff-editor.js | 45 ++++++++++++++++- .../app/admin/panel/staff/staff-editor.scss | 48 +++++++++++++++++++ server/controllers/staff/edit.php | 5 ++ 3 files changed, 96 insertions(+), 2 deletions(-) diff --git a/client/src/app/admin/panel/staff/staff-editor.js b/client/src/app/admin/panel/staff/staff-editor.js index 1581698f..a173bc1f 100644 --- a/client/src/app/admin/panel/staff/staff-editor.js +++ b/client/src/app/admin/panel/staff/staff-editor.js @@ -1,5 +1,6 @@ import React from 'react'; import _ from 'lodash'; +import classNames from 'classnames'; import i18n from 'lib-app/i18n'; import API from 'lib-app/api-call'; @@ -13,6 +14,8 @@ import FormField from 'core-components/form-field'; import SubmitButton from 'core-components/submit-button'; import Message from 'core-components/message'; import Button from 'core-components/button'; +import Icon from 'core-components/icon'; +import Loading from 'core-components/loading'; class StaffEditor extends React.Component { static propTypes = { @@ -32,6 +35,7 @@ class StaffEditor extends React.Component { email: this.props.email, level: this.props.level - 1, message: null, + loadingPicture: false, departments: this.getUserDepartments() }; @@ -67,9 +71,12 @@ class StaffEditor extends React.Component {
-
+
+ {(this.state.loadingPicture) ? : } + +
@@ -195,6 +202,15 @@ class StaffEditor extends React.Component { ); } + getPictureWrapperClass() { + let classes = { + 'staff-editor__card-pic-wrapper': true, + 'staff-editor__card-pic-wrapper_loading': this.state.loadingPicture + }; + + return classNames(classes); + } + getTicketListProps() { return { type: 'secondary', @@ -282,6 +298,31 @@ class StaffEditor extends React.Component { this.setState({message: 'FAIL'}); }); } + + onProfilePicChange(event) { + this.setState({ + loadingPicture: true + }); + + API.call({ + path: '/staff/edit', + data: { + staffId: this.props.staffId, + file: event.target.files[0] + } + }).then(() => { + this.setState({ + loadingPicture: false + }); + + if(this.props.onChange) { + this.props.onChange(); + } + }).catch(() => { + window.scrollTo(0,0); + this.setState({message: 'FAIL', loadingPicture: false}); + }); + } } export default StaffEditor; \ No newline at end of file diff --git a/client/src/app/admin/panel/staff/staff-editor.scss b/client/src/app/admin/panel/staff/staff-editor.scss index 2f601ddd..4b6f8684 100644 --- a/client/src/app/admin/panel/staff/staff-editor.scss +++ b/client/src/app/admin/panel/staff/staff-editor.scss @@ -11,13 +11,41 @@ border: 2px solid $grey; margin-bottom: 20px; + &__image-uploader { + opacity: 0; + } + &-pic { height: 100%; position: absolute; left: 50%; transform: translate(-50%, 0); + &-background { + background-color: black; + opacity: 0; + transition: opacity 0.2s ease; + width: 100%; + height: 100%; + position: absolute; + z-index: 10; + } + + &-icon { + position: absolute; + color: white; + opacity: 0; + transition: opacity 0.2s ease; + top: 70px; + bottom: 0; + left: 0; + right: 0; + z-index: 11; + } + &-wrapper { + transition: opacity 0.2s ease; + background-color: $grey; position: absolute; top: 20px; border: 4px solid $grey; @@ -28,6 +56,26 @@ text-align: center; left: 50%; transform: translate(-50%, 0); + opacity: 1; + + &_loading, + &:hover { + cursor: pointer; + + .staff-editor__card-pic-background { + opacity: 0.6; + } + + .staff-editor__card-pic-icon { + opacity: 0.8; + } + + .staff-editor__card-pic-loading { + position: absolute; + top: 0; + z-index: 11; + } + } } } diff --git a/server/controllers/staff/edit.php b/server/controllers/staff/edit.php index d62b6fb2..05c0b1af 100644 --- a/server/controllers/staff/edit.php +++ b/server/controllers/staff/edit.php @@ -57,6 +57,11 @@ class EditStaffController extends Controller { $this->staffInstance->sharedDepartmentList = $this->getDepartmentList(); } + if(Controller::request('file')) { + $fileUploader = $this->uploadFile(); + $this->staffInstance->profilePic = ($fileUploader instanceof FileUploader) ? $fileUploader->getFileName() : null; + } + $this->staffInstance->store(); } From dcb04f7927ec46143648afa647018812f1e0fbde Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 9 Feb 2017 21:12:38 -0300 Subject: [PATCH 78/84] Ivan - Improve last events animations [skip ci] --- client/package.json | 2 +- .../panel/dashboard/admin-panel-activity.js | 37 ++++++++++++++++++- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/client/package.json b/client/package.json index 0033b6df..22a71851 100644 --- a/client/package.json +++ b/client/package.json @@ -68,7 +68,7 @@ "react-document-title": "^1.0.2", "react-dom": "^15.0.1", "react-google-recaptcha": "^0.5.2", - "react-motion": "^0.4.4", + "react-motion": "^0.4.7", "react-redux": "^4.4.5", "react-router": "^2.4.0", "react-router-redux": "^4.0.5", diff --git a/client/src/app/admin/panel/dashboard/admin-panel-activity.js b/client/src/app/admin/panel/dashboard/admin-panel-activity.js index 251462fb..608cd3c7 100644 --- a/client/src/app/admin/panel/dashboard/admin-panel-activity.js +++ b/client/src/app/admin/panel/dashboard/admin-panel-activity.js @@ -1,4 +1,6 @@ import React from 'react'; +import _ from 'lodash'; +import {TransitionMotion, spring} from 'react-motion'; import API from 'lib-app/api-call'; import i18n from 'lib-app/i18n'; @@ -64,12 +66,30 @@ class AdminPanelActivity extends React.Component { renderList() { return (
- {this.state.activities.map(this.renderRow.bind(this))} + + {this.renderActivityList.bind(this)} + {(!this.state.limit) ? this.renderButton() : null}
); } + renderActivityList(styles) { + return ( +
+ {styles.map(this.renderAnimatedItem.bind(this))} +
+ ); + } + + renderAnimatedItem(config, index) { + return ( +
+ {this.renderRow(config.data, index)} +
+ ); + } + renderButton() { return ( @@ -84,6 +104,21 @@ class AdminPanelActivity extends React.Component { ); } + getStyles() { + return this.state.activities.map((item, index) => ({ + key: index + '', + data: item, + style: {marginTop: spring(0), opacity: spring(1)} + })); + } + + getEnterStyle() { + return { + marginTop: -20, + opacity: 0 + }; + } + onMenuItemClick(index) { this.setState({ page: 1, From dbfbd0cf80472bd20f8b00b408ce12da70267d23 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 13 Feb 2017 15:45:43 -0300 Subject: [PATCH 79/84] Ivan - WIP [skip ci] --- client/src/app/App.js | 3 +- .../admin-panel-system-preferences.js | 2 +- client/src/app/app.scss | 46 +++++++++++++++++++ client/src/data/fixtures/system-fixtures.js | 8 +--- 4 files changed, 51 insertions(+), 8 deletions(-) diff --git a/client/src/app/App.js b/client/src/app/App.js index 6d327fa8..2f855f21 100644 --- a/client/src/app/App.js +++ b/client/src/app/App.js @@ -45,7 +45,8 @@ class App extends React.Component { getClass() { let classes = { 'application': true, - 'application_modal-opened': (this.props.modal.opened) + 'application_modal-opened': (this.props.modal.opened), + 'application_full-width': (this.props.config.layout === 'full-width' && !_.includes(this.props.location.pathname, '/admin')) }; return classNames(classes); diff --git a/client/src/app/admin/panel/settings/admin-panel-system-preferences.js b/client/src/app/admin/panel/settings/admin-panel-system-preferences.js index 21c7d44b..59b2ab3a 100644 --- a/client/src/app/admin/panel/settings/admin-panel-system-preferences.js +++ b/client/src/app/admin/panel/settings/admin-panel-system-preferences.js @@ -213,7 +213,7 @@ class AdminPanelSystemPreferences extends React.Component { 'reCaptchaPrivate': result.data.reCaptchaPrivate, 'url': result.data['url'], 'title': result.data['title'], - 'layout': result.data['layout'] == 'Full width' ? 1 : 0, + 'layout': result.data['layout'] == 'full-width' ? 1 : 0, 'time-zone': result.data['time-zone'], 'no-reply-email': result.data['no-reply-email'], 'smtp-host': result.data['smtp-host'], diff --git a/client/src/app/app.scss b/client/src/app/app.scss index cc6679c9..d7914ff5 100644 --- a/client/src/app/app.scss +++ b/client/src/app/app.scss @@ -2,4 +2,50 @@ .application { padding: $half-space; + + &_full-width { + padding: 0; + + .main-layout { + width: 100%; + max-width: none; + + &-header { + border-radius: 0; + height: 40px; + + &__login-links { + padding-top: 8px; + padding-left: 22px; + } + + &__languages { + top: 10px; + left: -20px; + } + } + + &-footer { + height: 40px; + //position: fixed; + //bottom: 0; + + &--powered { + padding-top: 9px; + } + } + } + + .main-home-page { + width: 1100px; + margin: 0 auto; + } + + .main-signup-page { + + .signup-widget__captcha { + margin-left: 290px; + } + } + } } \ No newline at end of file diff --git a/client/src/data/fixtures/system-fixtures.js b/client/src/data/fixtures/system-fixtures.js index 379af5d4..f2745afc 100644 --- a/client/src/data/fixtures/system-fixtures.js +++ b/client/src/data/fixtures/system-fixtures.js @@ -12,16 +12,14 @@ module.exports = [ 'reCaptchaPrivate': 'LALA', 'url': 'http://www.opensupports.com/support', 'title': 'OpenSupports Support Center', - 'layout': 'Boxed', + 'layout': 'full-width', 'time-zone': 3, 'no-reply-email': 'shitr@post.com', 'smtp-host': 'localhost', 'smtp-port': '7070', 'smtp-user': 'Wesa', 'maintenance-mode': false, - 'user-system-enabled': true, 'allow-attachments': true, - 'registration': true, 'max-size': 500, 'departments': [ {id: 1, name: 'Sales Support', owners: 2}, @@ -41,11 +39,9 @@ module.exports = [ data: { 'language': 'en', 'title': '', - 'layout': 'Boxed', + 'layout': 'full-width', 'reCaptchaKey': '6LfM5CYTAAAAAGLz6ctpf-hchX2_l0Ge-Bn-n8wS', 'maintenance-mode': false, - 'user-system-enabled': true, - 'registration': true, 'departments': [ {id: 1, name: 'Sales Support', owners: 2}, {id: 2, name: 'Technical Issues', owners: 5}, From d85d76f20eee736b09b8b858c45e148be2c72162 Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 15 Feb 2017 02:52:14 -0300 Subject: [PATCH 80/84] Ivan - Add responsive style and full-width mode [skip ci] --- client/src/app/App.js | 18 ++- client/src/app/app.scss | 122 +++++++++++++++++- .../dashboard-create-ticket-page.js | 10 +- .../dashboard-edit-profile-page.js | 16 +-- .../dashboard-edit-profile-page.scss | 5 +- .../app/main/dashboard/dashboard-layout.js | 31 ++++- .../dashboard-list-articles-page.js | 4 +- .../src/app/main/dashboard/dashboard-menu.js | 2 +- client/src/app/main/main-check-ticket-page.js | 21 ++- .../main-home-page-login-widget.scss | 4 - .../src/app/main/main-home/main-home-page.js | 17 ++- client/src/app/main/main-layout-header.js | 4 +- .../app/main/main-signup/main-signup-page.js | 6 +- .../main/main-signup/main-signup-page.scss | 2 +- client/src/core-components/widget.scss | 13 +- client/src/data/fixtures/system-fixtures.js | 8 +- client/src/data/languages/en.js | 7 + client/src/lib-app/session-store.js | 10 +- client/src/scss/_vars.scss | 2 +- 19 files changed, 250 insertions(+), 52 deletions(-) diff --git a/client/src/app/App.js b/client/src/app/App.js index 2f855f21..340340c4 100644 --- a/client/src/app/App.js +++ b/client/src/app/App.js @@ -3,6 +3,7 @@ import _ from 'lodash'; import classNames from 'classnames'; import { connect } from 'react-redux' import { browserHistory } from 'react-router'; +import DocumentTitle from 'react-document-title'; import ModalContainer from 'app-components/modal-container'; @@ -33,12 +34,14 @@ class App extends React.Component { render() { return ( -
-
- {React.cloneElement(this.props.children, {})} -
- -
+ +
+
+ {React.cloneElement(this.props.children, {})} +
+ +
+
); } @@ -46,7 +49,8 @@ class App extends React.Component { let classes = { 'application': true, 'application_modal-opened': (this.props.modal.opened), - 'application_full-width': (this.props.config.layout === 'full-width' && !_.includes(this.props.location.pathname, '/admin')) + 'application_full-width': (this.props.config.layout === 'full-width' && !_.includes(this.props.location.pathname, '/admin')), + 'application_user-system': (this.props.config['user-system-enabled']) }; return classNames(classes); diff --git a/client/src/app/app.scss b/client/src/app/app.scss index d7914ff5..5a62ae04 100644 --- a/client/src/app/app.scss +++ b/client/src/app/app.scss @@ -25,10 +25,12 @@ } } + &--content { + position: relative; + } + &-footer { height: 40px; - //position: fixed; - //bottom: 0; &--powered { padding-top: 9px; @@ -37,14 +39,122 @@ } .main-home-page { - width: 1100px; margin: 0 auto; + + .widget { + background-color: $very-light-grey; + } } - .main-signup-page { + .signup-widget { + background-color: $very-light-grey; + } + + .dashboard { - .signup-widget__captcha { - margin-left: 290px; + .widget { + background-color: transparent; + } + + &__menu { + margin-left: -5px; + margin-top: -20px; + padding: 0; + background-color: $very-light-grey; + height: 100%; + position: absolute; + + .menu__list { + background-color: transparent; + height: 100%; + position: relative; + } + + .menu__header { + border-top-left-radius: 0; + border-top-right-radius: 0; + background-color: $secondary-blue; + text-align: right; + } + } + + &__content { + margin-top: -10px; + } + + @media screen and (max-width: 992px) { + + .dashboard__menu { + position: static; + } + } + } + + &__widget { + background-color: $very-light-grey; + } + + @media screen and (max-width: 467px) { + + .input { + width: 250px; + } + } + + &.application_user-system { + + .main-layout { + background-color: white; + } + + .main-home-page { + + &__login-widget { + position: absolute; + } + + &__portal-wrapper { + margin-left: 360px; + padding-left: 15px; + padding-right: 15px; + } + + @media screen and (max-width: 992px) { + .main-home-page { + + &__login-widget, + &__portal-wrapper { + float: none; + width: initial; + margin-left: 0; + position: static; + } + } + } + } + } + + @media screen and (max-width: 379px) { + + .main-home-page { + + .widget { + min-width: 313px !important; + width: initial !important; + } + } + } + } + + &_user-system { + @media screen and (max-width: 379px) { + + .main-home-page { + + .widget { + min-width: initial; + width: 283px; + } } } } diff --git a/client/src/app/main/dashboard/dashboard-create-ticket/dashboard-create-ticket-page.js b/client/src/app/main/dashboard/dashboard-create-ticket/dashboard-create-ticket-page.js index 8edc3bcc..81c4d6e8 100644 --- a/client/src/app/main/dashboard/dashboard-create-ticket/dashboard-create-ticket-page.js +++ b/client/src/app/main/dashboard/dashboard-create-ticket/dashboard-create-ticket-page.js @@ -1,5 +1,6 @@ import React from 'react'; import classNames from 'classnames'; +import {connect} from 'react-redux'; import CreateTicketForm from 'app/main/dashboard/dashboard-create-ticket/create-ticket-form'; import Widget from 'core-components/widget'; @@ -29,11 +30,16 @@ class DashboardCreateTicketPage extends React.Component { getClass() { let classes = { 'dashboard-create-ticket-page': true, - 'dashboard-create-ticket-page_wrapped': (this.props.location.pathname === '/create-ticket') + 'dashboard-create-ticket-page_wrapped': (this.props.location.pathname === '/create-ticket'), + 'col-md-10 col-md-offset-1': (!this.props.config['user-system-enabled']) }; return classNames(classes); } } -export default DashboardCreateTicketPage; +export default connect((store) => { + return { + config: store.config + }; +})(DashboardCreateTicketPage); diff --git a/client/src/app/main/dashboard/dashboard-edit-profile/dashboard-edit-profile-page.js b/client/src/app/main/dashboard/dashboard-edit-profile/dashboard-edit-profile-page.js index 0c8ef026..f2d8ad45 100644 --- a/client/src/app/main/dashboard/dashboard-edit-profile/dashboard-edit-profile-page.js +++ b/client/src/app/main/dashboard/dashboard-edit-profile/dashboard-edit-profile-page.js @@ -24,19 +24,19 @@ class DashboardEditProfilePage extends React.Component { render() { return (
-
-
Edit Email
+
+
{i18n('EDIT_EMAIL')}
- CHANGE EMAIL + {i18n('CHANGE_EMAIL')} {this.renderMessageEmail()} -
Edit password
+
{i18n('EDIT_PASSWORD')}
- - - - CHANGE PASSWORD + + + + {i18n('CHANGE_PASSWORD')} {this.renderMessagePass()}
diff --git a/client/src/app/main/dashboard/dashboard-edit-profile/dashboard-edit-profile-page.scss b/client/src/app/main/dashboard/dashboard-edit-profile/dashboard-edit-profile-page.scss index d42e3ec5..8e25de49 100644 --- a/client/src/app/main/dashboard/dashboard-edit-profile/dashboard-edit-profile-page.scss +++ b/client/src/app/main/dashboard/dashboard-edit-profile/dashboard-edit-profile-page.scss @@ -1,12 +1,15 @@ @import '../../../../scss/vars'; .edit-profile-page { + &__title { color: $dark-grey; font-size: 20px; text-align: left; + margin-bottom: 20px; } - &__message{ + + &__message { margin-top: 20px; margin-bottom: 20px; } diff --git a/client/src/app/main/dashboard/dashboard-layout.js b/client/src/app/main/dashboard/dashboard-layout.js index b1c5c25e..ae51fca4 100644 --- a/client/src/app/main/dashboard/dashboard-layout.js +++ b/client/src/app/main/dashboard/dashboard-layout.js @@ -1,5 +1,6 @@ import React from 'react'; import {connect} from 'react-redux'; +import classNames from 'classnames'; import DashboardMenu from 'app/main/dashboard/dashboard-menu'; import Widget from 'core-components/widget'; @@ -9,8 +10,10 @@ class DashboardLayout extends React.Component { render() { return (this.props.session.logged) ? (
-
-
+
+ +
+
{this.props.children} @@ -18,10 +21,32 @@ class DashboardLayout extends React.Component {
) : null; } + + getDashboardMenuClass() { + let classes = { + 'dashboard__menu': true, + 'col-md-3': (this.props.config.layout === 'boxed'), + 'col-md-2': (this.props.config.layout === 'full-width') + }; + + return classNames(classes); + } + + getDashboardContentClass() { + let classes = { + 'dashboard__content': true, + 'col-md-9': (this.props.config.layout === 'boxed'), + 'col-md-10': (this.props.config.layout === 'full-width'), + 'col-md-offset-2': (this.props.config.layout === 'full-width') + }; + + return classNames(classes); + } } export default connect((store) => { return { - session: store.session + session: store.session, + config: store.config }; })(DashboardLayout); diff --git a/client/src/app/main/dashboard/dashboard-list-articles/dashboard-list-articles-page.js b/client/src/app/main/dashboard/dashboard-list-articles/dashboard-list-articles-page.js index f7c434e8..4c0978ff 100644 --- a/client/src/app/main/dashboard/dashboard-list-articles/dashboard-list-articles-page.js +++ b/client/src/app/main/dashboard/dashboard-list-articles/dashboard-list-articles-page.js @@ -76,7 +76,8 @@ class DashboardListArticlesPage extends React.Component { getClass() { let classes = { 'dashboard-list-articles-page': true, - 'dashboard-list-articles-page_wrapped': (this.props.location.pathname == '/articles') + 'dashboard-list-articles-page_wrapped': (this.props.location.pathname == '/articles'), + 'col-md-10 col-md-offset-1': (!this.props.config['user-system-enabled']) }; return classNames(classes); @@ -124,6 +125,7 @@ class DashboardListArticlesPage extends React.Component { export default connect((store) => { return { + config: store.config, topics: store.articles.topics, loading: store.articles.loading }; diff --git a/client/src/app/main/dashboard/dashboard-menu.js b/client/src/app/main/dashboard/dashboard-menu.js index a44c470f..27f13466 100644 --- a/client/src/app/main/dashboard/dashboard-menu.js +++ b/client/src/app/main/dashboard/dashboard-menu.js @@ -24,7 +24,7 @@ class DashboardMenu extends React.Component { getProps() { return { - header: 'Dashboard', + header: i18n('DASHBOARD'), items: this.getMenuItems(), selectedIndex: this.getSelectedIndex(), onItemClick: this.onItemClick.bind(this), diff --git a/client/src/app/main/main-check-ticket-page.js b/client/src/app/main/main-check-ticket-page.js index e0a1df21..3e7c4d5c 100644 --- a/client/src/app/main/main-check-ticket-page.js +++ b/client/src/app/main/main-check-ticket-page.js @@ -1,5 +1,7 @@ import React from 'react'; -import { browserHistory } from 'react-router'; +import classNames from 'classnames'; +import {browserHistory} from 'react-router'; +import {connect} from 'react-redux'; import i18n from 'lib-app/i18n'; import API from 'lib-app/api-call'; @@ -25,7 +27,7 @@ class MainCheckTicketPage extends React.Component { render() { return ( -
+
@@ -47,6 +49,15 @@ class MainCheckTicketPage extends React.Component { ); } + getClass() { + let classes = { + 'main-check-ticket-page': true, + 'col-md-10 col-md-offset-1': (!this.props.config['user-system-enabled']) + }; + + return classNames(classes); + } + getFormProps() { return { className: 'main-check-ticket-page__form', @@ -92,4 +103,8 @@ class MainCheckTicketPage extends React.Component { } } -export default MainCheckTicketPage; \ No newline at end of file +export default connect((store) => { + return { + config: store.config + }; +})(MainCheckTicketPage); diff --git a/client/src/app/main/main-home/main-home-page-login-widget.scss b/client/src/app/main/main-home/main-home-page-login-widget.scss index 117fc2e2..f9de5447 100644 --- a/client/src/app/main/main-home/main-home-page-login-widget.scss +++ b/client/src/app/main/main-home/main-home-page-login-widget.scss @@ -17,8 +17,4 @@ &__message { margin-top: 18px; } - - &_password { - width: 324px; - } } \ No newline at end of file diff --git a/client/src/app/main/main-home/main-home-page.js b/client/src/app/main/main-home/main-home-page.js index 92840276..5bc6d323 100644 --- a/client/src/app/main/main-home/main-home-page.js +++ b/client/src/app/main/main-home/main-home-page.js @@ -1,5 +1,6 @@ import React from 'react'; -import {connect} from 'react-redux' +import {connect} from 'react-redux'; +import classNames from 'classnames'; import i18n from 'lib-app/i18n'; @@ -14,7 +15,7 @@ class MainHomePage extends React.Component {
{this.renderMessage()} {(this.props.config['user-system-enabled']) ? this.renderLoginWidget() : null} -
+
@@ -34,7 +35,7 @@ class MainHomePage extends React.Component { renderLoginWidget() { return ( -
+
); @@ -55,6 +56,16 @@ class MainHomePage extends React.Component { ); } + + getPortalClass() { + let classes = { + 'main-home-page__portal-wrapper': true, + 'col-md-8': (this.props.config['user-system-enabled'] && this.props.config['layout'] === 'boxed'), + 'col-md-10 col-md-offset-1' : (!this.props.config['user-system-enabled']) + }; + + return classNames(classes); + } } export default connect((store) => { diff --git a/client/src/app/main/main-layout-header.js b/client/src/app/main/main-layout-header.js index 5f575136..014afa5e 100644 --- a/client/src/app/main/main-layout-header.js +++ b/client/src/app/main/main-layout-header.js @@ -1,5 +1,5 @@ import React from 'react'; -import { connect } from 'react-redux' +import {connect} from 'react-redux'; import i18n from 'lib-app/i18n'; import ConfigActions from 'actions/config-actions'; @@ -32,7 +32,7 @@ class MainLayoutHeader extends React.Component { result = (
- {(this.props.config['registration'] === true) ? : null} + {(this.props.config['registration']) ? : null}
); } 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 e5baab65..293bdae7 100644 --- a/client/src/app/main/main-signup/main-signup-page.js +++ b/client/src/app/main/main-signup/main-signup-page.js @@ -4,7 +4,6 @@ import _ from 'lodash'; import i18n from 'lib-app/i18n'; import API from 'lib-app/api-call'; -import SessionStore from 'lib-app/session-store'; import Captcha from 'app/main/captcha'; import SubmitButton from 'core-components/submit-button'; @@ -12,7 +11,7 @@ import Message from 'core-components/message'; import Form from 'core-components/form'; import FormField from 'core-components/form-field'; import Widget from 'core-components/widget'; - +import Header from 'core-components/header'; class MainSignUpPageWidget extends React.Component { @@ -28,7 +27,8 @@ class MainSignUpPageWidget extends React.Component { render() { return (
- + +
diff --git a/client/src/app/main/main-signup/main-signup-page.scss b/client/src/app/main/main-signup/main-signup-page.scss index b3e0824d..866d62f3 100644 --- a/client/src/app/main/main-signup/main-signup-page.scss +++ b/client/src/app/main/main-signup/main-signup-page.scss @@ -15,7 +15,7 @@ } &__captcha { - margin: 10px 84px 20px; + margin: 10px auto 20px; height: 78px; width: 304px; } diff --git a/client/src/core-components/widget.scss b/client/src/core-components/widget.scss index a7a14c95..0b6cba69 100644 --- a/client/src/core-components/widget.scss +++ b/client/src/core-components/widget.scss @@ -5,7 +5,6 @@ border-radius: 4px; text-align: center; padding: 20px; - min-width: 324px; min-height: 361px; &--title { @@ -14,4 +13,16 @@ font-size: 17px; margin-bottom: 20px; } +} + +@media screen and (min-width: 379px) { + .widget { + min-width: 324px; + } +} +@media screen and (max-width: 409px) { + .widget { + min-width: 313px; + margin-left: -11px; + } } \ No newline at end of file diff --git a/client/src/data/fixtures/system-fixtures.js b/client/src/data/fixtures/system-fixtures.js index f2745afc..b71b7219 100644 --- a/client/src/data/fixtures/system-fixtures.js +++ b/client/src/data/fixtures/system-fixtures.js @@ -11,8 +11,8 @@ module.exports = [ 'reCaptchaKey': '6LfM5CYTAAAAAGLz6ctpf-hchX2_l0Ge-Bn-n8wS', 'reCaptchaPrivate': 'LALA', 'url': 'http://www.opensupports.com/support', - 'title': 'OpenSupports Support Center', - 'layout': 'full-width', + 'title': 'Support Center', + 'layout': 'boxed', 'time-zone': 3, 'no-reply-email': 'shitr@post.com', 'smtp-host': 'localhost', @@ -38,8 +38,8 @@ module.exports = [ status: 'success', data: { 'language': 'en', - 'title': '', - 'layout': 'full-width', + 'title': 'Support Center', + 'layout': 'boxed', 'reCaptchaKey': '6LfM5CYTAAAAAGLz6ctpf-hchX2_l0Ge-Bn-n8wS', 'maintenance-mode': false, 'departments': [ diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js index 5f44005d..739c770f 100644 --- a/client/src/data/languages/en.js +++ b/client/src/data/languages/en.js @@ -12,6 +12,7 @@ export default { 'FORGOT_PASSWORD': 'Forgot your password?', 'RECOVER_PASSWORD': 'Recover Password', 'RECOVER_SENT': 'An email with recover instructions has been sent.', + 'OLD_PASSWORD': 'Old password', 'NEW_PASSWORD': 'New password', 'REPEAT_NEW_PASSWORD': 'Repeat new password', 'BACK_LOGIN_FORM': 'Back to login form', @@ -82,6 +83,10 @@ export default { 'UN_BAN': 'Disable ban', 'BAN_NEW_EMAIL': 'Ban new email', 'BAN_EMAIL': 'Ban email', + 'EDIT_EMAIL': 'Edit email', + 'EDIT_PASSWORD': 'Edit password', + 'CHANGE_EMAIL': 'Change email', + 'CHANGE_PASSWORD': 'Change password', 'NAME': 'Name', 'SIGNUP_DATE': 'Sign up date', 'SEARCH_USERS': 'Search users...', @@ -243,6 +248,8 @@ export default { 'REGISTRATION_DISABLED': 'Registration has been disabled', 'REGISTRATION_ENABLED': 'Registration has been enabled', 'ADD_API_KEY_DESCRIPTION': 'Insert the name and a registration api key be generated.', + 'SIGN_UP_VIEW_DESCRIPTION': 'Here you can create an account for our support center. It is required for send tickets and see documentation.', + 'EDIT_PROFILE_VIEW_DESCRIPTION': 'Here you can edit your user by changing your email or your password.', //ERRORS 'EMAIL_OR_PASSWORD': 'Email or password invalid', diff --git a/client/src/lib-app/session-store.js b/client/src/lib-app/session-store.js index 6eaa5783..0deb8c60 100644 --- a/client/src/lib-app/session-store.js +++ b/client/src/lib-app/session-store.js @@ -58,6 +58,10 @@ class SessionStore { this.setItem('departments', JSON.stringify(configs.departments)); this.setItem('allowedLanguages', JSON.stringify(configs.allowedLanguages)); this.setItem('supportedLanguages', JSON.stringify(configs.supportedLanguages)); + this.setItem('layout', configs.layout); + this.setItem('title', configs.title); + this.setItem('registration', configs.registration); + this.setItem('user-system-enabled', configs['user-system-enabled']); } getConfigs() { @@ -66,7 +70,11 @@ class SessionStore { reCaptchaKey: this.getItem('reCaptchaKey'), departments: this.getDepartments(), allowedLanguages: JSON.parse(this.getItem('allowedLanguages')), - supportedLanguages: JSON.parse(this.getItem('supportedLanguages')) + supportedLanguages: JSON.parse(this.getItem('supportedLanguages')), + layout: this.getItem('layout'), + registration: this.getItem('registration'), + title: this.getItem('title'), + ['user-system-enabled']: this.getItem('user-system-enabled') }; } diff --git a/client/src/scss/_vars.scss b/client/src/scss/_vars.scss index 61188e1a..8e9f97f3 100644 --- a/client/src/scss/_vars.scss +++ b/client/src/scss/_vars.scss @@ -43,7 +43,7 @@ $font-size--xl: 32px; } &::-webkit-scrollbar-track { - backgroundr: transparent; + background: transparent; } &:hover { From 222dbdea04fccd0664ad4fb0a00a7622e6344e38 Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 15 Feb 2017 03:08:48 -0300 Subject: [PATCH 81/84] Ivan - Fix download get --- tests/libs.rb | 11 ++++++++--- tests/system/file-upload-download.rb | 6 +++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/tests/libs.rb b/tests/libs.rb index fef8e646..c90542ea 100644 --- a/tests/libs.rb +++ b/tests/libs.rb @@ -1,10 +1,15 @@ $agent = Mechanize.new -def plainRequest(path, data = {}) +def plainRequest(path, data = {}, method = 'POST') uri = 'http://localhost:8080' + path - response = $agent.post(uri, data) - return response + if method == 'POST' + @response = $agent.post(uri, data) + else + @response = $agent.get(uri, data) + end + + return @response end def request(path, data = {}) diff --git a/tests/system/file-upload-download.rb b/tests/system/file-upload-download.rb index 44bc3c37..87738188 100644 --- a/tests/system/file-upload-download.rb +++ b/tests/system/file-upload-download.rb @@ -32,7 +32,7 @@ describe 'File Upload and Download' do 'csrf_userid' => $csrf_userid, 'csrf_token' => $csrf_token, 'file' => ticket['file'] - }) + }, 'GET') (result.body).should.equal(file.read) end @@ -47,7 +47,7 @@ describe 'File Upload and Download' do 'csrf_userid' => $csrf_userid, 'csrf_token' => $csrf_token, 'file' => ticket['file'] - }) + }, 'GET') (result.body).should.equal('') end @@ -66,7 +66,7 @@ describe 'File Upload and Download' do 'csrf_userid' => $csrf_userid, 'csrf_token' => $csrf_token, 'file' => ticket['file'] - }) + }, 'GET') (result.body).should.equal(file.read) end From f9ad440bf28b59a9ec8202dea0f2bdaf484e1d1e Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 15 Feb 2017 16:14:27 -0300 Subject: [PATCH 82/84] Ivan - Fix download get --- server/controllers/user/login.php | 2 +- server/libs/Controller.php | 8 +++++++- tests/init.rb | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/server/controllers/user/login.php b/server/controllers/user/login.php index 1465210b..952578de 100644 --- a/server/controllers/user/login.php +++ b/server/controllers/user/login.php @@ -41,7 +41,7 @@ class LoginController extends Controller { Response::respondSuccess($this->getUserData()); } else { - Response::respondError(Controller::request('email')); + Response::respondError(ERRORS::INVALID_CREDENTIALS); } } diff --git a/server/libs/Controller.php b/server/libs/Controller.php index 88e6b997..95ca49ed 100644 --- a/server/libs/Controller.php +++ b/server/libs/Controller.php @@ -33,7 +33,13 @@ abstract class Controller { self::$dataRequester = function ($key) { $app = self::getAppInstance(); - return $app->request()->post($key); + $value = $app->request()->post($key); + + if(!$value) { + $value = $app->request()->get($key); + } + + return $value; }; } diff --git a/tests/init.rb b/tests/init.rb index 91e50a42..038e23b6 100644 --- a/tests/init.rb +++ b/tests/init.rb @@ -53,10 +53,10 @@ require './system/edit-mail-template.rb' require './system/recover-mail-template.rb' require './system/disable-registration.rb' require './system/enable-registration.rb' -require './system/get-stats.rb' require './system/add-api-key.rb' require './system/delete-api-key.rb' require './system/get-all-keys.rb' require './system/file-upload-download.rb' require './system/csv-import.rb' require './system/disable-user-system.rb' +require './system/get-stats.rb' From d4263d4b94f7c346f55dc6048f865b14d4079785 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 18 Feb 2017 15:28:23 -0300 Subject: [PATCH 83/84] Ivan - Fix uploading of files --- client/src/app-components/ticket-event.js | 19 +------- client/src/app-components/ticket-viewer.js | 1 + client/src/app/admin/admin-login-page.js | 3 +- .../admin/panel/admin-panel-staff-widget.js | 3 +- .../admin/panel/admin-panel-staff-widget.scss | 1 + .../src/app/admin/panel/staff/staff-editor.js | 3 +- .../app/admin/panel/staff/staff-editor.scss | 10 ++--- .../create-ticket-form.js | 1 + client/src/lib-app/api-call.js | 44 +++++++++++++++---- client/src/lib-core/APIUtils.js | 26 +++++++---- server/controllers/staff/edit.php | 3 +- server/controllers/system/download.php | 31 ++++++++----- server/controllers/system/init-settings.php | 2 +- server/libs/Controller.php | 10 ++--- server/models/Response.php | 10 +++-- server/models/Session.php | 4 ++ 16 files changed, 106 insertions(+), 65 deletions(-) diff --git a/client/src/app-components/ticket-event.js b/client/src/app-components/ticket-event.js index 719f417d..c088932f 100644 --- a/client/src/app-components/ticket-event.js +++ b/client/src/app-components/ticket-event.js @@ -223,26 +223,9 @@ class TicketEvent extends React.Component { const fileName = filePath.replace(/^.*[\\\/]/, ''); return ( - {fileName} + {fileName} ) } - - onFileClick(filePath) { - API.call({ - path: '/system/download', - plain: true, - data: { - file: filePath - } - }).then((result) => { - let contentType = 'application/octet-stream'; - let link = document.createElement('a'); - let blob = new Blob([result], {'type': contentType}); - link.href = window.URL.createObjectURL(blob); - link.download = filePath; - link.click(); - }); - } } export default TicketEvent; diff --git a/client/src/app-components/ticket-viewer.js b/client/src/app-components/ticket-viewer.js index c00b875a..ff21c462 100644 --- a/client/src/app-components/ticket-viewer.js +++ b/client/src/app-components/ticket-viewer.js @@ -323,6 +323,7 @@ class TicketViewer extends React.Component { API.call({ path: '/ticket/comment', + dataAsForm: true, data: _.extend({ ticketNumber: this.props.ticket.ticketNumber }, formState) diff --git a/client/src/app/admin/admin-login-page.js b/client/src/app/admin/admin-login-page.js index 9d7f2770..54d38d5d 100644 --- a/client/src/app/admin/admin-login-page.js +++ b/client/src/app/admin/admin-login-page.js @@ -3,6 +3,7 @@ import _ from 'lodash'; import {connect} from 'react-redux'; import i18n from 'lib-app/i18n'; +import API from 'lib-app/api-call'; import SessionActions from 'actions/session-actions'; import Form from 'core-components/form'; @@ -16,7 +17,7 @@ class AdminLoginPage extends React.Component { return (
-
OpenSupports Admin Panel
+
OpenSupports Admin Panel
diff --git a/client/src/app/admin/panel/admin-panel-staff-widget.js b/client/src/app/admin/panel/admin-panel-staff-widget.js index 913f151d..f44a7dc4 100644 --- a/client/src/app/admin/panel/admin-panel-staff-widget.js +++ b/client/src/app/admin/panel/admin-panel-staff-widget.js @@ -3,6 +3,7 @@ import classNames from 'classnames'; import {connect} from 'react-redux'; import i18n from 'lib-app/i18n'; +import API from 'lib-app/api-call'; import Button from 'core-components/button'; import SessionActions from 'actions/session-actions'; @@ -24,7 +25,7 @@ class AdminPanelStaffWidget extends React.Component {
- +
); diff --git a/client/src/app/admin/panel/admin-panel-staff-widget.scss b/client/src/app/admin/panel/admin-panel-staff-widget.scss index 1de336ad..b75184d3 100644 --- a/client/src/app/admin/panel/admin-panel-staff-widget.scss +++ b/client/src/app/admin/panel/admin-panel-staff-widget.scss @@ -8,6 +8,7 @@ text-align: center; &__profile-pic-wrapper { + background-color: white; position: absolute; top: 8px; border: 4px solid $grey; diff --git a/client/src/app/admin/panel/staff/staff-editor.js b/client/src/app/admin/panel/staff/staff-editor.js index a173bc1f..ea4e056d 100644 --- a/client/src/app/admin/panel/staff/staff-editor.js +++ b/client/src/app/admin/panel/staff/staff-editor.js @@ -73,7 +73,7 @@ class StaffEditor extends React.Component {
@@ -306,6 +306,7 @@ class StaffEditor extends React.Component { API.call({ path: '/staff/edit', + dataAsForm: true, data: { staffId: this.props.staffId, file: event.target.files[0] diff --git a/client/src/app/admin/panel/staff/staff-editor.scss b/client/src/app/admin/panel/staff/staff-editor.scss index 4b6f8684..6a48b2c3 100644 --- a/client/src/app/admin/panel/staff/staff-editor.scss +++ b/client/src/app/admin/panel/staff/staff-editor.scss @@ -2,6 +2,10 @@ .staff-editor { + &__image-uploader { + opacity: 0; + } + &__card { background-color: $primary-red; position: relative; @@ -11,10 +15,6 @@ border: 2px solid $grey; margin-bottom: 20px; - &__image-uploader { - opacity: 0; - } - &-pic { height: 100%; position: absolute; @@ -45,7 +45,7 @@ &-wrapper { transition: opacity 0.2s ease; - background-color: $grey; + background-color: white; position: absolute; top: 20px; border: 4px solid $grey; 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 1ce083b3..0e927776 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 @@ -119,6 +119,7 @@ class CreateTicketForm extends React.Component { API.call({ path: '/ticket/create', + dataAsForm: true, data: _.extend({}, formState, { captcha: captcha && captcha.getValue(), departmentId: SessionStore.getDepartments()[formState.departmentIndex].id diff --git a/client/src/lib-app/api-call.js b/client/src/lib-app/api-call.js index 032c5bc0..2979e9b9 100644 --- a/client/src/lib-app/api-call.js +++ b/client/src/lib-app/api-call.js @@ -2,19 +2,35 @@ const _ = require('lodash'); const APIUtils = require('lib-core/APIUtils'); const SessionStore = require('lib-app/session-store'); -const root = 'http://localhost:3000/api'; +const url = 'http://localhost:3000'; +const apiUrl = 'http://localhost:3000/api'; -function processData (data) { - return _.extend({ - csrf_token: SessionStore.getSessionData().token, - csrf_userid: SessionStore.getSessionData().userId - }, data); +function processData (data, dataAsForm = false) { + let newData; + + if(dataAsForm) { + newData = new FormData(); + + _.each(data, (value, key) => { + newData.append(key, value); + }); + + newData.append('csrf_token', SessionStore.getSessionData().token); + newData.append('csrf_userid', SessionStore.getSessionData().userId); + } else { + newData = _.extend({ + csrf_token: SessionStore.getSessionData().token, + csrf_userid: SessionStore.getSessionData().userId + }, data) + } + + return newData; } module.exports = { - call: function ({path, data, plain}) { + call: function ({path, data, plain, dataAsForm}) { return new Promise(function (resolve, reject) { - APIUtils.post(root + path, processData(data)) + APIUtils.post(apiUrl + path, processData(data, dataAsForm), dataAsForm) .then(function (result) { console.log(result); @@ -33,5 +49,17 @@ module.exports = { }); }); }); + }, + + getFileLink(filePath) { + return apiUrl + '/system/download?file=' + filePath; + }, + + getAPIUrl() { + return apiUrl; + }, + + getURL() { + return url; } }; \ No newline at end of file diff --git a/client/src/lib-core/APIUtils.js b/client/src/lib-core/APIUtils.js index 65b52ae6..e655deb4 100644 --- a/client/src/lib-core/APIUtils.js +++ b/client/src/lib-core/APIUtils.js @@ -3,15 +3,25 @@ const $ = require('jquery'); const APIUtils = { - getPromise(path, method, data) { + getPromise(path, method, data, dataAsForm) { return (resolve, reject) => { - $.ajax({ + let options = { url: path, method: method, - data: data, - processData: false, - contentType: false - }) + data: data + }; + + if(dataAsForm) { + options = { + url: path, + type: method, + data: data, + processData: false, + contentType: false + }; + } + + $.ajax(options) .done(resolve) .fail((jqXHR, textStatus) => { reject(textStatus); @@ -23,8 +33,8 @@ const APIUtils = { return new Promise(this.getPromise(path, 'GET')); }, - post(path, data) { - return new Promise(this.getPromise(path, 'POST', data)); + post(path, data, dataAsForm) { + return new Promise(this.getPromise(path, 'POST', data, dataAsForm)); }, patch(path, data) { diff --git a/server/controllers/staff/edit.php b/server/controllers/staff/edit.php index 05c0b1af..6bc3f7e1 100644 --- a/server/controllers/staff/edit.php +++ b/server/controllers/staff/edit.php @@ -57,8 +57,7 @@ class EditStaffController extends Controller { $this->staffInstance->sharedDepartmentList = $this->getDepartmentList(); } - if(Controller::request('file')) { - $fileUploader = $this->uploadFile(); + if($fileUploader = $this->uploadFile()) { $this->staffInstance->profilePic = ($fileUploader instanceof FileUploader) ? $fileUploader->getFileName() : null; } diff --git a/server/controllers/system/download.php b/server/controllers/system/download.php index b0b8e639..756fd56e 100644 --- a/server/controllers/system/download.php +++ b/server/controllers/system/download.php @@ -8,7 +8,7 @@ class DownloadController extends Controller { public function validations() { return [ - 'permission' => 'user', + 'permission' => 'any', 'requestData' => [ 'file' => [ 'validation' => DataValidator::alnum('_.-')->noWhitespace(), @@ -20,23 +20,32 @@ class DownloadController extends Controller { public function handler() { $fileName = Controller::request('file'); + $staffUser = Staff::getDataStore($fileName, 'profilePic'); - $loggedUser = Controller::getLoggedUser(); - $ticket = Ticket::getTicket($fileName, 'file'); + if($staffUser->isNull()) { + $loggedUser = Controller::getLoggedUser(); - if($ticket->isNull() || ($this->isNotAuthor($ticket, $loggedUser) && $this->isNotOwner($ticket, $loggedUser))) { - $ticketEvent = Ticketevent::getDataStore($fileName, 'file'); - - if($ticketEvent->isNull()) { + if($loggedUser->isNull()) { print ''; return; } - $ticket = $ticketEvent->ticket; + $ticket = Ticket::getTicket($fileName, 'file'); - if($this->isNotAuthor($ticket, $loggedUser) && $this->isNotOwner($ticket, $loggedUser)) { - print ''; - return; + if($ticket->isNull() || ($this->isNotAuthor($ticket, $loggedUser) && $this->isNotOwner($ticket, $loggedUser))) { + $ticketEvent = Ticketevent::getDataStore($fileName, 'file'); + + if($ticketEvent->isNull()) { + print ''; + return; + } + + $ticket = $ticketEvent->ticket; + + if($this->isNotAuthor($ticket, $loggedUser) && $this->isNotOwner($ticket, $loggedUser)) { + print ''; + return; + } } } diff --git a/server/controllers/system/init-settings.php b/server/controllers/system/init-settings.php index a3bfdf65..8ac8314b 100644 --- a/server/controllers/system/init-settings.php +++ b/server/controllers/system/init-settings.php @@ -116,7 +116,7 @@ class InitSettingsController extends Controller { 'name' => 'Emilia Clarke', 'email' => 'staff@opensupports.com', 'password' => Hashing::hashPassword('staff'), - 'profilePic' => 'http://www.opensupports.com/profilepic.jpg', + 'profilePic' => '', 'level' => 3, 'sharedDepartmentList' => Department::getAll(), 'sharedTicketList' => [] diff --git a/server/libs/Controller.php b/server/libs/Controller.php index 95ca49ed..3fe2db45 100644 --- a/server/libs/Controller.php +++ b/server/libs/Controller.php @@ -33,10 +33,10 @@ abstract class Controller { self::$dataRequester = function ($key) { $app = self::getAppInstance(); - $value = $app->request()->post($key); - - if(!$value) { + if (Controller::getAppInstance()->request()->isGet()) { $value = $app->request()->get($key); + } else { + $value = $app->request()->post($key); } return $value; @@ -55,9 +55,9 @@ abstract class Controller { $session = Session::getInstance(); if ($session->isStaffLogged()) { - return Staff::getUser((int)self::request('csrf_userid')); + return Staff::getUser($session->getUserId()); } else { - return User::getUser((int)self::request('csrf_userid')); + return User::getUser($session->getUserId()); } } diff --git a/server/models/Response.php b/server/models/Response.php index bd20c480..0220a225 100644 --- a/server/models/Response.php +++ b/server/models/Response.php @@ -9,8 +9,9 @@ class Response { ); $app = \Slim\Slim::getInstance(); - $app->response()->setBody(json_encode($response)); - $app->response()->finalize(); + $app->response->headers->set('Content-Type', 'application/json'); + $app->response->setBody(json_encode($response)); + $app->response->finalize(); } public static function respondSuccess($data = null) { @@ -20,7 +21,8 @@ class Response { ); $app = \Slim\Slim::getInstance(); - $app->response()->setBody(json_encode($response)); - $app->response()->finalize(); + $app->response->headers->set('Content-Type', 'application/json'); + $app->response->setBody(json_encode($response)); + $app->response->finalize(); } } diff --git a/server/models/Session.php b/server/models/Session.php index eceb9c13..bd5e987e 100644 --- a/server/models/Session.php +++ b/server/models/Session.php @@ -39,6 +39,10 @@ class Session { return $this->getStoredData('ticketNumber'); } + public function getUserId() { + return $this->getStoredData('userId'); + } + public function getToken() { return $this->getStoredData('token'); } From 8d0da0e4517cd811d02e3226f6f18049573884a1 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 18 Feb 2017 15:55:09 -0300 Subject: [PATCH 84/84] Ivan - Fix ruby tests --- tests/staff/add.rb | 6 +++--- tests/staff/edit.rb | 2 +- tests/staff/get-all.rb | 4 ++-- tests/system/file-upload-download.rb | 22 ++++++++++++++++++++++ 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/tests/staff/add.rb b/tests/staff/add.rb index 1f557034..f9bafedc 100644 --- a/tests/staff/add.rb +++ b/tests/staff/add.rb @@ -10,7 +10,7 @@ describe'/staff/add' do email: 'tyrion@opensupports.com', password: 'testpassword', level: 2, - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', departments: '[1]' }) @@ -20,7 +20,7 @@ describe'/staff/add' do (row['name']).should.equal('Tyrion Lannister') (row['email']).should.equal('tyrion@opensupports.com') - (row['profile_pic']).should.equal('http://www.opensupports.com/profilepic.jpg') + (row['profile_pic']).should.equal('') (row['level']).should.equal('2') row = $database.getRow('department', 1, 'id') @@ -38,7 +38,7 @@ describe'/staff/add' do email: 'tyrion@opensupports.com', password: 'testpassword', level: 2, - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', departments: '[1]' }) diff --git a/tests/staff/edit.rb b/tests/staff/edit.rb index 4181fb80..a42de635 100644 --- a/tests/staff/edit.rb +++ b/tests/staff/edit.rb @@ -39,7 +39,7 @@ describe'/staff/edit' do password: 'starkpassword', email: 'arya@opensupports.com', level: 2, - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', departments: '[1]' }) request('/user/logout') diff --git a/tests/staff/get-all.rb b/tests/staff/get-all.rb index ba5544f5..ca257ced 100644 --- a/tests/staff/get-all.rb +++ b/tests/staff/get-all.rb @@ -12,7 +12,7 @@ describe'/staff/get-all' do (result['data'][0]['name']).should.equal('Emilia Clarke') (result['data'][0]['email']).should.equal('staff@opensupports.com') - (result['data'][0]['profilePic']).should.equal('http://www.opensupports.com/profilepic.jpg') + (result['data'][0]['profilePic']).should.equal('') (result['data'][0]['level']).should.equal('3') (result['data'][0]['departments'][0]['id']).should.equal('1') (result['data'][0]['departments'][0]['name']).should.equal('Tech Support') @@ -25,7 +25,7 @@ describe'/staff/get-all' do (result['data'][1]['name']).should.equal('Arya Stark') (result['data'][1]['email']).should.equal('newwstaff@opensupports.com') - (result['data'][1]['profilePic']).should.equal('http://www.opensupports.com/profilepic.jpg') + (result['data'][1]['profilePic']).should.equal('') (result['data'][1]['level']).should.equal('2') (result['data'][1]['departments'][0]['id']).should.equal('1') (result['data'][1]['departments'][0]['name']).should.equal('Tech Support') diff --git a/tests/system/file-upload-download.rb b/tests/system/file-upload-download.rb index 87738188..9319422c 100644 --- a/tests/system/file-upload-download.rb +++ b/tests/system/file-upload-download.rb @@ -71,4 +71,26 @@ describe 'File Upload and Download' do (result.body).should.equal(file.read) end + it 'should upload profile picture' do + file = File.new('../server/files/profile.jpg', 'w+') + file.puts('file content') + file.close + + request('/staff/edit', { + 'csrf_userid' => $csrf_userid, + 'csrf_token' => $csrf_token, + 'staffId' => $csrf_userid, + 'file' => File.open( "../server/files/profile.jpg") + }) + + user = $database.getRow('staff', $csrf_userid) + + result = plainRequest('/system/download', { + 'csrf_userid' => $csrf_userid, + 'csrf_token' => $csrf_token, + 'file' => user['profile_pic'] + }, 'GET') + + (result.body).should.include('file content') + end end