From be4999009184e8c88f2d106ecf86d8d75e930ecd Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 12 Jan 2017 03:02:56 -0300 Subject: [PATCH 01/10] 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 134540fed957efa2e6e03fb216fbfcb48691f1f0 Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 12 Jan 2017 16:45:01 -0300 Subject: [PATCH 02/10] 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 f2401dcec718b09c44f02d8c644357c8b8c33aa6 Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 12 Jan 2017 18:29:50 -0300 Subject: [PATCH 03/10] 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 04/10] 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 db63948db700e5fd6a257d3afc663b5617cee49c Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Fri, 13 Jan 2017 14:40:21 -0300 Subject: [PATCH 05/10] 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 dffe4a87a0b0062085b4fdeee5b209998688f333 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Fri, 13 Jan 2017 21:58:59 -0300 Subject: [PATCH 06/10] 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 d575882bf2b2009ea3cde94067cf0fae4616bd52 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Sat, 14 Jan 2017 16:39:22 -0300 Subject: [PATCH 07/10] 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 35d9a166cfbe28c212e9873f97cb6f356686d4d9 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Sat, 14 Jan 2017 21:44:20 -0300 Subject: [PATCH 08/10] 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 09/10] 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 e8e29d8701ff06228291fdd6bd95cca8cd5ef3ea Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Sun, 15 Jan 2017 01:36:04 -0300 Subject: [PATCH 10/10] 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',