From 505257a98406bb3a8939b576d65b12da831216ca Mon Sep 17 00:00:00 2001
From: Jared Hancock <jared@osticket.com>
Date: Sat, 13 Dec 2014 17:40:50 -0600
Subject: [PATCH] upgrade: Fix several crashes upgrading

Handle missing `intl` module
Handle crash translating the staff login banner, when the %translation table
    does not yet exist
Handle `allow_client_updates` never having been configured
Handle staff login without @lang and @extra attributes in database
---
 include/class.format.php                      | 21 ++++++++++++++-----
 include/class.orm.php                         |  2 +-
 include/class.staff.php                       |  4 ++--
 include/class.translation.php                 |  8 ++++++-
 .../streams/core/b26f29a6-1ee831c8.patch.sql  |  6 ++++--
 5 files changed, 30 insertions(+), 11 deletions(-)

diff --git a/include/class.format.php b/include/class.format.php
index e6761abfe..28dc20991 100644
--- a/include/class.format.php
+++ b/include/class.format.php
@@ -513,7 +513,7 @@ class Format {
         $format = self::getStrftimeFormat($format);
         // TODO: Properly convert to local time
         $time = DateTime::createFromFormat('U', $timestamp, new DateTimeZone('UTC'));
-        $time->setTimeZone(new DateTimeZone($cfg->getTimezone()));
+        $time->setTimeZone(new DateTimeZone($cfg->getTimezone() ?: date_default_timezone_get()));
         $timestamp = $time->getTimestamp();
         return strftime($format ?: $strftimeFallback, $timestamp);
     }
@@ -546,7 +546,7 @@ class Format {
 
         return self::__formatDate($timestamp,
             $format ?: $cfg->getTimeFormat(), $fromDb,
-            IntlDateFormatter::NONE, IntlDateFormatter::SHORT,
+            IDF_NONE, IDF_SHORT,
             '%x', $timezone ?: $cfg->getTimezone());
     }
 
@@ -555,7 +555,7 @@ class Format {
 
         return self::__formatDate($timestamp,
             $format ?: $cfg->getDateFormat(), $fromDb,
-            IntlDateFormatter::SHORT, IntlDateFormatter::NONE,
+            IDF_SHORT, IDF_NONE,
             '%X', $timezone ?: $cfg->getTimezone());
     }
 
@@ -564,7 +564,7 @@ class Format {
 
         return self::__formatDate($timestamp,
                 $cfg->getDateTimeFormat(), $fromDb,
-                IntlDateFormatter::SHORT, IntlDateFormatter::SHORT,
+                IDF_SHORT, IDF_SHORT,
                 '%X %x', $timezone ?: $cfg->getTimezone());
     }
 
@@ -573,7 +573,7 @@ class Format {
 
         return self::__formatDate($timestamp,
                 $cfg->getDayDateTimeFormat(), $fromDb,
-                IntlDateFormatter::FULL, IntlDateFormatter::SHORT,
+                IDF_FULL, IDF_SHORT,
                 '%X %x', $timezone ?: $cfg->getTimezone());
     }
 
@@ -760,4 +760,15 @@ class Format {
         return $text;
     }
 }
+
+if (!class_exists('IntlDateFormatter')) {
+    define('IDF_NONE', 0);
+    define('IDF_SHORT', 1);
+    define('IDF_FULL', 2);
+}
+else {
+    define('IDF_NONE', IntlDateFormatter::NONE);
+    define('IDF_SHORT', IntlDateFormatter::SHORT);
+    define('IDF_FULL', IntlDateFormatter::FULL);
+}
 ?>
diff --git a/include/class.orm.php b/include/class.orm.php
index fcbe45754..afce3ea15 100644
--- a/include/class.orm.php
+++ b/include/class.orm.php
@@ -2076,7 +2076,7 @@ class MysqlExecutor {
 
     function execute() {
         if (!($this->stmt = db_prepare($this->sql)))
-            throw new Exception('Unable to prepare query: '.db_error()
+            throw new OrmException('Unable to prepare query: '.db_error()
                 .' '.$this->sql);
         if (count($this->params))
             $this->_bind($this->params);
diff --git a/include/class.staff.php b/include/class.staff.php
index 9a8ac128b..a6aecc63e 100644
--- a/include/class.staff.php
+++ b/include/class.staff.php
@@ -285,7 +285,7 @@ implements AuthenticatedUser {
     }
 
     function getLanguage() {
-        return $this->lang;
+        return (isset($this->lang)) ? $this->lang : false;
     }
 
     function getTimezone() {
@@ -430,7 +430,7 @@ implements AuthenticatedUser {
     }
 
     function getExtraAttr($attr=false, $default=null) {
-        if (!isset($this->_extra))
+        if (!isset($this->_extra) && isset($this->extra))
             $this->_extra = JsonDataParser::decode($this->extra);
 
         return $attr ? (@$this->_extra[$attr] ?: $default) : $this->_extra;
diff --git a/include/class.translation.php b/include/class.translation.php
index 1c09dbb6a..67037d2c0 100644
--- a/include/class.translation.php
+++ b/include/class.translation.php
@@ -1030,7 +1030,13 @@ class CustomDataTranslation extends VerySimpleModel {
         if ($lang)
             $criteria['lang'] = $lang;
 
-        return static::objects()->filter($criteria)->all();
+        try {
+            return static::objects()->filter($criteria)->all();
+        }
+        catch (OrmException $e) {
+            // Translation table might not exist yet — happens on the upgrader
+            return array();
+        }
     }
 }
 
diff --git a/include/upgrader/streams/core/b26f29a6-1ee831c8.patch.sql b/include/upgrader/streams/core/b26f29a6-1ee831c8.patch.sql
index fea1624b4..2b9944add 100644
--- a/include/upgrader/streams/core/b26f29a6-1ee831c8.patch.sql
+++ b/include/upgrader/streams/core/b26f29a6-1ee831c8.patch.sql
@@ -185,8 +185,10 @@ UPDATE `%TABLE_PREFIX%form_field` A1 JOIN `%TABLE_PREFIX%form` A2 ON(A2.id=A1.fo
     SET A1.`flags`=3
     WHERE A2.`type`='O' AND A1.`name` IN('name');
 
-set @client_edit = (
-    select value from `%TABLE_PREFIX%config` where `key` = 'allow_client_updates');
+-- Coalesce to zero here in case the config option has never been saved
+set @client_edit = coalesce(
+    (select value from `%TABLE_PREFIX%config` where `key` =
+    'allow_client_updates'), 0);
 
 -- Transfer previous visibility and requirement settings to new flag field
 UPDATE `%TABLE_PREFIX%form_field` SET `flags` = `flags` |
-- 
GitLab