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:
parent
91d2c203d3
commit
17e9dcf53b
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 "));
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
||||
];
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue