Merge branch 'master' into os-147-151-file-architecture-and-backup

Conflicts:
	server/controllers/system.php
	server/controllers/system/init-settings.php
	server/data/ERRORS.php
This commit is contained in:
Ivan Diaz 2017-01-13 14:42:04 -03:00
commit 012103c2ad
20 changed files with 581 additions and 6 deletions

View File

@ -0,0 +1,63 @@
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
})),
onChange: React.PropTypes.func
};
state = {
selected: []
};
render() {
return (
<div className="toggle-list">
{this.props.items.map(this.renderItem.bind(this))}
</div>
);
}
renderItem(obj, index) {
return (
<div className={this.getItemClass(index)} onClick={this.selectItem.bind(this, index)} key={index}>
{obj.content}
</div>
);
}
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 newSelected = _.clone(this.state.selected);
_.includes(this.state.selected, index) ? _.remove(newSelected, _index => _index == index) : newSelected.push(index);
this.setState({
selected: newSelected
});
if (this.props.onChange) {
this.props.onChange({
target: {
value: newSelected
}
});
}
}
}
export default ToggleList;

View File

@ -0,0 +1,21 @@
@import "../scss/vars";
.toggle-list {
&__item {
border: 1px $light-grey solid;
border-left: none;
width: 180px;
height: 120px;
display: inline-block;
transition: background-color 0.4s ease;
}
&__selected {
background-color: $light-grey;
}
&__first-item {
border: 1px $light-grey solid;
}
}

View File

@ -9,6 +9,9 @@ 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';
require_once 'system/disable-registration.php';
require_once 'system/enable-registration.php';
require_once 'system/backup-database.php';
require_once 'system/download.php';
@ -25,6 +28,9 @@ $systemControllerGroup->addController(new GetLogsController);
$systemControllerGroup->addController(new GetMailTemplatesController);
$systemControllerGroup->addController(new EditMailTemplateController);
$systemControllerGroup->addController(new RecoverMailTemplateController);
$systemControllerGroup->addController(new DisableRegistrationController);
$systemControllerGroup->addController(new EnableRegistrationController);
$systemControllerGroup->addController(new GetStatsController);
$systemControllerGroup->addController(new BackupDatabaseController);
$systemControllerGroup->addController(new DownloadController);

View File

@ -0,0 +1,28 @@
<?php
class DisableRegistrationController extends Controller {
const PATH = '/disable-registration';
public function validations() {
return [
'permission' => 'staff_3',
'requestData' => []
];
}
public function handler() {
$password = Controller::request('password');
if(!Hashing::verifyPassword($password, Controller::getLoggedUser()->password)) {
Response::respondError(ERRORS::INVALID_PASSWORD);
return;
}
$registrationRow = Setting::getSetting('registration');
$registrationRow->value = false;
$registrationRow->store();
Response::respondSuccess();
}
}

View File

