fix multiple session handle ticket and update 4.7.0 update script (#812)

* fix multiple session handle ticket

* update 4.7.0 script
This commit is contained in:
Guillermo Giuliana 2020-06-18 07:08:20 -03:00 committed by GitHub
parent 91d2c203d3
commit 17e9dcf53b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 456 additions and 21 deletions

View File

@ -54,6 +54,14 @@ class CheckTicketController extends Controller {
}
public function handler() {
///
$session = Session::getInstance();
if($session->isTicketSession()) {
$session->closeSession();
}
///
if (Controller::isLoginMandatory()) {
throw new RequestException(ERRORS::NO_PERMISSION);
}

View File

@ -91,6 +91,14 @@ class CreateController extends Controller {
}
public function handler() {
///
$session = Session::getInstance();
if($session->isTicketSession()) {
$session->closeSession();
}
///
$this->title = Controller::request('title');
$this->content = Controller::request('content', true);
$this->departmentId = Controller::request('departmentId');

View File

@ -178,20 +178,6 @@ describe'system/mandatory-login' do
$sessionTicketNumber = result['data']['ticketNumber']
end
it 'should fail if the creator creates a ticket using a diferent email of the session' do
result = request('/ticket/create', {
email: 'nonuser2@os4.com',
language: 'en',
name: 'nonuser2',
title: 'ticket3 created without login',
content: 'THis is the third content created without login',
departmentId: 1
})
(result['status']).should.equal('fail')
(result['message']).should.equal('INVALID_EMAIL')
end
it 'should allow the creator get the ticket checked' do
result = request('/ticket/get', {
csrf_token: $sessionToken,

View File

@ -5,16 +5,56 @@ use RedBeanPHP\Facade as RedBean;
print 'Begin update v4.7.0...' . PHP_EOL;
// Update User table
print '[1/3] Updating user table...' . PHP_EOL;
print '[1/4] Updating user table...' . PHP_EOL;
if ($mysql->query("SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'user' AND COLUMN_NAME = 'not_registered' AND TABLE_SCHEMA = '$mysql_db'")->num_rows == 0) {
$mysql->query("ALTER TABLE user ADD not_registered tinyint(1)");
$mysql->query("UPDATE setting SET not_registered = false ");
} else {
print '-not_registered column already exists' . PHP_EOL;
}
if(!Setting::getSetting('user-system-enabled')->isNull() && !Setting::getSetting('user-system-enabled')->getValue() ) {
$ticketList = Ticket::getAll();
foreach($ticketList as $ticket) {
if($ticket->authorStaff) {
continue;
}
$userInstance = User::getDataStore($ticket->authorEmail, 'email');
if($userInstance->isNull()) {
$userInstance = new User();
$password = Hashing::generateRandomToken();
$userInstance->setProperties([
'name' => $ticket->authorName,
'signupDate' => Date::getCurrentDate(),
'tickets' => 0,
'email' => $ticket->authorEmail,
'password' => Hashing::hashPassword($password),
'not_registered' => 1,
'verificationToken' => null
]);
$userInstance->store();
}
$userInstance->tickets = $userInstance->tickets + 1;
$userInstance->sharedTicketList->add($ticket);
$userInstance->store();
}
} else {
print '-The tickets created already have owner Users' . PHP_EOL;
}
// Update mailtemplate table
print '[2/3] Updating mailtemplate table...' . PHP_EOL;
print '[2/4] Updating mailtemplate table...' . PHP_EOL;
if ($mysql->query("SELECT * FROM mailtemplate WHERE template='USER_SYSTEM_DISABLED' ")->num_rows != 0) {
$mysql->query("DELETE FROM mailtemplate WHERE template='USER_SYSTEM_DISABLED' ");
} else {
@ -27,8 +67,17 @@ if ($mysql->query("SELECT * FROM mailtemplate WHERE template='USER_SYSTEM_ENABLE
print '-user_system_enabled template is already deleted' . PHP_EOL;
}
// Update Department table
print '[3/4] Updating department table...' . PHP_EOL;
if ($mysql->query("SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'department' AND COLUMN_NAME = 'private' AND TABLE_SCHEMA = '$mysql_db'")->num_rows == 0) {
$mysql->query("ALTER TABLE department ADD private tinyint(1)");
$mysql->query("UPDATE department SET private = 0 ");
} else {
print 'private column already exists' . PHP_EOL;
}
// Update setting table
print '[3/3] Updating setting table...' . PHP_EOL;
print '[4/4] Updating setting table...' . PHP_EOL;
if ($mysql->query("SELECT * FROM setting WHERE name='mandatory-login' ")->num_rows == 0) {
$userSystemEnabled = $mysql->query("SELECT * FROM setting WHERE name='user-system-enabled'");
if($userSystemEnabled->fetch_array(MYSQLI_ASSOC)['value']){
@ -39,11 +88,11 @@ if ($mysql->query("SELECT * FROM setting WHERE name='mandatory-login' ")->num_ro
} else {
print '-Mandatory-login already exists' . PHP_EOL;
}
if ($mysql->query("SELECT * FROM setting WHERE name='default-department-id' ")->num_rows == 0) {
$publicDepartment = $mysql->query("SELECT * FROM department WHERE private= false");
$publicDepartment = $mysql->query("SELECT * FROM department WHERE private= 0 OR private IS NULL");
if($publicDepartment->num_rows != 0){
$query = "INSERT into setting VALUES(NULL, 'default-department-id', ". $publicDepartment->fetch_array(MYSQLI_ASSOC)['value'] . " )";
$query = "INSERT into setting VALUES(NULL, 'default-department-id', ". $publicDepartment->fetch_array(MYSQLI_BOTH)[0]['value'] . " )";
$mysql->query($query);
}else{
print '-Fail DEFAULT-DEPARTMENT-ID update. A public department is required';
@ -64,4 +113,5 @@ if ($mysql->query("SELECT * FROM setting WHERE name='user-system-enabled' ")->nu
print '-User-system-enabled is realready deleted' . PHP_EOL;
}
print 'Update Completed!' . PHP_EOL;
print 'Update Completed!' . PHP_EOL;

View File

@ -0,0 +1,14 @@
<?php
class Date {
public static function getCurrentDate() {
return date('YmdHi');
}
public static function getPreviousDate($days = 1) {
return date('YmdHi', strtotime(" -$days day "));
}
public static function getNextDate($days = 1) {
return date('YmdHi', strtotime(" +$days day "));
}
}

View File

@ -0,0 +1,44 @@
<?php
class Hashing {
public static function hashPassword($password) {
return password_hash($password, PASSWORD_DEFAULT);
}
public static function verifyPassword($password, $hash) {
return password_verify($password, $hash);
}
public static function generateRandomToken() {
return md5(uniqid(rand()));
}
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;
if($number <= 1) return false;
for($i = 2; $i <= $sqrt; $i++) {
if($number % $i === 0) {
$prime = false;
break;
}
}
return $prime;
}
}

View File

@ -0,0 +1,21 @@
<?php
class Setting extends DataStore {
const TABLE = 'setting';
public static function getSetting($name) {
return parent::getDataStore($name, 'name');
}
public static function getProps() {
return array(
'name',
'value',
'permission'
);
}
public function getValue() {
return $this->value;
}
}

View File

@ -0,0 +1,235 @@
<?php
/**
* @api {OBJECT} Ticket Ticket
* @apiVersion 4.7.0
* @apiGroup Data Structures
* @apiParam {Number} ticketNumber The number of the ticket.
* @apiParam {String} title The title of the ticket.
* @apiParam {String} content The content of the ticket.
* @apiParam {Object} department The department of the ticket.
* @apiParam {Number} department.id The id of the department of the ticket.
* @apiParam {String} department.name The department's name of the ticket.
* @apiParam {String} file The filename of the ticket if attached.
* @apiParam {String} language The language of the ticket.
* @apiParam {Boolean} unread Indicates if the user has already read the last comment.
* @apiParam {Boolean} unreadStaff Indicates if the staff has already read the last comment.
* @apiParam {Boolean} closed Indicates if the ticket is closed.
* @apiParam {String} priority The priority of the ticket. It can be LOW, MEDIUM or HIGH.
* @apiParam {Object} author The author of the ticket.
* @apiParam {Number} author.id The id of the author of the ticket.
* @apiParam {String} author.name The author's name of the ticket.
* @apiParam {String} author.email The author's email of the ticket.
* @apiParam {Object} owner The owner of the ticket.
* @apiParam {Number} owner.id The owner's id of the ticket.
* @apiParam {String} owner.name The owner's name of the ticket.
* @apiParam {String} owner.email The owner's email of the ticket.
* @apiParam {[TicketEvent](#api-Data_Structures-ObjectTicketevent)[]} events Events related to the ticket.
*/
use RedBeanPHP\Facade as RedBean;
class Ticket extends DataStore {
const TABLE = 'ticket';
public static function getProps() {
return array(
'ticketNumber',
'title',
'content',
'language',
'department',
'file',
'date',
'unread',
'closed',
'priority',
'author',
'authorStaff',
'owner',
'ownTicketeventList',
'unreadStaff',
'language',
'authorEmail',
'authorName',
'sharedTagList',
'editedContent',
'editedTitle'
);
}
public static function getFetchAs() {
return [
'author' => 'user',
'authorStaff' => 'staff',
'owner' => 'staff',
];
}
public static function getTicket($value, $property = 'id') {
return parent::getDataStore($value, $property);
}
public static function getByTicketNumber($value) {
return Ticket::getTicket($value, 'ticketNumber');
}
public function setAuthor($author) {
if($author instanceof User) {
$this->author = $author;
} else if($author instanceof Staff) {
$this->authorStaff = $author;
}
}
public function getAuthor() {
if($this->author && !$this->author->isNull()) {
return $this->author;
} else {
return $this->authorStaff;
}
}
public function getDefaultProps() {
return array(
'priority' => 'low',
'unread' => false,
'unreadStaff' => true,
'ticketNumber' => $this->generateUniqueTicketNumber()
);
}
public function store() {
parent::store();
}
public function delete() {
parent::delete();
}
public function generateUniqueTicketNumber() {
$linearCongruentialGenerator = new LinearCongruentialGenerator();
if (Ticket::count() === 0) {
$ticketNumber = Setting::getSetting('ticket-first-number')->value;
} else {
$lastTicketId = Ticket::findOne(' ORDER BY id DESC')->id;
$linearCongruentialGenerator->setGap(Setting::getSetting('ticket-gap')->value);
$linearCongruentialGenerator->setFirst(Setting::getSetting('ticket-first-number')->value);
$ticketNumber = $linearCongruentialGenerator->generate($lastTicketId + 1);
}
return $ticketNumber;
}
public function toArray($minimized = false) {
return [
'ticketNumber' => $this->ticketNumber,
'title' => $this->title,
'content' => $minimized ? strip_tags($this->content) : $this->content,
'department' => [
'id' => $this->department->id,
'name' => $this->department->name
],
'date' => $this->date,
'file' => $this->file,
'language' => $this->language,
'unread' => !!$this->unread,
'unreadStaff' => !!$this->unreadStaff,
'closed' => !!$this->closed,
'priority' => $this->priority,
'author' => $this->authorToArray(),
'owner' => $this->ownerToArray(),
'events' => $minimized ? [] : $this->eventsToArray(),
'tags' => $this->sharedTagList->toArray(true),
'edited' => $this->editedContent,
'editedTitle' => $this->editedTitle
];
}
public function authorToArray() {
$author = $this->getAuthor();
if ($author && !$author->isNull()) {
return [
'id' => $author->id,
'name' => $author->name,
'staff' => $author instanceof Staff,
'profilePic' => ($author instanceof Staff) ? $author->profilePic : null,
'email' => $author->email,
'customfields' => $author->xownCustomfieldvalueList ? $author->xownCustomfieldvalueList->toArray() : [],
];
} else {
return [
'id' => NULL,
'staff' => false,
'name' => $this->authorName,
'email' => $this->authorEmail
];
}
}
public function ownerToArray() {
$owner = $this->owner;
if ($owner && !$owner->isNull()) {
return [
'id' => $owner->id,
'name' => $owner->name,
'email' => $owner->email
];
} else {
return null;
}
}
public function eventsToArray() {
$events = [];
foreach ($this->ownTicketeventList as $ticketEvent) {
$event = [
'type' => $ticketEvent->type,
'content'=> $ticketEvent->content,
'author' => [],
'date'=> $ticketEvent->date,
'file'=> $ticketEvent->file,
'private'=> $ticketEvent->private,
'edited' => $ticketEvent->editedContent,
'id' => $ticketEvent->id
];
$author = $ticketEvent->getAuthor();
if($author && !$author->isNull()) {
$event['author'] = [
'id'=> $author->id,
'name' => $author->name,
'email' =>$author->email,
'profilePic' => ($author instanceof Staff) ? $author->profilePic : null,
'staff' => $author instanceof Staff
];
}
if(!Controller::isStaffLogged() && $ticketEvent->private) {
continue;
}
$events[] = $event;
}
return $events;
}
public function addEvent(Ticketevent $event) {
$this->ownTicketeventList->add($event);
}
public function isAuthor($user) {
$ticketAuthor = $this->authorToArray();
if(is_string($user)) return $user == $ticketAuthor['email'];
if(!($user instanceof DataStore) || $user->isNull()) return false;
return $user->id == $ticketAuthor['id'] && ($user instanceof Staff) == $ticketAuthor['staff'];
}
public function isOwner($user) {
return !$user->isNull() && $this->owner && $user->id == $this->owner->id && ($user instanceof Staff);
}
}

View File

@ -0,0 +1,69 @@
<?php
use RedBeanPHP\Facade as RedBean;
/**
* @api {OBJECT} User User
* @apiVersion 4.7.0
* @apiGroup Data Structures
* @apiParam {String} email The email of the user.
* @apiParam {Number} id The id of the user.
* @apiParam {String} name The name of the user.
* @apiParam {Boolean} verified Indicates if the user has verified the email.
* @apiParam {Boolean} notRegistered Indicates if the user had logged at least one time.
* @apiParam {[CustomField](#api-Data_Structures-ObjectCustomfield)[]} customfields Indicates the values for custom fields.
*/
class User extends DataStore {
const TABLE = 'user';
public $ticketNumber = null;
public static function authenticate($userEmail, $userPassword) {
$user = User::getUser($userEmail, 'email');
return ($user && Hashing::verifyPassword($userPassword, $user->password) && !$user->notRegistered) ? $user : new NullDataStore();
}
public static function getProps() {
return [
'email',
'password',
'name',
'signupDate',
'tickets',
'sharedTicketList',
'verificationToken',
'disabled',
'xownCustomfieldvalueList',
'notRegistered'
];
}
public function getDefaultProps() {
return [];
}
public static function getUser($value, $property = 'id') {
return parent::getDataStore($value, $property);
}
public function canManageTicket(Ticket $ticket){
$ticketNumberInstanceValidation = true;
if($this->ticketNumber) {
$ticketNumberInstanceValidation = $this->ticketNumber == $ticket->ticketNumber;
}
return ($ticket->isAuthor($this) && $ticketNumberInstanceValidation);
}
public function toArray() {
return [
'email' => $this->email,
'id' => $this->id,
'name' => $this->name,
'verified' => !$this->verificationToken,
'disabled' => $this->disabled,
'customfields' => $this->xownCustomfieldvalueList->toArray(),
'notRegistered' => $this->notRegistered
];
}
}