diff --git a/README.md b/README.md index 4bc2ae0d..45894a2d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ![OpenSupports](http://www.opensupports.com/logo.png) -[![Build Status](https://travis-ci.org/opensupports/opensupports.svg?branch=master)](https://travis-ci.org/opensupports/opensupports) v4.1.0 +[![Build Status](https://travis-ci.org/opensupports/opensupports.svg?branch=master)](https://travis-ci.org/opensupports/opensupports) v4.1.1 OpenSupports is an open source ticket system built primarly with PHP and ReactJS. Please, visit our website for more information: [http://www.opensupports.com/](http://www.opensupports.com/) @@ -77,7 +77,7 @@ Just as there is the `gulp dev` task for development, there is also a `gulp prod 4. Run the MySQL server `sudo /etc/init.d/mysql start` - + ##### BACKEND API RUBY TESTING 1. Install ruby `sudo apt-get install ruby-full` diff --git a/client/package.json b/client/package.json index 8fc21755..228d77d4 100644 --- a/client/package.json +++ b/client/package.json @@ -1,6 +1,6 @@ { "name": "OpenSupports", - "version": "4.1.0", + "version": "4.1.1", "author": "Ivan Diaz ", "description": "Open source ticket system made with PHP and ReactJS", "repository": { diff --git a/server/controllers/system/init-settings.php b/server/controllers/system/init-settings.php index a4220171..b027e077 100755 --- a/server/controllers/system/init-settings.php +++ b/server/controllers/system/init-settings.php @@ -83,9 +83,10 @@ class InitSettingsController extends Controller { 'registration' => !!Controller::request('registration'), 'user-system-enabled' => !!Controller::request('user-system-enabled'), 'last-stat-day' => date('YmdHi', strtotime(' -12 day ')), - 'ticket-gap' => Hashing::generateRandomPrime(1000000, 9999999), - 'file-gap' => Hashing::generateRandomPrime(1000000, 9999999), - 'file-first-number' => Hashing::generateRandomNumber(1000000, 9999999), + 'ticket-gap' => Hashing::generateRandomPrime(100000, 999999), + 'ticket-first-number' => Hashing::generateRandomNumber(100000, 999999), + 'file-gap' => Hashing::generateRandomPrime(100000, 999999), + 'file-first-number' => Hashing::generateRandomNumber(100000, 999999), 'file-quantity' => 0, 'session-prefix' => 'opensupports-'.Hashing::generateRandomToken().'_' ]); diff --git a/server/libs/LinearCongruentialGenerator.php b/server/libs/LinearCongruentialGenerator.php index e82d4ed3..112b0d0b 100755 --- a/server/libs/LinearCongruentialGenerator.php +++ b/server/libs/LinearCongruentialGenerator.php @@ -26,8 +26,4 @@ class LinearCongruentialGenerator { 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); - } } diff --git a/server/libs/MailSender.php b/server/libs/MailSender.php index a0edd583..62bbaed3 100755 --- a/server/libs/MailSender.php +++ b/server/libs/MailSender.php @@ -36,10 +36,10 @@ class MailSender { public function setTemplate($type, $config) { $mailTemplate = MailTemplate::getTemplate($type); $compiledMailContent = $mailTemplate->compile($config); - + $this->mailOptions = array_merge($this->mailOptions, $compiledMailContent); } - + public function send() { $mailerInstance = $this->getMailerInstance(); @@ -49,6 +49,7 @@ class MailSender { throw new Exception('Mail sending data not available'); } + $mailerInstance->ClearAllRecipients(); $mailerInstance->addAddress($this->mailOptions['to']); $mailerInstance->Subject = $this->mailOptions['subject']; $mailerInstance->Body = $this->mailOptions['body']; @@ -88,4 +89,4 @@ class MailSender { return $this->mailerInstance; } -} \ No newline at end of file +} diff --git a/server/models/Ticket.php b/server/models/Ticket.php index 606c70bd..26993e6b 100755 --- a/server/models/Ticket.php +++ b/server/models/Ticket.php @@ -78,10 +78,10 @@ class Ticket extends DataStore { $ticketQuantity = Ticket::count(); if ($ticketQuantity === 0) { - $ticketNumber = $linearCongruentialGenerator->generateFirst(); + $ticketNumber = Setting::getSetting('ticket-first-number')->value; } else { $linearCongruentialGenerator->setGap(Setting::getSetting('ticket-gap')->value); - $linearCongruentialGenerator->setFirst(Ticket::getTicket(1)->ticketNumber); + $linearCongruentialGenerator->setFirst(Setting::getSetting('ticket-first-number')->value); $ticketNumber = $linearCongruentialGenerator->generate($ticketQuantity); } diff --git a/server/tests/libs/LinearCongruentialGeneratorTest.php b/server/tests/libs/LinearCongruentialGeneratorTest.php index b8addb94..f2f29410 100644 --- a/server/tests/libs/LinearCongruentialGeneratorTest.php +++ b/server/tests/libs/LinearCongruentialGeneratorTest.php @@ -16,7 +16,7 @@ class LinearCongruentialGeneratorTest extends TestCase { $linearCongruentialGenerator = new LinearCongruentialGenerator(); $linearCongruentialGenerator->setRange($min, $max); $linearCongruentialGenerator->setGap(Hashing::generateRandomPrime($min, $max)); - $linearCongruentialGenerator->setFirst($linearCongruentialGenerator->generateFirst()); + $linearCongruentialGenerator->setFirst(Hashing::generateRandomNumber($min, $max)); $used = []; diff --git a/version_upgrades/4.1.0/4.1.0.php b/version_upgrades/4.1.0/4.1.0.php new file mode 100644 index 00000000..b8dca3ef --- /dev/null +++ b/version_upgrades/4.1.0/4.1.0.php @@ -0,0 +1,4 @@ +query(file_get_contents('./4.1.0.sql')); diff --git a/db_upgrades/4.1.sql b/version_upgrades/4.1.0/4.1.0.sql similarity index 100% rename from db_upgrades/4.1.sql rename to version_upgrades/4.1.0/4.1.0.sql diff --git a/version_upgrades/4.1.1/4.1.1.php b/version_upgrades/4.1.1/4.1.1.php new file mode 100644 index 00000000..2fbf8ac8 --- /dev/null +++ b/version_upgrades/4.1.1/4.1.1.php @@ -0,0 +1,100 @@ +query("UPDATE setting SET value='$ticketGap' WHERE name='ticket-gap'"); +$mysql->query("UPDATE setting SET value='$fileGap' WHERE name='file-gap'"); +$mysql->query("UPDATE setting SET value='$ticketFirstNumber' WHERE name='ticket-first-number'"); +$mysql->query("UPDATE setting SET value='$fileFirstNumber' WHERE name='file-first-number'"); + +$smtpHost = $mysql->query("SELECT value FROM setting WHERE name='smtp-host'")->fetch_array(MYSQLI_ASSOC)['value']; +$smtpPort = $mysql->query("SELECT value FROM setting WHERE name='smtp-port'")->fetch_array(MYSQLI_ASSOC)['value']; +$smtpUser = $mysql->query("SELECT value FROM setting WHERE name='smtp-user'")->fetch_array(MYSQLI_ASSOC)['value']; +$smtpPassword = $mysql->query("SELECT value FROM setting WHERE name='smtp-pass'")->fetch_array(MYSQLI_ASSOC)['value']; +$noReplyEmail = $mysql->query("SELECT value FROM setting WHERE name='no-reply-email'")->fetch_array(MYSQLI_ASSOC)['value']; +$userSystemEnabled = $mysql->query("SELECT value FROM setting WHERE name='user-system-enabled'")->fetch_array(MYSQLI_ASSOC)['value']; +$url = $mysql->query("SELECT value FROM setting WHERE name='url'")->fetch_array(MYSQLI_ASSOC)['value']; + +$mailSender = MailSender::getInstance(); +$mailSender->setConnectionSettings( + $smtpHost, $smtpPort, $smtpUser, $smtpPassword, $noReplyEmail +); + +function compileString($string, $config) { + $compiledString = $string; + + foreach ($config as $configName => $configValue) { + $compiledString = str_replace("{{{$configName}}}", $configValue, $compiledString); + } + + return $compiledString; +} + +$migrationMail = file_get_contents('./libs/migration-mail.html'); + +if($tickets = $mysql->query("SELECT * FROM ticket ORDER BY id ASC")) { + $linearCongruentialGenerator = new LinearCongruentialGenerator(); + $linearCongruentialGenerator->setGap($ticketGap); + $linearCongruentialGenerator->setFirst($ticketFirstNumber); + $offset = 0; + $emails = []; + + while($ticket = $tickets->fetch_assoc()) { + $ticketId = $ticket['id']; + $ticketNumber = $linearCongruentialGenerator->generate($offset); + + $mysql->query("UPDATE ticket SET ticket_number='$ticketNumber' WHERE id='$ticketId'"); + + if(array_key_exists('author_email', $ticket) && $ticket['author_email']) { + if(!array_key_exists($ticket['author_email'], $emails)) { + $emails[$ticket['author_email']] = []; + } + + array_push( + $emails[$ticket['author_email']], + [ + 'old_number' => $ticket['ticket_number'], + 'new_number' => $ticketNumber, + 'title' => $ticket['title'] + ] + ); + } + + $offset++; + } + + foreach($emails as $email => $emailTickets) { + $ticketString = ''; + + foreach($emailTickets as $ticket) { + $ticketString .= '

'; + $ticketString .= $ticket['old_number']; + $ticketString .= ' => '; + $ticketString .= $ticket['new_number']; + $ticketString .= ' '; + $ticketString .= htmlentities($ticket['title']); + $ticketString .= '

'; + $ticketString .= PHP_EOL; + } + + $mailSender->setMailContent([ + 'to' => $email, + 'subject' => 'Tickets have been updated', + 'body' => compileString($migrationMail, [ + 'url' => $url, + 'email' => $email, + 'tickets' => $ticketString, + ]) + ]); + + $mailSender->send(); + } +} diff --git a/version_upgrades/4.1.1/libs/Hashing.php b/version_upgrades/4.1.1/libs/Hashing.php new file mode 100644 index 00000000..7b270459 --- /dev/null +++ b/version_upgrades/4.1.1/libs/Hashing.php @@ -0,0 +1,44 @@ +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) { + if(!$this->first) throw new Exception('LinearCongruentialGenerator: first is not set'); + if(!$this->gap) throw new Exception('LinearCongruentialGenerator: gap is not set'); + + return ($this->first - $this->min + $offset * $this->gap) % ($this->max - $this->min + 1) + $this->min; + } +} diff --git a/version_upgrades/4.1.1/libs/MailSender.php b/version_upgrades/4.1.1/libs/MailSender.php new file mode 100644 index 00000000..10751415 --- /dev/null +++ b/version_upgrades/4.1.1/libs/MailSender.php @@ -0,0 +1,83 @@ +mailOptions['from'] = $noReplyEmail; + $this->mailOptions['fromName'] = 'OpenSupports'; + + $this->mailOptions['smtp-host'] = $host; + $this->mailOptions['smtp-port'] = $port; + $this->mailOptions['smtp-user'] = $user; + $this->mailOptions['smtp-pass'] = $pass; + } + + public function setMailContent($mailContent) { + $this->mailOptions = array_merge($this->mailOptions, $mailContent); + } + + public function send() { + $mailerInstance = $this->getMailerInstance(); + + if( !array_key_exists('to', $this->mailOptions) || + !array_key_exists('subject', $this->mailOptions) || + !array_key_exists('body', $this->mailOptions) ) { + throw new Exception('Mail sending data not available'); + } + + $mailerInstance->ClearAllRecipients(); + $mailerInstance->addAddress($this->mailOptions['to']); + $mailerInstance->Subject = $this->mailOptions['subject']; + $mailerInstance->Body = $this->mailOptions['body']; + $mailerInstance->isHTML(true); + + if ($this->isConnected()) { + $mailerInstance->send(); + } + } + + public function isConnected() { + return $this->getMailerInstance()->smtpConnect(); + } + + private function getMailerInstance() { + if(!($this->mailerInstance instanceof PHPMailer)) { + $this->mailerInstance = new PHPMailer(); + + $this->mailerInstance->From = $this->mailOptions['from']; + $this->mailerInstance->FromName = $this->mailOptions['fromName']; + + $this->mailerInstance->isSMTP(); + $this->mailerInstance->SMTPAuth = true; + $this->mailerInstance->Host = $this->mailOptions['smtp-host']; + $this->mailerInstance->Port = $this->mailOptions['smtp-port']; + $this->mailerInstance->Username = $this->mailOptions['smtp-user']; + $this->mailerInstance->Password = $this->mailOptions['smtp-pass']; + $this->mailerInstance->Timeout = 1000; + $this->mailerInstance->SMTPOptions = [ + 'ssl' => [ + 'verify_peer' => false, + 'verify_peer_name' => false, + 'allow_self_signed' => true + ] + ]; + } + + return $this->mailerInstance; + } +} diff --git a/version_upgrades/4.1.1/libs/migration-mail.html b/version_upgrades/4.1.1/libs/migration-mail.html new file mode 100644 index 00000000..e3d78cff --- /dev/null +++ b/version_upgrades/4.1.1/libs/migration-mail.html @@ -0,0 +1,384 @@ + + + + + + Support Center + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+
+ + + + +
+ logo +
+
+ +
+
+
+
+ + + + + + + + + + +
+ Ticket numbers updated +
+ Hello, {{email}}. Due maintenance reasons, the following tickets have changed its number. +
+ + + + +
+ + + + + + + +
+ {{tickets}} +
+ +
+
+
+
+
+
+ + + + +
+ OpenSupports
+ Open source ticket system
+ www.opensupports.com

+
+
+
+ + diff --git a/version_upgrades/mysql_connect.php b/version_upgrades/mysql_connect.php new file mode 100644 index 00000000..48d150cd --- /dev/null +++ b/version_upgrades/mysql_connect.php @@ -0,0 +1,13 @@ +