@ -1,5 +1,4 @@
<?php
use Respect\Validation\Validator as DataValidator;
class EditSettingsController extends Controller {
const PATH = '/edit-settings';

View File

@ -0,0 +1,29 @@
<?php
use Respect\Validation\Validator as DataValidator;
class EnableRegistrationController extends Controller {
const PATH = '/enable-registration';
public function validations() {
return [
'permission' => 'staff_3',
'requestData' => []
];
}
public function handler() {
$password = Controller::request('password');
if(!Hashing::verifyPassword($password,Controller::getLoggedUser()->password)) {
Response::respondError(ERRORS::INVALID_PASSWORD);
return;
}
$registrationRow = Setting::getSetting('registration');
$registrationRow->value = true;
$registrationRow->store();
Response::respondSuccess();
}
}

View File

@ -28,6 +28,7 @@ class GetSettingsController extends Controller {
'smtp-port' => Setting::getSetting('smtp-port')->getValue(),
'smtp-host' => Setting::getSetting('smtp-host')->getValue(),
'smtp-user' => Setting::getSetting('smtp-user')->getValue(),
'registration' => Setting::getSetting('registration')->getValue(),
'departments' => Department::getDepartmentNames(),
'supportedLanguages' => Language::getSupportedLanguages(),
'allowedLanguages' => Language::getAllowedLanguages()
@ -42,6 +43,7 @@ class GetSettingsController extends Controller {
'allow-attachments' => Setting::getSetting('allow-attachments')->getValue(),
'max-size' => Setting::getSetting('max-size')->getValue(),
'title' => Setting::getSetting('title')->getValue(),
'registration' => Setting::getSetting('registration')->getValue(),
'departments' => Department::getDepartmentNames(),
'supportedLanguages' => Language::getSupportedLanguages(),
'allowedLanguages' => Language::getAllowedLanguages()

View File

@ -0,0 +1,141 @@
<?php
use Respect\Validation\Validator as DataValidator;
class GetStatsController extends Controller {
const PATH = '/get-stats';
public function validations() {
return [
'permission' => 'staff_1',
'requestData' => [
'period' => [
'validation' => DataValidator::in(['week', 'month', 'quarter', 'year']),
'error' => ERRORS::INVALID_PERIOD
]
]
];
}
public function handler() {
$this->generationNewStats();
$staffId = Controller::request('staffId');
if($staffId) {
if($staffId !== Controller::getLoggedUser()->id && !Controller::isStaffLogged(3)) {
Response::respondError(ERRORS::NO_PERMISSION);
return;
}
$this->getStaffStat();
} else {
$this->getGeneralStat();
}
}
public function generationNewStats() {
$lastStatDay = Setting::getSetting('last-stat-day');
$previousCurrentDate = floor(Date::getPreviousDate() / 10000);
$currentDate = floor(Date::getCurrentDate() / 10000);
if($lastStatDay->value !== $previousCurrentDate) {
$begin = new DateTime($lastStatDay->value);
$end = new DateTime($currentDate);
$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 = $currentDate;
$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;
}
return $daysToRetrieve;
}
}

View File

@ -41,6 +41,8 @@ class InitSettingsController extends Controller {
'max-size' => 1024,
'title' => 'Support Center',
'url' => 'http://www.opensupports.com/support',
'registration' => true,
'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),

View File

@ -51,6 +51,11 @@ class SignUpController extends Controller {
return;
}
if (!Setting::getSetting('registration')->value) {
Response::respondError(ERRORS::NO_PERMISSION);
return;
}
$userId = $this->createNewUserAndRetrieveId();
$this->sendRegistrationMail();

View File

@ -35,5 +35,6 @@ class ERRORS {
const INVALID_TEMPLATE = 'INVALID_TEMPLATE';
const INVALID_SUBJECT = 'INVALID_SUBJECT';
const INVALID_BODY = 'INVALID_BODY';
const INVALID_PERIOD = 'INVALID_PERIOD';
const INVALID_FILE = 'INVALID_FILE';
}

View File

@ -3,4 +3,8 @@ class Date {
public static function getCurrentDate() {
return date('YmdHi');
}
public static function getPreviousDate() {
return date('YmdHi', strtotime(' -1 day '));
}
}

View File

@ -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
];
}
}

View File

@ -18,13 +18,15 @@ class Staff extends DataStore {
'level',
'sharedDepartmentList',
'sharedTicketList',
'lastLogin'
'lastLogin',
'ownStatList'
];
}
public function getDefaultProps() {
return [
'level' => 1
'level' => 1,
'ownStatList' => new DataStoreList()
];
}

25
server/models/Stat.php Normal file
View File

@ -0,0 +1,25 @@
<?php
class Stat extends DataStore {
const TABLE = 'stat';
public static function getProps() {
return array (
'date',
'type',
'general',
'value'
);
}
public function getDefaultProps() {
return array();
}
public function toArray() {
return [
'date' => $this->date,
'type' => $this->type,
'general' => $this->general,
'value' => $this->value
];
}
}

View File

@ -5,6 +5,7 @@ require 'uri'
require 'mysql'
require 'json'
require 'mechanize'
require 'date'
require './libs.rb'
require './scripts.rb'
@ -51,3 +52,6 @@ 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/disable-registration.rb'
require './system/enable-registration.rb'
require './system/get-stats.rb'

View File

@ -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

View File

@ -0,0 +1,43 @@
describe'/system/disable-registration' do
request('/user/logout')
Scripts.login($staff[:email], $staff[:password], true)
it 'should not disable registration if password is not correct' do
result= request('/system/disable-registration', {
csrf_userid: $csrf_userid,
csrf_token: $csrf_token,
password: 'hello'
})
(result['status']).should.equal('fail')
row = $database.getRow('setting', 'registration', 'name')
(row['value']).should.equal('1')
end
it 'should disable registration' do
result= request('/system/disable-registration', {
csrf_userid: $csrf_userid,
csrf_token: $csrf_token,
password: $staff[:password]
})
(result['status']).should.equal('success')
row = $database.getRow('setting', 'registration', 'name')
(row['value']).should.equal('0')
end
it 'should not create user in database if registration is false' do
response = request('/user/signup', {
:name => 'ponzio',
:email => 'jc@ponziolandia.com',
:password => 'tequila'
})
(response['status']).should.equal('fail')
end
end

View File

@ -0,0 +1,33 @@
describe'/system/enable-registration' do
request('/user/logout')
Scripts.login($staff[:email], $staff[:password], true)
it 'should not enable registration if password is not correct' do
result= request('/system/enable-registration', {
csrf_userid: $csrf_userid,
csrf_token: $csrf_token,
password: 'hello'
})
(result['status']).should.equal('fail')
row = $database.getRow('setting', 'registration', 'name')
(row['value']).should.equal('0')
end
it 'should enable registration' do
result= request('/system/enable-registration', {
csrf_userid: $csrf_userid,
csrf_token: $csrf_token,
password: $staff[:password]
})
(result['status']).should.equal('success')
row = $database.getRow('setting', 'registration', 'name')
(row['value']).should.equal('1')
end
end

160
tests/system/get-stats.rb Normal file
View File

@ -0,0 +1,160 @@
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'
})
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
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, yesterday2, 'CREATE_TICKET', '3')
assertData(6, yesterday2, 'CLOSE', '10')
assertData(5, yesterday2, 'SIGNUP', '8')
assertData(4, yesterday2, 'COMMENT', '3')
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', {
csrf_userid: $csrf_userid,
csrf_token: $csrf_token,
period: 'week',
staffId: '1'
})
assertData(0, yesterday, 'CLOSE', '4')
assertData(1, yesterday, 'ASSIGN', '8')
assertData(2, yesterday2, 'CLOSE', '11')
assertData(3, yesterday2, 'ASSIGN', '3')
assertData(4, yesterday3, 'CLOSE', '9')
assertData(5, yesterday3, 'ASSIGN', '5')
assertData(6, yesterday4, 'CLOSE', '0')
assertData(7, yesterday4, 'ASSIGN', '0')
assertData(8, yesterday5, 'CLOSE', '0')
assertData(9, yesterday5, 'ASSIGN', '0')
assertData(10, yesterday6, 'CLOSE', '0')
assertData(11, yesterday6, 'ASSIGN', '0')
assertData(12, yesterday7, 'CLOSE', '0')
assertData(13, yesterday7, 'ASSIGN', '0')
assertData(14, yesterday8, 'CLOSE', '0')
assertData(15, yesterday8, 'ASSIGN', '0')
assertData(16, yesterday9, 'CLOSE', '0')
assertData(17, yesterday9, 'ASSIGN', '0')
assertData(18, yesterday10, 'CLOSE', '0')
assertData(19, yesterday10, 'ASSIGN', '0')
assertData(20, yesterday11, 'CLOSE', '0')
assertData(21, yesterday11, 'ASSIGN', '0')
end
end