fix #8131 - chinese translations master
authorAlan <alan@roojs.com>
Thu, 18 Apr 2024 04:19:57 +0000 (12:19 +0800)
committerAlan <alan@roojs.com>
Thu, 18 Apr 2024 04:19:57 +0000 (12:19 +0800)
107 files changed:
.roobuilder.jcfg [new file with mode: 0644]
Asset.php
AssetTrait.php
Config.php [new file with mode: 0644]
DataObjects/Core_company.php
DataObjects/Core_domain.php
DataObjects/Core_email.php
DataObjects/Core_enum.php
DataObjects/Core_group.php
DataObjects/Core_group_member.php
DataObjects/Core_holiday.php
DataObjects/Core_notify.php
DataObjects/Core_notify_blacklist.php [new file with mode: 0644]
DataObjects/Core_notify_sender.php [new file with mode: 0644]
DataObjects/Core_notify_sender_blacklist.php [new file with mode: 0644]
DataObjects/Core_notify_server.php [new file with mode: 0644]
DataObjects/Core_person.php
DataObjects/Core_project.php
DataObjects/Core_project_group.php [new file with mode: 0644]
DataObjects/Core_setting.php
DataObjects/Core_template.php
DataObjects/Core_templatestr.php
DataObjects/Core_watch.php
DataObjects/Events.php
DataObjects/Images.php
DataObjects/core.sql [deleted file]
DataObjects/pman.links.ini
DatabaseColumns.php
GnumericToExcel.php
GroupCountries.php
GroupMembers.php
Heartbeat.php [new file with mode: 0644]
I18n.php
Images.php
Import/Core_email.php
Import/Core_holiday.php
Import/Timezone.php [new file with mode: 0644]
JsCompile.php
JsTemplate.php
JsonOutputTrait.php [moved from RooJsonOutputTrait.php with 62% similarity]
Lock.php
Mailer.php
MessagePreview.php
Notify.php
NotifyAction.php
NotifySend.php
Pman.Delete.js
Pman.Dialog.CoreColumnConfig.bjs [new file with mode: 0644]
Pman.Dialog.CoreColumnConfig.js [new file with mode: 0644]
Pman.Dialog.CoreCompanies.bjs
Pman.Dialog.CoreCompanies.js
Pman.Dialog.CoreEmail.bjs
Pman.Dialog.CoreEmail.js
Pman.Dialog.CoreEmailPreview.bjs
Pman.Dialog.CoreEmailPreview.js
Pman.Dialog.CoreEnum.bjs
Pman.Dialog.CoreEnum.js
Pman.Dialog.CoreEnumMerge.bjs
Pman.Dialog.CoreEnumMerge.js
Pman.Dialog.CorePersonContact.bjs
Pman.Dialog.CorePersonContact.js
Pman.Dialog.CoreProject.bjs
Pman.Dialog.CoreProject.js
Pman.Dialog.Image.bjs
Pman.Dialog.Image.js
Pman.Dialog.PersonEditor.js
Pman.Download.js
Pman.Gnumeric.js
Pman.Lock.js
Pman.Login.js
Pman.Tab.PersonList.js
Process/FixMysqlCharset.php [new file with mode: 0644]
RefreshDatabaseCache.php
RooGetTrait.php
RooPostTrait.php
RooTrait.php
RunGenerator.php
SendIntro.php
SimpleExcel.php
TimeZone.php [new file with mode: 0644]
UpdateDatabase.php
UpdateDatabase/MysqlLinks.php
UploadProgress.php
mysql/core_notify_trigger_after_delete.sql
mysql/core_notify_trigger_after_update.sql
mysql/core_translate_lookup.sql
mysql/i18n_translate.sql
sql/I18n.sql
sql/core_column_settings.sql [new file with mode: 0644]
sql/core_company.sql
sql/core_email.sql
sql/core_group.sql
sql/core_holiday.sql
sql/core_notify.sql
sql/core_notify_blacklist.sql [new file with mode: 0644]
sql/core_notify_sender.sql [new file with mode: 0644]
sql/core_notify_sender_blacklist.sql [new file with mode: 0644]
sql/core_notify_server.sql [new file with mode: 0644]
sql/core_person.sql
sql/core_project.sql
sql/core_project_group.sql [new file with mode: 0644]
sql/core_templatestr.sql
sql/events.sql
sql/images.sql
templates/mail/MessagePreview.html
templates/master.html
widgets/SecurePass.js

diff --git a/.roobuilder.jcfg b/.roobuilder.jcfg
new file mode 100644 (file)
index 0000000..b1099f6
--- /dev/null
@@ -0,0 +1,13 @@
+{
+    "name" : "Pman.Core",
+    "xtype" : "Roo",
+    "fn" : "3ab3f691edabeed20ba58b844cde0cc6",
+    "runhtml" : "<script type=\"text/javascript\">\n Roo.namespace(\"Pman.Dialog\");\n</script>",
+    "rootURL" : "http://localhost/web.Texon/",
+    "base_template" : "roo.builder.html",
+    "html_gen" : "",
+    "DBTYPE" : "",
+    "DBNAME" : "",
+    "DBUSERNAME" : "",
+    "DBPASSWORD" : ""
+}
\ No newline at end of file
index eb5c053..3e49f8e 100644 (file)
--- a/Asset.php
+++ b/Asset.php
@@ -26,6 +26,7 @@ class Pman_Core_Asset extends Pman {
     var $types = array(
         'css' => 'text/css',
         'js' => 'text/javascript',
+        'map' => 'application/json'
     );
     
     function getAuth()
@@ -44,17 +45,23 @@ class Pman_Core_Asset extends Pman {
             $this->jerr("invalid url");
         }
        
+        $ext = $bits[0];
+        if (preg_match('/\.map$/',$_SERVER['REQUEST_URI'])) {
+            $ext = 'map';
+        }
+       
         $s = str_replace('/', '-', $bits[1]);
         
+        
         $ui = posix_getpwuid(posix_geteuid());
         $ff = HTML_FlexyFramework::get();
         
         $compile = self::getCompileDir($bits[0], '', false);
         
-        $fn = $compile . '/'. $s .'.'. $bits[0];
+        $fn = $compile . '/'. $s .'.'. $ext;
         
         if (!file_exists($fn)) {
-            header('Content-Type: '. $this->types[$bits[0]]);
+            header('Content-Type: '. $this->types[$ext]);
         
             echo "// compiled file not found = $fn";
             exit;
@@ -105,7 +112,7 @@ class Pman_Core_Asset extends Pman {
             $fh = fopen($fn,'r');
             fpassthru($fh);
             fclose($fh);
-            $content = $data;
+             
         }
         
         
@@ -151,6 +158,7 @@ class Pman_Core_Asset extends Pman {
                 return false;
         }
         
+        
         if (file_exists($compile_dir)) {
             return $compile_dir;
         }
index 6e8627e..0067d6f 100644 (file)
@@ -78,8 +78,8 @@ trait Pman_Core_AssetTrait {
         
         $ff = HTML_FlexyFramework::get();
         
-        if (!empty($ff->Pman['isDev']) && !empty($_REQUEST['isDev'])) {
-            echo "<!-- Javascript compile turned off (isDev on) -->\n";
+        if (empty($compiledir) || (!empty($ff->Pman['isDev']) && !empty($_REQUEST['isDev']))) {
+            echo "<!-- Javascript compile turned off (isDev on or mkdir failed) -->\n";
             $this->assetArrayToHtml($files,'js');
             return;
         }
@@ -260,7 +260,7 @@ trait Pman_Core_AssetTrait {
             file_put_contents($compiledir.'/'.$output , $x->minify( $this->baseURL.$asset));
             clearstatcache();
             if (!file_exists($compiledir.'/'.$output) ||
-                !filesize($compiledir.'/'.$routput)) {
+                !filesize($compiledir.'/'.$output)) {
                 echo "<!-- compile did not generate files : " . basename($compiledir) . "/{$output} -->\n";
                 $this->assetArrayToHtml($files,'css');
                 return;
@@ -283,18 +283,45 @@ trait Pman_Core_AssetTrait {
     
     function outputSCSS($smod)
     {
-        // we cant output non-cached versions of this.... 
+        // we cant output non-cached versions of this....
+        
+        // this doesnt really look like it would work!
+        $this->outputSCSSDir("{$this->rootDir}/Pman/{$smod}/scss/{$smod}.scss", $smod);
+        
+    }
+    /*
+     * Pman projects - expect
+     * /Pman/MyProject/scss/MyProject.less  <<
+     *           this should contain includes for the others?
+     *              @import "fonts.less";
+     *              ....
+     * Then all the files go here.
+     * /Pman/MyProject/scss/*.less
+     *
+     * For a Non Pman project
+     *  send:
+     *  /MyProject/scss/base.less << could be anything really...
+     *
+     * 
+     */
+     
+    
+    function outputSCSSDir($file, $smod= '')
+    {
+        
+         
         $ff = HTML_FlexyFramework::get();
-        $fp =   "{$this->rootDir}/Pman/$smod/scss/{$smod}.scss";
-       // var_dump($fp);
-        if (!file_exists($fp)) {
+        $asset = $ff->project == 'Pman' ? '/Core/Asset/css/' : '/Asset/css/';
+        
+        
+        if (!file_exists($file)) {
             return;
         }
         
-        $ar = glob(dirname($fp) . '/*.scss');
-        $maxtime = 0;
+        $ar = glob(dirname($file). '/*.scss');
+        $maxtime = filemtime($file);
         foreach($ar as $fn) {
-            $maxtime=max($maxtime, filemtime($fn));
+            $maxtime= max($maxtime, filemtime($fn));
         }
         
         
@@ -309,17 +336,14 @@ trait Pman_Core_AssetTrait {
             mkdir($compiledir,0700,true);
         }
         
-        
-        
          
-        $output = date('Y-m-d-H-i-s-', $maxtime). $smod .'-'.md5(serialize(array($this->baseURL, $ar))) .'.css';
+        $output = date('Y-m-d-H-i-s-', $maxtime). $smod .'-less-'.md5(serialize(array($this->baseURL, $ar))) .'.css';
          
-        $asset = $ff->project == 'Pman' ? '/Core/Asset/css/' : '/Asset/css/';
+        
         
         // where are we going to write all of this..
         // This has to be done via a
-        
-        
+         
         
         if ( !file_exists($compiledir.'/'.$output) || !filesize($compiledir.'/'.$output)) {
             
@@ -334,26 +358,26 @@ trait Pman_Core_AssetTrait {
                 die("INSTALL sassc");
             }
                  
-            $fd = dirname($fp);
-            
+             
             $ver = `$sassc --version`;
-            $bits = explode("\n", $ver);
+            $bits = explode("\n", trim($ver));
             foreach($bits as $b) {
+                 
                 $lr = explode(":", $b);
                 $vers[trim($lr[0])] = trim($lr[1]);
             } 
             
             $sm = $vers['sass'] > 3.4 ? ' --sourcemap=auto ' : '--sourcemap';
-            $cmd = "{$sassc} --style=compressed  {$sm} -I {$fd} -I {$this->rootDir}/roojs1/scss/bootstrap $smod.scss {$compiledir}/{$output}";
+            $cmd = "{$sassc} --style=compressed  {$sm} -I ". dirname($file) . " -I {$this->rootDir}/roojs1/scss/bootstrap ". basename($file) . " {$compiledir}/{$output}";
             //echo "$cmd\n";            echo `$cmd`;
             `$cmd`;
             
              
             clearstatcache();
             if (!file_exists($compiledir.'/'.$output) ||
-                !filesize($compiledir.'/'.$routput)) {
+                !filesize($compiledir.'/'.$output)) {
                 echo "<!-- compile did not generate files : $cmd -->\n";
-                echo "<script type=\"text/javascript\">alert('Failed to compile {$fp}');</script>\n";
+                echo "<script type=\"text/javascript\">alert('Failed to compile Less Dir: ". basename($file). "');</script>\n";
                 return;
             } 
             
@@ -371,4 +395,8 @@ trait Pman_Core_AssetTrait {
     }
     
     
+    
+     
+    
+    
 }
\ No newline at end of file
diff --git a/Config.php b/Config.php
new file mode 100644 (file)
index 0000000..d6dc5e6
--- /dev/null
@@ -0,0 +1,117 @@
+<?php
+
+// default framework settings for release
+
+class Pman_Core_Config {
+    
+    
+    var $memory_limit = 0;
+    
+    var $defaults = array(  ); // override... 
+    
+    
+    // note if other extended 'config's require more, then you porbably need to include these first.
+    var $required_extensions = array(
+        'json',        
+        'curl',
+        'gd',
+        'mbstring',
+        'http'
+    );
+    
+    function init($ff, $cfg)
+    {
+        
+        
+        
+        $cfg = $this->overlayDefaults($cfg);
+        
+        if (!empty($this->memory_limit)) {
+            $mem = ini_get('memory_limit');
+            if (php_sapi_name() != 'cli' && $this->to_bytes($mem) < $this->to_bytes($this->memory_limit)) {
+                trigger_error("increase the memory limit settings to 2048M or more", E_USER_ERROR);
+            }
+        
+        }
+        
+        $this->verifyExtensions();
+        
+        
+        if (!isset($cfg['Pman']['timezone'])) {
+            trigger_error("timezone needs setting in Pman[timezone]", E_USER_ERROR);
+        }
+        if ($cfg['Pman']['timezone'] != ini_get('date.timezone')) {
+            trigger_error("timezone needs setting in php.ini date.timezone = " . $cfg['Pman']['timezone'], E_USER_ERROR);
+        }
+        
+        
+        return $cfg;
+    }
+    
+    function to_bytes($val) {
+        $val = trim($val);
+        $last = strtolower($val[strlen($val)-1]);
+        switch($last) {
+            // The 'G' modifier is available since PHP 5.1.0
+            case 'g':
+                $val = substr($val, 0, -1);
+                $val *= 1024;
+            case 'm':
+                $val = substr($val, 0, -1);
+                $val *= 1024;
+                $val = substr($val, 0, -1);
+            case 'k':
+                $val *= 1024;
+        }
+    
+        return $val;
+    }
+    function overlayDefaults($cfg)
+    {
+        if (isset($this->defaults['disable']) && is_array($this->defaults['disable']) ) {
+            $this->defaults['disable'] = implode(',', $this->defaults['disable']);
+        }
+        foreach($this->defaults as $k=>$v) {
+            if (is_array($v)) {
+                
+                if (!isset($cfg[$k])) {
+                    $cfg[$k] = $v;
+                    continue;
+                }
+                
+                foreach($v as $kk=>$vv) {
+                    if (isset($cfg[$k][$kk])) {
+                        continue;
+                    }
+                    
+                    $cfg[$k][$kk] = $vv;
+                }
+            }
+            
+            if (!isset($cfg[$k])) {
+                $cfg[$k] = $v;
+            }
+        }
+        
+        return $cfg;
+    }
+    function verifyExtensions()
+    {
+        $error = array();
+        
+        foreach ($this->required_extensions as $e){
+            
+            if(empty($e) || extension_loaded($e)) {
+                continue;
+            }
+            
+            $error[] = "Error: Please install php extension: {$e}";
+        }
+        
+        if(empty($error)){
+           return true; 
+        }
+        trigger_error("Missing Extensions: \n" . implode('\n', $error), E_USER_ERROR);
+    }
+
+}
index ac63449..4ae8fb3 100644 (file)
@@ -35,10 +35,17 @@ class Pman_Core_DataObjects_Core_Company extends DB_DataObject
     public $country;                         // string(4)  not_null
     public $is_system;                       // int(2)
     
+    
+    public $comptype_id;
+    public $address1;
+    public $address2;
+    public $address3;
+    
+    
     /* the code above is auto generated do not remove the tag below */
     ###END_AUTOCODE
     
-    function applyFilters($q, $au)
+    function applyFilters($q, $au, $roo)
     {
         
         $tn = $this->tableName();
@@ -79,7 +86,7 @@ class Pman_Core_DataObjects_Core_Company extends DB_DataObject
         }
         if (!empty($q['query']['comptype'])) {
            
-            $this->whereAddIn('comptype', explode(',', $q['query']['comptype']), 'string');
+            $this->whereAddIn($tn.'.comptype', explode(',', $q['query']['comptype']), 'string');
             
         }
         
@@ -280,7 +287,7 @@ class Pman_Core_DataObjects_Core_Company extends DB_DataObject
                 $roo->jok('OK');
             }
             
-            $roo->jerr('EXIST');
+            $roo->jerror('NOTICE-EXIST-CHECK','EXIST');
         }
     }
     
@@ -320,7 +327,7 @@ class Pman_Core_DataObjects_Core_Company extends DB_DataObject
                 $roo->jok('OK');
             }
             
-            $roo->jerr('EXIST');
+            $roo->jerror('NOTICE-EXIST-CHECK','EXIST');
         }
         
         if(!empty($q['_merge_id'])){
@@ -497,12 +504,38 @@ class Pman_Core_DataObjects_Core_Company extends DB_DataObject
         $companies->insert();
         $companies->onInsert(array(), $roo);
     }
+    
+    function owner()
+    {
+        if (empty($this->owner_id)) {
+            return false;
+        }
+        static $cache = false;
+        if ($cache !== false && isset($cache[$this->owner_id])) {
+            return $cache[$this->owner_id]; 
+        }
+        $o = DB_DataObject::factory('core_company');
+        if (!$o->get($this->owner_id)) {
+            return false;
+        }
+        $cache[$this->owner_id] = $o;
+        return $o;
+        
+    }
+    
+    /// look up the company which is the system owner...
     static function lookupOwner()
     {
+        static $cache = false;
+        if ($cache !== false) {
+            return clone($cache); // no updating this object..
+        }
+        
         $enum = DB_DataObject::Factory('core_enum')->lookup('COMPTYPE', 'OWNER'  );
         $companies = DB_DataObject::factory('core_company');
         $companies->comptype_id = $enum;
         if ($companies->find(true)) {
+            $cache = clone($companies);
             return $companies;
         }
         return false;
index 89b4587..3c50da4 100644 (file)
@@ -15,5 +15,22 @@ class Pman_Core_DataObjects_Core_domain extends DB_DataObject
 
     /* the code above is auto generated do not remove the tag below */
     ###END_AUTOCODE
-    
+    function loadOrCreate($dom)
+    {
+        // should we validate domain?
+        static $cache = array();
+        if (isset($cache[$dom])) {
+            return $cache[$dom];
+        }
+        
+        $cd = DB_DataObject::Factory($this->tableName());
+        if ($cd->get('domain', $dom)) {
+            $cache[$dom] = $cd;
+            return $cd;
+        }
+        $cd->domain = $dom;
+        $cd->insert();
+        $cache[$dom] = $cd;
+        return $cd;
+    }
 }
index cbaba21..02ce342 100644 (file)
@@ -23,9 +23,7 @@ class Pman_Core_DataObjects_Core_email extends DB_DataObject
     public $active;
     public $bcc_group_id;
     public $test_class;
-    
-
+     
     /* the code above is auto generated do not remove the tag below */
     ###END_AUTOCODE
     
@@ -61,6 +59,7 @@ class Pman_Core_DataObjects_Core_email extends DB_DataObject
                     bcc_group_id = {$cgm}.group_id
             )  AS bcc_group_member_count
         ");
+
        
        if (!empty($_REQUEST['_hide_system_emails'])) {
            $this->whereAddIn("!{$this->tableName()}.name", array('EVENT_ERRORS_REPORT'), 'string');
@@ -75,7 +74,7 @@ class Pman_Core_DataObjects_Core_email extends DB_DataObject
         $i->ontable = $this->tableName();
         $i->find();
         while ($i->fetch()){
-            $i->beforeDelete();
+            $i->beforeDelete(array(), $roo);
             $i->delete();
         }
     }
@@ -295,7 +294,7 @@ class Pman_Core_DataObjects_Core_email extends DB_DataObject
                 $html->item(0)->appendChild($element);
             }
             
-            $this->plaintext = str_replace("{unsubscribe_link}", $unsubscribe, $this->plaintext);
+            $this->plaintext = str_replace("{unsubscribe_link}", $unsubscribe, empty($this->plaintext) ? '' : $this->plaintext);
         }
         
         
@@ -381,7 +380,15 @@ class Pman_Core_DataObjects_Core_email extends DB_DataObject
             }
             $contents['rcpts'] = $admin;
         }
-        
+        if (empty($contents['rcpts']) && $this->to_group_id > 0) {
+           $members = $this->to_group()->members();
+           $contents['rcpts'] = array();
+           foreach($this->to_group()->members() as $m) {
+               $contents['rcpts'][] = $m->email;
+           }
+           //var_dump($contents['rcpts']);
+           
+       }
         //subject replacement
         if(empty($contents['subject'])){
            $contents['subject'] = $this->subject; 
@@ -709,4 +716,11 @@ Content-Transfer-Encoding: 7bit
         
            
     }
+    
+    function to_group()
+    {
+       $g = DB_DataObject::Factory('core_group');
+       $g->get($this->to_group_id);
+       return $g;
+    }
 }
index f609201..a2d08ca 100644 (file)
@@ -16,7 +16,9 @@ class Pman_Core_DataObjects_Core_enum extends DB_DataObject
     public $seqid;                           // int(11)  not_null multiple_key
     public $seqmax;                           // int(11)  not_null multiple_key
     public $display_name;
-
+    public $is_system_enum;
+   
+    
     /* the code above is auto generated do not remove the tag below */
     ###END_AUTOCODE
 
@@ -254,6 +256,12 @@ class Pman_Core_DataObjects_Core_enum extends DB_DataObject
 
     function lookupCreate($etype,$name, $display_name=false) {
 
+        static $cache = array();
+        $ckey = json_encode(array($etype, $name));
+        if (isset($cache[$ckey])) {
+            return $cache[$ckey];
+        }
+        
         // check
         $ce = DB_DataObject::Factory('core_enum');
         $ce->setFrom(array(
@@ -269,11 +277,14 @@ class Pman_Core_DataObjects_Core_enum extends DB_DataObject
         $ce->etype = $etype;
         $ce->name = $name;
         if ($ce->find(true)) {
+            $cache[$ckey] = $ce->id;
             return $ce->id;
         }
         $ce->active = 1;
         $ce->display_name = $display_name === false ? $ce->name : $display_name;
-        return  $ce->insert();
+        $ret = $ce->insert();
+        $cache[$ckey] = $ret;
+        return  $ret;
 
     }
 
@@ -379,7 +390,7 @@ class Pman_Core_DataObjects_Core_enum extends DB_DataObject
 
             if (empty($t->name) && $t->name != 0) {
                 print_R($data);
-                die("ERROR: invalid name used for core_enum\n\n");
+                die("ERROR:   invalid name used for core_enum\n\n" );
             }
 
             if (!$t->count()) {
index 613a77d..54f83f5 100644 (file)
@@ -45,6 +45,10 @@ class Pman_Core_DataObjects_Core_group extends DB_DataObject
             $v = $this->escape($q['query']['name_starts']);
             $this->whereAdd("{$this->tableName()}.name like '{$v}%'");
         }
+        if (!empty($q['query']['name_contains'])) {
+            $v = $this->escape($q['query']['name_contains']);
+            $this->whereAdd("{$this->tableName()}.name like '%{$v}%'");
+        }
         
         if(!empty($q['_count_member_by_name'])){
             
@@ -76,17 +80,17 @@ class Pman_Core_DataObjects_Core_group extends DB_DataObject
         
         $this->selectAdd("
            (
-            SELECT COUNT(${cgm}.user_id) 
+            SELECT COUNT({$cgm}.user_id) 
                 FROM 
                     {$cgm}
                 LEFT JOIN
                     {$cp}
                 ON
-                    ${cp}.id = {$cgm}.user_id
+                    {$cp}.id = {$cgm}.user_id
                 WHERE
-                    ${cgm}.group_id = {$this->tableName()}.id
+                    {$cgm}.group_id = {$this->tableName()}.id
                 AND
-                    ${cp}.active = 1
+                    {$cp}.active = 1
                 ) AS group_member_count            
         ");
         
@@ -115,7 +119,8 @@ class Pman_Core_DataObjects_Core_group extends DB_DataObject
                         $g->addMember($uid,$roo);
                         break;
                     case 'sub':
-                        $g->removeMember($uid);
+                        
+                        $g->removeMember($uid, $roo);
                         break;
                     default:
                         $roo->jerr('invalid action');
@@ -124,8 +129,18 @@ class Pman_Core_DataObjects_Core_group extends DB_DataObject
             $roo->jok('updated');
 
         }
+        if (isset($q['display_name']) && !isset($q['name']) && !$this->is_system) {
+            $this->name = $q['display_name'];
+        }
 
     }
+    
+    function beforeUpdate($old, $q,$roo)
+    {
+        if (isset($q['display_name']) && empty($q['name']) && !$this->is_system) {
+            $this->name = $q['display_name'];
+        }
+    }
 
 
     function beforeDelete()
@@ -216,12 +231,16 @@ class Pman_Core_DataObjects_Core_group extends DB_DataObject
         }
     }
 
-    function removeMember($person)
+    function removeMember($person, $roo)
     {
         $gm = DB_Dataobject::factory('core_group_member');
         $gm->group_id = $this->id;
         $gm->user_id = is_object($person) ? $person->id : $person;
-
+        $au = $roo->getAuthUser();
+        if ($gm->group()->name == 'Administrators' && $gm->user_id = $au->id) {
+            $roo->jerr("You can not remove yourself from the admin group");
+        }
+        
         if ($gm->find(true)) {
             $gm->delete();
         }
index ecbb2db..a652273 100755 (executable)
@@ -42,6 +42,14 @@ class Pman_Core_DataObjects_Core_group_member extends DB_DataObject
         
     }
     
+    function group()
+    {
+        $grp = DB_DataObject::factory('core_group');
+        $grp->get($this->group_id);
+        return $grp;
+        
+    }
+    
     /**
      * Get a list of memberships for a person
      * @param Pman_Core_DataObjects_Person $person who
@@ -88,7 +96,9 @@ class Pman_Core_DataObjects_Core_group_member extends DB_DataObject
     
     function checkPerm($lvl, $au) 
     {
-        return false;
+        // not sure if this is correct - but we need it on texon
+        return  $au->hasPerm("Core.Staff", $lvl);
+    
     }
     
 }
index b453133..cd26445 100644 (file)
@@ -20,9 +20,26 @@ class Pman_Core_DataObjects_Core_holiday extends DB_DataObject
     
     
     static $map = array(
-        'hk' => 'http://www.1823.gov.hk/common/ical/gc/en.ics'
+        'hk' => 'http://www.1823.gov.hk/common/ical/gc/en.ics',
+        'cny' => 'https://raw.githubusercontent.com/andrewlkho/cny.ics/master/cny.ics', // CNY
     );
     
+    
+    function applyFilters($q, $au, $roo)
+    {
+        if (isset($q['date_from'])) {
+            $dt = date("Y-m-d",strtotime($q['date_from']));
+            $this->whereAdd("holiday_date > '$dt'");
+        }
+        if (isset($q['date_to'])) {
+            $dt = date("Y-m-d",strtotime($q['date_to']));
+            $this->whereAdd("holiday_date < '$dt'");
+        }
+        
+        
+    }
+    
+    
      
     function updateHolidays($country)
     {
@@ -43,7 +60,14 @@ class Pman_Core_DataObjects_Core_holiday extends DB_DataObject
         
         
         
-        $data = file_get_contents("http://www.1823.gov.hk/common/ical/gc/en.ics");
+        $data = file_get_contents("https://www.1823.gov.hk/common/ical/gc/en.ics", false,
+            stream_context_create(array(
+                "ssl"=>array(
+                    "verify_peer"=>false,
+                    "verify_peer_name"=>false,
+                ),
+            ))
+        );
         
         $vevents = explode('BEGIN:VEVENT', $data);
         
@@ -65,13 +89,15 @@ class Pman_Core_DataObjects_Core_holiday extends DB_DataObject
                     $fmt = substr($matches[1], 0, 4) . "-" . substr($matches[1], 4, 2) . "-" . substr($matches[1], 6, 2);
                     $end_dt = date('Y-m-d', strtotime($fmt));
                 }
-                
+                if(preg_match('/^SUMMARY[^:]*:(.*)/', $line, $matches)){
+                    $name = trim($matches[1]);
+                }
             }
             
             if(empty($start_dt) || empty($end_dt)){
                 continue;
             }
-            
+            //DB_DataObject::DebugLevel(1);
             //var_dump($start_dt); var_dump($end_dt); exit;
             
             for ($i = strtotime($start_dt); $i < strtotime($end_dt) ; $i += (60 * 60 * 24)) {
@@ -81,7 +107,13 @@ class Pman_Core_DataObjects_Core_holiday extends DB_DataObject
                 $d->holiday_date = date('Y-m-d', $i);
                 if (!$d->count()) {
                     $d->insert();
-                }
+                } else {
+                    $d->find(true);
+                    $dd = clone($d);
+                    $d->name = $name;
+                    $d->update($dd);
+                 }
                 
                 
             }
index 2cc4a12..2570c86 100644 (file)
@@ -43,8 +43,8 @@ class Pman_Core_DataObjects_Core_notify extends DB_DataObject
     public $evtype;                         // event type (or method to call)fall
     public $act_start;
     public $person_table;
-
-
+    public $to_email;
     /* the code above is auto generated do not remove the tag below */
     ###END_AUTOCODE
     
@@ -237,6 +237,11 @@ class Pman_Core_DataObjects_Core_notify extends DB_DataObject
     
     function applyFilters($q, $au, $roo)
     {
+        
+        if (!empty($q['search']['contains'])) {
+            $this->whereAdd("join_event_id_id.remarks LIKE '%".$this->escape($q['search']['contains']) ."%'");
+            
+        }
         if (isset($q['ontable']) && !in_array($q['ontable'], array('Person', 'Events',  'core_watch'))) {
             // this will only work on tables not joined to ours.
             
@@ -274,6 +279,7 @@ class Pman_Core_DataObjects_Core_notify extends DB_DataObject
                     break;
                 case 'PENDING';
                     $this->whereAdd('event_id = 0 OR (event_id  > 0 AND act_when > NOW() )');
+                    $this->whereAdd("sent < '2000-01-01'");
                     break;
                 
                 case 'OPENED';
@@ -339,5 +345,24 @@ class Pman_Core_DataObjects_Core_notify extends DB_DataObject
         
         return true;
     }
+    // after called do not rely on content as it includes NOW()
+    function flagDone($event,$msgid)
+    {
+        $ww = clone($this);
+        if(strtotime($this->act_when) > strtotime("NOW")){
+            $this->act_when = $this->sqlValue('NOW()');
+        }
+        $this->sent = empty($this->sent) || strtotime($this->sent) < 1 ? $this->sqlValue('NOW()') :$this->sent; // do not update if sent.....
+        $this->msgid = $msgid;
+        $this->event_id = $event->id;
+        $this->update($ww);
+    }
+    
+    function flagLater($when)
+    {
+        $ww = clone($this);
+        $this->act_when = $when;
+        $this->update($ww);
+    }
     
 }
diff --git a/DataObjects/Core_notify_blacklist.php b/DataObjects/Core_notify_blacklist.php
new file mode 100644 (file)
index 0000000..305f0af
--- /dev/null
@@ -0,0 +1,73 @@
+<?php
+/**
+ * Table Definition for core_notify_blacklist
+ */
+class_exists('DB_DataObject') ? '' : require_once 'DB/DataObject.php';
+
+class Pman_Core_DataObjects_Core_notify_blacklist extends DB_DataObject 
+{
+    ###START_AUTOCODE
+    /* the code below is auto generated do not remove the above tag */
+
+    public $__table = 'core_notify_blacklist';    // table name
+    public $id;                              // int(11)  not_null primary_key auto_increment
+    public $server_id;
+    public $domain_id;
+    public $error_msg;
+    public $added_dt;
+    
+    
+    function messageIsBlacklisted($err)
+    {
+        $match = array(
+            '5.7.0 DT:SPM', // 163.com
+            '5.7.1 H:DYNB', // some other black list
+            'on our block list',  // live.com
+            'spameatingmonkey.net', // spameatingmonkey.net (users)
+            'sender is listed on the block', // korian?
+            'proofpoint.com', // another spam detecotr
+            'cloud-security.net', // another spam protector..
+            'spam complain',
+            'ANTISPAM',
+            'probability of spam',
+            'block list by spam', // spamhaus
+            'blocked using Spamhaus',
+            'spamhaus.org',  // www zen rbl...
+            'detected as Spam',
+            'poor reputation',
+            'AntiSpam',
+            'ip address in rbl',
+            'blacklisted',
+            'spamauditor.org',
+            'detect spam',
+            'message as spam',
+            'DNSBL:RBL',
+            'SpamHaus SBL-XBL',
+            'blocked by sbl-xbl.spam',
+            'Sophos Anti Spam Engine',
+            'spam filters',
+            'JunkMail',
+            'block list',
+            'Cloudmark Sender Intelligence',
+            'Blocked by CSI',
+            
+            
+        );
+        foreach($match as $str) {
+            if (strpos($err, $str) !== false) {
+                return true;
+            }
+        }
+        return false;
+    }
+    
+    // delete blacklists older than 1 week (and try again)
+    function prune()
+    {
+        $this->query("
+            DELETE FROM {$this->tableName()} where added_dt < NOW()  - INTERVAL 1 WEEK
+        ");
+            
+    }
+    
+}
\ No newline at end of file
diff --git a/DataObjects/Core_notify_sender.php b/DataObjects/Core_notify_sender.php
new file mode 100644 (file)
index 0000000..881902c
--- /dev/null
@@ -0,0 +1,136 @@
+<?php
+/**
+ * Table Definition for core_notify_sender
+ */
+class_exists('DB_DataObject') ? '' : require_once 'DB/DataObject.php';
+
+class Pman_Core_DataObjects_Core_notify_sender extends DB_DataObject 
+{
+    ###START_AUTOCODE
+    /* the code below is auto generated do not remove the above tag */
+
+    public $__table = 'core_notify_sender';    // table name
+    public $id;                              // int(11)  not_null primary_key auto_increment
+    public $email;
+    public $poolname;
+    public $is_active;
+    public $priority;
+    
+    
+    
+    function emailAddrToSender($from_addr , $notify)
+    {
+        
+        $from = $from_addr->mailbox . '@' . $from_addr->host;
+
+        $ns = DB_DataObject::Factory($this->tableName());
+        $ns->setFrom(array(
+            'email' => $from,
+            'poolname' => $notify->tableName()
+        ));
+        if (!$ns->find(true)) {
+            $ns->is_active = 1;
+            $ns->priority = 1;
+            $ns->insert();
+            return false;
+        }
+        return $ns;
+    }
+    
+    
+    function emailToAddr($email)
+    {
+        require_once 'Mail/RFC822.php';
+        $parser = new Mail_RFC822();
+        $addresses = $parser->parseAddressList( $email['headers']['From'], 'localhost', false);
+        if (is_a($addresses, 'PEAR_Error')) {
+            return false;
+        }
+        return $addresses[0];
+        //print_r($email['headers']['From']);         print_R($from_addr);exit;
+
+      
+    }
+    
+    
+    function filterEmail($email, $notify)
+    {
+        //
+        if (empty($email['headers']['From']) || empty($notify)) {
+            return $email;
+        }
+        $bits = explode('@', $notify->to_email);
+        $to_dom = DB_DataObject::factory('core_domain')->loadOrCreate($bits[1]);
+        
+        $from_addr = $this->emailToAddr($email);
+        
+        $ns = $this->emailAddrToSender($from_addr, $notify);
+        if ($ns == false) {
+            return $email;
+        }
+        // is it blacklisted?
+        $bl = DB_DAtaObject::Factory('core_notify_sender_blacklist');
+        $bl->setFrom(array(
+                'sender_id'=> $ns->id,
+                'domain_id' => $to_dom->id
+        ));
+        if (!$bl->count()) {
+            return $email;
+        }
+        // it's blacklisted..
+        // try finding alternative.
+        $bl = DB_DAtaObject::Factory('core_notify_sender_blacklist');
+        $bl->domain_id = $to_dom->id;
+        $bad_ids = $bl->fetchAll('sender_id');
+        
+        $ns = DB_DataObject::Factory($this->tableName());
+        $ns->setFrom(array(
+             'poolname' => $notify->tableName(),
+            'is_active' => 1,
+        ));
+        $ns->whereAddIn('!id', $bad_ids, 'int');
+        if (!$ns->count()){
+            return $email; // no alternative available
+        }
+        $ns->limit(1);
+        $ns->find(true);
+        $email['headers']['From'] = $from_addr->personal . ' <' . $ns->email .'>';
+        
+        return $email;
+        
+        //check blacklist for 
+        
+         
+        
+    }
+    
+    function checkSmtpResponse($email, $notify, $errmsg)
+    {
+        $bl = DB_DataObject::factory('core_notify_sender_blacklist');
+        if (!$bl->messageIsBlacklisted($errmsg)) {
+            return; // ok.
+        }
+        // create a record.
+        
+        $bits = explode('@', $notify->to_email);
+        $to_dom = DB_DataObject::factory('core_domain')->loadOrCreate($bits[1]);
+        
+        
+        
+        $from_addr = $this->emailToAddr($email);
+        $ns = $this->emailAddrToSender($from_addr, $notify);
+      
+        $bl->setFrom(array(
+            'sender_id' => $ns->id,
+            'domain_id' => $to_dom->id,
+        ));
+        if ($bl->count()) {
+            return;
+        }
+        $bl->error_str = $errmsg;
+        $bl->added_dt = $bl->sqlValue('NOW()');
+        $bl->insert();
+        
+    }
+    
+}
\ No newline at end of file
diff --git a/DataObjects/Core_notify_sender_blacklist.php b/DataObjects/Core_notify_sender_blacklist.php
new file mode 100644 (file)
index 0000000..7ada643
--- /dev/null
@@ -0,0 +1,43 @@
+<?php
+/**
+ * Table Definition for core_notify_sender_blacklist
+ */
+class_exists('DB_DataObject') ? '' : require_once 'DB/DataObject.php';
+
+class Pman_Core_DataObjects_Core_notify_sender_blacklist extends DB_DataObject 
+{
+    ###START_AUTOCODE
+    /* the code below is auto generated do not remove the above tag */
+
+    public $__table = 'core_notify_sender_blacklist';    // table name
+    public $id;                              // int(11)  not_null primary_key auto_increment
+    public $sender_id;
+    public $domain_id;
+    public $error_msg;
+    public $added_dt;
+     
+    function messageIsBlacklisted($err)
+    {
+        $match = array(
+            'BLOCK-SEND-ER',
+            'sender is listed on the block mail', // 'sniper?
+            'sender is in my black list',
+        );
+        foreach($match as $str) {
+            if (strpos($err, $str) !== false) {
+                return true;
+            }
+        }
+        return false;
+    }
+    
+    // delete blacklists older than 1 week (and try again)
+    function prune()
+    {
+        $this->query("
+            DELETE FROM {$this->tableName()} where added_dt < NOW()  - INTERVAL 1 WEEK
+        ");
+            
+    }
+    
+}
\ No newline at end of file
diff --git a/DataObjects/Core_notify_server.php b/DataObjects/Core_notify_server.php
new file mode 100644 (file)
index 0000000..33b73d1
--- /dev/null
@@ -0,0 +1,384 @@
+<?php
+/**
+ * Table Definition for core_notify_server
+ */
+class_exists('DB_DataObject') ? '' : require_once 'DB/DataObject.php';
+
+class Pman_Core_DataObjects_Core_notify_server extends DB_DataObject 
+{
+    ###START_AUTOCODE
+    /* the code below is auto generated do not remove the above tag */
+
+    public $__table = 'core_notify_server';    // table name
+    public $id;                              // int(11)  not_null primary_key auto_increment
+    public $hostname;
+    public $helo;
+    public $poolname;
+    public $is_active;
+    public $last_send;
+    
+    
+    
+    function  applyFilters($q, $au, $roo)
+    {
+        if (isset($q['_with_queue_size'])) {
+            $this->addQueueSize();
+        }
+    }
+    
+    
+    function addQueueSize()
+    {
+        // look for database links for server_id (which should find core_notify + others..)
+        $cn = get_class(DB_DataObject::factory('core_notify'));
+        $tables = array();
+        foreach($this->databaseLinks() as $tbl => $kv) {
+            foreach($kv as $k=>$v) {
+                if ($v != 'core_notify_server:id') {
+                    continue;
+                }
+                
+                $test = DB_DAtaObject::factory($tbl);
+                if (!is_a($test, $cn)) {
+                    break;
+                }
+                $tables[] = $tbl;
+            }
+        }
+        if (empty($tables)) {
+            die("OOPS - no tables for notify_server references");
+        }
+        $totals = array();
+        foreach($tables as $t) {
+            $totals[] = "
+                COALESCE((SELECT
+                    count(id)
+                FROM
+                    $t
+                WHERE
+                    server_id = core_notify_server.id
+                AND
+                    sent < '1970-01-01' OR sent IS NULL
+                 and
+                        event_id = 0
+                ),0)
+            ";
+        }
+        $this->selectAdd("(" . implode(" + ", $totals) . ") as in_queue ");
+        
+        
+        
+        
+        
+    }
+    
+    
+    // most services should call this first..
+    
+    function getCurrent($notify, $force = false)
+    {
+        static $current = false;;
+        
+        if ($current !== false) {
+            return $current;
+        }
+        
+        $ns = DB_DataObject::factory('core_notify_server');
+        if (!$ns->count()) {
+            $ns->id = 0;
+            return $ns;
+        }
+        
+        
+        $ns->poolname = $notify->poolname;
+        $ns->is_active = 1;
+        $ns->hostname = gethostname();
+        $ns->limit(1);
+        if ($ns->find(true)) {
+            $current = $ns;
+            return $ns;
+        }
+        if (!$force) {
+            $notify->jerr("Server not found for this server " .  gethostname() . " in core_notify_server" );
+        }
+        // fallback to any server - if we are using force. (this is so helo will work...)
+        
+        $ns = DB_DataObject::factory('core_notify_server');
+        $ns->is_active = 1;
+        $ns->hostname = gethostname();
+        if (!$ns->find(true)) {
+            $notify->jerr("Server not found for this server " .  gethostname() . " in core_notify_server" );
+        }
+        $current = $ns;
+        return $ns;
+    }
+    
+    
+    function isFirstServer()
+    {
+        if (!$this->id) {
+            return true;
+        }
+        
+        $servers = $this->availableServers();
+        if (empty($servers)) {
+            return false;
+        }
+        // only run this on the first server...
+        return $this->id == $servers[0]->id;
+    }
+    
+    
+    // called on current server.
+    function assignQueues($notify)
+    {
+        if (!$this->id) {
+            return true;
+        }
+        
+        $servers = $this->availableServers();
+        $ids = array();
+        $up = array();
+        foreach($servers as $s) {
+            $ids[] = $s->id;
+        }
+        
+        
+        if (empty($ids)) {
+            $notify->jerr("no configured servers in core_notify_server for poolname = {$notify->poolname}");
+            
+        }
+         
+        // only run this on the first server...
+        if ($this->id != $ids[0]) {
+            return; 
+        }
+        foreach($ids as $rn) {
+            $up[$rn]  = array();
+        }
+        
+        $num_servers = count($ids);
+        
+        if ($num_servers == 1) {
+            $p = DB_DataObject::factory($notify->table);
+            $p->query("
+                UPDATE
+                    {$notify->table}
+                SET
+                    server_id = {$ids[0]}
+                WHERE
+                    sent < '2000-01-01'
+                    and
+                    event_id = 0
+                    and
+                    act_start < NOW() +  INTERVAL 3 HOUR 
+                    and
+                    server_id != {$ids[0]}
+            ");
+            return;
+        }
+        
+        
+        
+        $p = DB_DataObject::factory($notify->table);
+        $p->whereAdd("
+                sent < '2000-01-01'
+                and
+                event_id = 0
+                and
+                act_start < NOW() +  INTERVAL 3 HOUR 
+                and
+                server_id NOT IN (" . implode(",", $ids) . ")
+        ");
+        $p->orderBy('act_when asc'); //?
+        $total_add = $p->count();
+        if ($total_add < 1) {
+            return;
+        }
+        
+        $to_add = $p->fetchAll('id');
+        
+        $p = DB_DataObject::factory($notify->table);
+        $p->whereAdd("
+                sent < '2000-01-01'
+                and
+                event_id = 0
+        
+                and
+                server_id IN (" . implode(",", $ids) . ")
+        ");
+        $p->selectAdd();
+        $p->selectAdd('server_id, count(id) as  n');
+        $p->groupBy('server_id');
+        $in_q = $p->fetchAll('server_id', 'n');
+        
+        // if queue is empty it will not get allocated anything.
+        foreach($ids as $sid) {
+            if (!isset($in_q[$sid])) {
+                $in_q[$sid] = 0;
+            }
+        }
+        $totalq = 0;
+        foreach($in_q as $sid => $n) {
+            $totalq += $n;
+        }
+        
+        
+        // new average queue
+        $target_len = floor(  ($totalq + $total_add) / $num_servers );
+        
+        foreach($in_q as $sid => $cq) {
+            if ( $cq > $target_len) {
+                continue;
+            }
+            $up[ $sid ] = array_slice($to_add, 0, $target_len - $cq);
+        }
+        
+        // add the reminder evently
+        foreach($to_add as $n=>$i) {
+            
+            $up[  $ids[$n % $num_servers] ][] = $i;
+        }
+        
+        // distribution needs to go to ones that have the shortest queues. - so to balance out the queues
+        
+         
+        
+        foreach($up as $sid => $nids) {
+            if (empty($nids)) {
+                continue;
+            }
+            $p = DB_DataObject::factory($notify->table);
+            $p->query("
+                UPDATE
+                    {$notify->table}
+                SET
+                    server_id = $sid
+                WHERE
+                    id IN (". implode(',', $nids). ')'
+            );
+        }
+         
+        DB_DataObject::factory("core_notify_blacklist")->prune();
+        
+    }
+        // called on current server.
+
+    function availableServers()
+    {
+        $ns = DB_DataObject::factory('core_notify_server');
+        $ns->poolname = $this->poolname;
+        $ns->is_active = 1;
+        $ns->orderBy('id ASC');
+        return  $ns->fetchAll();
+        
+    }
+    
+    function updateNotifyToNextServer( $cn , $when = false, $allow_same = false)
+    {
+        if (!$this->id) {
+            return;
+        }
+        
+        // fixme - this should take into account blacklisted - and return false if no more servers are available
+        $email = empty($cn->to_email) ? ($cn->person() ? $cn->person()->email : $cn->to_email) : $cn->to_email;
+
+        $w = DB_DataObject::factory($cn->tableName());
+        $w->get($cn->id);
+        
+        $servers = $this->availableServers();
+        $start = 0;
+        foreach($servers as $i => $s) {
+            if ($s->id == $this->id) {
+                $start = $i;
+            }
+        }
+        
+        $offset = ($start + 1)  % count($servers);
+        $good = false;
+        while ($offset  != $start) {
+            $s = $servers[$offset];
+            if (!$s->isBlacklisted($email)) {
+                $good = $s;
+                break;
+            }
+            $offset = ($offset + 1)  % count($servers);
+            var_dump($offset);
+        }
+        if ($good == false && $allow_same) {
+            $good = $this;
+        }
+        
+        if ($good == false) {
+            return false;
+        }
+        
+        
+        // next server..
+        $pp = clone($w);
+        $w->server_id = $good->id;   
+        $w->act_when = $when === false ? $w->sqlValue('NOW() + INTERVAL 1 MINUTE') : $when;
+        $w->update($pp);
+        return true;
+    }
+    
+    
+    function isBlacklisted($email)
+    {
+        if (!$this->id) {
+            return false;
+        }
+        
+        // return current server id..
+        static $cache = array();
+         // get the domain..
+        $ea = explode('@',$email);
+        $dom = strtolower(array_pop($ea));
+        if (isset( $cache[$this->id . '-'. $dom])) {
+            return  $cache[$this->id . '-'. $dom];
+        }
+        
+        $cd = DB_DataObject::factory('core_domain')->loadOrCreate($dom);
+        
+        $bl = DB_DataObject::factory('core_notify_blacklist');
+        $bl->server_id = $this->id;
+        $bl->domain_id = $cd->id;
+        if ($bl->count()) {
+            $cache[$this->id . '-'. $dom] = true;
+            return true;
+        }
+        
+        return false; 
+    }
+    function initHelo()
+    {
+        if (!$this->id) {
+            return;
+        }
+        $ff = HTML_FlexyFramework::get();
+        $ff->Mail['helo'] = $this->helo;
+        
+    }
+    function checkSmtpResponse($errmsg, $core_domain)
+    {
+        if (!$this->id) {
+            return false;
+        }
+        $bl = DB_DataObject::factory('core_notify_blacklist');
+        $bl->server_id = $this->id;
+        $bl->domain_id = $core_domain->id;
+        if ($bl->count()) {
+            return true;
+        }
+        // is it a blacklist message
+        if (!$bl->messageIsBlacklisted($errmsg)) {
+            return false;
+        }
+        $bl->error_str = $errmsg;
+        $bl->added_dt = $bl->sqlValue("NOW()");
+        $bl->insert();
+        return true;
+        
+    }
+    
+}
\ No newline at end of file
index b45eef4..4208198 100644 (file)
@@ -48,6 +48,8 @@ class Pman_Core_DataObjects_Core_person extends DB_DataObject
     public $phone_direct; // varchar(32)  NOT NULL  DEFAULT '';
     public $countries; // VARCHAR(128) NULL;
     
+    public $language;
+    
     /* the code above is auto generated do not remove the tag below */
     ###END_AUTOCODE
     
@@ -252,11 +254,14 @@ class Pman_Core_DataObjects_Core_person extends DB_DataObject
     function isAuth()
     {
         // do not start a session if we are using http auth...
-        if (empty($_SERVER['PHP_AUTH_USER']) && php_sapi_name() != "cli") {
-            @session_start();
-        }
-       
+        // we have a situation where the app is behind a http access and is also login
+        // need to work out a way to handle that.
         $ff= HTML_FlexyFramework::get();
+        if (php_sapi_name() != "cli" && (empty($_SERVER['PHP_AUTH_USER']) || !empty($ff->disable_http_auth)))  {
+             @session_start();
+        }
+        
+         
        
         $sesPrefix = $this->sesPrefix();
         
@@ -278,14 +283,16 @@ class Pman_Core_DataObjects_Core_person extends DB_DataObject
             }
             unset($_SESSION[get_class($this)][$sesPrefix .'-auth']);
             unset($_SESSION[get_class($this)][$sesPrefix .'-timeout']);
-            setcookie('Pman.timeout', -1, time() + (30*60), '/');
+            //setcookie('Pman.timeout', -1, time() + (30*60), '/');
             return false;
         }
         
         // http basic auth..
         $u = DB_DataObject::factory($this->tableName());
         
-        if (!empty($_SERVER['PHP_AUTH_USER']) 
+        if (empty($ff->disable_http_auth)  // http auth requests should not have this...
+            &&
+            !empty($_SERVER['PHP_AUTH_USER']) 
             &&
             !empty($_SERVER['PHP_AUTH_PW'])
             &&
@@ -299,6 +306,10 @@ class Pman_Core_DataObjects_Core_person extends DB_DataObject
             self::$authUser = $u;
             return true; 
         }
+        
+        // at this point all http auth stuff is done, so we can init session
+        
+        
         //die("test init");
         if (!$this->canInitializeSystem()) {
           //  die("can not init");
@@ -334,7 +345,7 @@ class Pman_Core_DataObjects_Core_person extends DB_DataObject
         if (empty($_SERVER['PATH_INFO']) ||  $_SERVER['PATH_INFO'] == '/Login') {
             $auto_auth_allow  = false;
         }
-        //var_dump($auto_auth_allow);
+         //var_dump($auto_auth_allow);
         // local auth - 
         $default_admin = false;
         if ($auto_auth_allow) {
@@ -384,6 +395,9 @@ class Pman_Core_DataObjects_Core_person extends DB_DataObject
         $u = DB_DataObject::factory($this->tableName());
         $u->whereAdd(' LENGTH(passwd) > 0');
         $n = $u->count();
+        if (empty($_SESSION[get_class($this)]) || !is_array($_SESSION[get_class($this)])) { 
+            $_SESSION[get_class($this)] = array();
+        }
         $_SESSION[get_class($this)][$sesPrefix .'-empty']  = $n;
         if (class_exists('PEAR')) {
             $error =  PEAR::getStaticProperty('DB_DataObject','lastError');
@@ -420,7 +434,7 @@ class Pman_Core_DataObjects_Core_person extends DB_DataObject
              
             if (isset($_SESSION[get_class($this)][$sesPrefix .'-auth'])) {
                 $_SESSION[get_class($this)][$sesPrefix .'-auth-timeout'] = time() + (30*60); // eg. 30 minutes
-                setcookie('Pman.timeout', time() + (30*60), time() + (30*60), '/');
+                //setcookie('Pman.timeout', time() + (30*60), time() + (30*60), '/');
             }
             // not really sure why it's cloned..
             return   clone (self::$authUser);
@@ -500,7 +514,7 @@ class Pman_Core_DataObjects_Core_person extends DB_DataObject
         $d = $p->toArray();
         
         $_SESSION[get_class($this)][$sesPrefix .'-auth-timeout'] = time() + (30*60); // eg. 30 minutes
-        setcookie('Pman.timeout', time() + (30*60), time() + (30*60), '/');
+        //setcookie('Pman.timeout', time() + (30*60), time() + (30*60), '/');
         
         //var_dump(array(get_class($this),$sesPrefix .'-auth'));
         $_SESSION[get_class($this)][$sesPrefix .'-auth'] = serialize((object)$d);
@@ -520,11 +534,8 @@ class Pman_Core_DataObjects_Core_person extends DB_DataObject
         $this->isAuth(); // force session start..
         
         $sesPrefix = $this->sesPrefix();
-        
         $_SESSION[get_class($this)][$sesPrefix .'-auth-timeout'] = -1;
-        
         $_SESSION[get_class($this)][$sesPrefix .'-auth'] = "";
-        
         self::$authUser = false;
         
     }    
@@ -692,6 +703,9 @@ class Pman_Core_DataObjects_Core_person extends DB_DataObject
         $uu = clone($this);
         $this->lang = $val;
         $this->update($uu);
+        if(!empty(self::$authUser) && self::$authUser->id == $this->id) {
+            self::$authUser->lang = $this->lang;
+        }
         return $this->lang;
     }
             
@@ -753,18 +767,28 @@ class Pman_Core_DataObjects_Core_person extends DB_DataObject
         $oath_require = $s->lookup('core', 'two_factor_auth_required');
         $aur['require_oath'] = $oath_require ?  $oath_require->val : 0;
         
-        $aur['core_person_settings'] = array();
-                
-        $core_person_settings = DB_DataObject::factory('core_person_settings');
-        $core_person_settings->setFrom(array(
-            'person_id' => $this->id
-        ));
-        
-        $aur['core_person_settings'] = $core_person_settings->fetchAll('scope', 'data');
+        $aur['core_person_settings'] = $this->settings();
         
         return $aur;
     }
     
+    function settings($return_obj = false)
+    {
+        $cs = DB_DataObject::factory('core_person_settings');
+        $cs->setFrom(array(
+            'person_id' => $this->id
+        ));
+        return $return_obj ? $cs->fetchAll() : $cs->fetchAll('scope', 'data');;
+    }
+    function toRooSingleArray($authUser, $request)  
+    {
+        $ret = $this->toArray();
+        foreach( $this->settings() as $k=>$v) {
+            $ret['core_person_settings['. $k .']'] = $v;
+        }
+    
+        return $ret;
+    }
     //   ----------PERMS------  ----------------
     function getPerms() 
     {
@@ -1004,11 +1028,30 @@ class Pman_Core_DataObjects_Core_person extends DB_DataObject
                 )"
             );
         }
+        if(!empty($q['in_group_starts'])){
+            
+            $v = $this->escape($q['in_group_starts']);
+            
+            $this->whereAdd("
+                $tn_p.id IN (
+                    SELECT 
+                        DISTINCT(user_id) FROM $tn_gm
+                    LEFT JOIN
+                        $tn_g
+                    ON
+                        $tn_g.id = $tn_gm.group_id
+                    WHERE 
+                        $tn_g.name LIKE '{$v}%'
+                )"
+            );
+        }
+        
+        
         
         // #2307 Search Country!!
         if (!empty($q['query']['in_country'])) {
             // DB_DataObject::debugLevel(1);
-            $inc = $q['query']['in_country'];
+            $inc = $this->escape($q['query']['in_country']);
             $this->whereAdd("$tn_p.countries LIKE '%{$inc}%'");
         }
         
@@ -1074,6 +1117,15 @@ class Pman_Core_DataObjects_Core_person extends DB_DataObject
                 {$this->tableName()}.name LIKE '%{$this->escape($q['query']['name'])}%'
             ");
         }
+        
+         if(!empty($q['query']['name_or_email'])){
+            $v = $this->escape($q['query']['name_or_email']);
+            $this->whereAdd("
+                {$this->tableName()}.name LIKE '%{$v}%'
+                OR
+                {$this->tableName()}.email LIKE '%{$v}%'
+            ");
+        }
          if(!empty($q['query']['name_starts'])){
             $this->whereAdd("
                 {$this->tableName()}.name LIKE '{$this->escape($q['query']['name_starts'])}%'
@@ -1153,7 +1205,7 @@ class Pman_Core_DataObjects_Core_person extends DB_DataObject
             
             if (!$roo->hasPerm('Core.Projects_All', 'S')) {
                 $peps = $p->people($pids);
-                $this->whereAddIn("{$tn}.id", $peps, 'int');
+                $this->whereAddIn("{$this->tableName()}.id", $peps, 'int');
             }
         }    
         
@@ -1203,7 +1255,7 @@ class Pman_Core_DataObjects_Core_person extends DB_DataObject
             
             COALESCE((
                 SELECT
-                    GROUP_CONCAT(  core_group.name separator  '\n')
+                    GROUP_CONCAT(  CASE WHEN core_group.display_name = '' THEN core_group.name ELSE core_group.display_name  END  separator  '\n')
                 FROM
                     core_group_member
                 LEFT JOIN
@@ -1212,6 +1264,8 @@ class Pman_Core_DataObjects_Core_person extends DB_DataObject
                     core_group.id = core_group_member.group_id
                 WHERE
                     core_group_member.user_id = core_person.id
+                ORDER BY
+                    core_group.display_name ASC
             ), '')  as member_of");
     }
     
@@ -1331,10 +1385,18 @@ class Pman_Core_DataObjects_Core_person extends DB_DataObject
         // determine if it's staff!!!
         $owncomp = DB_DataObject::Factory('core_company');
         $owncomp->get('comptype', 'OWNER');
-        $isStaff = ($au->company_id ==  $owncomp->id);
-       
+        $editor_is_staff = ($au->company_id ==  $owncomp->id);
+        
+        if (!$editor_is_staff) {
+            // non staff editing should not user roo/isPerm?
+            return false; // no permission if user is not staff!?
+        
+        }
+        
+        $this_is_staff = ($this->company_id ==  $owncomp->id);
        
-        if (!$isStaff) {
+       /*
+        if (!$this_is_staff ) {
             
             // - can not change company!!!
             if ($changes && 
@@ -1358,7 +1420,7 @@ class Pman_Core_DataObjects_Core_person extends DB_DataObject
             
             //return $this->company_id == $au->company_id;
         }
-        
+        */
          
         // yes, only owner company can mess with this...
         
@@ -1369,11 +1431,13 @@ class Pman_Core_DataObjects_Core_person extends DB_DataObject
             // extra case change passwod?
             case 'P': //??? password
                 // standard perms -- for editing + if the user is dowing them selves..
-                $ret = $isStaff ? $au->hasPerm("Core.Staff", "E") : $au->hasPerm("Core.Person", "E");
-                return $ret || $au->id == $this->id;
+                $ret = $this_is_staff  ? $au->hasPerm("Core.Staff", "E") : $au->hasPerm("Core.Person", "E");
+                return $ret || $au->id == $this->id;   // can change own data?
             
             default:                
-                return $isStaff ? $au->hasPerm("Core.Staff", $lvl) : $au->hasPerm("Core.Person", $lvl);
+                return $this_is_staff ? $au->hasPerm("Core.Staff", $lvl) : $au->hasPerm("Core.Person", $lvl);
+                
+                    
         
         }
         return false;
@@ -1381,8 +1445,20 @@ class Pman_Core_DataObjects_Core_person extends DB_DataObject
     
     function beforeInsert($req, $roo)
     {
+         if (!empty($req['_bulk_update_passwords'])) {
+            $this->bulkUpdatePasswords($req['_bulk_update_passwords'], $roo);
+            return;
+        }
+        
         $p = DB_DataObject::factory('core_person');
         if ($roo->authUser->id > -1 ||  $p->count() > 1) {
+            $pp = DB_DataObject::factory('core_person');
+            $pp->whereAdd('LOWER(email) = "' . $pp->escape(strtolower(trim($this->email))) . '"');
+            if ($pp->count()){
+                $roo->jerror("NOTICE-DUPE-EMAIL", "that email already exists in the database");
+            }
+            
+            
             return;
         }
         $c = DB_DataObject::Factory('core_company');
@@ -1395,6 +1471,11 @@ class Pman_Core_DataObjects_Core_person extends DB_DataObject
         $this->company_id = $c->id;
         $this->email = trim($this->email);
         
+        
+        
+        
+        
+        
     }
     
     function onInsert($req, $roo)
@@ -1428,9 +1509,45 @@ class Pman_Core_DataObjects_Core_person extends DB_DataObject
             $pd->company_id = $this->company_id;
             $pd->insert();
         }
-        
+        if (!empty($req['core_person_settings'])) {
+            $this->updateSettings($req['core_person_settings'], $roo);
+        }
     }
     
+    function onUpdate($old, $req,$roo, $event)
+    {
+        if (!empty($req['core_person_settings'])) {
+            $this->updateSettings($req['core_person_settings'], $roo);
+        }
+    }
+    
+    // there should really be a registry of valid scope values!?
+    function updateSettings($ar, $roo)
+    {
+        //DB_DataObject::debugLevel(1);
+        $old = array();
+        foreach($this->settings(true) as $o) {
+            $old[$o->scope] = $o;
+        }
+        foreach($ar as $k=>$v) {
+            if (isset($old[$k])) {
+                $oo = clone($old[$k]);
+                $old[$k]->data = $v;
+                $old[$k]->update($oo);
+                continue;
+            }
+            $cs = DB_DataObject::Factory('core_person_settings');
+            $cs->setFrom(array(
+                'person_id' =>$this->id,
+                'scope' => $k,
+                'data' => $v
+            ));
+            $cs->insert();
+        }
+        // we dont delete old stuff....
+    }
+    
+    
     function importFromArray($roo, $persons, $opts)
     {
         if (empty($opts['prefix'])) {
@@ -1507,9 +1624,7 @@ class Pman_Core_DataObjects_Core_person extends DB_DataObject
         $ff= HTML_FlexyFramework::get();
         
         $appname = empty($ff->appNameShort) ? $ff->project : $ff->project . '-' . $ff->appNameShort;
-        
         $dname = method_exists($this, 'getDatabaseConnection') ? $this->getDatabaseConnection()->dsn['database'] : $this->databaseNickname();
-        
         $sesPrefix = $appname.'-' .get_class($this) .'-' . $dname;
 
         return $sesPrefix;
@@ -1518,9 +1633,7 @@ class Pman_Core_DataObjects_Core_person extends DB_DataObject
     function loginPublic() // used where???
     {
         $this->isAuth(); // force session start..
-         
         $db = $this->getDatabaseConnection();
-        
         $ff = HTML_FlexyFramework::get();
         
         if(empty($ff->Pman) || empty($ff->Pman['login_public'])){
@@ -1540,6 +1653,16 @@ class Pman_Core_DataObjects_Core_person extends DB_DataObject
     function beforeUpdate($old, $q, $roo)
     {
         $this->email = trim($this->email);
+
+        $p = DB_DataObject::factory('core_person');
+        if ($roo->authUser->id > -1 ||  $p->count() > 1) {
+            $pp = DB_DataObject::factory('core_person');
+            $pp->whereAdd('LOWER(email) = "' . $pp->escape(strtolower(trim($this->email))) . '"');
+            $pp->whereAdd('id != ' . $old->id);
+            if ($pp->count()){
+                $roo->jerror("NOTICE-DUPE-EMAIL", "that email already exists in the database");
+            }
+        }
     }
     
     function generateOathKey()
@@ -1606,6 +1729,62 @@ class Pman_Core_DataObjects_Core_person extends DB_DataObject
         
         return $content;
     }
-    
+    function bulkUpdatePasswords($data, $roo)
+    {
+        
+        if ( !$roo->hasPerm("Core.Staff", "E")) {
+            $roo->jerr("permission denied");
+        }
+        $rows = explode("\n",$data);
+        $upd = array();
+        $bad  = array();
+        
+        foreach($rows  as $i=>$row) {
+            if (!strlen(trim($row))) {
+                continue;
+            }
+            $bits = preg_split('/\s+/', trim($row));
+            if (count($bits) != 2) {
+                $bad[] = "Invalid line: {$row}";
+                continue;
+            }
+            // validate.
+            $upd[strtolower($bits[0])] = $bits[1];
+            
+        }
+        if (empty($upd)) {
+            
+            $roo->jerr(empty($bad) ? "No rows to update": ("ERRORS: ". implode("\n", $bad)));
+            return;
+        }
+        // next fetch them all.
+        $p = DB_DataObject::factory('core_person');
+        $p->whereAddIn('email', array_keys($upd), 'string');
+        foreach($p->fetchAll() as $p) {
+            $map[strtolower($p->email)] = $p;
+        }
+        foreach($upd as $k=>$nv) {
+            if (!isset($map[$k])) {
+                $bad[] = "Missing account with email: " . $k;
+                continue;
+            }
+            if ($map[$k]->id == $roo->authUser->id) {
+                $bad[] = "You can not update your own password here: " . $k;
+                continue;
+            }
+        }
+        if (!empty($bad)) {
+            $roo->jerr("ERRORS: ". implode("\n", $bad));
+            return;
+        }
+        foreach($map as $k => $p) {
+            $pp = clone($p);
+            $p->setPassword($upd[$k]);
+            $p->update($pp);
+        }
+        $roo->jok("Updated");
+        
+        
+    }
     
  }
index 3611b98..5cc1f55 100644 (file)
@@ -27,6 +27,8 @@ class Pman_Core_DataObjects_Core_project extends DB_DataObject
     public $languages;                       // string(128)  not_null
     public $agency_id;                       // int(11)  not_null
     public $updated_dt;                      // datetime(19)  not_null binary
+    public $deleted_by;                      // INT
+    public $deleted_dt;                      // datetime(19)  not_null binary
 
     
     /* the code above is auto generated do not remove the tag below */
@@ -89,7 +91,10 @@ class Pman_Core_DataObjects_Core_project extends DB_DataObject
     
     function applyFilters($q, $au, $roo)
     {
-         
+        if (empty($q['_show_deleted']) && empty($q['_is_update_request'])) {
+            $this->whereAdd('core_project.deleted_by = 0');
+        }
+        
         $tn = $this->tableName();
         if (!empty($q['query']['project_search'])) {
             $s = $this->escape($q['query']['project_search']);
@@ -130,7 +135,7 @@ class Pman_Core_DataObjects_Core_project extends DB_DataObject
         
         //&& $au->hasPerm('Documents.Documents','S') << this is dependant on the doc modules
           
-        if (!$au->hasPerm('Core.Projects_All','S') ) {
+        if (php_sapi_name() != 'cli' && !$au->hasPerm('Core.Projects_All','S') ) {
             
             
             
@@ -174,8 +179,22 @@ class Pman_Core_DataObjects_Core_project extends DB_DataObject
         
         
     }
+    
+    function beforeUpdate($old, $q, $roo)
+    {
+        if (!empty($q['_flag_deleted'])) {
+            //DB_DataObject::DebugLevel(1);
+            $this->deleted_by = $roo->getAuthUser()->id;
+            $this->deleted_dt = date("Y-m-d H:i:s");
+        }
+        if (!empty($q['_flag_undeleted'])) {
+            $this->deleted_by = 0;
+            $this->deleted_dt = '1000-01-01 00:00:00';
+        }
+    }
+    
  
-    function onInsert($request,$roo)
+    function onInsert($request,$roo,$event)
     {
         $oo = clone($this);
         if (empty($this->code)) {
@@ -186,7 +205,7 @@ class Pman_Core_DataObjects_Core_project extends DB_DataObject
         }
     }
     
-    function onUpdate($old, $request, $roo)
+    function onUpdate($old, $request, $roo,$event)
     {
         $oo = clone($this);
         if (empty($this->code)) {
@@ -321,4 +340,23 @@ class Pman_Core_DataObjects_Core_project extends DB_DataObject
         return $au->hasPerm("Core.Projects_Member_Of",$lvl) || $au->hasPerm("Core.Projects_All",$lvl);
     }
     
+    static $cache = array();
+    function cacheLoad($id)
+    {
+        if (isset(self::$cache[$id])) {
+            return self::$cache[$id];
+        }
+        $n = $this->factorySelf();
+        $n->get($id);
+        $n->cacheSave();
+        return $n;
+    }
+    
+    function cacheSave()
+    {
+        self::$cache[$this->id] = $this;
+    }
+    
+    
+    
 }
diff --git a/DataObjects/Core_project_group.php b/DataObjects/Core_project_group.php
new file mode 100644 (file)
index 0000000..99a52cc
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+/**
+ */
+class_exists('DB_DataObject') ? '' : require_once 'DB/DataObject.php';
+
+class Pman_Core_DataObjects_Core_project_group extends DB_DataObject 
+{
+  
+    public $__table = 'core_project_group'; 
+    var $group_id; // int(11) default NULL default 0;
+    var $project_id;// int(11) default NULL default 0;
+
+}
\ No newline at end of file
index 97ec8bd..e1eea76 100644 (file)
@@ -55,7 +55,11 @@ class Pman_Core_DataObjects_Core_setting extends DB_DataObject
     
     function beforeInsert($q, $roo)
     {
-        exit;
+        if (isset($q['is_encrypt'])) {
+            $roo->jerr("no direct access for setting encrypted data at present?");
+        }
+        // we store column data in here now - so it has to be insertable.
+        //exit;
     }
     
     function getKeyDirectory()
index 03f9b97..e64c9a8 100644 (file)
@@ -58,10 +58,45 @@ class Pman_Core_DataObjects_Core_template  extends DB_DataObject
         
     }
     
+    function beforeUpdate($old, $q, $roo)
+    {
+        if (!empty($q['_rescan'])){
+            if ($this->filetype != 'html') {
+                $roo->jerr("can not update a php source file currently - TDOD");
+            }
+            $pg = HTML_FlexyFramework::get()->page;
+            
+            $this->syncTemplatePage(array(
+                'template_dir' => $pg->rootDir . '/'. str_replace('.', '/', $this->view_name). '/templates',
+                'template' => $this->template,
+                'base' => $this->view_name,
+                'force' => true
+            ));
+            // update the different langage versions of this page.
+            $x = DB_Dataobject::Factory('core_templatestr');
+            $x->selectAdd();
+            $x->selectAdd('distinct(lang) as lang');
+            $x->whereAdd("lang != ''");
+            $langs  = $x->fetchAll('lang');
+            foreach($langs as $l) {
+                $x = DB_Dataobject::Factory('core_templatestr');
+                $x->syncLang($l, $this->id);
+            }
+           
+            
+            $roo->jok("updated -" .  $this->template);
+        }
+    }
+   
+    
+    
+    
     /*
+     * USED? - this is in updateBJSTemplate ?
      * @param base (should be full path to template directory)
      * @param subdir = empty for top or subpath.
      */
+    /*
     function syncTemplateDir($base = false,  $subdir = '', $force = false)
     {
         echo "syncTemplateDir: $base , $subdir, $force \n";
@@ -153,15 +188,17 @@ class Pman_Core_DataObjects_Core_template  extends DB_DataObject
             }
         }
     }
-    
-    /* compile a html template
+    */
+    /* compile a html template  - called by UpdateBjsTemplates - scan Pman Templates
      *  
      *  @param template_dir  << the path to the template dir ... Pman/XXX/template ...
      *  @param template   << name of template used by name field)
      *  @param base  << view name (module ? + templates?)
+     *  @param force << optional - forces even if database is newer.
      *  
      *  
      */
+    
     function syncTemplatePage($pgdata)
     {
         //print_r($pgdata);
@@ -172,7 +209,7 @@ class Pman_Core_DataObjects_Core_template  extends DB_DataObject
         ini_set('memory_limit', '512M');
         
         //var_dump($n);
-        $n= $pgdata['template'];  // remove trailing slash..
+        $n = $pgdata['template'];  // remove trailing slash..
         
         $fopts = HTML_FlexyFramework::get()->HTML_Template_Flexy;
         $opts = HTML_FlexyFramework::get()->Pman_Core;
@@ -207,27 +244,31 @@ class Pman_Core_DataObjects_Core_template  extends DB_DataObject
        
         $tmpl->view_name = $pgdata['base'];
         if ($tmpl->get('template',  $pgdata['template'])) {
-            if (strtotime($tmpl->updated) >= filemtime($flexy->resolvePath ($pgdata['template']))) {
+            clearstatcache();
+            if (strtotime($tmpl->updated) >= filemtime($flexy->resolvePath ($pgdata['template']) . '/'. $pgdata['template'])) {
                 if ($tmpl->is_deleted != 0 ||  $tmpl->filetype != 'html') {
                     $oo = clone($tmpl);
                     $tmpl->is_deleted = 0;
                     $tmpl->filetype = 'html';
                     $tmpl->update($oo);
                 }
-                
-                
-                
-                return $tmpl;
+                if (empty($pgdata['force'])) {
+                  //  echo "SKIP NO UPDATE: " . $pgdata['template'] ."\n";
+                   // echo $flexy->resolvePath ($pgdata['template']).  ':'. $tmpl->updated  . ">=" .  date('Y-m-d H:i:s',filemtime($flexy->resolvePath ($pgdata['template']))) . "\n";
+                    return $tmpl;
+                }
             }
         }
         
-        
+        //die("got here");
         
         try {
             $r = $flexy->compile($pgdata['template']);
+           
+            
         } catch(Exception $e) {
             $old = clone($tmpl);
-            $tmpl->updated   = date('Y-m-d H:i:s',filemtime($flexy->resolvePath ($pgdata['template'])));
+            $tmpl->updated   = date('Y-m-d H:i:s',filemtime($flexy->resolvePath ($pgdata['template']) . '/'. $pgdata['template']));
             if ($tmpl->id) {
                 $tmpl->is_deleted = 0;
                 $tmpl->filetype = 'html';
@@ -238,15 +279,15 @@ class Pman_Core_DataObjects_Core_template  extends DB_DataObject
                 $tmpl->lang = 'en';
                 $tmpl->insert();
             }
-            
-            
+            //echo "SKIP: " . $pgdata['template'] ."\n";
+           //   echo "SKIP - exception\n"; print_r($e);
             return false;
         }
        
       
         if (is_a($r,'PEAR_Error')) {
-            
-           // echo $r->toString(). "\n";
+            //echo "SKIP: " . $pgdata['template'] ."\n";
+            //echo $r->toString(). "\n";
             return $r;
         }
           
@@ -262,7 +303,7 @@ class Pman_Core_DataObjects_Core_template  extends DB_DataObject
         
         $tmpl->view_name = $pgdata['base'];
         
-        
+        //echo $pgdata['template'] ."\n";
         if (!$tmpl->get('template',  $pgdata['template'])) {
             $tmpl->is_deleted = 0;
             $tmpl->filetype = 'html';
@@ -307,7 +348,14 @@ class Pman_Core_DataObjects_Core_template  extends DB_DataObject
         return clone($tmpl);
     
     }
-    function syncPhpGetText($pgdata)
+    
+    // allow reuse in cms templatstr
+    function factoryStr()
+    {
+        return DB_DataObject::factory('core_templatestr');
+    }
+
+    function syncFileWord($pgdata, $filetype)
     {
         $tmpl = DB_DataObject::Factory($this->tableName());
         $tmpl->view_name = $pgdata['base'];
@@ -315,73 +363,103 @@ class Pman_Core_DataObjects_Core_template  extends DB_DataObject
         
         if ($tmpl->get('template',  $pgdata['template'])) {
             if (strtotime($tmpl->updated) >= filemtime( $tmpl->currentTemplate )) {
-                if ($tmpl->is_deleted != 0 ||  $tmpl->filetype != 'html') {
+                if ($tmpl->is_deleted != 0 ||  $tmpl->filetype != $filetype) {
                     $oo = clone($tmpl);
                     $tmpl->is_deleted = 0;
-                    $tmpl->filetype = 'php';
+                    $tmpl->filetype = $filetype;
                     $tmpl->update($oo);
                 }
                 return $tmpl;
             }
         }
+
         $words = array();
-        
-        $ar = token_get_all(file_get_contents( $tmpl->currentTemplate  ));
-        foreach( $ar as $i=> $tok) {
-            if (!is_array($tok) || $tok[0] != T_CONSTANT_ENCAPSED_STRING) {
-                continue;
-            }
-            if ($i < 2) {
-                continue;
-            }
-            if (is_array($ar[$i-1]) || $ar[$i-1] != '(') {
-                continue;
-            }
-            if (!is_array($ar[$i-2]) || $ar[$i-2][1] != '_') {
-                continue;
-            }
-            $ct = $tok[1][0];
-            $words[] =  str_replace('\\'. $ct, $ct, trim($tok[1] , $ct));
-            
+
+        switch($filetype) {
+            case "php":
+                $ar = token_get_all(file_get_contents( $tmpl->currentTemplate  ));
+                foreach( $ar as $i=> $tok) {
+                    if (!is_array($tok) || $tok[0] != T_CONSTANT_ENCAPSED_STRING) {
+                        continue;
+                    }
+                    if ($i < 2) {
+                        continue;
+                    }
+                    if (is_array($ar[$i-1]) || $ar[$i-1] != '(') {
+                        continue;
+                    }
+                    if (!is_array($ar[$i-2]) || $ar[$i-2][1] != '_') {
+                        continue;
+                    }
+                    $ct = $tok[1][0];
+                    $words[] =  str_replace('\\'. $ct, $ct, trim($tok[1] , $ct));
+                    
+                }
+                break;
+            case "js":
+                $fc = file_get_contents( $tmpl->currentTemplate );
+        
+                preg_match_all('/\._\("([^"]+)"\)/', $fc, $outd);
+                $words = $outd[1];
+                 
+                preg_match_all('/\._\(\'([^\']+)\'\)/', $fc, $outs);
+                
+                // ?? seriously adding two arrays?
+                $words =  array_diff(array_merge($words, $outs[1]), array_intersect($words, $outs[1]));
+                break;
+            case "xml":
+                $words = $pgdata['words'];
+                break;
         }
-        // create the template...
-        
-        
-         if (!$tmpl->id) {
-            
-            $tmpl->template = $pgdata['template'];
-            $tmpl->lang = 'en'; /// ??? hard coded??
-            $tmpl->filetype = 'php';
+
+        $words = array_unique($words);
+
+        if(empty($words)) {
+            return;
+        }
+
+        if ($tmpl->id) {
+            $oo = clone($tmpl);
             $tmpl->is_deleted = 0;
+            $tmpl->filetype = $filetype;
             $tmpl->updated = date('Y-m-d H:i:s', filemtime($tmpl->currentTemplate));
-            $tmpl->insert();
+            $tmpl->update($oo);
         } else {
-            $xx =clone($tmpl);
-            $tmpl->filetype = 'php';
             $tmpl->is_deleted = 0;
-            $tmpl->lang = 'en'; /// ??? hard coded??
+            $tmpl->filetype = $filetype;
+            $tmpl->lang = 'en';
             $tmpl->updated = date('Y-m-d H:i:s', filemtime($tmpl->currentTemplate));
-            $tmpl->update($xx);
-        }
-      
-        $words = array_unique($words);
-        
-        if (!count($words)) {
-            return;
+            $tmpl->insert();
         }
-        
-             
+
         $tmpl->words = $words;
-            
-        $x = DB_DataObject::Factory('core_templatestr');
-        $x->syncTemplateWords($tmpl);    
-         
-        
+
+        $this->factoryStr()->syncTemplateWords($tmpl);
+
         return $tmpl;
-        
-        
-        
     }
+
+    function syncPhpGetText($pgdata)
+    {
+        return $this->syncFileWord($pgdata, 'php'); 
+    }
+
+    /**
+     * plain JS files use ._(....) to flag 
+     * it does not support quoted strings or anything really
+     * very simple strings only
+     */ 
+    
+    function syncJsWords($pgdata)
+    {
+        return $this->syncFileWord($pgdata, 'js');   
+    }
+
+    function syncPowerpointXMLText($pgdata) 
+    {
+        return $this->syncFileWord($pgdata, 'xml');
+    }
+    
     /*
     SELECT LOWER(
 CONCAT(
@@ -400,7 +478,7 @@ WHERE (
     
     function genGetText($clsname, $lang=false)
     {
-        static $done = false;
+        static $done = array();
         $clsname = strtolower($clsname);
 
         textdomain($clsname);
@@ -411,12 +489,12 @@ WHERE (
         
 
         if (!empty($done[$clsname.':'.$lang])) {
-            return; // already sent headers and everything.
+            return true; // already sent headers and everything.
         }
         
         putenv("LANGUAGE=$lang");
-        if ($lang != 'en' && !setlocale(LC_ALL, $lang)) {
-            if (!setlocale(LC_ALL, $lang.'.UTF8')) {
+        if ($lang != 'en') {
+            if (!setlocale(LC_ALL, $lang.'.UTF-8')) {
                 $ff->page->jerr("Language is not available {$lang}");
             }
         }
@@ -435,7 +513,7 @@ WHERE (
         $d->filetype = 'php';
         if (! $d->find(true) ){
             $done[$clsname.':'.$lang] = true;
-            return;
+            return false;
         }
         $user = 'www-data'; // ?? do we need other ones
         $compileDir = ini_get('session.save_path') .'/' . 
@@ -464,24 +542,25 @@ WHERE (
         $done[$clsname.':'.$lang] = 1;
         
         // do we need to compile the file..
-        $ts = DB_DataObject::Factory('core_templatestr');
-        $ts->selectAdd('MAX(updated) as updated');
+        $ts = $this->factoryStr();
+        $ts->selectAdd('COALESCE(MAX(updated), "1000-01-01") as updated');
         $ts->lang = $lang;
         $ts->template_id = $d->id;
         if (!$ts->find(true)) {
             // then in theory there are no translations
-            return;
+            return false;
         }
         if (file_exists($fname) && strtotime($ts->updated) < filemtime($fname)) {
-            return; // file exists and is newer than our updated line.
+            return $fname; // file exists and is newer than our updated line.
         }
         //DB_DataObject::debugLevel(1);
 
-        $ts = DB_DataObject::Factory('core_templatestr');
+        $ts = $this->factoryStr();
         $ts->autoJoin();
-        $ts->selectAdd('join_src_id_id.txt as src_id_txt, core_templatestr.txt as txt');
+        $ts->selectAdd("join_src_id_id.txt as src_id_txt, {$ts->tableName()}.txt as txt");
         $ts->lang = $lang;
         $ts->template_id = $d->id;
+        $ts->whereAdd("LENGTH(join_src_id_id.txt) > 0 AND LENGTH({$ts->tableName()}.txt) > 0");
         $words = $ts->fetchAll('src_id_txt', 'txt' );
                
         if (!file_exists($fdir)) {
@@ -518,7 +597,7 @@ WHERE (
         
          
         
-        return;
+        return $fname;
         
         require_once 'File/Gettext.php';
         $gt = File_Gettext::factory('MO', $fname);
index 88a9785..a800750 100644 (file)
@@ -84,7 +84,6 @@ class Pman_Core_DataObjects_Core_templatestr extends DB_DataObject
      */
     function onTableChange($roo, $obj, $chg)
     {
-        
         $ff = HTML_FlexyFramework::get()->Pman_Core;
             
         if(empty($ff['DataObjects_Core_templatestr']['tables'])){
@@ -95,18 +94,42 @@ class Pman_Core_DataObjects_Core_templatestr extends DB_DataObject
             return;
         }
         $cols = $ff['DataObjects_Core_templatestr']['tables'][$tn];
-        
-        
+
+        $used = array();
         foreach($cols as $c) {
+            
+            if(strpos($c, ',') !== false) {
+                $arr = explode(',', $c);
+                $c = $arr[0];
+                $cond = $arr[1];
+
+                $ar = explode('=', $cond);
+                $key = $ar[0];
+
+                // skip if condition not fulfilled
+                if($obj->{$ar[0]} != $ar[1]) {
+                    continue;
+                }
+            }
+
+            // skip if empty string
+            if(empty($obj->$c)) {
+                continue;
+            }
+
             $x = $this->factory($this->tableName());
             $x->on_id = $obj->pid();
             $x->on_table = $tn;
             $x->on_col = $c;
             $x->lang = ''; /// eg. base language..
             $up = $x->find(true);
-            if ($up && $x->txt == $obj->$c) {
-                continue; // update an no change..
+
+            // skip when no change
+            if($up && $x->txt == $obj->$c) {
+                $used[] = $x->id;
+                continue;
             }
+
             $x->active = 1;
             $x->src_id = 0;
             $x->txt = $obj->$c;
@@ -115,6 +138,23 @@ class Pman_Core_DataObjects_Core_templatestr extends DB_DataObject
             $x->updated = date('Y-m-d H:i:s', strtotime("NOW"));
             $up ? $x->update() : $x->insert();
         }
+
+        // make sure the used one are active
+        if(count($used)) {
+            $t = DB_DataObject::factory($this->tableName());
+            // activate the aprent data
+            $t->query("UPDATE core_templatestr
+                SET active = 1 WHERE id in (" . implode(',' ,$used) . ")
+            ");
+            // activate the child data
+            $t->query("UPDATE  core_templatestr 
+            SET active = 1
+              WHERE
+                 src_id IN (". implode(',' ,$used) . ")
+                AND
+                lang != ''
+            ");
+        }
         
         
     }
@@ -261,9 +301,8 @@ class Pman_Core_DataObjects_Core_templatestr extends DB_DataObject
         //print_r($words);exit;
         // grab original
         $tt = DB_DataObject::factory($this->tableName());
-
-
-        $t = DB_DataObject::factory($this->tableName());
+        $t = clone($tt);
         $t->template_id = $tmpl->id;
         $t->whereAdd("lang = ''");
         
@@ -290,6 +329,11 @@ class Pman_Core_DataObjects_Core_templatestr extends DB_DataObject
             
             
             $v = trim($v);
+
+            // skip empty words
+            if(empty($v)) {
+                continue;
+            }
             
             $md = $keyvalue ? $k : md5($v);
             
@@ -316,7 +360,8 @@ class Pman_Core_DataObjects_Core_templatestr extends DB_DataObject
             $active[] = $cur[$md];
             
             // we have it already? - 
-            $tt->query("UPDATE {$this->tableName()}
+            $t = DB_DataObject::factory($this->tableName());
+            $t->query("UPDATE {$this->tableName()}
                         SET active= 1
                         WHERE
                         id = ".$cur[$md]);
@@ -443,18 +488,23 @@ class Pman_Core_DataObjects_Core_templatestr extends DB_DataObject
         
         // find all the id's from lang that have not been generated..
         
-        //find the origanal 
-        $t = DB_DataObject::factory($tn);
-        $t->whereAdd("lang = ''");
-        $t->active = 1;
         
-        //old code, this did not support the on_table
-//        $id_tmp = $t->fetchAll('id','template_id');
-//        $ids = array_keys($id_tmp);
-        $id_tmp = array();
-        //new code for support the sync tables 
-        foreach($t->fetchAll() as $ori){
-            $id_tmp[$ori->id] = $ori;
+        static $id_tmp = false;
+        
+        if ($id_tmp == false) {
+            //find the origanal 
+            $t = DB_DataObject::factory($tn);
+            $t->whereAdd("lang = ''");
+            $t->active = 1;
+            
+            //old code, this did not support the on_table
+    //        $id_tmp = $t->fetchAll('id','template_id');
+    //        $ids = array_keys($id_tmp);
+            $id_tmp = array();
+            //new code for support the sync tables 
+            foreach($t->fetchAll() as $ori){
+                $id_tmp[$ori->id] = $ori;
+            }
         }
         $ids = array_keys($id_tmp);
         
@@ -465,25 +515,33 @@ class Pman_Core_DataObjects_Core_templatestr extends DB_DataObject
         //$t->active = 1;
         $got = $t->fetchAll('src_id');
         $missing = array_diff($ids, $got);
-        foreach($missing as $id) {
-            
-            $t = DB_DataObject::factory($tn);
-            $t->setFrom(array(
-                'src_id' => $id,
-                'txt' =>  '',
-                'lang' => $lang,
-                'updated' => date('Y-m-d H:i:s', strtotime("NOW")),
-                'template_id'=> $id_tmp[$id]->template_id,
-                'on_table' => $id_tmp[$id]->on_table,
-                'on_id' => $id_tmp[$id]->on_id,
-                'on_col' => $id_tmp[$id]->on_col,
-                'active' => 1,
-                // no md5um
-            ));
-            $t->insert();
-        }
-        
         
+        if (empty($missing)) {
+            return;
+        }
+        $t = DB_DataObject::factory($tn);
+        $q = "CREATE TEMPORARY TABLE core_templatestr_insert SELECT
+            id as src_id,
+            '' as txt,
+            '$lang' as lang,
+            NOW() as updated,
+            template_id,
+            on_table,
+            on_id,
+            on_col,
+            1 as active
+            FROM core_templatestr
+            WHERE
+            id IN (". implode(',', $missing) . ")
+        ";
+        //echo $q; exit;
+        DB_DataObject::factory($tn)->query($q);
+        $q = "INSERT INTO $tn (src_id, txt, lang, updated, template_id, on_table,on_id, on_col, active) SELECT * FROM core_templatestr_insert";
+        DB_DataObject::factory($tn)->query($q);
+        $q = "DROP TEMPORARY TABLE core_templatestr_insert";
+        DB_DataObject::factory($tn)->query($q);
+            
+      
         
     }
     
@@ -604,9 +662,21 @@ class Pman_Core_DataObjects_Core_templatestr extends DB_DataObject
         
     }
     
-    // determine if a complied template need recompling
     
     function translateChanged($flexy)
+    {
+        
+        $date = $this->lastUpdated($flexy);
+        if ($date === false) {
+            return false;
+        }
+        $utime = file_exists($flexy->compiledTemplate) ?  filemtime( $flexy->compiledTemplate) : 0;
+        return strtotime($date) >  $utime;
+    }
+    
+    // determine if a complied template need recompling
+    
+    function lastUpdated($flexy)
     {
         //return true;
         // var_dump('check changed?');
@@ -616,12 +686,14 @@ class Pman_Core_DataObjects_Core_templatestr extends DB_DataObject
         //var_dump($flexy->compiledTemplate);
         $utime = file_exists($flexy->compiledTemplate) ?  filemtime( $flexy->compiledTemplate) : 0;
         
-        
+       
         static $cache = array(); // cache of templates..
         
         $ff = HTML_FlexyFramework::get();
         $view_name = isset($ff->Pman_Core['view_name']) ? $ff->Pman_Core['view_name'] : false;
         
+        // find which of the template directories was actually used for the template.
+        
         $tempdir = '';
         foreach($flexy->options['templateDir'] as $td) {
             if (substr($flexy->currentTemplate, 0, strlen($td)) == $td) {
@@ -633,6 +705,7 @@ class Pman_Core_DataObjects_Core_templatestr extends DB_DataObject
         
         $tmpname = substr($flexy->currentTemplate, strlen($td) +1);
         
+        // we do not have any record of this template..
         if (isset($cache[$tmpname]) && $cache[$tmpname] === false) {
             return false;
         }
@@ -666,11 +739,67 @@ class Pman_Core_DataObjects_Core_templatestr extends DB_DataObject
         $x->lang = $flexy->options['locale'];
         $x->active = 1;
         $x->template_id = $tmpl->id;
-        $x->whereAdd("updated > '". date('Y-m-d H:i:s', $utime)."'");
-        
-        return $x->count() ? true : false;
+        //$x->whereAdd("updated > '". date('Y-m-d H:i:s', $utime)."'");
+        if ($x->count() < 1) {
+            return false; // we don't have any record of it.
+        }
+        $x->selectAdd();
+        $x->selectAdd('max(updated) as max_updated');
+        $x->find(true);
+        return $x->max_updated;
         
         
     }
     
+    function toRooArray($req) {
+        $ret = $this->toArray();
+
+        if (empty($req['csvCols'])) {
+            return $ret;
+        }
+
+        // for download
+
+        // translations for table columns
+        if(!empty($ret['on_table']) && !empty($ret['on_id']) && !empty($ret['on_col'])) {
+            $ret['template_id_view_name'] = 'database';
+            $ret['template_id_template'] = $ret['on_table'] . ':' . $ret['on_col'];
+        }
+
+        return $ret;
+    }
+
+    function postListFilter($ar, $au, $req)
+    {
+        if (empty($req['csvCols'])) {
+            return $ar;
+        }
+
+        // for download
+
+        $ret = array();
+
+        foreach($ar as $v) {
+            if(empty($v['on_table']) || empty($v['on_id']) || empty($v['on_col'])) {
+                $ret[] = $v;
+                continue;
+            }
+
+            // translations for table columns
+            // avoid duplicate (same src_id_mdsum, same on_table, same on_col, but different on_id)
+
+            $key = $v['on_table'] . ':' . $v['on_col'] . ':' . $v['src_id_mdsum'];
+
+            if(!empty($ret[$key])) {
+                continue;
+            }
+
+            $ret[$key] = $v;
+        }
+
+        $ret = array_values($ret);
+        
+        return $ret;
+
+    }
 }
index e41d10d..2e207ff 100644 (file)
@@ -282,6 +282,7 @@ class Pman_Core_DataObjects_Core_watch extends DB_DataObject
             $n->trigger_event_id = $event->id;
             $n->person_id = $watch->person_id;
             $n->watch_id =  $watch->id;
+            $n->evtype   = $watch->medium;
             
             // does this watch already have a flag...
             $nf = clone($n);
@@ -295,9 +296,7 @@ class Pman_Core_DataObjects_Core_watch extends DB_DataObject
             $n->act_start( empty($n->act_start) ? date("Y-m-d H:i:s") : $n->act_start );
             $n->insert();
         }
-        
-        
-        
+         
     }
     function initDatabase($roo, $data) {
         foreach($data as $d) {
index e8682ac..a04484c 100644 (file)
@@ -54,7 +54,6 @@ class Pman_Core_DataObjects_Events extends DB_DataObject
                 $this->selectAs();
 
                 $this->selectAs($jt, 'person_id_%s', 'join_person_id_id');
-
                 if (method_exists($jt,'nameColumn')) {
                     $this->selectAdd("join_person_id_id.{$jt->nameColumn()} as person_id_name");
                 }
@@ -150,7 +149,7 @@ class Pman_Core_DataObjects_Events extends DB_DataObject
             //DB_DataObject::DebugLevel(1);
             $joins = explode(',',$q['_join']);
             
-            $this->selectAdd(); // ???
+            //$this->selectAdd(); // ??? << this wipes out the default options
             $distinct = false;
             
             foreach($joins as $t) {
@@ -160,7 +159,8 @@ class Pman_Core_DataObjects_Events extends DB_DataObject
                     continue;
                 }
                 $jtn = $x->tableName();
-                $jk = array_shift($x->keys());
+                $jks = $x->keys();
+                $jk = array_shift($jks);
                 $this->_join .= "
                 
                     LEFT JOIN {$jtn} as join_on_id_{$jtn} ON {$tn}.on_id = join_on_id_{$jtn}.{$jk}
@@ -475,18 +475,39 @@ class Pman_Core_DataObjects_Events extends DB_DataObject
     static function writeEventLogExtra($data) {
         self::$extra_data = $data;
     }
+    static $files = array();
+    
+    /**
+     * Add a file to the output log
+     * this needs to be called before addEvent, and the data format should be the same as $_FILES
+     * eg.
+     * 
+     * DB_DataObject::factory('Events')->addFile(array(
+     *    'tmp_name' => real file location
+     *    'name' => real file name
+     *    'type' => mimetype
+     *    'size' => filesize
+     *    
+     * ))
+     * 
+     */
+    function addFile($data)
+    {
+        self::$files[] = $data;
+    }
     
-    function logDir()
+    function logDir($user = false)
     {
         $ff  = HTML_FlexyFramework::get();
-        if (function_exists('posix_getpwuid')) {
-            $uinfo = posix_getpwuid( posix_getuid () ); 
-         
-            $user = $uinfo['name'];
-        } else {
-            $user = getenv('USERNAME'); // windows.
-        }
-        
+        if ($user === false) {
+            if (function_exists('posix_getpwuid')) {
+                $uinfo = posix_getpwuid( posix_getuid () ); 
+             
+                $user = $uinfo['name'];
+            } else {
+                $user = getenv('USERNAME'); // windows.
+            }
+        } 
         
    
         if (!empty($ff->Pman['storedir'])) {
@@ -516,6 +537,7 @@ class Pman_Core_DataObjects_Events extends DB_DataObject
         if (!file_exists(dirname($file))) {
             
             @mkdir(dirname($file),0700,true); // this might fail if it does not have correct permissions..
+            clearstatcache();
             if (!file_exists(dirname($file))) {
                 //print_r($this);
                 die("Events:: writeEventLog: could not create $file - permissons are not correct\n"); // fatal, otherwise we loop!?
@@ -534,9 +556,10 @@ class Pman_Core_DataObjects_Events extends DB_DataObject
         
         $i=0;
         $files = array();
+          
          
-        $i = 0;
-        foreach ($_FILES as $k=>$f){
+        
+        foreach (array_merge($_FILES, self::$files) as $k=>$f){
             // does not handle any other file[] arrary very well..
             if (empty($f['tmp_name']) || !file_exists($f['tmp_name'])) {
                 continue;
@@ -644,8 +667,13 @@ class Pman_Core_DataObjects_Events extends DB_DataObject
         $date = date('/Y/m/d/', strtotime($this->event_when));
         
         $file = $logdir. $date. $this->id . ".json";
-        if (!file_exists(dirname($file))) {
-            return false;
+        if (!file_exists($file)) {
+            
+            // try looking www-dir..
+            $file = $this->logDir('www-data'). $date. $this->id . ".json";
+            if (!file_exists($file)) {   
+                return false;
+            }
         }
         
         return $file;
index 4c4feed..d866e48 100644 (file)
@@ -38,6 +38,12 @@ class Pman_Core_DataObjects_Images extends DB_DataObject
                 $tn.filename LIKE '%{$this->escape($q['search']['filename'])}%' OR $tn.title LIKE '%{$this->escape($q['search']['filename'])}%'
             ");
         }
+
+        if(!empty($q['_to_base64']) && !empty($q['image_id'])) {
+            $i = DB_DataObject::factory("Images");
+            $i->get($q['image_id']);
+            $roo->jok($i->toBase64());
+        }
         
 
     }
@@ -53,7 +59,7 @@ class Pman_Core_DataObjects_Images extends DB_DataObject
         
         $o = $this->object();
         //print_r($o);
-        if (method_exists($o, 'checkPerm')) {
+        if ($o &&  method_exists($o, 'checkPerm')) {
             // edit permissions on related object needed...
             return $o->checkPerm( $lvl == 'S' ? 'S' : 'E' , $au);
             
@@ -195,15 +201,79 @@ class Pman_Core_DataObjects_Images extends DB_DataObject
      * @return - target file name
      */
     function getStoreName() 
+    {
+        return self::staticGetStoreName($this);
+          
+    }
+
+    static function staticGetStoreName($o)
     {
         $opts = HTML_FlexyFramework::get()->Pman;
-        $fn = preg_replace('/[^a-z0-9\.]+/i', '_', $this->filename);
+        $fn = preg_replace('/[^a-z0-9\.]+/i', '_', $o->filename);
         return implode( '/', array(
-            $opts['storedir'], '_images_', date('Y/m', strtotime($this->created)), $this->id . '-'. $fn
+            $opts['storedir'], '_images_', date('Y/m', strtotime($o->created)), $o->id . '-'. $fn
         ));
-          
     }
-     
+    
+    /**
+     * does the files exist?
+     */
+    function exists()
+    {
+        return self::staticExists($this);
+    }
+
+    static function staticExists($o)
+    {
+        clearstatcache();
+        $ret =  file_exists(self::staticGetStoreName($o));
+        if (!$ret) {
+            return self::staticCanFix($o);
+        }
+        return $ret;
+    }
+
+    /**
+     * the getStorename code got changed, and some old files may not end up with the correct name anymore.
+     * this tries to fix it.
+     *
+     */
+    function canFix() 
+    {
+        return self::staticCanFix($this);
+    }
+
+    static function staticCanFix($o)
+    {
+        // look for the image in the folder, with matching id.
+        // this is problematic..
+        $fn = self::staticGetStoreName($o);
+        if (file_exists($fn . '-really-missing')) {
+            return false;
+        }
+        if (!file_exists(dirname($fn))) {
+            return false;
+        }
+        foreach( scandir(dirname($fn)) as $n) {
+            if (empty($n) || $n[0] == '.') {
+                continue;
+            }
+            $bits = explode('-', $n);
+            if ($bits[0] != $o->id) {
+                continue;
+            }
+            if (preg_match('/\.[0-9]+x[0-9]]+\.jpeg$/', $n)) {
+                continue;
+            }
+            copy(dirname($fn). '/'.  $n, $fn);
+            clearstatcache();
+            return true;
+        }
+        // fixme - flag it as bad
+        touch($fn . '-really-missing');
+    }
+    
+    
     /**
      * deletes all the image instances of it...
      * 
@@ -212,14 +282,20 @@ class Pman_Core_DataObjects_Images extends DB_DataObject
     function beforeDelete($dependants_array, $roo)
     {
         
+        if (!empty($dependants_array)) {
+            return;
+        }
+        
         $opts = HTML_FlexyFramework::get()->Pman;
         $deldir = $opts['storedir']. '/_deleted_images_';
+        clearstatcache();
         if (!file_exists( $deldir )) {
-            mkdir($deldir, 0755);
+            @mkdir($deldir, 0755); // not sure why we are erroring here.. after checking - maybe permissions?
         }
             
         $fn = $this->getStoreName();
         $b = basename($fn);
+        clearstatcache();
         if (file_exists($fn)) {
             
             if (file_exists($deldir . '/'. $b)) {
@@ -238,12 +314,14 @@ class Pman_Core_DataObjects_Images extends DB_DataObject
             $dh = opendir($d);
             while (false !== ($fn = readdir($dh))) {
                 if (substr($fn, 0, strlen($b)) == $b) {
-                    
+                    clearstatcache();
                     if (file_exists($deldir . '/'. $fn)) {
                         unlink($d. '/'. $fn);
                         continue;
                     }
-                    rename($d. '/'. $fn, $deldir .'/'. $fn);
+                    if (file_exists($d. '/'. $fn)) {
+                        rename($d. '/'. $fn, $deldir .'/'. $fn);
+                    }
                     
                 }
             }
@@ -483,7 +561,7 @@ class Pman_Core_DataObjects_Images extends DB_DataObject
             
             
         }
-        $ret['shorten_name'] = $ret['filename'] = $this->shorten_name();
+        $ret['shorten_name']   = $this->shorten_name();
         
         return $ret;
     }
@@ -495,11 +573,14 @@ class Pman_Core_DataObjects_Images extends DB_DataObject
      * 
      * 
      */
-    function URL($size , $provider = '/Images/Thumb', $baseURL=false)
+    function URL($size , $provider = '/Images/Thumb', $baseURL=false, $to_type=false)
     {
         if (!$this->id) {
             return 'about:blank';
         }
+        if (!$this->exists()) {
+            return 'about:missing';
+        }
         
         $shorten_name = $this->shorten_name();
         
@@ -519,24 +600,29 @@ class Pman_Core_DataObjects_Images extends DB_DataObject
         //$size = min(1024, (int) $size);
         // the size should 200x150 to convert
         $sizear = preg_split('/(x|c)/', $size);
-        if(empty($sizear[1])){
-            $sizear[1] = 0;
+        if(!isset($sizear[1])){
+            $sizear[1] =   0; // 0x with '0' is a box? why
         }
+        
         $size = implode(strpos($size,'c') > -1 ? 'c' : 'x', $sizear);
 //        print_r($size);
         $fc = $this->toFileConvert();
 //        print_r($size);
 //        exit;
-        $mt = $this->mimetype;
+        $mt = $to_type === false ? $this->mimetype : $to_type;
         if (!preg_match('#^image/#i',$mt)) {
             $mt = 'image/jpeg';
         }
         
-        $fc->convert($mt, $size);
+        $cn = $fc->convert($mt, $size);
+        $shorten_name = $this->shorten_name(basename($cn));
         
         return $baseURL . $provider . "/$size/{$this->id}/{$shorten_name}"; // -- this breaks the rss feed #image-{$this->id}";
     }
-    
+    /**
+     *
+     * tries to get an image from then URL - not always has based... - also from the normal url
+     */
     function getFromHashURL($url)
     {
         $id = false;
@@ -546,8 +632,12 @@ class Pman_Core_DataObjects_Images extends DB_DataObject
             $id = $matches[1];
         } else if (preg_match('#Images/([0-9]+)/#', $url, $matches)) {
             $id = $matches[1];
+        } else if (preg_match('#images[^/]+/([0-9]+)/#i', $url, $matches)) {
+            // supports images.xxxxx.com/{number}/name...
+            $id = $matches[1];
+        } else if (preg_match('#Thumb/[^/]+/([0-9]+)/#', $url, $matches)) {
+            $id = $matches[1];
         }
-        
         if ($id === false ||  $id < 1) {
             return false;
         }
@@ -560,13 +650,14 @@ class Pman_Core_DataObjects_Images extends DB_DataObject
     }
     
     
-    function shorten_name()
+    function shorten_name($fn = false)
     {
         if(empty($this->filename)) {
             return;
         }
+        $fn = $fn === false ? $this->filename : $fn;
         
-        $filename = explode('.', $this->filename);
+        $filename = explode('.', $fn);
         $ext = array_pop($filename);
         $name = preg_replace("/[^A-Z0-9.]+/i", '-', implode('-', $filename)) ;
         
@@ -583,7 +674,7 @@ class Pman_Core_DataObjects_Images extends DB_DataObject
      * 
      * 
      */
-    function toHTML($size, $provider = '/Images/Thumb') 
+    function toHTML($size, $provider = '/Images/Thumb', $extra = ''
     {
         
         
@@ -598,12 +689,12 @@ class Pman_Core_DataObjects_Images extends DB_DataObject
         }
         if (empty($sz[1])) {
             $ratio =  empty($this->width) ? 1 : $this->height/ ($this->width *1.0);
-            $sy = $ratio * $sx;
+            $sy = intval($ratio * $sx);
         } else {
             $sy = $sz[1];
         }
         // create it?
-        $extra = '';
+       
         if (strlen($this->title)) {
             $extra = ' title="'. htmlspecialchars($this->title) . '"';
         }
@@ -642,6 +733,8 @@ class Pman_Core_DataObjects_Images extends DB_DataObject
      */
     function toFileConvert()
     {
+        $fn = $this->getStoreName();
+        
         require_once 'File/Convert.php';
         $fc = new File_Convert($this->getStoreName(), $this->mimetype);
         return $fc;
@@ -825,13 +918,31 @@ class Pman_Core_DataObjects_Images extends DB_DataObject
     function createFromData($data)
     {   
         
-        $this->mimetype= strtolower($this->mimetype);
+        if (0 === strpos($data, "data:")) {
+            // data:image/png;base64, 
+            $data = substr($data,5);
+            $bits = explode(";", $data);
+            $this->mimetype = $bits[0];
+        }
+        static $imgid = 1;
+        if (empty($this->filename)) {
+            require_once 'File/MimeType.php';
+            $y = new File_MimeType();
+            $this->filename = 'image-'.$imgid++.'.'.$y->toExt($this->mimetype);
+        }
+        
+        
+        $this->mimetype = strtolower($this->mimetype);
+        if ($this->mimetype == 'image/jpg') {
+            $this->mimetype = 'image/jpeg';
+        }
+        
         
         $explode_mimetype = explode('/', $this->mimetype);
         
         if (array_shift($explode_mimetype) == 'image') { 
         
-            $imgs = @getimagesize($data);
+            $imgs = @getimagesize('data://'. $data);
             
             if (!empty($imgs) && !empty($imgs[0]) && !empty($imgs[1])) {
                 list($this->width , $this->height)  = $imgs;
@@ -855,7 +966,7 @@ class Pman_Core_DataObjects_Images extends DB_DataObject
         }
         
         file_put_contents($f, file_get_contents("data://" . $data));
-        
+        //var_dump($f);exit;
         $o = clone($this);
         
         $this->filesize = filesize($f);
@@ -877,7 +988,7 @@ class Pman_Core_DataObjects_Images extends DB_DataObject
         }
         
         $file = $this->getStoreName();
-        
+
         if(!file_exists($file)){
             return false;
         }
diff --git a/DataObjects/core.sql b/DataObjects/core.sql
deleted file mode 100644 (file)
index a0047eb..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
--- file is not really used any more..
-
-
--- // core comapy types - use core enums (Company Type)
-DROP TABLE IF EXISTS core_company_type;
-
--- // old core image type - merged into enum.
-DROP TABLE IF EXISTS core_image_type;
-
-
-
-                       
-        
-    
--- ----------------------------
-
index 6e1c70d..7603880 100644 (file)
@@ -24,6 +24,7 @@ logo_id = Images:id
 owner_id = core_person:id
 main_office_id = core_office:id
 comptype_id = core_enum:id
+parent_id = core_company:id
 
 [core_office]
 company_id = core_company:id
@@ -34,7 +35,7 @@ agency_id = core_company:id
 team_id = core_group:id
 open_by = core_person:id
 owner_id = core_person:id
-
+deleted_by = core_person:id
 
 [core_group]
 leader = core_person:id
@@ -64,12 +65,28 @@ watch_id = core_watch:id
 trigger_person_id = core_person:id
 trigger_event_id = Events:id
 domain_id = core_domain:id
+server_id = core_notify_server:id
+
 
 [core_notify_recur]
 person_id = core_person:id
 last_event_id = Events:id
 method_id = core_enum:id
 
+
+[core_notify_blacklist]
+server_id = core_notify_server:id
+domain_id = core_domain:id
+
+[core_notify_sender_blacklist]
+domain_id = core_domain:id
+sender_id = core_notify_sender:id
+
+
+
+
+
 [core_email]
 owner_id = core_person:id
 bcc_group_id = core_group:id
@@ -92,6 +109,11 @@ template_id = core_template:id
 [core_template_element]
 template_id = core_template:id
 
+[core_project_group]
+project_id = core_project:id
+group_id = core_group:id
+
+
 [database__render]
 core_project = name
 core_company= name
index fd674a3..703b1fa 100644 (file)
@@ -11,10 +11,10 @@ class Pman_Core_DatabaseColumns extends Pman {
         $au = $this->getAuthUser();
        
         if (!$au) {  
-            $this->jerr("Not authenticated", array('authFailure' => true));
+            $this->jerror("LOGIN-NOAUTH", "Not authenticated", array('authFailure' => true));
         }
         if (!$au->pid()   ) { // not set up yet..
-            $this->jerr("Not authenticated", array('authFailure' => true));
+            $this->jerror("LOGIN-NOAUTH", "Not authenticated", array('authFailure' => true));
         }
         
         
index a14633e..feb940c 100644 (file)
@@ -30,7 +30,7 @@ class Pman_Core_GnumericToExcel extends Pman
 
     function get($v, $opts=array())
     {
-        
+         
     }
     function post($fname) {
         
@@ -66,7 +66,7 @@ class Pman_Core_GnumericToExcel extends Pman
             exit;
         }
         
-        $ext = '.xls';
+        $ext = 'xls';
         $outfmt = 'Gnumeric_Excel:excel_biff8';
         $mime = 'application/vnd.ms-excel';
         
@@ -98,7 +98,7 @@ class Pman_Core_GnumericToExcel extends Pman
                 " --export-type={$outfmt} " . 
                 $srcTmp . ' ' . $targetTmp . ' 2>&1';
         // echo $cmd;
-        //passthru($cmd);exit;
+        //passthru($cmd);exit; 
         //exit;
         $out = `$cmd`;
         clearstatcache(); 
@@ -111,23 +111,31 @@ class Pman_Core_GnumericToExcel extends Pman
         if (!empty($_POST['format']) && $_POST['format']=='xlsx') {
             require_once 'File/Convert.php';
             $cc = new File_Convert($targetTmp,'application/vnd.ms-excel');
-           
             $targetTmp = $cc->convert('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
+            if (empty($targetTmp)) {
+                $this->jerr("convert to xlsx failed");
+            }
+            
             $mime = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
             $ext = "xlsx";
          }
-        
-        
-        
-        
-        
-        
-       // unlink($srcTmp);
         if (empty($fname)) {
            $fname = basename($targetTmp);
         }
         $fname .= preg_match('/\.' . $ext . '/i', $fname) ? '' :  ('.' . $ext); // make sure it ends in xls..
        
+        
+        DB_DataObject::factory('Events')->addFile(array(
+            'tmp_name' => $targetTmp,
+            'name' => $fname,
+            'type' => $mime,
+            'size' => filesize($targetTmp)
+        ));
+        
+        $this->addEvent("DOWNLOAD",  false, $fname  );
+        
+       // unlink($srcTmp);
+        
         header('Content-type: ' . $mime);
         header('Content-Disposition: attachment; filename="' .addslashes($fname). '"');
         header('Content-length: '. filesize($targetTmp));   
index e694d8d..fdd8fca 100644 (file)
@@ -15,7 +15,7 @@ class Pman_Core_GroupCountries extends Pman
         parent::getAuth(); // load company!
         $au = $this->getAuthUser();
         if (!$au) {
-            $this->jerr("Not authenticated", array('authFailure' => true));
+            $this->jerror("LOGIN-NOAUTH", "Not authenticated", array('authFailure' => true));
         }
         if ($au->company()->comptype != 'OWNER') {
             $this->jerr("Permission Denied" );
index f501042..ce061d7 100644 (file)
@@ -15,7 +15,7 @@ class Pman_Core_GroupMembers extends Pman
         parent::getAuth(); // load company!
         $au = $this->getAuthUser();
         if (!$au) {
-            $this->jerr("Not authenticated", array('authFailure' => true));
+            $this->jerror("LOGIN-NOAUTH", "Not authenticated", array('authFailure' => true));
         }
         if ($au->company()->comptype != 'OWNER') {
             $this->jerr("Permission Denied" );
diff --git a/Heartbeat.php b/Heartbeat.php
new file mode 100644 (file)
index 0000000..88d4607
--- /dev/null
@@ -0,0 +1,63 @@
+<?php
+
+// check if database is workign - used by nagios checking - to see if server is really up.
+
+require_once 'Pman.php';
+
+class Pman_Core_Heartbeat extends Pman
+{
+    function getAuth()
+    {
+        return true;
+    }
+    
+    function get($req, $opts = array())
+    {
+        $this->post($req);
+        die("POST only");
+    }
+    
+    function post($req)
+    {
+        $this->initErrorHandling();
+        
+        if ($this->database_is_locked()) {
+            die("FAILED");
+        }
+        
+        
+        $cd = DB_DataObject::Factory('core_enum');
+        $cd->setFrom(array(
+            'etype' => 'heartbeat',
+            'name' => 'last_update'
+        ));
+        if (!$cd->count()) {
+            $cd->display_name = date("Y-m-d H:i:s");
+            $cd->insert();
+            die("OK - HEARTBEAT WORKING");
+        }
+        $cd->find(true);
+        $cc = clone($cd);
+        if ( (time() - strtotime($cc->display_name)) < 30) {
+            die("OK - HEARTBEAT WORKING");
+        }
+        
+        $cd->display_name = date("Y-m-d H:i:s");
+        $cd->update($cc);
+        die("OK - HEARTBEAT WORKING");
+    }
+    
+     
+    function onPearError($err)
+    {
+      //  print_r($err);
+        die("FAILED");
+    }
+    function onException($err)
+    {
+      //  print_r($err);
+        die("FAILED");
+    }
+    
+   
+}
\ No newline at end of file
index 5f70c7a..bab0b2d 100644 (file)
--- a/I18n.php
+++ b/I18n.php
@@ -62,7 +62,7 @@ class Pman_Core_I18n extends Pman
         //return true;
         $au = $this->getAuthUser();
         //if (!$au) {
-        //    $this->jerr("Not authenticated", array('authFailure' => true));
+        //    $this->jerror("LOGIN-NOAUTH", "Not authenticated", array('authFailure' => true));
         //}
         $this->authUser = $au;
         
@@ -86,8 +86,7 @@ class Pman_Core_I18n extends Pman
         $this->sessionState(0);
         
         $lang = !$this->authUser || empty($this->authUser->lang ) ? 'en' : $this->authUser->lang;
-        
-        /// verify the selected language..
+         /// verify the selected language..
         $i = DB_DataObject::Factory('I18n');
         $i->ltype = 'l';                           // string(1)  not_null multiple_key
         $i->lkey = $lang;                            // string(8)  not_null
@@ -235,7 +234,13 @@ class Pman_Core_I18n extends Pman
         if (empty($k)) {
             return '??';
         }
-        $fo = &PEAR::getStaticProperty('HTML_Template_Flexy','options');
+
+        if(class_exists('HTML_FlexyFramework2', false)) {
+            $fo = HTML_FlexyFramework2::get()->HTML_Template_Flexy;
+        }
+        else {
+            $fo = &PEAR::getStaticProperty('HTML_Template_Flexy','options');
+        }
         
         $fallback_lang = empty($fo['locale']) ? 'en' : $fo['locale'];
             
index bfda282..bcedb00 100644 (file)
@@ -78,6 +78,8 @@ class Pman_Core_Images extends Pman
     var $method = 'inline';
     var $page = false;
     var $is_local = false;
+    var $size;
+    
     
     function get($s, $opts=array()) // determin what to serve!!!!
     {
@@ -85,6 +87,8 @@ class Pman_Core_Images extends Pman
         //if (!empty($_GET['_post'])) {
         //   return $this->post();
         //}
+     
+        
         
         $this->is_local = (!empty($_SERVER['HTTP_HOST']) && $_SERVER['HTTP_HOST'] == 'localhost') ? true : false;
         
@@ -126,7 +130,7 @@ class Pman_Core_Images extends Pman
         }
         
         if (strpos($id,':') > 0) {  // id format  tablename:id:-imgtype
-            
+            //DB_DataObject::debugLevel(1);
             if (!$this->authUser) {
                 $this->imgErr("not-authenticated-using-colon-format",$s);
                 
@@ -183,7 +187,8 @@ class Pman_Core_Images extends Pman
         
         $img = DB_DataObjecT::factory('Images');
          
-        if (!$id || !$img->get($id)) {
+        if (!$id || !$img->get($id) || !$img->exists()) {
+           //print_r($img);           die("HERE");
             $this->imgErr("image has been removed or deleted.",$s);
         }
         
@@ -217,8 +222,9 @@ class Pman_Core_Images extends Pman
     }
     
     function imgErr($reason,$path) {
-        header('Location: ' . $this->rootURL . '/Pman/templates/images/file-broken.png?reason=' .
-            urlencode($reason) .'&path='.urlencode($path));
+        header('Location: ' . $this->rootURL . '/Pman/templates/images/file-broken.png?reason=' . urlencode($reason) );
+        header('X-Error: ' . $reason . ':' . $path);
+        echo $reason . ':' . $path;
         exit;
     }
     
@@ -282,23 +288,27 @@ class Pman_Core_Images extends Pman
  
     function serve($img)
     {
-        $this->sessionState(0); // turn off session... - locking...
         
+        $this->sessionState(0); // turn off session... - locking...
         require_once 'File/Convert.php';
-        if (!file_exists($img->getStoreName())) {
-//            print_r($img);exit;
-            header('Location: ' . $this->rootURL . '/Pman/templates/images/file-broken.png?reason=' .
-                urlencode("Original file was missing : " . $img->getStoreName()));
-    
+        if (!$img->exists()) {
+            $this->imgErr("serve = missing-image", $img->getStoreName());
+             
         }
 //        print_r($img);exit;
         $x = $img->toFileConvert();
         if (empty($this->as_mimetype) || $img->mimetype == 'image/gif') {
             $this->as_mimetype  = $img->mimetype;
         }
+        
+        
         if (!$this->thumb) {
+            if ($x->mimetype == $this->as_mimetype) {
+                $x->serveOnly($this->method, $img->filename);
+                exit;
+            }
             $x->convert( $this->as_mimetype);
-            $x->serve($this->method);
+            $x->serve($this->method, $img->filename);
             exit;
         }
         //echo "SKALING?  $this->size";
@@ -323,6 +333,7 @@ class Pman_Core_Images extends Pman
         if (!file_exists($fn)) {    
             $this->validateSize();
         }
+       
         
         if(!empty($this->page) && !is_nan($this->page * 1)){
             $x->convert( $this->as_mimetype, $this->size, 0, $this->page);
@@ -394,7 +405,7 @@ class Pman_Core_Images extends Pman
      */
     
     
-    static function replaceImageURLS($html)
+    static function replaceImageURLS($html, $obj = false)
     {
         
         $ff = HTML_FlexyFramework::get();
@@ -404,61 +415,142 @@ class Pman_Core_Images extends Pman
         //var_dump($ff->Pman_Images['public_baseURL']);
         $baseURL = $ff->Pman_Images['public_baseURL'];
         
-        preg_match_all('/<img\s+[^>]+>/i',$html, $result); 
-        //print_r($result);
-        $matches = array_unique($result[0]);
-        foreach($matches as $img) {
-            $imatch = array();
-            preg_match_all('/(width|height|src)="([^"]*)"/i',$img, $imatch);
-            // build a keymap
-            $attr =  array();
-            
-            foreach($imatch[1] as $i=>$key) {
-                $attr[$key] = $imatch[2][$i];
-            }
-            // does it contain baseURL??? --- well what about relative paths...
-            //print_R($attr);
-            
-            if (empty($attr['src'])) {
+        libxml_use_internal_errors(true);
+        $dom = new DOMDocument();
+        $dom->loadHTML("<?xml encoding='utf-8'?> <div id='tmp_dom_wrapper'>{$html}</div>");
+        $imgs = $dom->getElementsByTagName('img');
+       
+        
+        foreach($imgs as $img) {
+            $src = $img->getAttribute('src');
+            if (!$src|| !strlen(trim($src))) {
                 continue;
             }
-            if (0 !== strpos($attr['src'], $baseURL)) {
-                // it starts with our 'new' baseURL?
-                $html = self::replaceImgUrl($html, $baseURL, $img, $attr,  'src' );
+             
+            if (0 === strpos($src, 'data:')) {
+                if (!$obj) {
+                    HTML_FlexyFramework::get()->page->jerr("no object to attach data url");
+                }
+                
+                self::replaceDataUrl($baseURL, $img, $obj);
                 continue;
             }
-            if (false !== strpos($attr['src'], '//') && false === strpos($attr['src'], $baseURL)) {
-                // contains an absolute path.. that is probably not us...
+            
+            
+            if (false !== strpos($src, '//') && false === strpos($src, $baseURL)) {
+                // contains an absolute path.. and not our baseURL.
                 continue;
             }
+             
+            $img->setAttribute('src', self::domImgUrl($baseURL, $img));
+              
             // what about mailto or data... - just ignore?? for images...
             
-            $html = self::replaceImgUrl($html, $baseURL, $img, $attr,  'src' );
             
         }
         
-        
+        $anchors = $dom->getElementsByTagName('a');
         $result = array();
         preg_match_all('/<a\s+[^>]+>/i',$html, $result); 
 
         $matches = array_unique($result[0]);
-        foreach($matches as $img) {
-            $imatch = array();
-            preg_match_all('/(href)="([^"]*)"/i',$img, $imatch);
-            // build a keymap
-            $attr =  array();
-            
-            foreach($imatch[1] as $i=>$key) {
-                $attr[$key] = $imatch[2][$i];
-            }
-            if (!isset($attr['href']) || 0 !== strpos($attr['href'], $baseURL)) { 
+        foreach($anchors as $anc) {
+            $href = $anc->getAttribute('href');
+            if (!empty($href) || 0 !== strpos($href, $baseURL)) { 
                 continue;
             }
-            $html = self::replaceImgUrl($html, $baseURL, $img, $attr, 'href' );
+            $anc->setAttribute('href', self::domImgUrl($baseURL, $href));
         }
         
+        
+        $inner = $dom->getElementById("tmp_dom_wrapper");
+        $html = '';
+        foreach ($inner->childNodes as $child) {
+            $html .= ($dom->saveHTML($child));
+        }
         return $html;
     }
+    
+    static function domImgUrl($baseURL, $dom) 
+    {
+        $url = $dom;
+        if (!is_string($url)) {
+            $url = $dom->getAttribute('src');
+        }
+         $umatch  = false;
+        if(!preg_match('#/(Images|Images/Thumb/[a-z0-9]+|Images/Download)/([0-9]+)/(.*)$#', $url, $umatch))  {
+            return $url;
+        }
+        $id = $umatch[2];
+        $hash = '';
+        
+        if (!empty($umatch[3]) && strpos($umatch[3],'#')) {
+            $hh = explode('#',$umatch[3]);
+            $hash = '#'. array_pop($hh);
+        }
+        
+        
+        $img = DB_DataObject::factory('Images');
+        if (!$img->get($id)) {
+            return $url;
+        }
+        $type = explode('/', $umatch[1]);
+        $thumbsize = -1;
+         
+        if (count($type) > 2 && $type[1] == 'Thumb') {
+            $thumbsize = $type[2];
+            $provider = '/Images/Thumb';
+        } else {
+            $provider = '/'.$umatch[1];
+        }
+        
+        $w =  is_string($dom) ? false : $dom->getAttribute('width');
+        $h =  is_string($dom) ? false : $dom->getAttribute('height');
+        
+        if (!is_string($dom) && (!empty($w) || !empty($h) ) && is_numeric($w) && is_numeric($h))
+        {
+            // no support for %...
+            $thumbsize =
+                (empty($w) ? '0' : intval($w) * 1) .
+                'x' .
+                (empty($h) ? '0' : intval($h) * 1);
+             $provider = '/Images/Thumb';
+            
+        }
+        
+        if ($thumbsize !== -1) {
+            // change in size..
+            // need to regenerate it..
+            
+            $type = array('Images', 'Thumb', $thumbsize);
+                
+            $fc = $img->toFileConvert();
+            // make sure it's available..
+            $fc->convert($img->mimetype, $thumbsize);
+            
+            
+        } else {
+            $provider = $provider == 'Images/Thumb' ? 'Images' : $provider; 
+        }
+        
+        
+        // finally replace the original TAG with the new version..
+        
+        return $img->URL($thumbsize, $provider, $baseURL) . $hash ;
+        
+         
+    }
+    
+    static function replaceDataUrl($baseURL, $img, $obj)
+    {
+        $d = DB_DataObject::Factory('Images');
+        $d->object($obj);
+        
+        
+        $d->createFromData($img->getAttribute('src'));
+        $img->setAttribute('src', $d->URL(-1, '/Images' , $baseURL));
+    }
+    
     static function replaceImgUrl($html, $baseURL, $tag, $attr, $attr_name) 
     {
         
@@ -579,4 +671,8 @@ class Pman_Core_Images extends Pman
         }
     }
     
+     
+        
+        
+         
 }
index db526e7..c198d27 100644 (file)
@@ -38,6 +38,14 @@ class Pman_Core_Import_Core_email extends Pman
             'min' => 0,
             'max' => 0,  
         ),
+        'raw_content' => array(
+            'desc' => 'Raw contents of email (used by API) - not by Command line',
+            'short' => 'R',
+            'default' => '',
+            'min' => 0,
+            'max' => 0,  
+        )
+         
     );
     
     function getAuth()
@@ -49,34 +57,41 @@ class Pman_Core_Import_Core_email extends Pman
         }
     }
     
-    function get($part = '', $opts=array()) {
+    function get($part = '', $opts=array())
+    {
         $this->updateOrCreateEmail($part, $opts, false);
     }
 
-    function updateOrCreateEmail($part='', $opts, $cm = false, $mapping = false){
+    function updateOrCreateEmail($part='', $opts= array(), $cm = false, $mapping = false){
         
        // DB_DataObject::debugLevel(1);
         
-        $template_name = preg_replace('/\.[a-z]+$/i', '', basename($opts['file']));
-        
-        if (!file_exists($opts['file'])) {
-            $this->jerr("file does not exist : " . $opts['file']);
-        }
-        
         
-        if (!empty($opts['master']) && !file_exists($opts['master'])) {
-            $this->jerr("master file does not exist : " . $opts['master']);
-        }
-        
-        
-        if (empty($cm)) {
-            $cm = DB_dataObject::factory('core_email');
-            $ret = $cm->get('name',$template_name);
-            if($ret && empty($opts['update'])) {
-                $this->jerr("use --update   to update the template..");
+        if (empty($opts['raw_content'])) {
+            $template_name = preg_replace('/\.[a-z]+$/i', '', basename($opts['file']));
+
+            if (!file_exists($opts['file'])) {
+                $this->jerr("file does not exist : " . $opts['file']);
+            }
+            
+            
+            if (!empty($opts['master']) && !file_exists($opts['master'])) {
+                $this->jerr("master file does not exist : " . $opts['master']);
+            }
+            
+            
+            if (empty($cm)) {
+                $cm = DB_dataObject::factory('core_email');
+                $ret = $cm->get('name',$template_name);
+                if($ret && empty($opts['update'])) {
+                    $this->jerr("use --update   to update the template..");
+                }
             }
+            $mailtext = file_get_contents($opts['file']);
+        } else {
+            $template_name = $opts['name'];
+            $mailtext =  $opts['raw_content'];
         }
-        $mailtext = file_get_contents($opts['file']);
         
         if (!empty($opts['master'])) {
             $body = $mailtext;
@@ -95,6 +110,10 @@ class Pman_Core_Import_Core_email extends Pman
         
         $decoder = new Mail_mimeDecode($mailtext);
         $parts = $decoder->getSendArray();
+        $structure = $decoder->decode(array(
+            'include_bodies' => true,
+            'decode_bodies' => true
+        ));
         if (is_a($parts,'PEAR_Error')) {
             echo $parts->toString() . "\n";
             exit;
@@ -103,22 +122,62 @@ class Pman_Core_Import_Core_email extends Pman
         $headers = $parts[1];
         $from = new Mail_RFC822();
         $from_str = $from->parseAddressList($headers['From']);
+        if (is_a($from_str,'PEAR_Error')) {
+            echo $from_str->toString() . "\n";
+            exit;
+        }
+
         
         $from_name  = trim($from_str[0]->personal, '"');
         
         $from_email = $from_str[0]->mailbox . '@' . $from_str[0]->host;
         
         
-        if (!empty($opts['use-file'])) {
-            $parts[2] = '';
+        $bodyhtml  = '';
+        $bodytext  = '';
+        if (empty($opts['use-file'])) {
+            
+            switch($structure->ctype_primary .'/'. $structure->ctype_secondary ) {
+                case 'multipart/alternative':
+                    foreach($structure->parts as $p) {
+                        switch($p->ctype_primary .'/'. $p->ctype_secondary ) {
+                            case 'text/plain':
+                                $bodytext = $p->body;
+                                break;
+                        
+                            case 'text/html':
+                                $bodyhtml = $p->body;
+                                break;
+                                 // no default...
+                        }
+                            
+                    }
+                    break;
+                case 'text/plain':
+                    $bodytext = $parts[2];
+                    break;
+                
+                case 'text/html':
+                
+                    $bodyhtml = $parts[2];
+                    break;
+                default:
+                    var_dump($structure->ctype_primary .'/'. $structure->ctype_secondary );
+                    die("UNKNOWN TYPE");
+            }
+            
+          
         }
         
         
+        
+        
         if ($cm->id) {
             
             $cc =clone($cm);
             $cm->setFrom(array(
-               'bodytext'      => !empty($opts['use-file']) ? '' : $parts[2],
+               'bodytext'      => $bodyhtml,
+               'plaintext' => $bodytext,
                'updated_dt'     => date('Y-m-d H:i:s'),
                'use_file' => !empty($opts['use-file']) ? realpath($opts['file']) : '',
             ));
@@ -131,7 +190,8 @@ class Pman_Core_Import_Core_email extends Pman
                 'from_email'    => $from_email,
                 'subject'       => $headers['Subject'],
                 'name'          => $template_name,
-                'bodytext'      => !empty($opts['use-file']) ? '' : $parts[2],
+                'bodytext'      => $bodyhtml,
+                'plaintext'     => $bodytext,
                 'updated_dt'     => date('Y-m-d H:i:s'),
                 'created_dt'     => date('Y-m-d H:i:s'),
                 'use_file' => !empty($opts['use-file']) ? realpath($opts['file']) : '',
index 71b6aad..e01c11c 100644 (file)
@@ -1,8 +1,8 @@
 <?php
 
-require_once 'Pman/Roo.php';
+require_once 'Pman/Core/Cli.php';
 
-class Pman_Core_Import_Core_holiday extends Pman_Roo 
+class Pman_Core_Import_Core_holiday extends Pman_Core_Cli 
 {
     static $cli_desc = "Update the holiday database (HK Only at present)"; 
     
@@ -27,7 +27,7 @@ class Pman_Core_Import_Core_holiday extends Pman_Roo
         DB_DAtaObject::debugLevel(1);
         $d = DB_DataObject::factory('core_holiday');
         $d->updateHolidays('hk');
-        
+        $d->updateHolidays('cny');
     }
     
     function log($str)
diff --git a/Import/Timezone.php b/Import/Timezone.php
new file mode 100644 (file)
index 0000000..5c0f4b9
--- /dev/null
@@ -0,0 +1,79 @@
+<?php
+
+
+
+require_once 'Pman.php';
+
+class Pman_Core_Import_Timezone extends Pman 
+{
+    static $cli_desc = "Import timezone region name and area name to core_enum"; 
+    
+    static $cli_opts = array();
+
+    function getAuth()
+    {
+        $ff = HTML_FlexyFramework::get();
+        
+        if (!$ff->cli) {
+            die("cli only");
+        }
+    }
+    
+    function get($part = '', $opts=array())
+    {
+        $ce = DB_DataObject::factory('core_enum');
+        $ce->query("
+            SELECT
+                *, TIME_FORMAT(TIMEDIFF(NOW(), CONVERT_TZ(NOW(), Name, 'UTC')), '%H:%i') as timeOffset
+            FROM
+                mysql.time_zone_name
+            WHERE
+                Name LIKE '%/%'
+                AND
+                Name NOT LIKE '%/%/%'
+                AND
+                Name NOT LIKE 'right%'
+                AND
+                Name NOT LIKE 'posix%'
+                AND
+                Name NOT LIKE 'Etc%'
+            ORDER BY
+                SUBSTRING_INDEX(Name, '/', 1) ASC,
+                timeoffset ASC,
+                Name ASC
+        ");
+
+        $values = array();
+
+        $regions = array();
+        $areas = array();
+
+        while($ce->fetch()) {
+            $ar = explode('/', $ce->Name);
+            $region = $ar[0];
+            $area = str_replace('_', ' ', $ar[1]);
+
+            if(!in_array($region, $regions)) {
+                $regions[] = $region;
+                $values[] = "('Timezone.Region', '" . $region . "', 1, 0, 0, '" . $region . "', 0)";
+            }
+
+            if(!in_array($area, $areas)) {
+                $areas[] = $area;
+                $values[] = "('Timezone.Area', '" . $area . "', 1, 0, 0, '" . $area . "', 0)";
+            }
+        }
+
+        $sql = "
+            INSERT INTO
+                core_enum (etype, name, active, seqid, seqmax, display_name, is_system_enum)
+            VALUES
+                " . implode(", \n", $values) . "
+        ";
+
+        $ce = DB_DataObject::factory('core_enum');
+        $ce->query($sql);
+        
+        $this->jok('DONE');
+    }
+}
\ No newline at end of file
index a5b9159..089db58 100644 (file)
@@ -199,50 +199,18 @@ class Pman_Core_JsCompile  extends Pman
     function packCssCore($files, $output)
     {
         
-         
-        $o = HTML_FlexyFramework::get()->Pman_Core;
-        
-        if (empty($o['cssminify']) || !file_exists($o['cssminify'])) {
-            echo '<!-- cssminify not set -->';
-            return false;
-        }
-        require_once 'System.php';
+
         
-        $seed= System::which('seed');
-        $gjs = System::which('gjs');
+        echo '<!-- JSCOMPILE - should not be used for CSS packing ?? -->';
+        return false;
+        // if we did.. use this?
         
-        if (!$seed && !$gjs) {
-            echo '<!-- seed or gjs are  not installed -->';
-            return false;
+        //require_once 'HTML/CSS/Minify.php';
+        //$x = new HTML_CSS_Minify(substr($relpath,0,-1), $dir, $relfiles);
             
-        }
-        $targetm = file_exists($output) ? filemtime($output) : 0;
-        $max = 0;
-        $ofiles = array();
-        foreach($files as $f => $mt) {
-            $max = max($max,$mt);
-            $ofiles[] = escapeshellarg($f);
-        }
-        if ($max < $targetm)  {
-            return true;
-        }
-        if (!file_exists(dirname($output))) {
-            mkdir(dirname($output), 0755, true);
-        }
-        $eoutput = escapeshellarg($output);
-        $cmd = $seed ?
-            ("$seed {$o['cssminify']}  $eoutput " . implode($ofiles, ' ')) :
-            ("$gjs {$o['cssminify']} -- -- $eoutput " . implode($ofiles, ' ')); 
-        //echo "<PRE>$cmd\n"; echo `$cmd`; exit;
-        `$cmd`;
+          //  file_put_contents($compiledir.'/'.$output , $x->minify( $this->baseURL.$asset));
         
         
-        // we should do more checking.. return val etc..
-        if (file_exists($output) && ($max < filemtime($output) ) ) {
-            return true;
-        }
-        return false;
-        
     }
     /**
      * wrapper arround packer...
@@ -260,10 +228,7 @@ class Pman_Core_JsCompile  extends Pman
             return false;
         }
         
-        $o = HTML_FlexyFramework::get()->Pman_Core;
-        if (isset($o['packseed'])) {
-            return $this->packSeed($files,$output,$translation_base);
-        }
+        // if packer is running, then dont compile - just output onebyone...
         
         
         require_once 'System.php';
@@ -287,6 +252,23 @@ class Pman_Core_JsCompile  extends Pman
             return true;
         }
         
+        
+        
+        $pg = System::which('pgrep');
+        if ($pg == '') {
+            echo '<!--  install pgrep -->';
+            return false;
+        }
+        
+        $cmd = "$pg roojspacker";
+        $res = `$cmd`;
+        $out = empty($res) ? '' : trim($res);
+        if (strlen($out) > 0) {
+            echo '<!--  onther process is compiling compile. -->';
+            return false;
+        }
+         
+        
         if (file_exists($output)) {
             unlink($output);
         }
@@ -342,6 +324,15 @@ class Pman_Core_JsCompile  extends Pman
         
     }
     
+    
+    function packIsRunning()
+    {
+        require_once 'System.php';
+      
+        
+    }
+    
+    
     // depricated verison using seed.
     function packSeed($files, $output, $translation_base=false)
     {
index ec79d0c..302b1c6 100644 (file)
@@ -65,7 +65,7 @@ class Pman_Core_JsTemplate extends Pman {
          
             $dir =  $this->rootDir .'/'.$pdir .  $mod . '/jtemplates';
             if (!file_exists($dir)) {
-                echo '// missing directory '. htmlspecialchars($dir) ."\n";
+                //echo '// missing directory '. htmlspecialchars($dir) ."\n";
                 continue;
             }
             // got a directory..
similarity index 62%
rename from RooJsonOutputTrait.php
rename to JsonOutputTrait.php
index c307d27..394eaf8 100644 (file)
@@ -1,6 +1,8 @@
 <?php
 
-trait Pman_Core_RooJsonOutputTrait {
+trait Pman_Core_JsonOutputTrait {
+    
+    var $transObj = false;
     
     function jok($str)
     {
@@ -9,13 +11,10 @@ trait Pman_Core_RooJsonOutputTrait {
         }
         
         $cli = HTML_FlexyFramework::get()->cli;
-        
         if ($cli) {
             echo "OK: " .$str . "\n";
             exit;
         }
-        require_once 'Services/JSON.php';
-        $json = new Services_JSON();
         
         $retHTML = isset($_SERVER['CONTENT_TYPE']) && 
                 preg_match('#multipart/form-data#i', $_SERVER['CONTENT_TYPE']);
@@ -33,37 +32,94 @@ trait Pman_Core_RooJsonOutputTrait {
             echo "<HTML><HEAD></HEAD><BODY>";
             // encode html characters so they can be read..
             echo  str_replace(array('<','>'), array('\u003c','\u003e'),
-                        $json->encodeUnsafe(array('success'=> true, 'data' => $str)));
+                        $this->jsencode(array('success'=> true, 'data' => $str), false));
             echo "</BODY></HTML>";
             exit;
         }
         
         
-        echo  $json->encode(array('success'=> true, 'data' => $str));
+        echo  $this->jsencode(array('success'=> true, 'data' => $str),true);
         
         exit;
+        
     }
     
     
-    function jerr($str, $errors=array(), $content_type = false)
+      /**
+     * ---------------- Standard JSON outputers. - used everywhere
+     * JSON error - simple error with logging.
+     * @see Pman::jerror
+     */
+    
+    function jerr($str, $errors=array(), $content_type = false) // standard error reporting..
     {
-        if ($this->transObj) {
-            $this->transObj->query('ROLLBACK');
-        }
-        
         return $this->jerror('ERROR', $str,$errors,$content_type);
     }
     
+    function jnotice($type, $str, $errors=array(), $content_type = false)
+    {
+        return $this->jerror('NOTICE-' . $type, $str, $errors, $content_type);
+    }
+    
+     /**
+     * jerrAuth: standard auth failure - with data that let's the UI know..
+     */
+    function jerrAuth()
+    {
+        $au = $this->authUser;
+        if ($au) {
+            // is it an authfailure?
+            $this->jerror("LOGIN-NOPERM", "Permission denied to view this resource", array('authFailure' => true));
+        }
+        $this->jerror("LOGIN-NOAUTH", "Not authenticated", array('authFailure' => true));
+    }
+     
+     
+    /**
+     * Recomended JSON error indicator
+     *
+     * 
+     * @param string $type  - normally 'ERROR' - you can use this to track error types.
+     * @param string $message - error message displayed to user.
+     * @param array $errors - optioanl data to pass to front end.
+     * @param string $content_type - use text/plain to return plan text - ?? not sure why...
+     *
+     */
+    
     function jerror($type, $str, $errors=array(), $content_type = false) // standard error reporting..
     {
-        if ($type !== false) {
+        if ($this->transObj) {
+            $this->transObj->query('ROLLBACK');
+        }
+        
+        $cli = HTML_FlexyFramework::get()->cli;
+        if ($cli) {
+            echo "ERROR: " .$str . "\n"; // print the error first, as DB might fail..
+        }
+        $pman = HTML_FlexyFramework::get();
+        
+       
+        
+
+        
+        if ($type !== false  &&  empty($pman->nodatabase)) {
+            
+            if(!empty($errors)){
+                DB_DataObject::factory('Events')->writeEventLogExtra($errors);
+            }
+            // various codes that are acceptable.
+            // 
+            if (!preg_match('/^(ERROR|NOTICE|LOG)/', $type )) {
+                $type = 'ERROR-' . $type;
+            }
+            
             $this->addEvent($type, false, $str);
+            
         }
          
         $cli = HTML_FlexyFramework::get()->cli;
         if ($cli) {
-            echo "ERROR: " .$str . "\n";
-            exit;
+            exit(1); // cli --- exit code to stop shell execution if necessary.
         }
         
         
@@ -74,8 +130,7 @@ trait Pman_Core_RooJsonOutputTrait {
             exit;
         } 
         
-        require_once 'Services/JSON.php';
-        $json = new Services_JSON();
+     // log all errors!!!
         
         $retHTML = isset($_SERVER['CONTENT_TYPE']) && 
                 preg_match('#multipart/form-data#i', $_SERVER['CONTENT_TYPE']);
@@ -88,17 +143,18 @@ trait Pman_Core_RooJsonOutputTrait {
             $retHTML = isset($_REQUEST['returnHTML']) && $_REQUEST['returnHTML'] !='NO';
         }
         
+        
         if ($retHTML) {
             header('Content-type: text/html');
             echo "<HTML><HEAD></HEAD><BODY>";
-            echo  $json->encodeUnsafe(array(
+            echo  $this->jsencode(array(
                     'success'=> false, 
                     'errorMsg' => $str,
                     'message' => $str, // compate with exeption / loadexception.
 
                     'errors' => $errors ? $errors : true, // used by forms to flag errors.
                     'authFailure' => !empty($errors['authFailure']),
-                ));
+                ), false);
             echo "</BODY></HTML>";
             exit;
         }
@@ -116,19 +172,33 @@ trait Pman_Core_RooJsonOutputTrait {
                 
         }
         
-        echo $json->encode(array(
+        echo $this->jsencode(array(
             'success'=> false, 
-            'data'=> array(), 
+            'data'=> array(),
+            'code' => $type,
             'errorMsg' => $str,
             'message' => $str, // compate with exeption / loadexception.
             'errors' => $errors ? $errors : true, // used by forms to flag errors.
             'authFailure' => !empty($errors['authFailure']),
-        ));
+        ),true);
+        
         
         exit;
         
     }
     
+     
+   
+    
+    
+    
+    /**
+     * output data for grids or tree
+     * @ar {Array} ar Array of data
+     * @total {Number|false} total number of records (or false to return count(ar)
+     * @extra {Array} extra key value list of data to pass as extra data.
+     * 
+     */
     function jdata($ar,$total=false, $extra=array(), $cachekey = false)
     {
         // should do mobile checking???
@@ -136,8 +206,7 @@ trait Pman_Core_RooJsonOutputTrait {
             $total = count($ar);
         }
         $extra=  $extra ? $extra : array();
-        require_once 'Services/JSON.php';
-        $json = new Services_JSON();
+        
         
         $retHTML = isset($_SERVER['CONTENT_TYPE']) && 
                 preg_match('#multipart/form-data#i', $_SERVER['CONTENT_TYPE']);
@@ -153,11 +222,11 @@ trait Pman_Core_RooJsonOutputTrait {
         if ($retHTML) {
             
             header('Content-type: text/html');
-            echo "<HTML><HEAD></HEAD><BODY>";
+            echo "<HTML><HEAD></HEAD><BODY><![CDATA[";
             // encode html characters so they can be read..
             echo  str_replace(array('<','>'), array('\u003c','\u003e'),
-                        $json->encodeUnsafe(array('success' =>  true, 'total'=> $total, 'data' => $ar) + $extra));
-            echo "</BODY></HTML>";
+                        $this->jsencode(array('success' =>  true, 'total'=> $total, 'data' => $ar) + $extra, false));
+            echo "]]></BODY></HTML>";
             exit;
         }
         
@@ -181,7 +250,7 @@ trait Pman_Core_RooJsonOutputTrait {
         }
         
       
-        $ret =  $json->encode(array('success' =>  true, 'total'=> $total, 'data' => $ar) + $extra);  
+        $ret =  $this->jsencode(array('success' =>  true, 'total'=> $total, 'data' => $ar) + $extra,true);  
         
         if (!empty($cachekey)) {
             
@@ -191,10 +260,13 @@ trait Pman_Core_RooJsonOutputTrait {
             }
             file_put_contents($fn, $ret);
         }
+        
         echo $ret;
         exit;
     }
     
+    
+   
     /** a daily cache **/
     function jdataCache($cachekey)
     {
@@ -207,4 +279,24 @@ trait Pman_Core_RooJsonOutputTrait {
         return false;
         
     }
+    
+     function jsencode($v, $header = false)
+    {
+        if ($header) {
+            header("Content-type: text/javascript");
+        }
+        if (function_exists("json_encode")) {
+            $ret=  json_encode($v);
+            if ($ret !== false) {
+                return $ret;
+            }
+        }
+        require_once 'Services/JSON.php';
+        $js = new Services_JSON();
+        return $js->encodeUnsafe($v);
+        
+        
+        
+    }
+    
 }
\ No newline at end of file
index b0e7ea9..661381f 100644 (file)
--- a/Lock.php
+++ b/Lock.php
@@ -40,7 +40,7 @@ class Pman_Core_Lock extends Pman
     {
          $au = $this->getAuthUser();
         if (!$au) {
-             $this->jerr("Not authenticated", array('authFailure' => true));
+             $this->jerror("LOGIN-NOAUTH", "Not authenticated", array('authFailure' => true));
         }
         $this->authUser = $au;
         // check that it's a supplier!!!! 
@@ -77,7 +77,7 @@ class Pman_Core_Lock extends Pman
             $this->jok("No lock exists"); // been deleted before.. probably ok..
         }
         
-        if ($curlock->person_id != $this->authUser->id) {
+        if ($curlock->person_id != $this->authUser->id && empty($_REQUEST['force'])) {
             // this is an error conditon..
             $this->jerr("Lock id is invalid");
         }
index 2b3c274..a79169f 100644 (file)
@@ -65,7 +65,7 @@
 class Pman_Core_Mailer {
     var $debug          = 0;
     var $page           = false; /* usually a html_flexyframework_page */
-    var $contents       = false; /* object or array */
+    var $contents       = array(); /* object or array */
     var $template       = false; /* string */
     var $replaceImages  = false; /* boolean */
     var $rcpts   = false;
@@ -73,6 +73,8 @@ class Pman_Core_Mailer {
     var $locale = false; // eg. 'en' or 'zh_HK'
     var $urlmap = array();
     
+    var $htmlbody;
+    var $textbody;
     
     var $html_locale = false; // eg. 'en' or 'zh_HK'
     var $images         = array(); // generated list of cid images for sending
@@ -105,7 +107,12 @@ class Pman_Core_Mailer {
     }
      
     /**
-     * ---------------- Global Tools ---------------   
+     * ---------------- Global Tools ---------------
+     *
+     * applies this variables to a object
+     * msgid
+     * HTTP_HOIST
+     * 
      */
     
     function toData()
@@ -120,13 +127,15 @@ class Pman_Core_Mailer {
         
         $content->msgid = empty($content->msgid ) ? md5(time() . rand()) : $content->msgid ;
         
+        // content can override this now
         $ff = HTML_FlexyFramework::get();
         $http_host = isset($_SERVER["HTTP_HOST"]) ? $_SERVER["HTTP_HOST"] : 'pman.HTTP_HOST.not.set';
         if (isset($ff->Pman['HTTP_HOST']) && $http_host != 'localhost') {
             $http_host  = $ff->Pman['HTTP_HOST'];
         }
-        
-        $content->HTTP_HOST = $http_host;
+        if (empty($content->HTTP_HOST )) {
+            $content->HTTP_HOST = $http_host;
+        }
         
         // this should be done by having multiple template sources...!!!
         
@@ -137,16 +146,23 @@ class Pman_Core_Mailer {
             'site_prefix' => false,
             'multiSource' => true,
         );
-        if (!empty($this->templateDir)) {
-            $tmp_opts['templateDir'] = $this->templateDir;
-        }
+        
         $fopts = HTML_FlexyFramework::get()->HTML_Template_Flexy;
+        
+        //print_R($fopts);exit;
         if (!empty($fopts['DB_DataObject_translator'])) {
             $tmp_opts['DB_DataObject_translator'] = $fopts['DB_DataObject_translator'];
         }
         if (!empty($fopts['locale'])) {
             $tmp_opts['locale'] = $fopts['locale'];
         }
+        if (!empty($fopts['templateDir'])) {
+            $tmp_opts['templateDir'] = $fopts['templateDir'];
+        }
+        // override.
+        if (!empty($this->templateDir)) {
+            $tmp_opts['templateDir'] = $this->templateDir;
+        }
         
         // local opt's overwrite
         if (!empty($this->locale)) {
@@ -189,12 +205,13 @@ class Pman_Core_Mailer {
             
         }
         $tmp_opts['nonHTML'] = true;
+        //$tmp_opts['debug'] = true;
         
-        
-        //print_R($tmp_opts);
+        // print_R($tmp_opts);
         // $tmp_opts['force'] = true;
         
         $template = new HTML_Template_Flexy(  $tmp_opts );
+        
         $template->compile('mail/'. $templateFile.'.txt');
         
         /* use variables from this object to ouput data. */
@@ -241,7 +258,9 @@ class Pman_Core_Mailer {
                 unset($parts[1]['Content-Type']);
             }
             $mime->setTXTBody($parts[2]);
+            $this->textbody = $parts[2];
             $mime->setHTMLBody($htmlbody);
+            
 //            var_dump($mime);exit;
             foreach($this->images as $cid=>$cdata) { 
             
@@ -269,8 +288,10 @@ class Pman_Core_Mailer {
                 if(preg_match('/text\/html/', $header['Content-Type'])){
                     $mime->setHTMLBody($parts[2]);
                     $mime->setTXTBody('This message is in HTML only');
+                    $this->textbody = 'This message is in HTML only';
                 }else{
                     $mime->setTXTBody($parts[2]);
+                    $this->textbody = $parts[2];
                     $mime->setHTMLBody('<PRE>'.htmlspecialchars($parts[2]).'</PRE>');
                 }
             }
@@ -365,6 +386,12 @@ class Pman_Core_Mailer {
         }
         
         $oe = error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT);
+        if ($this->debug) {
+            print_r(array(
+                'rcpts' => $rcpts,
+                'email' => $email
+            ));
+        }
         $ret = $mail->send($rcpts,$email['headers'],$email['body']);
         error_reporting($oe);
         if ($ret === true) { 
index 6a7e94f..384cdbd 100644 (file)
@@ -6,6 +6,10 @@ class Pman_Core_MessagePreview extends Pman
 {
     var $masterTemplate = 'mail/MessagePreview.html';
     
+    
+    var $showHtml;
+    var $msg;
+    
     function getAuth()
     {
         if (HTML_FlexyFramework::get()->cli) {
@@ -21,17 +25,59 @@ class Pman_Core_MessagePreview extends Pman
     function get($v, $opts=array())
     {
  
-        if(empty($_REQUEST['_id']) || empty($_REQUEST['_table'])){
+        if((empty($_REQUEST['_id']) && empty($_REQUEST['template_name']) )|| empty($_REQUEST['_table'])){
             $this->jerr('Missing Options');
         }
         
         $mlq = DB_DataObject::factory($_REQUEST['_table']);
+        if (!empty($_REQUEST['template_name'])) {
+            $res = $mlq->get('name', $_REQUEST['template_name']);
+        } else {
+            $res = $mlq->get($_REQUEST['_id']);
+        }
+        if (!$res) {
+            $this->jerr("invalid id/name");
+        }
         
-        $mlq->get($_REQUEST['_id']);
+        $this->showHtml = isset($_REQUEST['_as_html']) ? true : false;
         
-        $this->msg = $mlq;
+        
+        if (isset($_REQUEST['ontable']) && !empty($_REQUEST['onid']) && !empty($_REQUEST['evtype'])) {
+            $tn = preg_replace('/[^a-z_]+/i', '', $_REQUEST['ontable']);
+            
+            $t = DB_DataObject::factory($tn);
+            if (!is_a($t, 'DB_DataObject') && !is_a($t, 'PDO_DataObject')) {
+                $this->jerr("invalid URL");
+            }
+            if (!$t->get($_REQUEST['onid'])) {
+                $this->jerr("invalid id");
+            }
+            if (!method_exists($t,'notify'.$_REQUEST['evtype'])) {
+                $this->jerr("invalid evtype");
+            }
+              
+            $m = 'notify'.$_REQUEST['evtype'];
+            $this->msg = (object)$t->$m('test@test.com', false, false, false);
+           // print_R($this->msg->mailer );
+            $this->msg->subject = $this->msg->headers['Subject'];
+            $this->msg->from_email = $mlq->from_email;
+            $this->msg->from_name = $mlq->from_name;
+            $this->msg->plaintext  = $this->msg->mailer->textbody ;
+            $this->msg->bodytext = $this->msg->mailer->htmlbody;
+            $this->msg->rcpts = $this->msg->mailer->rcpts;
+            // htmlbody 
+            //$this->plaintext = 
+            //$data->subject = $data['Subject;
+             
+            
+             
 
-        $this->showHtml = isset($_REQUEST['_as_html']) ? true : false;
+            return;
+        }
+        
+        $this->msg = $mlq;
+        $this->msg->rcpts = "send to <these@people>";
+        
         
     }
     
index fd58209..3fd4c5b 100644 (file)
@@ -97,22 +97,49 @@ class Pman_Core_Notify extends Pman
     var $max_to_domain = 10;
     
     /**
-     * @var $maxruntime - maximum time a child is allowed to run - defaut 2 minutes
+     * @var $maxruntime - maximum seconds a child is allowed to run - defaut 2 minutes
      */
     var $maxruntime = 120;
     
+    /**
+    * @var {Boolean} log_events - default true if events should be logged.
+    */
+    var $log_events = true;
+    /**
+    * @var {Number} try_again_minutes how long after failing to try again default = 30 if max runtime fails
+    */
+    var $try_again_minutes = 30;
+    
+    /**
+     * @var {String} table - the table that the class will query for notification events
+     */
     var $table = 'core_notify';
+    /**
+     * @var {String} target - the application that will run for each Row in the table (eg. Pman/Core/NotifySend)
+     */
     var $target = 'Core/NotifySend';
+    
+    
+    
     var $evtype = ''; // any notification...
                     // this script should only handle EMAIL notifications..
+    
+    var $server;  // core_notify_server
+    
+    var $poolname = 'core';
+    
+    var $opts; 
     var $force = false;
+    
+    var $clear_interval = '1 WEEK'; // how long to clear the old queue of items.
+    
     function getAuth()
     {
         $ff = HTML_FlexyFramework::get();
         if (!$ff->cli) {
             die("access denied");
         }
-        HTML_FlexyFramework::ensureSingle($_SERVER["SCRIPT_NAME"] .'|'. __FILE__, $this);
+        HTML_FlexyFramework::ensureSingle($_SERVER["SCRIPT_NAME"] .'|'. __FILE__ .'|'. (empty($_SERVER['argv'][1]) ? '': $_SERVER['argv'][1]), $this);
         return true;
     }
     
@@ -144,9 +171,19 @@ class Pman_Core_Notify extends Pman
         }
     }
     
-    
+    var $queue = array();
+    var $domain_queue = array(); // false to use nextquee
+    var $next_queue = array();
+
+   
     function get($r,$opts=array())    
     {
+        
+       // if ($this->database_is_locked()) {
+        //    die("LATER - DATABASE IS LOCKED");
+        //}
+        
+        
         $this->parseArgs($opts); 
          
         //date_default_timezone_set('UTC');
@@ -154,11 +191,30 @@ class Pman_Core_Notify extends Pman
         
         $this->generateNotifications();
         
-         
-        //DB_DataObject::debugLevel(1);
+         //DB_DataObject::debugLevel(1);
         $w = DB_DataObject::factory($this->table);
         $total = 0;
         
+        
+        
+        $ff = HTML_FlexyFramework::get();
+        
+        
+        $this->server = DB_DataObject::Factory('core_notify_server')->getCurrent($this);
+        
+        $this->server->assignQueues($this);
+        
+        
+        $this->clearOld();
+        
+        
+        if (!empty($this->evtype)) {
+            $w->evtype = $this->evtype;
+        }
+        
+        $w->server_id = $this->server->id;
+
+        
         if (!empty($opts['old'])) {
             // show old and new...
             
@@ -175,6 +231,7 @@ class Pman_Core_Notify extends Pman
             if (!$this->force) {
                 $w->whereAdd('act_when < NOW()'); // eg.. not if future..
             }
+            
     
             $w->orderBy('act_when ASC'); // oldest first.
             $total = min($w->count(), $opts['limit']);
@@ -183,14 +240,18 @@ class Pman_Core_Notify extends Pman
             $w->limit($opts['limit']); // we can run 1000 ...
         }
         
-        if (!empty($this->evtype)) {
-            $w->evtype = $this->evtype;
-        }
         
+    
+        
+         
         $w->autoJoin();
-        $w->find();
+        $total = $w->find();
+        
+        if (empty($total)) {
+            $this->logecho("Nothing In Queue - DONE");
+            exit;
+        }
         
-        $ar = array(); // $w->fetchAll();
         
         if (!empty($opts['list'])) {
             
@@ -206,46 +267,59 @@ class Pman_Core_Notify extends Pman
         }
         
         //echo "BATCH SIZE: ".  count($ar) . "\n";
-        $pushed = array();
-        $requeue = array();
+       
+        
         while (true) {
-            if ($w->fetch()) {
-                $ar[] = clone($w);
+            // only add if we don't have any queued up..
+            if (empty($this->queue) && $w->fetch()) {
+                $this->queue[] = clone($w);
                 $total--;
             }
+          
+            $this->logecho("BATCH SIZE: Queue=".  count($this->queue) . " TOTAL = " . $total  );
             
-            $this->logecho("BATCH SIZE: ".  (count($ar) + $total) );
-            
-            if (empty($ar)) {
-                $this->logecho("COMPLETED MAIN QUEUE - running deleted");
-                
-                if (empty($pushed)) {
-                    break;
+            if (empty($this->queue)) {
+                $this->logecho("COMPLETED MAIN QUEUE - running maxed out domains");
+                if ($this->domain_queue !== false) {
+                    $this->queue  = $this->remainingDomainQueue();
+                     
+                    continue;
                 }
-                $ar = $pushed;
-                $pushed = false;
-                continue;
+                break; // nothing more in queue.. and no remaining one
             }
             
             
-            $p = array_shift($ar);
+            $p = array_shift($this->queue);
             if (!$this->poolfree()) {
-                array_unshift($ar,$p); /// put it back on..
+                array_unshift($this->queue,$p); /// put it back on..
                 sleep(3);
                 continue;
             }
-            $email = $p->person() ? $p->person()->email : $p->to_email;
+            // not sure what happesn if person email and to_email is empty!!?
+            $email = empty($p->to_email) ? ($p->person() ? $p->person()->email : $p->to_email) : $p->to_email;
             
-            if ($this->poolHasDomain($email) > $this->max_to_domain) {
-                
-                if ($pushed === false) {
-                    // we only try once to requeue..
-                    $requeue[] = $p;
-                    continue;
+            $black = $this->server->isBlacklisted($email);
+            if ($black !== false) {
+                $this->logecho("Blacklisted - try giving it to next server");
+                if (false === $this->server->updateNotifyToNextServer($p)) {
+                    $ev = $this->addEvent('NOTIFY', $p, 'BLACKLISTED  FROM our DB');
+                    // we dont have an althenative server to update it with.
+                    $this->logecho("Blacklisted - next server did not work - try again in 30 mins");
+                    $this->server->updateNotifyToNextServer($w,  date("Y-m-d H:i:s",  strtotime('NOW +  30 MINUTES')),true);
+                   // $this->errorHandler( $ev->remarks);
+                   
                 }
-                $pushed[] = $p;
                 
+                continue;
+            }
+             
+            
+            if ($this->poolHasDomain($email) > $this->max_to_domain) {
                 
+                // push it to a 'domain specific queue'
+                $this->logecho("REQUEING - maxed out that domain - {$email}");
+                $this->pushQueueDomain($p, $email);
+                   
                 //sleep(3);
                 continue;
             }
@@ -255,26 +329,39 @@ class Pman_Core_Notify extends Pman
             
             
             
+        }
+        $this->logecho("REQUEUING all emails that maxed out:" . count($this->next_queue));
+        if (!empty($this->next_queue)) {
+             
+            foreach($this->next_queue as $p) {
+                if (false === $this->server->updateNotifyToNextServer($p)) {
+                    $p->updateState("????");
+                }
+            }
         }
         
+        
+        $this->logecho("QUEUE COMPLETE - waiting for pool to end");
         // we should have a time limit here...
         while(count($this->pool)) {
             $this->poolfree();
-             sleep(3);
+            sleep(3);
         }
          
-        foreach($requeue as $p) {
-            $pp = clone($p);
-            $p->act_when = $p->sqlValue('NOW + INTERVAL 1 MINUTE');
-            $p->update($pp);
-            
-        }
+        
         
         
         $this->logecho("DONE");
         exit;
     }
     
+    
+   
+    
+    // this sequentially distributes requeued emails.. - to other servers. (can exclude current one if we have that flagged.)
+     
+  
+    
     function generateNotifications()
     {
         // this should check each module for 'GenerateNotifications.php' class..
@@ -309,9 +396,9 @@ class Pman_Core_Notify extends Pman
     
     }
     
+     
     
-    
-    function run($id, $email, $cmdOpts="")
+    function run($id, $email='', $cmdOpts="")
     {
         
         static $renice = false;
@@ -321,13 +408,15 @@ class Pman_Core_Notify extends Pman
         }
         
         // phpinfo();exit;
-        $tnx = tempnam(ini_get('session.save_path'),'stdout');
-        unlink($tnx);
-        $tn =  $tnx . '.stdout';
+        
+        
+        $tn =  $this->tempName('stdout', true);
+        $tne =  $this->tempName('stderr', true);
         $descriptorspec = array(
             0 => array("pipe", 'r'),  // stdin is a pipe that the child will read from
             1 => array("file", $tn, 'w'),  // stdout is a pipe that the child will write to
-            2 => array("pipe", "w") // stderr is a file to write to
+            2 => array("file", $tne, 'w'),   // stderr is a file to write to
+          //  2 => array("pipe", "w") // stderr is a file to write to
          );
         
         static $php = false;
@@ -350,10 +439,11 @@ class Pman_Core_Notify extends Pman
         
        
         $pipe = array();
-        $this->logecho("call proc_open $cmd");
+        //$this->logecho("call proc_open $cmd");
         
         
         if ($this->max_pool_size === 1) {
+            $this->logecho("call passthru [{$email}] $cmd");
             passthru($cmd);
             return;
         }
@@ -375,6 +465,7 @@ class Pman_Core_Notify extends Pman
                 'proc' => $p,
                 'pid' => $info['pid'],
                 'out' => $tn,
+                'oute' => $tne,
                 'cmd' => $cmd,
                 'email' => $email,
                 'pipes' => $pipes,
@@ -383,7 +474,7 @@ class Pman_Core_Notify extends Pman
             
                 
         );
-        $this->logecho("RUN ({$info['pid']}) $cmd ");
+        $this->logecho("RUN [{$email}] ({$info['pid']}) $cmd ");
     }
     
     function poolfree()
@@ -394,6 +485,8 @@ class Pman_Core_Notify extends Pman
         foreach($this->pool as $p) {
              
             //echo "CHECK PID: " . $p['pid'] . "\n";
+            
+            
             $info =  proc_get_status($p['proc']);
             //var_dump($info);
             
@@ -415,18 +508,21 @@ class Pman_Core_Notify extends Pman
                     proc_terminate($p['proc'], 9);
                     //fclose($p['pipes'][1]);
                     fclose($p['pipes'][0]);
-                    fclose($p['pipes'][2]);
-                    $this->logecho("TERMINATING: ({$p['pid']}) " . $p['cmd'] . " : " . file_get_contents($p['out']));
+                    
+                    $this->logecho("TERMINATING: ({$p['pid']}) {$p['email']} " . $p['cmd'] . " : " . file_get_contents($p['out']) . " : " . file_get_contents($p['oute']));
                     @unlink($p['out']);
+                    @unlink($p['oute']);
                     
+                    // schedule again
                     $w = DB_DataObject::factory($this->table);
                     $w->get($p['notify_id']);
                     $ww = clone($w);
-                    $this->addEvent('NOTIFY', $w, 'TERMINATED - TIMEOUT');
-                    $w->act_when = date('Y-m-d H:i:s', strtotime('NOW + 30  MINUTES'));
+                    if ($this->log_events) {
+                        $this->addEvent('NOTIFY', $w, 'TERMINATED - TIMEOUT');
+                    }
+                    $w->act_when = date('Y-m-d H:i:s', strtotime("NOW + {$this->try_again_minutes} MINUTES"));
                     $w->update($ww);
                     
-                    
                     continue;
                 }
                 
@@ -434,20 +530,28 @@ class Pman_Core_Notify extends Pman
                 continue;
             }
             fclose($p['pipes'][0]);
-            fclose($p['pipes'][2]);
             //echo "CLOSING: ({$p['pid']}) " . $p['cmd'] . " : " . file_get_contents($p['out']) . "\n";
             //fclose($p['pipes'][1]);
             
             proc_close($p['proc']);
-            
-            
+             sleep(1);
+            clearstatcache();
+            if (file_exists('/proc/'. $p['pid'])) {
+                $this->logecho("proc PID={$p['pid']} still here - trying to wait");
+                pcntl_waitpid($p['pid'], $status, WNOHANG);
+            }
+
             //clearstatcache();
             //if (file_exists('/proc/'.$p['pid'])) {
             //    $pool[] = $p;
             //    continue;
             //}
-            $this->logecho("ENDED: ({$p['pid']}) " .  $p['cmd'] . " : " . file_get_contents($p['out']) );
+            $this->logecho("ENDED: ({$p['pid']}) {$p['email']} " .  $p['cmd'] . " : " . file_get_contents($p['out']) . " : " . file_get_contents($p['oute']));
             @unlink($p['out']);
+            @unlink($p['oute']);
+            // at this point we could pop onto the queue the 
+            $this->popQueueDomain($p['email']);
+            
             //unlink($p['out']);
         }
         $this->logecho("POOL SIZE: ". count($pool) );
@@ -466,9 +570,11 @@ class Pman_Core_Notify extends Pman
     function poolHasDomain($email)
     {
         $ret = 0;
-        $dom = strtolower(array_pop(explode('@',$email)));
+        $ea = explode('@',$email);
+        $dom = strtolower(array_pop($ea));
         foreach($this->pool as $p) {
-            $mdom = strtolower(array_pop(explode('@',$p['email'])));
+            $ea = explode('@',$p['email']);
+            $mdom = strtolower(array_pop($ea));
             if ($mdom == $dom) {
                 $ret++;
             }
@@ -476,6 +582,77 @@ class Pman_Core_Notify extends Pman
         return $ret;
         
     }
+    function popQueueDomain($email)
+    {
+        $ea = explode('@',$email);
+        $dom = strtolower(array_pop($ea));
+        if (empty($this->domain_queue[$dom])) {
+            return;
+        }
+        array_unshift($this->queue, array_shift($this->domain_queue[$dom]));
+        
+    }
+    
+    function pushQueueDomain($e, $email)
+    {
+        if ($this->domain_queue === false) {
+            $this->next_queue[] = $e;
+            return;
+        }
+        
+        $ea = explode('@',$email);
+        $dom = strtolower(array_pop($ea));
+        if (!isset($this->domain_queue[$dom])) {
+            $this->domain_queue[$dom] = array();
+        }
+        $this->domain_queue[$dom][] = $e;
+    }
+    function remainingDomainQueue()
+    {
+        $ret = array();
+        foreach($this->domain_queue as $dom => $ar) {
+            $ret = array_merge($ret, $ar);
+        }
+        $this->domain_queue = false;
+        return $ret;
+    }
+    function clearOld()
+     {
+          if ($this->server->isFirstServer()) {
+            
+            $p = DB_DataObject::factory($this->table);
+            $p->whereAdd("
+                sent < '2000-01-01'
+                and
+                event_id = 0
+                and
+                act_start < NOW() - INTERVAL {$this->clear_interval}
+            ");
+           // $p->limit(1000);
+            if ($p->count()) {
+                $ev = $this->addEvent('NOTIFY', false, "RETRY TIME EXCEEDED");
+                $p = DB_DataObject::factory($this->table);
+                $p->query("
+                    UPDATE
+                        {$this->table}
+                    SET
+                        sent = NOW(),
+                        msgid = '',
+                        event_id = {$ev->id}
+                    WHERE
+                        sent < '2000-01-01'
+                        and
+                        event_id = 0
+                        and
+                        act_start < NOW() - INTERVAL {$this->clear_interval}
+                    LIMIT
+                        1000
+                ");
+                
+            }
+        }
+     }
+    
 
     function output()
     {
@@ -486,4 +663,4 @@ class Pman_Core_Notify extends Pman
     {
         echo date("Y-m-d H:i:s - ") . $str . "\n";
     }
-}
\ No newline at end of file
+}
index e3b9af5..968eace 100644 (file)
@@ -16,7 +16,7 @@ class Pman_Core_NotifyAction extends Pman
     {
         $au = $this->getAuthUser();
         if (!$au) {
-             $this->jerr("Not authenticated", array('authFailure' => true));
+             $this->jerror("LOGIN-NOAUTH", "Not authenticated", array('authFailure' => true));
         }
         // workflow only applicable to owner company..
         if ($au->company()->comptype != 'OWNER') {
index 91afa5a..f94ff33 100644 (file)
@@ -71,6 +71,8 @@ class Pman_Core_NotifySend extends Pman
     );
     var $table = 'core_notify';
     var $error_handler = 'die';
+    var $poolname = 'core';
+    var $server; // core_notify_server
     
     function getAuth()
     {
@@ -85,7 +87,9 @@ class Pman_Core_NotifySend extends Pman
    
     function get($id,$opts=array())
     {
-        
+        //if ($this->database_is_locked()) {
+        //    die("LATER - DATABASE IS LOCKED");
+       // }
         //print_r($opts);
         if (!empty($opts['DB_DataObject-debug'])) {
             DB_DataObject::debugLevel($opts['DB_DataObject-debug']);
@@ -101,11 +105,18 @@ class Pman_Core_NotifySend extends Pman
         if (!$w->get($id)) {
             $this->errorHandler("invalid id\n");
         }
-        if (!$force && strtotime($w->act_when) < strtotime($w->sent)) {
-            
-            
-            $this->errorHandler("send repeat to early\n");
+
+        if (!$force && !empty($w->sent) && strtotime($w->act_when) < strtotime($w->sent)) {
+             
+            $this->errorHandler("already sent - repeat to early\n");
         }
+        
+        $this->server = DB_DataObject::Factory('core_notify_server')->getCurrent($this, $force);
+        if (!$force &&  $w->server_id != $this->server->id) {
+            $this->errorHandler("Server id does not match - use force to try again\n");
+        }
+        
+        
         if (!empty($opts['debug'])) {
             print_r($w);
             $ff = HTML_FlexyFramework::get();
@@ -115,31 +126,37 @@ class Pman_Core_NotifySend extends Pman
             HTML_FlexyFramework::get()->Core_Mailer['debug'] = true;
         }
         
-        $sent = (empty($w->sent) || preg_match('/^0000/', $w->sent)) ? false : true;
+        $sent = (empty($w->sent) || strtotime( $w->sent) < 100 ) ? false : true;
         
         if (!$force && (!empty($w->msgid) || $sent)) {
             $ww = clone($w);
-            if (!$sent) { 
-                $w->sent = $w->sent == '0000-00-00 00:00:00' ? $w->sqlValue('NOW()') :$w->sent; // do not update if sent.....
+            if (!$sent) {   // fix sent.
+                $w->sent = strtotime( $w->sent) < 100 ? $w->sqlValue('NOW()') :$w->sent; // do not update if sent.....
                 $w->update($ww);
             }    
             $this->errorHandler("message has been sent already.\n");
         }
         
+        // we have a bug with msgid not getting filled.
+        $cev = DB_DataObject::Factory('Events');
+        $cev->on_table =  $this->table;
+        $cev->on_id =  $w->id;
+        $cev->whereAdd("action IN ('NOTIFYSENT', 'NOTIFYFAIL')");
+        $cev->limit(1);
+        if ($cev->count()) {
+            $cev->find(true);
+            $w->flagDone($cev, $cev->action == 'NOTIFYSENT' ? 'alreadysent' : '');
+            $this->errorHandler( $cev->action . " (fix old) ".  $cev->remarks);
+        }
+        
+        
         $o = $w->object();
         
         if ($o === false)  {
-            
-            $ev = $this->addEvent('NOTIFY', $w,
-                            "Notification event cleared (underlying object does not exist)" );;
-            $ww = clone($w);
-            $w->sent = $w->sent == '0000-00-00 00:00:00' ? $w->sqlValue('NOW()') :$w->sent; // do not update if sent.....
-            $w->msgid = '';
-            $w->event_id = $ev->id;
-            $w->update($ww);
-            $this->errorHandler(date('Y-m-d h:i:s ') . 
-                     "Notification event cleared (underlying object does not exist)" 
-                    ."\n");
+             
+            $ev = $this->addEvent('NOTIFY', $w,   "Notification event cleared (underlying object does not exist)" );
+            $w->flagDone($ev, '');
+            $this->errorHandler(  $ev->remarks);
         }
      
         
@@ -147,19 +164,17 @@ class Pman_Core_NotifySend extends Pman
         $p = $w->person();
         
         if (isset($p->active) && empty($p->active)) {
-            $ev = $this->addEvent('NOTIFY', $w,
-                            "Notification event cleared (not user not active any more)" );;
-            $ww = clone($w);
-            $w->sent = $w->sent == '0000-00-00 00:00:00' ? $w->sqlValue('NOW()') :$w->sent; // do not update if sent.....
-            $w->msgid = '';
-            $w->event_id = $ev->id;
-            $w->update($ww);
-            $this->errorHandler(date('Y-m-d h:i:s ') . 
-                     "Notification event cleared (not user not active any more)" 
-                    ."\n");
-            $this->errorHandler("message has been sent already.\n");
+            $ev = $this->addEvent('NOTIFY', $w, "Notification event cleared (not user not active any more)" );;
+             $w->flagDone($ev, '');
+            $this->errorHandler(  $ev->remarks);
         }
+        // has it failed mutliple times..
         
+        if (!empty($w->field) && isset($p->{$w->field .'_fails'}) && $p->{$w->field .'_fails'} > 9) {
+            $ev = $this->addEvent('NOTIFY', $w, "Notification event cleared (user has to many failures)" );;
+            $w->flagDone($ev, '');
+            $this->errorHandler(  $ev->remarks);
+        }
         
         // let's work out the last notification sent to this user..
         $l = DB_DataObject::factory($this->table);
@@ -169,9 +184,11 @@ class Pman_Core_NotifySend extends Pman
                 'onid' => $w->onid,
         );
         // only newer version of the database us this..
-        $personid_col = strtolower($w->person_table).'_id';
-        if (isset($w->{$personid_col})) {
-            $lar[$personid_col] = $w->{$personid_col};
+        if (isset($w->person_table)) {
+            $personid_col = strtolower($w->person_table).'_id';
+            if (isset($w->{$personid_col})) {
+                $lar[$personid_col] = $w->{$personid_col};
+            }
         }
         
         
@@ -200,17 +217,9 @@ class Pman_Core_NotifySend extends Pman
         $email =  $this->makeEmail($o, $p, $last, $w, $force);
         
         if ($email === true)  {
-            
-            $ev = $this->addEvent('NOTIFY', $w,
-                            "Notification event cleared (not required any more)" );;
-            $ww = clone($w);
-            $w->sent = (!$w->sent || $w->sent == '0000-00-00 00:00:00') ? $w->sqlValue('NOW()') : $w->sent; // do not update if sent.....
-            $w->msgid = '';
-            $w->event_id = $ev->id;
-            $w->update($ww);
-            $this->errorHandler(date('Y-m-d h:i:s ') . 
-                     "Notification event cleared (not required any more)" 
-                    ."\n");
+            $ev = $this->addEvent('NOTIFY', $w, "Notification event cleared (not required any more) - toEmail=true" );;
+            $w->flagDone($ev, '');
+            $this->errorHandler( $ev->remarks);
         }
         if (is_a($email, 'PEAR_Error')) {
             $email =array(
@@ -227,25 +236,18 @@ class Pman_Core_NotifySend extends Pman
          
         if ($email === false || isset($email['error']) || empty($p)) {
             // object returned 'false' - it does not know how to send it..
-            $ev = $this->addEvent('NOTIFY', $w, isset($email['error'])  ?
-                            $email['error'] : "INTERNAL ERROR  - We can not handle " . $w->ontable); 
-            $ww = clone($w);
-            $w->sent = (!$w->sent || $w->sent == '0000-00-00 00:00:00') ? $w->sqlValue('NOW()') : $w->sent; // do not update if sent.....
-            $w->msgid = '';
-            $w->event_id = $ev->id;
-            $w->update($ww);
-            $this->errorHandler(date('Y-m-d h:i:s ') . 
-                    (isset($email['error'])  ?
-                            $email['error'] : "INTERNAL ERROR  - We can not handle " . $w->ontable)
-                    ."\n");
+            $ev = $this->addEvent('NOTIFYFAIL', $w, isset($email['error'])  ? $email['error'] : "INTERNAL ERROR  - We can not handle " . $w->ontable); 
+            $w->flagDone($ev, '');
+            $this->errorHandler(  $ev->remarks);
         }
         
+         
         
         if (isset($email['later'])) {
-            $old = clone($w);
-            $w->act_when = $email['later'];
-            $w->update($old);
-            $this->errorHandler(date('Y-m-d h:i:s ') . " Delivery postponed by email creator to {$email['later']}");
+             
+            $this->server->updateNotifyToNextServer($w, $email['later'],true);
+             
+            $this->errorHandler("Delivery postponed by email creator to {$email['later']}");
         }
         
          
@@ -272,26 +274,33 @@ class Pman_Core_NotifySend extends Pman
         
             // since some of them have spaces?!?!
         $p->email = trim($p->email);
+        $ww = clone($w);
+        $ww->to_email = empty($ww->to_email) ? $p->email : $ww->to_email;
+        $explode_email = explode('@', $ww->to_email);
+        $dom = array_pop($explode_email);
+        
+        $core_domain = DB_DataObject::factory('core_domain')->loadOrCreate($dom);
+
+        
+        $ww->domain_id = $core_domain->id;
+        // if to_email has not been set!?
+        $ww->update($w); // if nothing has changed this will not do anything.
+        $w = clone($ww);
+    
       
         
         require_once 'Validate.php';
         if (!Validate::email($p->email, true)) {
-            $ev = $this->addEvent('NOTIFY', $w, "INVALID ADDRESS: " . $p->email);
-            $ww = clone($w);
-            $w->sent = (!$w->sent || $w->sent == '0000-00-00 00:00:00') ? $w->sqlValue('NOW()') : $w->sent; // do not update if sent.....
-            $w->msgid = '';
-            $w->event_id = $ev->id;
-            $w->update($ww);
-            $this->errorHandler(date('Y-m-d h:i:s ') . "INVALID ADDRESS: " . $p->email. "\n");
+            $ev = $this->addEvent('NOTIFYFAIL', $w, "INVALID ADDRESS: " . $p->email);
+            $w->flagDone($ev, '');
+            $this->errorHandler($ev->remarks);
             
         }
         
         
         $ff = HTML_FlexyFramework::get();
         
-        $explode_email = explode('@', $p->email);
-        $dom = array_pop($explode_email);
-        
+     
         $mxs = $this->mxs($dom);
         $ww = clone($w);
 
@@ -299,37 +308,33 @@ class Pman_Core_NotifySend extends Pman
         // need to handle temporary failure..
        
         
-          // we try for 3 days..
-        $retry = 5;
+          // we try for 2 days..
+        $retry = 15;
         if (strtotime($w->act_start) <  strtotime('NOW - 1 HOUR')) {
             // older that 1 hour.
-            $retry = 15;
+            $retry = 60;
         }
         
         if (strtotime($w->act_start) <  strtotime('NOW - 1 DAY')) {
             // older that 1 day.
-            $retry = 60;
+            $retry = 120;
         }
         if (strtotime($w->act_start) <  strtotime('NOW - 2 DAY')) {
             // older that 1 day.
-            $retry = 120;
+            $retry = 240;
         }
         
-        if ($mxs === false) {
-            // only retry for 2 day son the MX issue..
-            if ($retry < 120) {
+        if (empty($mxs)) {
+            // only retry for 1 day if the MX issue..
+            if ($retry < 240) {
                 $this->addEvent('NOTIFY', $w, 'MX LOOKUP FAILED ' . $dom );
-                $w->act_when = date('Y-m-d H:i:s', strtotime('NOW + ' . $retry . ' MINUTES'));
-                $w->update($ww);
-                $this->errorHandler(date('Y-m-d h:i:s') . " - MX LOOKUP FAILED\n");
+                $w->flagLater(date('Y-m-d H:i:s', strtotime('NOW + ' . $retry . ' MINUTES')));
+                $this->errorHandler($ev->remarks);
             }
             
-            $ev = $this->addEvent('NOTIFY', $w, "BAD ADDRESS - BAD DOMAIN - ". $p->email );
-            $w->sent = (!$w->sent || $w->sent == '0000-00-00 00:00:00') ? $w->sqlValue('NOW()') : $w->sent; // do not update if sent.....
-            $w->msgid = '';
-            $w->event_id = $ev->id;
-            $w->update($ww);
-            $this->errorHandler(date('Y-m-d h:i:s') . " - FAILED -  BAD EMAIL - {$p->email} \n");
+            $ev = $this->addEvent('NOTIFYFAIL', $w, "BAD ADDRESS - BAD DOMAIN - ". $p->email );
+            $w->flagDone($ev, '');
+            $this->errorHandler($ev->remarks);
             
             
         }
@@ -337,21 +342,19 @@ class Pman_Core_NotifySend extends Pman
         
         
         
-        if (!$force && strtotime($w->act_start) <  strtotime('NOW - 14 DAY')) {
-            $ev = $this->addEvent('NOTIFY', $w, "BAD ADDRESS - GIVE UP - ". $p->email );
-            $w->sent = (!$w->sent || $w->sent == '0000-00-00 00:00:00') ? $w->sqlValue('NOW()') :$w->sent; // do not update if sent.....
-            $w->msgid = '';
-            $w->event_id = $ev->id;
-            $w->update($ww);
-            $this->errorHandler(date('Y-m-d h:i:s') . " - FAILED -  GAVE UP TO OLD - {$p->email} \n");
+        if (!$force && strtotime($w->act_start) <  strtotime('NOW - 3 DAY')) {
+            $ev = $this->addEvent('NOTIFYFAIL', $w, "BAD ADDRESS - GIVE UP - ". $p->email );
+            $w->flagDone($ev, '');
+            $this->errorHandler(  $ev->remarks);
         }
         
+        $retry_when = date('Y-m-d H:i:s', strtotime('NOW + ' . $retry . ' MINUTES'));
         
-        
-        $w->to_email = $p->email; 
         //$this->addEvent('NOTIFY', $w, 'GREYLISTED ' . $p->email . ' ' . $res->toString());
         // we can only update act_when if it has not been sent already (only happens when running in force mode..)
-        $w->act_when =  (!$w->act_when || $w->act_when == '0000-00-00 00:00:00') ? date('Y-m-d H:i:s', strtotime('NOW + ' . $retry . ' MINUTES')) : $w->act_when;
+        // set act when if it's empty...
+        $w->act_when =  (!$w->act_when || $w->act_when == '0000-00-00 00:00:00') ? $retry_when : $w->act_when;
+        
         $w->update($ww);
         
         $ww = clone($w);   
@@ -359,20 +362,19 @@ class Pman_Core_NotifySend extends Pman
         $fail = false;
         require_once 'Mail.php';
         
-        $core_domain = DB_DataObject::factory('core_domain');
-        if(!$core_domain->get('domain', $dom)){
-            $core_domain = DB_DataObject::factory('core_domain');
-            $core_domain->setFrom(array(
-                'domain' => $dom
-            ));
-            $core_domain->insert();
+        
+        $this->server->initHelo();
+        
+        if (!isset($ff->Mail['helo'])) {
+            $this->errorHandler("config Mail[helo] is not set");
         }
+        
+        $email = DB_DataObject::factory('core_notify_sender')->filterEmail($email, $w);
+            
                         
         foreach($mxs as $mx) {
             
-            if (!isset($ff->Mail['helo'])) {
-                $this->errorHandler("config Mail[helo] is not set");
-            }
+           
             $this->debug_str = '';
             $this->debug("Trying SMTP: $mx / HELO {$ff->Mail['helo']}");
             $mailer = Mail::factory('smtp', array(
@@ -383,76 +385,75 @@ class Pman_Core_NotifySend extends Pman
                     //'debug' => isset($opts['debug']) ?  1 : 0,
                     'debug' => 1,
                     'debug_handler' => array($this, 'debugHandler')
-                ));
+            ));
             
             // if the host is the mail host + it's authenticated add auth details
             // this normally will happen if you sent  Pman_Core_NotifySend['host']
+             
+            
             if (isset($ff->Mail['host']) && $ff->Mail['host'] == $mx && !empty($ff->Mail['auth'] )) {
                 
-                $username = $ff->Mail['username'] ;
-                $password = $ff->Mail['password'] ;
+                $mailer->auth = true;
+                $mailer->username = $ff->Mail['username'];
+                $mailer->password = $ff->Mail['password'];        
+            }
+            
+            if(!empty($ff->Core_Notify) && !empty($ff->Core_Notify['routes'])){
                 
-                if(!empty($ff->Core_Notify) && !empty($ff->Core_Notify['routes'])){
+                // we might want to regex 'office365 as a mx host 
+                foreach ($ff->Core_Notify['routes'] as $server => $settings){
+                    if(!in_array($dom, $settings['domains'])){
+                        continue;
+                    }
                     
-                    foreach ($ff->Core_Notify['routes'] as $server => $settings){
-                        if(!in_array($dom, $settings['domains'])){
-                            continue;
-                        }
-                        
-                        // what's the minimum timespan.. - if we have 60/hour.. that's 1 every minute.
-                        // if it's newer that '1' minute...
-                        // then shunt it..
-                        
-                        $seconds = floor((60 * 60) / $settings['rate']);
-                        
-                        $core_notify = DB_DataObject::factory($this->table);
-                        $core_notify->domain_id = $core_domain->id;
-                        $core_notify->whereAdd("
-                            sent >= NOW() - INTERVAL $seconds SECONDS
-                        ");
-                        
-                        if($core_notify->count()){
-                            $old = clone($w);
-                            $w->act_when = date("Y-m-d H:i:s", time() + $seconds);
-                            $w->update($old);
-                            $this->errorHandler(date('Y-m-d h:i:s ') . " Too many emails sent by {$dom}");
-                        }
-                        
-                        // that make's this test obsolete...
-                        /*
-                        
-                        $core_notify = DB_DataObject::factory($this->table);
-                        $core_notify->domain_id = $core_domain->id;
-                        $core_notify->whereAdd("
-                            sent >= NOW() - INTERVAL 1 HOUR
-                        ");
-                        
-                        if($core_notify->count() >= $settings['rate']){
-                            $old = clone($w);
-                            $w->act_when = date("Y-m-d H:i:s", strtotime('+1 HOUR'));
-                            $w->update($old);
-                            $this->errorHandler(date('Y-m-d h:i:s ') . " Too many emails sent by {$dom}");
-                        }
-                        */
-                        
-                        
-                        
-                        $mailer->host = $server;
-                        $username = $settings['username'];
-                        $password = $settings['password'];
+                    // what's the minimum timespan.. - if we have 60/hour.. that's 1 every minute.
+                    // if it's newer that '1' minute...
+                    // then shunt it..
+                    
+                    $settings['rate'] = isset( $settings['rate']) ?  $settings['rate']  : 360;
+                    
+                    $seconds = floor((60 * 60) / $settings['rate']);
+                    
+                    $core_notify = DB_DataObject::factory($this->table);
+                    $core_notify->domain_id = $core_domain->id;
+                    $core_notify->server_id = $this->server->id;
+                    $core_notify->whereAdd("
+                        sent >= NOW() - INTERVAL $seconds SECOND
+                    ");
+                    
+                    if($core_notify->count()){
+                        $this->server->updateNotifyToNextServer( $w , date("Y-m-d H:i:s", time() + $seconds), true);
+                        $this->errorHandler( " Too many emails sent by {$dom} - requeing");
+                    }
+                     
+                    
+                    
+                    $mailer->host = $server;
+                    $mailer->auth = isset($settings['auth']) ? $settings['auth'] : true;
+                    $mailer->username = $settings['username'];
+                    $mailer->password = $settings['password'];
+                    if (isset($settings['port'])) {
+                        $mailer->port = $settings['port'];
+                    }
+                    if (isset($settings['socket_options'])) {
+                        $mailer->socket_options = $settings['socket_options'];
                         
-                        break;
                     }
                     
+                    
+                    break;
                 }
                 
-                $mailer->auth = true;
-                $mailer->username = $username;
-                $mailer->password = $password;        
             }
+        
+           
+            
             
             $res = $mailer->send($p->email, $email['headers'], $email['body']);
-             
+            if (is_object($res)) {
+                $res->backtrace = array(); 
+            }
+            $this->debug("GOT response to send: ". print_r($res,true)); 
             
             if ($res === true) {
                 // success....
@@ -462,46 +463,36 @@ class Pman_Core_NotifySend extends Pman
                 $ev = $this->addEvent($successEventName, $w, "{$w->to_email} - {$email['headers']['Subject']}");
                 
                 $ev->writeEventLog($this->debug_str);
+                 
+                $w->flagDone($ev, $email['headers']['Message-Id']);
                 
-                if(strtotime($w->act_when) > strtotime("NOW")){
-                    $w->act_when = date('Y-m-d H:i:s');
-                }
-                
-                $w->sent = (!$w->sent || $w->sent == '0000-00-00 00:00:00') ? $w->sqlValue('NOW()') : $w->sent; // do not update if sent.....
-                $w->msgid = $email['headers']['Message-Id'];
-                $w->event_id = $ev->id; // sent ok.. - no need to record it..
-                $w->domain_id = $core_domain->id;
-                $w->update($ww);
-                
+                 
                 // enable cc in notify..
                 if (!empty($email['headers']['Cc'])) {
                     $cmailer = Mail::factory('smtp',  isset($ff->Mail) ? $ff->Mail : array() );
                     $email['headers']['Subject'] = "(CC): " . $email['headers']['Subject'];
-                    $cmailer->send($email['headers']['Cc'],
-                                  $email['headers'], $email['body']);
+                    $cmailer->send($email['headers']['Cc'],    $email['headers'], $email['body']);
                     
                 }
                 
                 if (!empty($email['bcc'])) {
                     $cmailer = Mail::factory('smtp', isset($ff->Mail) ? $ff->Mail : array() );
                     $email['headers']['Subject'] = "(CC): " . $email['headers']['Subject'];
-                    $res = $cmailer->send($email['bcc'],
-                                  $email['headers'], $email['body']);
+                    $res = $cmailer->send($email['bcc'],  $email['headers'], $email['body']);
                     if (!$res || is_a($res, 'PEAR_Error')) {
                         echo "could not send bcc..\n";
                     } else {
                         echo "Sent BCC to {$email['bcc']}\n";
                     }
                 }
-                
-                
-                $this->errorHandler(date('Y-m-d h:i:s') . " - SENT {$w->id} - {$w->to_email} \n", true);
+                 
+                $this->errorHandler( " SENT {$w->id} - {$ev->remarks}", true);
             }
             // what type of error..
             $code = empty($res->userinfo['smtpcode']) ? -1 : $res->userinfo['smtpcode'];
             if (!empty($res->code) && $res->code == 10001) {
                 // fake greylist if timed out.
-                $code = 421;
+                $code = -1; 
             }
             
             if ($code < 0) {
@@ -518,51 +509,67 @@ class Pman_Core_NotifySend extends Pman
                     $errmsg=  $res->userinfo['smtpcode'] . ':' . $res->userinfo['smtptext'];
                 }
                 //print_r($res);
-                $this->addEvent('NOTIFY', $w, 'GREYLISTED - ' . $errmsg);
-                $w->act_when = date('Y-m-d H:i:s', strtotime('NOW + ' . $retry . ' MINUTES'));
-                $w->domain_id = $core_domain->id;
-                $w->update($ww);
+                $ev = $this->addEvent('NOTIFY', $w, 'GREYLISTED - ' . $errmsg);
                 
+                $this->server->updateNotifyToNextServer($w,  $retry_when,true);
                 
-                $this->errorHandler(date('Y-m-d h:i:s') . " - GREYLISTED -  $errmsg \n");
+                $this->errorHandler(  $ev->remarks);
             }
+            
             $fail = true;
             break;
         }
-        if ($fail || $next_try_min > (2*24*60)) {
+        
+        // after trying all mxs - could not connect...
+        if  (!$fail && ($next_try_min > (2*24*60) || strtotime($w->act_start) < strtotime('NOW - 3 DAYS'))) {
+            
+            $errmsg=  " - UNKNOWN ERROR";
+            if (isset($res->userinfo['smtptext'])) {
+                $errmsg=  $res->userinfo['smtpcode'] . ':' . $res->userinfo['smtptext'];
+            }
+            
+            $ev = $this->addEvent('NOTIFYFAIL', $w,  "RETRY TIME EXCEEDED - " .  $errmsg);
+            $w->flagDone($ev, '');
+            $this->errorHandler( $ev->remarks);
+        }
+        
+        if ($fail) { //// !!!!<<< BLACKLIST DETECT?
         // fail.. = log and give up..
-            $errmsg=  $fail ? ($res->userinfo['smtpcode'] . ': ' .$res->toString()) :  " - UNKNOWN ERROR";
+            $errmsg=   $res->userinfo['smtpcode'] . ': ' .$res->toString();
             if (isset($res->userinfo['smtptext'])) {
                 $errmsg=  $res->userinfo['smtpcode'] . ':' . $res->userinfo['smtptext'];
             }
             
-            $ev = $this->addEvent('NOTIFY', $w, ($fail ? "FAILED - " : "RETRY TIME EXCEEDED - ") .
-                       $errmsg);
-            $w->sent = (!$w->sent || $w->sent == '0000-00-00 00:00:00') ? $w->sqlValue('NOW()') : $w->sent; // do not update if sent.....
-            $w->msgid = '';
-            $w->event_id = $ev->id;
-            $w->domain_id = $core_domain->id;
-            $w->update($ww);
-            $this->errorHandler(date('Y-m-d h:i:s') . ' - FAILED - '. ($fail ? $res->toString() : "RETRY TIME EXCEEDED\n"));
-        }
-        
-        // handle no host availalbe forever...
-        if (strtotime($w->act_start) < strtotime('NOW - 3 DAYS')) {
-            $ev = $this->addEvent('NOTIFY', $w, "RETRY TIME EXCEEDED - ". $p->email);
-            $w->sent = (!$w->sent || $w->sent == '0000-00-00 00:00:00') ? $w->sqlValue('NOW()') : $w->sent; // do not update if sent.....
-            $w->msgid = '';
-            $w->event_id = $ev->id;
-            $w->domain_id = $core_domain->id;
-            $w->update($ww);
-            $this->errorHandler(date('Y-m-d h:i:s') . " - FAILED - RETRY TIME EXCEEDED\n");
-        }
-        
-        
-        $this->addEvent('NOTIFY', $w, 'NO HOST CAN BE CONTACTED:' . $p->email);
-        $w->act_when = date('Y-m-d H:i:s', strtotime('NOW + 5 MINUTES'));
-        $w->domain_id = $core_domain->id;
-        $w->update($ww);
-        $this->errorHandler(date('Y-m-d h:i:s') ." - NO HOST AVAILABLE\n");
+            if ( $res->userinfo['smtpcode']> 500 ) {
+                
+                DB_DataObject::factory('core_notify_sender')->checkSmtpResponse($email, $w, $errmsg);
+
+                
+                if ($this->server->checkSmtpResponse($errmsg, $core_domain)) {
+                    $ev = $this->addEvent('NOTIFY', $w, 'BLACKLISTED  - ' . $errmsg);
+                    $this->server->updateNotifyToNextServer($w,  $retry_when,true);
+                    $this->errorHandler( $ev->remarks);
+                }
+            }
+             
+            $ev = $this->addEvent('NOTIFYFAIL', $w, ($fail ? "FAILED - " : "RETRY TIME EXCEEDED - ") .  $errmsg);
+            $w->flagDone($ev, '');
+             
+            $this->errorHandler( $ev->remarks);
+        }
+        
+        // at this point we just could not find any MX records..
+        
+        
+        // try again.
+        
+        $ev = $this->addEvent('NOTIFY', $w, 'GREYLIST - NO HOST CAN BE CONTACTED:' . $p->email);
+        
+        $this->server->updateNotifyToNextServer($w,  $retry_when ,true);
+
+        
+         
+        $this->errorHandler($ev->remarks);
 
         
     }
@@ -586,9 +593,11 @@ class Pman_Core_NotifySend extends Pman
         asort($mx_weight,SORT_NUMERIC);
         
         foreach($mx_weight as $k => $weight) {
-            $mxs[] = $mx_records[$k];
+            if (!empty($mx_records[$k])) {
+                $mxs[] = $mx_records[$k];
+            }
         }
-        return $mxs;
+        return empty($mxs) ? false : $mxs;
     }
     
     /**
@@ -621,7 +630,8 @@ class Pman_Core_NotifySend extends Pman
             echo "calling :" . get_class($object) . '::' .$m . "\n";
             return $object->$m($rcpt, $last_sent_date, $notify, $force);
         }
-                
+        // fallback if evtype is empty..
+        
         if (method_exists($object, 'toMailerData')) {
             return $object->toMailerData(array(
                 'rcpts'=>$rcpt,
@@ -630,8 +640,12 @@ class Pman_Core_NotifySend extends Pman
             //var_Dump($object);
             //exit;
         }
+        if (method_exists($object, 'toEmail')) {
+            return $object->toEmail($rcpt, $last_sent_date, $notify, $force);
+        }
+        // no way to send this.. - this needs to handle core_notify how we have used it for the approval stuff..
         
-        return $object->toEmail($rcpt, $last_sent_date, $notify, $force);
+        return false;
     }
     
     function debug($str)
@@ -652,6 +666,7 @@ class Pman_Core_NotifySend extends Pman
     {
         $this->debug_str .= strlen($this->debug_str) ? "\n" : '';
         $this->debug_str .= $message;
+        //echo $message ."\n";
     }
     
     function errorHandler($msg, $success = false)
@@ -664,8 +679,27 @@ class Pman_Core_NotifySend extends Pman
             throw new Pman_Core_NotifySend_Exception_Fail($msg);
         }
         
-        die($msg);
+        die(date('Y-m-d h:i:s') . ' ' . $msg ."\n");
         
         
     }
+    
+    function updateServer($w)
+    {
+        $ff = HTML_FlexyFramework::get();
+         
+        if (empty($ff->Core_Notify['servers'])) {
+            return;
+        }
+        // some classes dont support server routing
+        if (!property_exists($w, 'server_id')) {
+            return;
+        }
+        // next server..
+        $w->server_id = ($w->server_id + 1) % count(array_keys($ff->Core_Notify['servers']));
+         
+    }
+    
+
+    
 }
\ No newline at end of file
index 30aa19b..11efd6d 100644 (file)
@@ -126,12 +126,12 @@ Pman.Delete = {
             tab.paging.onClick('refresh');   
         } else if (tab.grid.footer && tab.grid.footer.onClick) {
             // new xtype built grids
-            tab.grid.footer.onClick('refresh');   
+            tab.grid.footer.onClick('refresh');
+        } else if (tab.grid) {
+            tab.grid.getDataSource().load({});
         } else if (tab.refresh) {
             tab.refresh(); // this might cause problems as panels have a refresh method?
-        } else {
-            tab.grid.getDataSource().load();
-        }
+        } 
     
     }
 }
\ No newline at end of file
diff --git a/Pman.Dialog.CoreColumnConfig.bjs b/Pman.Dialog.CoreColumnConfig.bjs
new file mode 100644 (file)
index 0000000..1bff557
--- /dev/null
@@ -0,0 +1,113 @@
+{
+ "name" : "Pman.Dialog.CoreColumnConfig",
+ "parent" : "",
+ "title" : "",
+ "path" : "/home/alan/gitlive/Pman.Core/Pman.Dialog.CoreColumnConfig.bjs",
+ "permname" : "",
+ "modOrder" : "001",
+ "strings" : {
+  "cfcd208495d565ef66e7dff9f98764da" : "0",
+  "ea4788705e6873b424c65e91c2846b19" : "Cancel",
+  "c40cab5f875bb6c270d800eff77a4af0" : "Save Column Configuration",
+  "b5a7adde1af5c87d7fd797b6245c2a39" : "Description",
+  "c9cc8cce247e49bae79f15173ce97354" : "Save"
+ },
+ "named_strings" : {
+  "description_fieldLabel" : "b5a7adde1af5c87d7fd797b6245c2a39",
+  "name_value" : "cfcd208495d565ef66e7dff9f98764da"
+ },
+ "items" : [
+  {
+   "listeners" : {
+    "show" : "function (_self)\n{\n    \n}"
+   },
+   "modal" : true,
+   "collapsible" : false,
+   "background" : true,
+   "title" : "Save Column Configuration",
+   "xtype" : "LayoutDialog",
+   "width" : 400,
+   "$ xns" : "Roo",
+   "closable" : false,
+   "resizable" : false,
+   "height" : 110,
+   "items" : [
+    {
+     "xtype" : "LayoutRegion",
+     "$ xns" : "Roo",
+     "titlebar" : false,
+     "* prop" : "center"
+    },
+    {
+     "background" : true,
+     "region" : "center",
+     "fitToFrame" : true,
+     "xtype" : "ContentPanel",
+     "$ xns" : "Roo",
+     "items" : [
+      {
+       "listeners" : {
+        "|actioncomplete" : "function (_self, action)\n{\n  if (action.type == 'setdata') {\n\n        \n        \n        if(typeof(_this.data.title) != 'undefined' && _this.data.title.length){\n            _this.dialog.setTitle(_this.data.title);\n        }\n  \n        if(_this.data.id){\n            _this.dialog.el.mask(\"Loading\");\n            this.load({ method: 'GET', params: { '_id' : _this.data.id }}); \n        }\n       \n       return;\n    }\n    if (action.type == 'load') {\n        _this.dialog.el.unmask();\n        return;\n    }\n    if (action.type == 'submit' ) {\n        _this.dialog.el.unmask();\n        _this.dialog.hide();\n\n        if (_this.callback) {\n           _this.callback.call(_this, action.result.data);\n        }\n        _this.form.reset();\n    }\n}\n",
+        "|rendered" : "function (form)\n{\n   _this.form = form;\n}"
+       },
+       "$ url" : "baseURL + '/Roo/core_setting'",
+       "method" : "POST",
+       "xtype" : "Form",
+       "style" : "padding:5px",
+       "$ xns" : "Roo.form",
+       "items" : [
+        {
+         "fieldLabel" : "Description",
+         "xtype" : "TextField",
+         "allowBlank" : false,
+         "width" : 250,
+         "$ xns" : "Roo.form",
+         "name" : "description"
+        },
+        {
+         "xtype" : "Hidden",
+         "$ xns" : "Roo.form",
+         "name" : "module"
+        },
+        {
+         "xtype" : "Hidden",
+         "$ xns" : "Roo.form",
+         "name" : "val"
+        },
+        {
+         "xtype" : "Hidden",
+         "value" : 0,
+         "$ xns" : "Roo.form",
+         "name" : "name"
+        },
+        {
+         "xtype" : "Hidden",
+         "$ xns" : "Roo.form",
+         "name" : "id"
+        }
+       ]
+      }
+     ]
+    },
+    {
+     "listeners" : {
+      "|click" : "function() {\n    _this.form.reset();\n    _this.dialog.hide();\n}"
+     },
+     "text" : "Cancel",
+     "xtype" : "Button",
+     "$ xns" : "Roo",
+     "* prop" : "buttons[]"
+    },
+    {
+     "listeners" : {
+      "|click" : "function() {\n\n     \n    _this.form.doAction('submit');\n    \n}"
+     },
+     "text" : "Save",
+     "xtype" : "Button",
+     "$ xns" : "Roo",
+     "* prop" : "buttons[]"
+    }
+   ]
+  }
+ ]
+}
\ No newline at end of file
diff --git a/Pman.Dialog.CoreColumnConfig.js b/Pman.Dialog.CoreColumnConfig.js
new file mode 100644 (file)
index 0000000..9e9cbed
--- /dev/null
@@ -0,0 +1,191 @@
+//<script type="text/javascript">
+
+// Auto generated file - created by app.Builder.js- do not edit directly (at present!)
+
+Roo.namespace('Pman.Dialog');
+
+Pman.Dialog.CoreColumnConfig = {
+
+ _strings : {
+  'cfcd208495d565ef66e7dff9f98764da' :"0",
+  'ea4788705e6873b424c65e91c2846b19' :"Cancel",
+  'c40cab5f875bb6c270d800eff77a4af0' :"Save Column Configuration",
+  'b5a7adde1af5c87d7fd797b6245c2a39' :"Description",
+  'c9cc8cce247e49bae79f15173ce97354' :"Save"
+ },
+ _named_strings : {
+  'description_fieldLabel' : 'b5a7adde1af5c87d7fd797b6245c2a39' /* Description */ ,
+  'name_value' : 'cfcd208495d565ef66e7dff9f98764da' /* 0 */ 
+ },
+
+ dialog : false,
+ callback:  false,
+
+ show : function(data, cb)
+ {
+  if (!this.dialog) {
+   this.create();
+  }
+
+  this.callback = cb;
+  this.data = data;
+  this.dialog.show(this.data._el);
+  if (this.form) {
+   this.form.reset();
+   this.form.setValues(data);
+   this.form.fireEvent('actioncomplete', this.form,  { type: 'setdata', data: data });
+  }
+
+ },
+
+ create : function()
+ {
+   var _this = this;
+   this.dialog = Roo.factory({
+    xtype : 'LayoutDialog',
+    background : true,
+    closable : false,
+    collapsible : false,
+    height : 110,
+    modal : true,
+    resizable : false,
+    title : _this._strings['c40cab5f875bb6c270d800eff77a4af0'] /* Save Column Configuration */,
+    width : 400,
+    listeners : {
+     show : function (_self)
+      {
+          
+      }
+    },
+    xns : Roo,
+    '|xns' : 'Roo',
+    center : {
+     xtype : 'LayoutRegion',
+     titlebar : false,
+     xns : Roo,
+     '|xns' : 'Roo'
+    },
+    buttons : [
+     {
+      xtype : 'Button',
+      text : _this._strings['ea4788705e6873b424c65e91c2846b19'] /* Cancel */,
+      listeners : {
+       click : function() {
+            _this.form.reset();
+            _this.dialog.hide();
+        }
+      },
+      xns : Roo,
+      '|xns' : 'Roo'
+     },
+     {
+      xtype : 'Button',
+      text : _this._strings['c9cc8cce247e49bae79f15173ce97354'] /* Save */,
+      listeners : {
+       click : function() {
+        
+             
+            _this.form.doAction('submit');
+            
+        }
+      },
+      xns : Roo,
+      '|xns' : 'Roo'
+     }
+    ],
+    items  : [
+     {
+      xtype : 'ContentPanel',
+      background : true,
+      fitToFrame : true,
+      region : 'center',
+      xns : Roo,
+      '|xns' : 'Roo',
+      items  : [
+       {
+        xtype : 'Form',
+        method : 'POST',
+        style : 'padding:5px',
+        url : baseURL + '/Roo/core_setting',
+        listeners : {
+         actioncomplete : function (_self, action)
+          {
+            if (action.type == 'setdata') {
+          
+                  
+                  
+                  if(typeof(_this.data.title) != 'undefined' && _this.data.title.length){
+                      _this.dialog.setTitle(_this.data.title);
+                  }
+            
+                  if(_this.data.id){
+                      _this.dialog.el.mask("Loading");
+                      this.load({ method: 'GET', params: { '_id' : _this.data.id }}); 
+                  }
+                 
+                 return;
+              }
+              if (action.type == 'load') {
+                  _this.dialog.el.unmask();
+                  return;
+              }
+              if (action.type == 'submit' ) {
+                  _this.dialog.el.unmask();
+                  _this.dialog.hide();
+          
+                  if (_this.callback) {
+                     _this.callback.call(_this, action.result.data);
+                  }
+                  _this.form.reset();
+              }
+          },
+         rendered : function (form)
+          {
+             _this.form = form;
+          }
+        },
+        xns : Roo.form,
+        '|xns' : 'Roo.form',
+        items  : [
+         {
+          xtype : 'TextField',
+          allowBlank : false,
+          fieldLabel : _this._strings['b5a7adde1af5c87d7fd797b6245c2a39'] /* Description */,
+          name : 'description',
+          width : 250,
+          xns : Roo.form,
+          '|xns' : 'Roo.form'
+         },
+         {
+          xtype : 'Hidden',
+          name : 'module',
+          xns : Roo.form,
+          '|xns' : 'Roo.form'
+         },
+         {
+          xtype : 'Hidden',
+          name : 'val',
+          xns : Roo.form,
+          '|xns' : 'Roo.form'
+         },
+         {
+          xtype : 'Hidden',
+          name : 'name',
+          value : 0,
+          xns : Roo.form,
+          '|xns' : 'Roo.form'
+         },
+         {
+          xtype : 'Hidden',
+          name : 'id',
+          xns : Roo.form,
+          '|xns' : 'Roo.form'
+         }
+        ]
+       }
+      ]
+     }
+    ]
+   });
+ }
+};
index 70ea94e..ef6cffb 100644 (file)
@@ -91,8 +91,8 @@
       {
        "listeners" : {
         "actionfailed" : "function(f, act) {\n    _this.dialog.el.unmask();\n    // error msg???\n    Pman.standardActionFailed(f,act);\n              \n}",
-        "actioncomplete" : "function(f, act) {\n    _this.dialog.el.unmask();\n    //console.log('load completed'); \n    // error messages?????\n    if(act.type == 'setdata'){\n        this.load({ method: 'GET', params: { '_id' : _this.data.id }});\n        return;\n    }\n   \n    if (act.type == 'load') {\n        _this.data = act.result.data;\n        var meth = _this.data.comptype == 'OWNER' ? 'disable' : 'enable';\n     \n            \n        if (_this.form.findField('comptype')) {\n            _this.form.findField('comptype')[meth]();\n        }\n         \n       // _this.loaded();\n        return;\n    }\n    \n    \n    if (act.type == 'submit') { // only submitted here if we are \n        _this.dialog.hide();\n       \n        if (_this.callback) {\n            _this.callback.call(this, act.result.data);\n        }\n        return; \n    }\n    // unmask?? \n}",
-        "rendered" : "function (form)\n{\n    _this.form = form;\n}"
+        "rendered" : "function (form)\n{\n    _this.form = form;\n}",
+        "actioncomplete" : "function(f, act) {\n    _this.dialog.el.unmask();\n    //console.log('load completed'); \n    // error messages?????\n    if(act.type == 'setdata'){\n        this.load({ method: 'GET', params: { '_id' : _this.data.id }});\n        return;\n    }\n   \n    if (act.type == 'load') {\n        _this.data = act.result.data;\n        var meth = _this.data.comptype == 'OWNER' ? 'disable' : 'enable';\n     \n            \n        if (_this.form.findField('comptype')) {\n            _this.form.findField('comptype')[meth]();\n        }\n         \n       // _this.loaded();\n        return;\n    }\n    \n    \n    if (act.type == 'submit') { // only submitted here if we are \n        _this.dialog.hide();\n       \n        if (_this.callback) {\n            _this.callback.call(this, act.result.data);\n        }\n        return; \n    }\n    // unmask?? \n}"
        },
        "$ url" : "baseURL + '/Roo/core_company.php'",
        "fileUpload" : true,
        "items" : [
         {
          "xtype" : "Column",
-         "width" : 500,
          "$ xns" : "Roo.form",
+         "width" : 500,
          "items" : [
           {
            "fieldLabel" : "Company ID (for filing Ref.)",
            "listeners" : {
             "render" : "function (_self)\n{\n    _this.etypeCombo = _self;\n}"
            },
+           "alwaysQuery" : true,
            "listWidth" : 250,
            "Boolean allowBlank" : false,
-           "alwaysQuery" : true,
            "triggerAction" : "all",
            "fieldLabel" : "Type",
            "forceSelection" : true,
              "items" : [
               {
                "$ url" : "baseURL + '/Roo/core_enum.php'",
-               "xtype" : "HttpProxy",
                "method" : "GET",
+               "xtype" : "HttpProxy",
                "$ xns" : "Roo.data",
                "* prop" : "proxy"
               },
           },
           {
            "fieldLabel" : "Address",
-           "xtype" : "TextField",
+           "xtype" : "TextArea",
            "allowBlank" : true,
            "width" : 300,
            "$ xns" : "Roo.form",
           },
           {
            "fieldLabel" : "Logo Image",
-           "xtype" : "DisplayField",
            "style" : "border: 1px solid #ccc;",
+           "xtype" : "DisplayField",
            "$ valueRenderer" : "function(v) {\n    //var vp = v ? v : 'Companies:' + _this.data.id + ':-LOGO';\n    if (!v) {\n        return \"No Image Available\" + '<BR/>';\n    }\n    return String.format('<a target=\"_new\" href=\"{1}\"><img src=\"{0}\" width=\"150\"></a>', \n            baseURL + '/Images/Thumb/150x150/' + v + '/logo.jpg',\n            baseURL + '/Images/'+v+'/logo.jpg'           // fixme - put escaped company name..\n    );\n}",
            "icon" : "rootURL + 'images/default/dd/drop-add.gif'",
            "width" : 170,
index e44744a..15ac818 100644 (file)
@@ -356,7 +356,7 @@ Pman.Dialog.CoreCompanies = {
             '|xns' : 'Roo.form'
            },
            {
-            xtype : 'TextField',
+            xtype : 'TextArea',
             allowBlank : true,
             fieldLabel : _this._strings['dd7bf230fde8d4836917806aff6a6b27'] /* Address */,
             name : 'address',
index 3dd0bd6..9a62caa 100644 (file)
 {
- "name" : "Pman.Dialog.CoreEmail",
- "parent" : "",
- "title" : "",
- "path" : "/home/johns/gitlive/Pman.Core/Pman.Dialog.CoreEmail.bjs",
- "permname" : "",
- "modOrder" : "001",
- "strings" : {
-  "e44b145bd8b49b06e0ad2ced1ad56466" : "Plain Text",
-  "2f26e35d61be90501e099089dc533638" : "Select Images",
-  "f2a6c498fb90ee345d997f888fce3b18" : "Delete",
-  "b357b524e740bc85b9790a0712d84a30" : "Email address",
-  "962b90039a542a29cedd51d87a9f28a1" : "Html Editor",
-  "72d6d7a1885885bb55a565fd1070581a" : "Import",
-  "ea30b40c3caf28acb29198d20d243e54" : "Images / Attachments >>",
-  "31fde7b05ac8952dacf4af8a704074ec" : "Preview",
-  "b337c8a67244afb6551ee1f8f9717676" : "Test Class <BR/> (for system reference only)",
-  "884df8e413319ff51a3f5f528606238a" : "Use template",
-  "e6b391a8d2c4d45902a23a8b6585703d" : "URL",
-  "2393ad754ba179442d85e415d1d5167c" : "Displayorder",
-  "6f16a5f8ff5d75ab84c018adacdfcbb7" : "Field",
-  "ec211f7c20af43e742bf2570c3cb84f9" : "Add",
-  "e9968623956c15023d54335ea3699855" : "Convert Html to Text",
-  "1243daf593fa297e07ab03bf06d925af" : "Searching...",
-  "5b8ef4e762c00a15a41cfc26dc3ef99c" : "Send me a test copy",
-  "c7892ebbb139886662c6f2fc8c450710" : "Subject",
-  "dc0de523c25be298ba751c63c694109e" : "Responsive Email (1)",
-  "396ecabf0cd1f9503e591418851ef406" : "Edit / Create Message",
-  "b9c49611cfda3259a2b837b39489e650" : "Add Image",
-  "ea4788705e6873b424c65e91c2846b19" : "Cancel",
-  "68b00d723d37122f64da8d9939f836f0" : "BCC Group",
-  "c4ca4238a0b923820dcc509a6f75849b" : "1",
-  "bd88a20b53a47f7b5704a83a15ff5506" : "Saved Version",
-  "b20a8b77b05d53b4e695738731400c85" : "Mailout Name",
-  "1bd18d39370b7f26c1c5e18067b74c6f" : "Html File",
-  "2c466a2c159463f1d9ef5a7b57b52827" : "Select BCC Group",
-  "5da618e8e4b89c66fe86e32cdafde142" : "From",
-  "31bb2f6e9b8fb11cbb7fb63c6025223f" : "Select Template",
-  "b78a3223503896721cca1303f776159b" : "Title",
-  "278c491bdd8a53618c149c4ac790da34" : "Template",
-  "1351017ac6423911223bc19a8cb7c653" : "Filename",
-  "308f2757bfc9ce92fb00ff93fdffd279" : "Images / Attachments",
-  "c9cc8cce247e49bae79f15173ce97354" : "Save",
-  "5feb9bf3c03b32635135006cbacb9542" : "Insert Field",
-  "4c2a8fe7eaf24721cc7a9f0175115bd4" : "Message",
-  "fff0d600f8a0b5e19e88bfb821dd1157" : "Images"
- },
  "items" : [
   {
-   "listeners" : {
-    "show" : "function (_self)\n{\n    \n    _self.layout.getRegion('center').showPanel(0);\n    var w = Roo.lib.Dom.getViewWidth();\r\n    var h = Roo.lib.Dom.getViewHeight();    \r    this.resizeTo(w-50, h-50);\r\n    this.center();\r    \n    var ew = Math.max(250, w-320);\r\n    var eh = Math.max(250, h-350) ;\r\n    var e = _this.dialog.layout.getRegion('east');\n    if (e.visible) {\n        e.hide();\n    }\n    \n    var el = _self.getEl();\n    var elw = el.dom.clientWidth;\n    \n    var bdtext = _this.form.findField('bodytext');\n    var ptext = _this.form.findField('plaintext');\n    if(bdtext.resizeEl){\n        bdtext.width = elw-100;\n        bdtext.resizeEl.resizeTo.defer(110, bdtext.resizeEl,[ bdtext.width, bdtext.height  ] );\n        ptext.setSize(bdtext.width , bdtext.height);\n    }\n    \n}"
-   },
-   "modal" : true,
-   "collapsible" : false,
-   "title" : "Edit / Create Message",
-   "xtype" : "LayoutDialog",
-   "width" : 800,
    "$ xns" : "Roo",
    "closable" : true,
-   "resizable" : true,
+   "collapsible" : false,
    "height" : 500,
    "items" : [
     {
-     "xtype" : "LayoutRegion",
-     "tabPosition" : "top",
      "$ xns" : "Roo",
-     "* prop" : "center"
+     "* prop" : "center",
+     "tabPosition" : "top",
+     "xtype" : "LayoutRegion"
     },
     {
+     "$ xns" : "Roo",
+     "* prop" : "east",
      "hidden" : true,
+     "split" : true,
      "title" : "Images / Attachments",
-     "xtype" : "LayoutRegion",
+     "titlebar" : true,
      "width" : 500,
-     "$ xns" : "Roo",
-     "split" : true,
-     "* prop" : "east",
-     "titlebar" : true
+     "xtype" : "LayoutRegion"
     },
     {
+     "$ xns" : "Roo",
      "autoScroll" : false,
-     "fitToFrame" : true,
-     "region" : "center",
-     "xtype" : "NestedLayoutPanel",
      "fitContainer" : true,
-     "$ xns" : "Roo",
+     "fitToFrame" : true,
      "items" : [
       {
-       "xtype" : "Toolbar",
        "$ xns" : "Roo",
        "* prop" : "toolbar",
        "items" : [
         {
-         "text" : "Import",
-         "xtype" : "Button",
          "$ xns" : "Roo.Toolbar",
          "items" : [
           {
-           "xtype" : "Menu",
            "$ xns" : "Roo.menu",
            "* prop" : "menu",
            "items" : [
             {
+             "$ xns" : "Roo.menu",
              "listeners" : {
-              "click" : "function (_self, e)\n{\n    Pman.Dialog.CoreImportUrl.show({\n        target : '/Core/ImportMailMessage.php'\n    }, function(data) {\n        if  (data) {\n          //  Roo.log(data);\n            _this.form.findField('bodytext').setValue(data);\n        }\n    });\n}"
+              "click" : [
+               "function (_self, e)",
+               "{",
+               "    Pman.Dialog.CoreImportUrl.show({",
+               "        target : '/Core/ImportMailMessage.php'",
+               "    }, function(data) {",
+               "        if  (data) {",
+               "          //  Roo.log(data);",
+               "            _this.form.findField('bodytext').setValue(data);",
+               "        }",
+               "    });",
+               "}"
+              ]
              },
              "text" : "URL",
-             "xtype" : "Item",
-             "$ xns" : "Roo.menu"
+             "xtype" : "Item"
             },
             {
+             "$ xns" : "Roo.menu",
              "listeners" : {
-              "click" : "function (_self, e)\n{\n    Pman.Dialog.Image.show({\n        _url : baseURL + '/Core/ImportMailMessage.php'\n    }, function(data) {\n        if  (data) {\n            _this.form.findField('bodytext').setValue(data);\n        }\n    });\n}"
+              "click" : [
+               "function (_self, e)",
+               "{",
+               "    Pman.Dialog.Image.show({",
+               "        _url : baseURL + '/Core/ImportMailMessage.php'",
+               "    }, function(data) {",
+               "        if  (data) {",
+               "            _this.form.findField('bodytext').setValue(data);",
+               "        }",
+               "    });",
+               "}"
+              ]
              },
              "text" : "Html File",
-             "xtype" : "Item",
-             "$ xns" : "Roo.menu"
+             "xtype" : "Item"
             }
-           ]
+           ],
+           "xtype" : "Menu"
           }
-         ]
+         ],
+         "text" : "Import",
+         "xtype" : "Button"
         },
         {
-         "text" : "Use template",
-         "xtype" : "Button",
          "$ xns" : "Roo.Toolbar",
          "items" : [
           {
-           "xtype" : "Menu",
            "$ xns" : "Roo.menu",
            "* prop" : "menu",
            "items" : [
             {
+             "$ xns" : "Roo.menu",
              "listeners" : {
-              "click" : "function (_self, e)\n{\n\n    var l = document.location;\n    new Pman.Request({\n\n        url : baseURL + '/Core/ImportMailMessage.php',\n\n        method: 'POST',\n        mask : \"Loading\",\n        params : {\n              importUrl : l.protocol +'//' + l.host +   rootURL + '/Pman/Crm/mail_templates/responsive1.html'\n       },\n        success : function (res) {\n\n         _this.form.findField('bodytext').setValue(res.data);\n        }\n  \n    });\n}"
+              "click" : [
+               "function (_self, e)",
+               "{",
+               "",
+               "    var l = document.location;",
+               "    new Pman.Request({",
+               "",
+               "        url : baseURL + '/Core/ImportMailMessage.php',",
+               "",
+               "        method: 'POST',",
+               "        mask : \"Loading\",",
+               "        params : {",
+               "              importUrl : l.protocol +'//' + l.host +   rootURL + '/Pman/Crm/mail_templates/responsive1.html'",
+               "       },",
+               "        success : function (res) {",
+               "",
+               "         _this.form.findField('bodytext').setValue(res.data);",
+               "        }",
+               "  ",
+               "    });",
+               "}"
+              ]
              },
              "text" : "Responsive Email (1)",
-             "xtype" : "Item",
-             "$ xns" : "Roo.menu"
+             "xtype" : "Item"
             }
-           ]
+           ],
+           "xtype" : "Menu"
           }
-         ]
+         ],
+         "text" : "Use template",
+         "xtype" : "Button"
         },
         {
-         "listeners" : {
-          "select" : "function (combo, record, index)\n{\n   \n/*\n    (function() { \n        combo.setValue('');\n    }).defer(100);\n*/    \n    if(!record){\n        return;\n    }\n    _this.form.findField('bodytext').setValue(record.data.content);\n\n}"
-         },
+         "$ xns" : "Roo.form",
+         "allowBlank" : true,
          "alwaysQuery" : true,
-         "listWidth" : 400,
-         "triggerAction" : "all",
-         "fieldLabel" : "Template",
-         "forceSelection" : true,
-         "selectOnFocus" : true,
-         "pageSize" : 20,
          "displayField" : "file",
+         "editable" : false,
          "emptyText" : "Select Template",
+         "fieldLabel" : "Template",
+         "forceSelection" : true,
          "hiddenName" : "template",
-         "minChars" : 2,
-         "valueField" : "file",
-         "xtype" : "ComboBox",
-         "allowBlank" : true,
-         "typeAhead" : true,
-         "editable" : false,
-         "width" : 200,
-         "$ xns" : "Roo.form",
-         "name" : "template",
-         "qtip" : "Select Template",
-         "tpl" : "<div class=\"x-grid-cell-text x-btn button\"><b>{file}</b> </div>",
-         "loadingText" : "Searching...",
          "items" : [
           {
-           "listeners" : {
-            "|beforeload" : "function (_self, o){\n    o.params = o.params || {};\n    // set more here\n   \n}\n"
-           },
-           "xtype" : "Store",
-           "remoteSort" : true,
            "$ sortInfo" : "{ direction : 'DESC', field: 'file' }",
            "$ xns" : "Roo.data",
            "* prop" : "store",
            "items" : [
             {
              "$ url" : "baseURL + '/Core/MailTemplateList.php'",
-             "xtype" : "HttpProxy",
-             "method" : "GET",
              "$ xns" : "Roo.data",
-             "* prop" : "proxy"
+             "* prop" : "proxy",
+             "method" : "GET",
+             "xtype" : "HttpProxy"
             },
             {
-             "id" : "name",
-             "root" : "data",
-             "xtype" : "JsonReader",
              "$ fields" : "[{\"name\":\"file\",\"type\":\"string\"},{\"name\":\"content\",\"type\":\"string\"}]",
              "$ xns" : "Roo.data",
              "* prop" : "reader",
-             "totalProperty" : "total"
+             "id" : "name",
+             "root" : "data",
+             "totalProperty" : "total",
+             "xtype" : "JsonReader"
             }
-           ]
+           ],
+           "listeners" : {
+            "|beforeload" : [
+             "function (_self, o){",
+             "    o.params = o.params || {};",
+             "    // set more here",
+             "   ",
+             "}",
+             ""
+            ]
+           },
+           "remoteSort" : true,
+           "xtype" : "Store"
           }
-         ]
+         ],
+         "listWidth" : 400,
+         "listeners" : {
+          "select" : [
+           "function (combo, record, index)",
+           "{",
+           "   ",
+           "/*",
+           "    (function() { ",
+           "        combo.setValue('');",
+           "    }).defer(100);",
+           "*/    ",
+           "    if(!record){",
+           "        return;",
+           "    }",
+           "    _this.form.findField('bodytext').setValue(record.data.content);",
+           "",
+           "}"
+          ]
+         },
+         "loadingText" : "Searching...",
+         "minChars" : 2,
+         "name" : "template",
+         "pageSize" : 20,
+         "qtip" : "Select Template",
+         "selectOnFocus" : true,
+         "tpl" : "<div class=\"x-grid-cell-text x-btn button\"><b>{file}</b> </div>",
+         "triggerAction" : "all",
+         "typeAhead" : true,
+         "valueField" : "file",
+         "width" : 200,
+         "xtype" : "ComboBox"
         },
         {
-         "xtype" : "Fill",
-         "$ xns" : "Roo.Toolbar"
+         "$ xns" : "Roo.Toolbar",
+         "xtype" : "Fill"
         },
         {
+         "$ xns" : "Roo.Toolbar",
          "listeners" : {
-          "click" : "function (_self, e)\n{\n    var el = _this.dialog.layout.getRegion('east');\n    if (el.visible) {\n        el.hide();\n    } else {\n        el.show();\n        el.showPanel(0);\n    }\n    \n}"
+          "click" : [
+           "function (_self, e)",
+           "{",
+           "    var el = _this.dialog.layout.getRegion('east');",
+           "    if (el.visible) {",
+           "        el.hide();",
+           "    } else {",
+           "        el.show();",
+           "        el.showPanel(0);",
+           "    }",
+           "    ",
+           "}"
+          ]
          },
          "text" : "Images / Attachments >>",
-         "xtype" : "Button",
-         "$ xns" : "Roo.Toolbar"
+         "xtype" : "Button"
         }
-       ]
+       ],
+       "xtype" : "Toolbar"
       },
       {
-       "xtype" : "BorderLayout",
        "$ xns" : "Roo",
        "* prop" : "layout",
        "items" : [
         {
-         "autoScroll" : true,
-         "xtype" : "LayoutRegion",
          "$ xns" : "Roo",
-         "* prop" : "center"
+         "* prop" : "center",
+         "autoScroll" : true,
+         "xtype" : "LayoutRegion"
         },
         {
-         "listeners" : {
-          "resize" : "function (_self, width, height)\r\n{\r\n   var ew = Math.max(250, width-50);\r\n    var eh = Math.max(250,height-50) ;\n    \n    if (!_this.form) {\r\n        return;\r\n    }\r\n    var bdtext = _this.form.findField('bodytext');\r\n    var ptext = _this.form.findField('plaintext');\r\n    if(bdtext.resizeEl){\r\n        bdtext.width = ew-50;\r\n        bdtext.resizeEl.resizeTo.defer(110, bdtext.resizeEl,[ bdtext.width, bdtext.height  ] );\r\n        ptext.setSize(bdtext.width , bdtext.height);\r\n    }\r\r\n\r\n}",
-          "render" : "function (_self, width, height)\n{\n    \n      Roo.log(\"RESIZE, \" + width + ',' + height);\n    \n    var ew = Math.max(250, width-50);\n    var eh = Math.max(250,height-50) ;\n    \n   \n\n}"
-         },
+         "$ xns" : "Roo",
          "autoScroll" : false,
          "background" : false,
-         "fitToFrame" : true,
-         "region" : "center",
-         "title" : "Message",
-         "xtype" : "ContentPanel",
          "fitContainer" : true,
-         "$ xns" : "Roo",
+         "fitToFrame" : true,
          "items" : [
           {
-           "listeners" : {
-            "|actioncomplete" : "function(_self,action)\n{\n   \n    if (action.type == 'setdata') {\n    \n        setInterval(_this.form.findField('bodytext').autosave, 5000);\n        \n        _this.data.module = _this.data.module || 'crm_mailing_list_message';\n        \n        _this.form.url = baseURL + '/Roo/' + _this.data.module;\n        \n        _this.html_preview.hide();\n        _this.preview_btn.hide();\n            \n        if(_this.data.id*1 > 0){\n            _this.dialog.el.mask(\"Loading\");\n            this.load({ method: 'GET', params: { '_id' : _this.data.id }});\n            _this.html_preview.show();\n            _this.preview_btn.show();\n            \n        } else {\n            _this.form.setValues({\n                'from_name' : Pman.Login.authUser.name,\n                'from_email' : Pman.Login.authUser.email\n            });\n        }\n       return;\n    }\n    if (action.type == 'load') {\n        _this.dialog.el.unmask();\n        \n        _this.form.findField('bodytext').originalValue = _this.form.findField('bodytext').getValue();\n        \n        return;\n    }\n    if (action.type =='submit') {\n    \n        _this.dialog.el.unmask();\n        _this.dialog.hide();\n    \n         if (_this.callback) {\n            _this.callback.call(_this, action.result.data);\n         }\n         _this.form.reset();\n         return;\n    }\n}\n",
-            "|rendered" : "function (form)\n{\n    _this.form= form;\n}\n"
-           },
+           "$ preValidate" : [
+            "function(done_callback) {",
+            "    ",
+            "    Roo.MessageBox.progress(\"Uploading Images\", \"Uploading\");",
+            "    ",
+            "    if(!_this.form.findField('bodytext').editorcore.sourceEditMode){",
+            "        _this.form.findField('bodytext').syncValue();",
+            "    }else{",
+            "        _this.form.findField('bodytext').pushValue();",
+            "    }",
+            "    ",
+            "    var html = _this.form.findField('bodytext').getValue();",
+            "    ",
+            "    var s = Roo.get(_this.form.findField('bodytext').editorcore.doc.documentElement);",
+            "    ",
+            "    var ontable = (_this.data.module) ? _this.data.module : 'crm_mailing_list_message';",
+            "    ",
+            "    var nodes = [];",
+            "    s.select('img[src]').each(function(i) {",
+            "        nodes.push(i.dom);",
+            "    });",
+            "    var total = nodes.length;",
+            "    var mkimg = function() {",
+            "    ",
+            "        if (!nodes.length) {",
+            "              Roo.MessageBox.hide();",
+            "              _this.form.findField('bodytext').syncValue();",
+            "              done_callback(true);",
+            "           //    _this.form.doAction(\"submit\");",
+            "              return;",
+            "        }",
+            "        var i = nodes.pop(); ",
+            "        ",
+            "        var n = i.getAttribute('src').match(/(baseURL|server_baseurl)/);",
+            "        ",
+            "        if(n){",
+            "            mkimg();",
+            "            return;",
+            "        }",
+            "        ",
+            "        n = i.getAttribute('src').match(/^http(.*)/);",
+            "       ",
+            "        if(!n ){",
+            "            mkimg();",
+            "            return;",
+            "        }",
+            "        ",
+            "        new Pman.Request({",
+            "            url : baseURL + '/Roo/Images.php',",
+            "            method : 'POST',",
+            "            params : {",
+            "                onid : _this.form.findField('id').getValue(),",
+            "                ontable : ontable ,",
+            "                _remote_upload : i.src",
+            "            },",
+            "            success : function(res){",
+            "                if(res.success == true){      ",
+            "                    i.setAttribute('src', res.data);",
+            "                    Roo.MessageBox.updateProgress( (total - nodes.length) / total , \"Done \" + (total - nodes.length) + '/' + total);",
+            "                }",
+            "                mkimg();",
+            "            }",
+            "        });",
+            "       ",
+            "    }",
+            "    ",
+            "    if (!_this.form.findField('bodytext').getValue().match(/unsubscribe/i)) {",
+            "        Roo.MessageBox.confirm(\"Missing unusubscribe\",",
+            "            \"There is no unsubscribe link on the email  are you sure you want to save it\",",
+            "            function(res) {",
+            "                if (res == 'no') {",
+            "                    return;",
+            "                }",
+            "                mkimg();",
+            "            }",
+            "        );",
+            "",
+            "        return;",
+            "    }",
+            "    ",
+            "    mkimg();",
+            "}",
+            ""
+           ],
            "$ url" : "baseURL + '/Roo/crm_mailing_list_message.php'",
-           "labelAlign" : "right",
-           "$ preValidate" : "function(done_callback) {\n    \n    Roo.MessageBox.progress(\"Uploading Images\", \"Uploading\");\n    \n    if(!_this.form.findField('bodytext').editorcore.sourceEditMode){\n        _this.form.findField('bodytext').syncValue();\n    }else{\n        _this.form.findField('bodytext').pushValue();\n    }\n    \n    var html = _this.form.findField('bodytext').getValue();\n    \n    var s = Roo.get(_this.form.findField('bodytext').editorcore.doc.documentElement);\n    \n    var ontable = (_this.data.module) ? _this.data.module : 'crm_mailing_list_message';\n    \n    var nodes = [];\n    s.select('img[src]').each(function(i) {\n        nodes.push(i.dom);\n    });\n    var total = nodes.length;\n    var mkimg = function() {\n    \n        if (!nodes.length) {\n              Roo.MessageBox.hide();\n              _this.form.findField('bodytext').syncValue();\n              done_callback(true);\n           //    _this.form.doAction(\"submit\");\n              return;\n        }\n        var i = nodes.pop(); \n        \n        var n = i.getAttribute('src').match(/(baseURL|server_baseurl)/);\n        \n        if(n){\n            mkimg();\n            return;\n        }\n        \n        n = i.getAttribute('src').match(/^http(.*)/);\n       \n        if(!n ){\n            mkimg();\n            return;\n        }\n        \n        new Pman.Request({\n            url : baseURL + '/Roo/Images.php',\n            method : 'POST',\n            params : {\n                onid : _this.form.findField('id').getValue(),\n                ontable : ontable ,\n                _remote_upload : i.src\n            },\n            success : function(res){\n                if(res.success == true){      \n                    i.setAttribute('src', res.data);\n                    Roo.MessageBox.updateProgress( (total - nodes.length) / total , \"Done \" + (total - nodes.length) + '/' + total);\n                }\n                mkimg();\n            }\n        });\n       \n    }\n    mkimg();\n}\n",
-           "method" : "POST",
-           "style" : "margin:10px",
-           "xtype" : "Form",
-           "labelWidth" : 120,
            "$ xns" : "Roo.form",
            "items" : [
             {
-             "xtype" : "Row",
              "$ xns" : "Roo.form",
              "items" : [
               {
-               "fieldLabel" : "Mailout Name",
-               "xtype" : "TextField",
+               "$ xns" : "Roo.form",
                "allowBlank" : false,
+               "fieldLabel" : "Mailout Name",
+               "name" : "name",
                "width" : 400,
-               "$ xns" : "Roo.form",
-               "name" : "name"
+               "xtype" : "TextField"
               },
               {
-               "xtype" : "Column",
                "$ xns" : "Roo.form",
-               "Boolean hideLabels" : true,
+               "Number labelWidth" : 0,
+               "String labelSeparator" : " ",
                "items" : [
                 {
-                 "listeners" : {
-                  "check" : "function (_self, checked)\n{\n    var boxLabel = 'Enabled - will be sent out';\n    \n    if(!checked){\n        boxLabel = 'Disabled - will NOT be sent out';\n    }\n    \n    this.setBoxLabel(boxLabel);\n}"
-                 },
-                 "String name" : "active",
+                 "$ xns" : "Roo.form",
                  "Boolean checked" : true,
-                 "xtype" : "Checkbox",
-                 "String valueOff" : 0,
+                 "Mixed value" : 1,
                  "String boxLabel" : "Enabled - will be sent out",
-                 "$ xns" : "Roo.form",
-                 "Mixed value" : 1
+                 "String name" : "active",
+                 "String valueOff" : 0,
+                 "listeners" : {
+                  "check" : [
+                   "function (_self, checked)",
+                   "{",
+                   "    var boxLabel = 'Enabled - will be sent out';",
+                   "    ",
+                   "    if(!checked){",
+                   "        boxLabel = 'Disabled - will NOT be sent out';",
+                   "    }",
+                   "    ",
+                   "    this.setBoxLabel(boxLabel);",
+                   "}"
+                  ]
+                 },
+                 "xtype" : "Checkbox"
                 }
-               ]
+               ],
+               "xtype" : "Column"
               }
-             ]
+             ],
+             "xtype" : "Row"
             },
             {
-             "xtype" : "Row",
              "$ xns" : "Roo.form",
              "items" : [
               {
-               "fieldLabel" : "From",
-               "xtype" : "TextField",
+               "$ xns" : "Roo.form",
                "allowBlank" : false,
+               "fieldLabel" : "From",
+               "name" : "from_name",
                "width" : 300,
-               "$ xns" : "Roo.form",
-               "name" : "from_name"
+               "xtype" : "TextField"
               },
               {
-               "fieldLabel" : "Email address",
-               "xtype" : "TextField",
+               "$ xns" : "Roo.form",
                "allowBlank" : false,
+               "fieldLabel" : "Email address",
+               "name" : "from_email",
                "width" : 300,
-               "$ xns" : "Roo.form",
-               "name" : "from_email"
+               "xtype" : "TextField"
               },
               {
+               "$ xns" : "Roo.form",
+               "Boolean forceSelection" : true,
+               "allowBlank" : true,
                "alwaysQuery" : true,
-               "triggerAction" : "all",
-               "fieldLabel" : "BCC Group",
-               "forceSelection" : true,
-               "selectOnFocus" : true,
-               "pageSize" : 25,
                "displayField" : "name",
+               "editable" : false,
                "emptyText" : "Select BCC Group",
+               "fieldLabel" : "BCC Group",
                "hiddenName" : "bcc_group_id",
-               "minChars" : 2,
-               "valueField" : "id",
-               "xtype" : "ComboBox",
-               "allowBlank" : true,
-               "typeAhead" : true,
-               "editable" : false,
-               "width" : 300,
-               "$ xns" : "Roo.form",
-               "name" : "bcc_group_id_name",
-               "qtip" : "Select BCC Group",
-               "tpl" : "<div class=\"x-grid-cell-text x-btn button\"><b>{name}</b> </div>",
-               "loadingText" : "Searching...",
-               "Boolean forceSelection" : true,
                "items" : [
                 {
-                 "listeners" : {
-                  "|beforeload" : "function (_self, o){\n    o.params = o.params || {};\n    \n    o.params._direct_return = 1;\n}\n"
-                 },
-                 "xtype" : "Store",
-                 "remoteSort" : true,
                  "$ sortInfo" : "{ direction : 'ASC', field: 'name' }",
                  "$ xns" : "Roo.data",
                  "* prop" : "store",
                  "items" : [
                   {
                    "$ url" : "baseURL + '/Roo/Core_group'",
-                   "method" : "GET",
-                   "xtype" : "HttpProxy",
                    "$ xns" : "Roo.data",
-                   "* prop" : "proxy"
+                   "* prop" : "proxy",
+                   "method" : "GET",
+                   "xtype" : "HttpProxy"
                   },
                   {
-                   "id" : "name",
-                   "root" : "data",
-                   "xtype" : "JsonReader",
                    "$ fields" : "[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"id\",\"type\":\"int\"}]",
                    "$ xns" : "Roo.data",
                    "* prop" : "reader",
-                   "totalProperty" : "total"
+                   "id" : "name",
+                   "root" : "data",
+                   "totalProperty" : "total",
+                   "xtype" : "JsonReader"
                   }
-                 ]
+                 ],
+                 "listeners" : {
+                  "|beforeload" : [
+                   "function (_self, o){",
+                   "    o.params = o.params || {};",
+                   "    ",
+                   "    o.params._direct_return = 1;",
+                   "}",
+                   ""
+                  ]
+                 },
+                 "remoteSort" : true,
+                 "xtype" : "Store"
                 }
-               ]
+               ],
+               "loadingText" : "Searching...",
+               "minChars" : 2,
+               "name" : "bcc_group_id_name",
+               "pageSize" : 25,
+               "qtip" : "Select BCC Group",
+               "selectOnFocus" : true,
+               "tpl" : "<div class=\"x-grid-cell-text x-btn button\"><b>{name}</b> </div>",
+               "triggerAction" : "all",
+               "typeAhead" : true,
+               "valueField" : "id",
+               "width" : 300,
+               "xtype" : "ComboBox"
               }
-             ]
+             ],
+             "xtype" : "Row"
             },
             {
-             "fieldLabel" : "Subject",
-             "xtype" : "TextField",
-             "allowBlank" : false,
-             "width" : 600,
              "$ xns" : "Roo.form",
-             "name" : "subject"
+             "items" : [
+              {
+               "$ xns" : "Roo.form",
+               "allowBlank" : false,
+               "fieldLabel" : "Subject",
+               "name" : "subject",
+               "width" : 600,
+               "xtype" : "TextField"
+              },
+              {
+               "$ xns" : "Roo.form",
+               "allowBlank" : false,
+               "displayField" : "title",
+               "editable" : false,
+               "fieldLabel" : "Language",
+               "hiddenName" : "language",
+               "items" : [
+                {
+                 "$ fields" : "['code', 'title']",
+                 "$ xns" : "Roo.data",
+                 "* prop" : "store",
+                 "xtype" : "SimpleStore",
+                 "| data" : "(function() {return typeof(Pman) == 'object'  ? Pman.I18n.simpleStoreData('l') : []})()"
+                }
+               ],
+               "listWidth" : 200,
+               "mode" : "local",
+               "name" : "language_name",
+               "tpl" : "<div class=\"x-grid-cell-text x-btn button\"><b>{title}</b> </div>",
+               "triggerAction" : "all",
+               "valueField" : "code",
+               "width" : 200,
+               "xtype" : "ComboBox"
+              }
+             ],
+             "xtype" : "Row"
             },
             {
-             "hideLabels" : true,
-             "xtype" : "Row",
              "$ xns" : "Roo.form",
+             "hideLabels" : true,
              "items" : [
               {
-               "hideLabels" : true,
-               "style" : "text-align:center;",
-               "legend" : "Html Editor",
-               "xtype" : "FieldSet",
                "$ xns" : "Roo.form",
+               "hideLabels" : true,
                "items" : [
                 {
-                 "listeners" : {
-                  "savedpreview" : "function (_self)\n{\n    var id = _this.form.findField('id').getValue() * 1;\n    \n    var successFn = function(res){\n        return res.data.POST.source;\n    };\n    \n    var params = {\n        action : 'AUTOSAVE',\n        remarks : 'BODY',\n        on_id : (id < 1) ? 0 : id,\n        on_table : 'crm_mailing_list_message',\n        successFn : successFn\n    };\n    \n    \n    Pman.Dialog.CoreAutoSavePreview.show(params, function(res){\n        _self.setValue(res);\n        _self.originalValue = res;\n    });\n}",
-                  "autosave" : "function (_self)\n{\n    Roo.log('autosave');\n    \n    var id = _this.form.findField('id').getValue() * 1;\n    \n    /*\n    if(!_self.editorcore.sourceEditMode){\n        _self.syncValue();\n    }else{\n        _self.pushValue();\n    }\n    */\n    \n    new Pman.Request({\n        url : baseURL + '/Roo/Events.php',\n        method :'POST',\n        params : {\n            id : 0,\n            action : 'AUTOSAVE',\n            on_id : (id > 0) ? id : 0,\n            on_table : 'crm_mailing_list_message',\n            remarks : 'BODY',\n            source: _self.getValue()\n        },\n        success : function() {\n            _self.originalValue = _self.getValue();\n            \n        },\n        failure : function() \n        {\n            Roo.log('body autosave failed?!');\n        }\n    });\n    \n}"
-                 },
-                 "$ cwhite" : "[ \n    'margin',\n    'padding',\n    'text-align',\n    'background',\n    'height',\n    'width',\n    'background-color',\n    'font-size',\n    'line-height',\n    'color',\n    'outline',\n    'text-decoration',\n    'position',\n    'clear',\n    'overflow',\n    'margin-top',\n    'border-bottom',\n    'top',\n    'list-style',\n    'margin-left',\n    'border',\n    'float' ,\n    'margin-right',\n    'padding-top',\n    'min-height',\n    'left',\n    'padding-left',\n    'font-weight',\n    'font-family',\n    'display',\n    'margin-bottom',\n    'padding-bottom',\n    'vertical-align',\n    'cursor',\n    'z-index',\n    'right'\n ]",
-                 "| function autosave" : "function() {\n    \n    var body = _this.form.findField('bodytext');\n    \n    if(!body.wrap.isVisible(true) || body.getValue() == '' || !body.isDirty()){\n        Roo.log('body not dirty');\n        return;\n    }\n    \n    Roo.log('body dirty, auto save!');\n    \n    body.fireEvent('autosave', body);\n   \n}\n",
-                 "xtype" : "HtmlEditor",
+                 "$ cwhite" : [
+                  "[ ",
+                  "    'background',",
+                  "    'background-color',",
+                  "    'border',",
+                  "    'border-radius',",
+                  "    'border-bottom',",
+                  "    'border-left',",
+                  "    'border-right',",
+                  "    'border-top',",
+                  "    'border-collapse',",
+                  "     'border-color',",
+                  "     'border-style',",
+                  "    'border-width',",
+                  "",
+                  "    ",
+                  "    'box-shadow',",
+                  "    'clear',",
+                  "    'color',",
+                  "    'cursor',",
+                  "    'display',",
+                  "    'float' ,",
+                  "    'font-family',",
+                  "    'font-size',",
+                  "    'font-style',        ",
+                  "    'font-weight',",
+                  "",
+                  "    'height',",
+                  "    'left',",
+                  "    'line-height',",
+                  "    'list-style',",
+                  "    'margin',",
+                  "    'margin-bottom',",
+                  "    'margin-left',",
+                  "    'margin-right',",
+                  "    'margin-top',",
+                  "    'max-width',",
+                  "    'min-height',",
+                  "    '-ms-interpolation-mode',",
+                  "    'mso-table-rspace',",
+                  "    '-ms-text-size-adjust',",
+                  "    'outline',",
+                  "    'overflow',",
+                  "    'padding',",
+                  "    'padding-bottom',",
+                  "    'padding-left',",
+                  "    'padding-right',",
+                  "    'padding-top',",
+                  "    'position',",
+                  "    'right',",
+                  "    'text-align',",
+                  "    'text-decoration',",
+                  "    'top',",
+                  "    'vertical-align',",
+                  "    '-webkit-text-size-adjust',",
+                  "    'width',",
+                  "    'width',",
+                  "    'z-index'",
+                  " ]"
+                 ],
                  "$ xns" : "Roo.form",
-                 "resizable" : "s",
-                 "name" : "bodytext",
-                 "height" : 250,
+                 "bool allowComments" : true,
+                 "boolean autoClean" : false,
+                 "boolean enableBlocks" : false,
                  "clearUp" : false,
+                 "height" : 250,
                  "items" : [
                   {
-                   "xtype" : "ToolbarContext",
                    "$ xns" : "Roo.form.HtmlEditor",
-                   "* prop" : "toolbars[]"
+                   "* prop" : "toolbars[]",
+                   "xtype" : "ToolbarContext"
                   },
                   {
-                   "xtype" : "ToolbarStandard",
                    "$ xns" : "Roo.form.HtmlEditor",
                    "* prop" : "toolbars[]",
                    "items" : [
                     {
-                     "listeners" : {
-                      "render" : "function (_self)\n{\n    _this.extendimgselect = _self;\n}",
-                      "beforequery" : "function (combo, query, forceAll, cancel, e)\n{\n    var id = _this.form.findField('id').getValue() * 1;    \n    if (!id) {\n        Roo.MessageBox.alert(\"Error\", \"Save message first\");\n        return false;\n    }\n}",
-                      "select" : "function (combo, record, index)\n{\n    Roo.log(record);\n    (function() { \n        combo.setValue('');\n    }).defer(100);\n    var editor = _this.form.findField('bodytext').editorcore;\n    \n    var curnode = editor.getSelectedNode();\n    if (curnode && curnode.tagName == 'IMG') {\n        curnode.src= String.format('{0}/Images/{1}/{2}#image-{1}',\n                baseURL,  record.data.id, record.data.filename\n            );\n            // note -forces an update... hopefully...\n        editor.owner.fireEvent('editorevent', editor, false);\n    } else {\n    \n        editor.insertAtCursor(\n            String.format('<img src=\"{0}/Images/{1}/{2}#image-{1}\">',\n            baseURL,  record.data.id, record.data.filename\n            )\n        );\n\n    }\n    \n }"
-                     },
+                     "$ xns" : "Roo.form",
+                     "* prop" : "btns[]",
                      "alwaysQuery" : true,
-                     "listWidth" : 400,
-                     "triggerAction" : "all",
-                     "fieldLabel" : "Images",
-                     "forceSelection" : true,
-                     "selectOnFocus" : true,
-                     "pageSize" : 20,
                      "displayField" : "name",
-                     "emptyText" : "Add Image",
-                     "minChars" : 2,
-                     "valueField" : "id",
-                     "xtype" : "ComboBox",
-                     "typeAhead" : true,
                      "editable" : false,
-                     "width" : 100,
-                     "$ xns" : "Roo.form",
-                     "* prop" : "btns[]",
-                     "qtip" : "Select Images",
-                     "tpl" : "<div class=\"x-grid-cell-text x-btn button\"><img src=\"{public_baseURL}/Core/Images/Thumb/150x150/{id}.jpg\" height=\"150\" width=\"150\"><b>{filename}</b> </div>",
-                     "loadingText" : "Searching...",
+                     "emptyText" : "Add Image",
+                     "fieldLabel" : "Images",
+                     "forceSelection" : true,
                      "items" : [
                       {
-                       "listeners" : {
-                        "|beforeload" : "function (_self, o){\n    o.params = o.params || {};\n\n    var id = _this.form.findField('id').getValue() * 1;    \n    if (!id) {\n        Roo.MessageBox.alert(\"Error\", \"Save email template first\");\n        return false;\n    }\n    o.params.onid = id;\n    o.params.ontable = (_this.data.module) ? _this.data.module : 'crm_mailing_list_message';\n    \n   // o.params.imgtype = 'PressRelease';\n    //o.params['query[imagesize]'] = '150x150';\n    // set more here\n}\n"
-                       },
-                       "xtype" : "Store",
-                       "remoteSort" : true,
                        "$ sortInfo" : "{ direction : 'ASC', field: 'id' }",
                        "$ xns" : "Roo.data",
                        "* prop" : "store",
                        "items" : [
                         {
                          "$ url" : "baseURL + '/Roo/Images.php'",
-                         "method" : "GET",
-                         "xtype" : "HttpProxy",
                          "$ xns" : "Roo.data",
-                         "* prop" : "proxy"
+                         "* prop" : "proxy",
+                         "method" : "GET",
+                         "xtype" : "HttpProxy"
                         },
                         {
-                         "id" : "id",
-                         "root" : "data",
-                         "xtype" : "JsonReader",
                          "$ fields" : "[{\"name\":\"id\",\"type\":\"int\"},{\"name\":\"filename\",\"type\":\"string\"},{\"name\":\"url_thumb\",\"type\":\"string\"}]",
                          "$ xns" : "Roo.data",
                          "* prop" : "reader",
-                         "totalProperty" : "total"
+                         "id" : "id",
+                         "root" : "data",
+                         "totalProperty" : "total",
+                         "xtype" : "JsonReader"
                         }
-                       ]
+                       ],
+                       "listeners" : {
+                        "|beforeload" : [
+                         "function (_self, o){",
+                         "    o.params = o.params || {};",
+                         "",
+                         "    var id = _this.form.findField('id').getValue() * 1;    ",
+                         "    if (!id) {",
+                         "        Roo.MessageBox.alert(\"Error\", \"Save email template first\");",
+                         "        return false;",
+                         "    }",
+                         "    o.params.onid = id;",
+                         "    o.params.ontable = (_this.data.module) ? _this.data.module : 'crm_mailing_list_message';",
+                         "    ",
+                         "   // o.params.imgtype = 'PressRelease';",
+                         "    //o.params['query[imagesize]'] = '150x150';",
+                         "    // set more here",
+                         "}",
+                         ""
+                        ]
+                       },
+                       "remoteSort" : true,
+                       "xtype" : "Store"
                       }
-                     ]
-                    },
-                    {
+                     ],
+                     "listWidth" : 400,
                      "listeners" : {
-                      "render" : "function (_self)\n{\n    _this.unsubscribeselect = _self;\n}",
-                      "select" : "function (combo, record, index)\n{\n    Roo.log(record);\n    (function() { \n        combo.setValue('');\n    }).defer(100);\n    var editor = _this.form.findField('bodytext').editorcore;\n    \n    if(record.data.name == 'Unsubscribe'){\n        editor.insertAtCursor(\n            String.format('<a href=\"{0}\">{1}</a>',\n                record.data.type,  record.data.name\n            )\n        );\n        return;     \n    }\n    \n    editor.insertAtCursor(\n        String.format('{0}',\n            record.data.type\n        )\n    );\n    \n }"
+                      "beforequery" : [
+                       "function (combo, query, forceAll, cancel, e)",
+                       "{",
+                       "    var id = _this.form.findField('id').getValue() * 1;    ",
+                       "    if (!id) {",
+                       "        Roo.MessageBox.alert(\"Error\", \"Save message first\");",
+                       "        return false;",
+                       "    }",
+                       "}"
+                      ],
+                      "render" : [
+                       "function (_self)",
+                       "{",
+                       "    _this.extendimgselect = _self;",
+                       "}"
+                      ],
+                      "select" : [
+                       "function (combo, record, index)",
+                       "{",
+                       "    Roo.log(record);",
+                       "    (function() { ",
+                       "        combo.setValue('');",
+                       "    }).defer(100);",
+                       "    var editor = _this.form.findField('bodytext').editorcore;",
+                       "    ",
+                       "    var curnode = editor.getSelectedNode();",
+                       "    if (curnode && curnode.tagName == 'IMG') {",
+                       "        curnode.src= String.format('{0}/Images/{1}/{2}#image-{1}',",
+                       "                baseURL,  record.data.id, record.data.filename",
+                       "            );",
+                       "            // note -forces an update... hopefully...",
+                       "        editor.owner.fireEvent('editorevent', editor, false);",
+                       "    } else {",
+                       "    ",
+                       "        editor.insertAtCursor(",
+                       "            String.format('<img src=\"{0}/Images/{1}/{2}#image-{1}\">',",
+                       "            baseURL,  record.data.id, record.data.filename",
+                       "            )",
+                       "        );",
+                       "",
+                       "    }",
+                       "    ",
+                       " }"
+                      ]
                      },
-                     "alwaysQuery" : true,
-                     "listWidth" : 400,
-                     "triggerAction" : "all",
-                     "fieldLabel" : "Field",
-                     "forceSelection" : true,
-                     "selectOnFocus" : true,
-                     "pageSize" : 20,
-                     "displayField" : "name",
-                     "emptyText" : "Insert Field",
+                     "loadingText" : "Searching...",
                      "minChars" : 2,
-                     "valueField" : "type",
-                     "xtype" : "ComboBox",
+                     "pageSize" : 20,
+                     "qtip" : "Select Images",
+                     "selectOnFocus" : true,
+                     "tpl" : "<div class=\"x-grid-cell-text x-btn button\"><img src=\"{public_baseURL}/Core/Images/Thumb/150x150/{id}.jpg\" height=\"150\" width=\"150\"><b>{filename}</b> </div>",
+                     "triggerAction" : "all",
                      "typeAhead" : true,
-                     "editable" : false,
+                     "valueField" : "id",
                      "width" : 100,
+                     "xtype" : "ComboBox"
+                    },
+                    {
                      "$ xns" : "Roo.form",
                      "* prop" : "btns[]",
-                     "qtip" : "Insert Field",
-                     "tpl" : "<div class=\"x-grid-cell-text x-btn button\"><b>{name}</b> </div>",
-                     "loadingText" : "Searching...",
+                     "alwaysQuery" : true,
+                     "displayField" : "name",
+                     "editable" : false,
+                     "emptyText" : "Insert Field",
+                     "fieldLabel" : "Field",
+                     "forceSelection" : true,
                      "items" : [
                       {
-                       "xtype" : "SimpleStore",
-                       "$ data" : "[ \n    [ '{person.firstname}', \"First Name\"],\n    [ '{person.lastname}' , \"Last Name\"],\n    [ '{person.name}', \"Full Name\"],\n    [ '#unsubscribe', \"Unsubscribe\"]\n]\n",
+                       "$ data" : [
+                        "[ ",
+                        "    [ '{person.firstname}', \"First Name\"],",
+                        "    [ '{person.lastname}' , \"Last Name\"],",
+                        "    [ '{person.name}', \"Full Name\"],",
+                        "    [ '#unsubscribe', \"Unsubscribe\"]",
+                        "]",
+                        ""
+                       ],
                        "$ fields" : "[  'type', 'name']",
                        "$ xns" : "Roo.data",
-                       "* prop" : "store"
+                       "* prop" : "store",
+                       "xtype" : "SimpleStore"
                       }
-                     ]
+                     ],
+                     "listWidth" : 400,
+                     "listeners" : {
+                      "render" : [
+                       "function (_self)",
+                       "{",
+                       "    _this.unsubscribeselect = _self;",
+                       "}"
+                      ],
+                      "select" : [
+                       "function (combo, record, index)",
+                       "{",
+                       "    Roo.log(record);",
+                       "    (function() { ",
+                       "        combo.setValue('');",
+                       "    }).defer(100);",
+                       "    var editor = _this.form.findField('bodytext').editorcore;",
+                       "    ",
+                       "    if(record.data.name == 'Unsubscribe'){",
+                       "        editor.insertAtCursor(",
+                       "            String.format('<a href=\"{0}\">{1}</a>',",
+                       "                record.data.type,  record.data.name",
+                       "            )",
+                       "        );",
+                       "        return;     ",
+                       "    }",
+                       "    ",
+                       "    editor.insertAtCursor(",
+                       "        String.format('{0}',",
+                       "            record.data.type",
+                       "        )",
+                       "    );",
+                       "    ",
+                       " }"
+                      ]
+                     },
+                     "loadingText" : "Searching...",
+                     "minChars" : 2,
+                     "pageSize" : 20,
+                     "qtip" : "Insert Field",
+                     "selectOnFocus" : true,
+                     "tpl" : "<div class=\"x-grid-cell-text x-btn button\"><b>{name}</b> </div>",
+                     "triggerAction" : "all",
+                     "typeAhead" : true,
+                     "valueField" : "type",
+                     "width" : 100,
+                     "xtype" : "ComboBox"
                     },
                     {
-                     "xtype" : "Separator",
                      "$ xns" : "Roo.Toolbar",
-                     "* prop" : "btns[]"
+                     "* prop" : "btns[]",
+                     "xtype" : "Separator"
                     },
                     {
+                     "$ xns" : "Roo.Toolbar",
+                     "* prop" : "btns[]",
+                     "String cls" : "x-init-enable",
                      "listeners" : {
-                      "click" : "function (_self, e)\n{\n    this.scope.owner.fireEvent('savedpreview', this.scope.owner);\n    \n}"
+                      "click" : [
+                       "function (_self, e)",
+                       "{",
+                       "    this.scope.owner.fireEvent('savedpreview', this.scope.owner);",
+                       "    ",
+                       "}"
+                      ]
                      },
-                     "String cls" : "x-init-enable",
                      "text" : "Saved Version",
-                     "xtype" : "Button",
-                     "$ xns" : "Roo.Toolbar",
-                     "* prop" : "btns[]"
+                     "xtype" : "Button"
                     }
-                   ]
+                   ],
+                   "xtype" : "ToolbarStandard"
                   }
+                 ],
+                 "listeners" : {
+                  "autosave" : [
+                   "function (_self)",
+                   "{",
+                   "    Roo.log('autosave');",
+                   "    ",
+                   "    var id = _this.form.findField('id').getValue() * 1;",
+                   "    ",
+                   "    /*",
+                   "    if(!_self.editorcore.sourceEditMode){",
+                   "        _self.syncValue();",
+                   "    }else{",
+                   "        _self.pushValue();",
+                   "    }",
+                   "    */",
+                   "    ",
+                   "    new Pman.Request({",
+                   "        url : baseURL + '/Roo/Events.php',",
+                   "        method :'POST',",
+                   "        params : {",
+                   "            id : 0,",
+                   "            action : 'AUTOSAVE',",
+                   "            on_id : (id > 0) ? id : 0,",
+                   "            on_table : 'crm_mailing_list_message',",
+                   "            remarks : 'BODY',",
+                   "            source: _self.getValue()",
+                   "        },",
+                   "        success : function() {",
+                   "            _self.originalValue = _self.getValue();",
+                   "            ",
+                   "        },",
+                   "        failure : function() ",
+                   "        {",
+                   "            Roo.log('body autosave failed?!');",
+                   "        }",
+                   "    });",
+                   "    ",
+                   "}"
+                  ],
+                  "savedpreview" : [
+                   "function (_self)",
+                   "{",
+                   "    var id = _this.form.findField('id').getValue() * 1;",
+                   "    ",
+                   "    var successFn = function(res){",
+                   "        return res.data.POST.source;",
+                   "    };",
+                   "    ",
+                   "    var params = {",
+                   "        action : 'AUTOSAVE',",
+                   "        remarks : 'BODY',",
+                   "        on_id : (id < 1) ? 0 : id,",
+                   "        on_table : 'crm_mailing_list_message',",
+                   "        successFn : successFn",
+                   "    };",
+                   "    ",
+                   "    ",
+                   "    Pman.Dialog.CoreAutoSavePreview.show(params, function(res){",
+                   "        _self.setValue(res);",
+                   "        _self.originalValue = res;",
+                   "    });",
+                   "}"
+                  ]
+                 },
+                 "name" : "bodytext",
+                 "resizable" : "s",
+                 "xtype" : "HtmlEditor",
+                 "| function autosave" : [
+                  "function() {",
+                  "    ",
+                  "    var body = _this.form.findField('bodytext');",
+                  "    ",
+                  "    if(!body.wrap.isVisible(true) || body.getValue() == '' || !body.isDirty()){",
+                  "        Roo.log('body not dirty');",
+                  "        return;",
+                  "    }",
+                  "    ",
+                  "    Roo.log('body dirty, auto save!');",
+                  "    ",
+                  "    body.fireEvent('autosave', body);",
+                  "   ",
+                  "}",
+                  ""
                  ]
                 }
-               ]
+               ],
+               "legend" : "Html Editor",
+               "style" : "text-align:center;",
+               "xtype" : "FieldSet"
               }
-             ]
+             ],
+             "xtype" : "Row"
             },
             {
-             "hideLabels" : true,
-             "xtype" : "Row",
              "$ xns" : "Roo.form",
+             "hideLabels" : true,
              "items" : [
               {
+               "$ xns" : "Roo",
                "listeners" : {
-                "click" : "function (_self, e)\n{\n    var h = _this.form.findField('bodytext').getValue();\n    var p = _this.form.findField('plaintext');\n    \n    new Pman.Request({\r\n        url : baseURL + '/Core/ImportMailMessage.php',\r\n        method : 'POST',\r\n        params : {\n          bodytext : h,\r\n          _convertToPlain : true,\n          _check_unsubscribe : true\r\n        }, \r\n        success : function(res) {\r\n            if(res.success == true){\n               p.setValue(res.data);\n            }\r\n        }\r\n    });\n    \n}"
+                "click" : [
+                 "function (_self, e)",
+                 "{",
+                 "    var h = _this.form.findField('bodytext').getValue();",
+                 "    var p = _this.form.findField('plaintext');",
+                 "    ",
+                 "    new Pman.Request({\r",
+                 "        url : baseURL + '/Core/ImportMailMessage.php',\r",
+                 "        method : 'POST',\r",
+                 "        params : {",
+                 "          bodytext : h,\r",
+                 "          _convertToPlain : true,",
+                 "          _check_unsubscribe : true\r",
+                 "        }, \r",
+                 "        success : function(res) {\r",
+                 "            if(res.success == true){",
+                 "               p.setValue(res.data);",
+                 "            }\r",
+                 "        }\r",
+                 "    });",
+                 "    ",
+                 "}"
+                ]
                },
                "text" : "Convert Html to Text",
-               "xtype" : "Button",
-               "$ xns" : "Roo"
+               "xtype" : "Button"
               }
-             ]
+             ],
+             "xtype" : "Row"
             },
             {
-             "hideLabels" : true,
-             "xtype" : "Row",
              "$ xns" : "Roo.form",
+             "hideLabels" : true,
              "items" : [
               {
-               "hideLabels" : true,
-               "style" : "text-align:center;",
-               "legend" : "Plain Text",
-               "xtype" : "FieldSet",
                "$ xns" : "Roo.form",
+               "hideLabels" : true,
                "items" : [
                 {
-                 "xtype" : "TextArea",
                  "$ xns" : "Roo.form",
                  "height" : 50,
-                 "name" : "plaintext"
+                 "name" : "plaintext",
+                 "xtype" : "TextArea"
                 }
-               ]
+               ],
+               "legend" : "Plain Text",
+               "style" : "text-align:center;",
+               "xtype" : "FieldSet"
               }
-             ]
+             ],
+             "xtype" : "Row"
             },
             {
-             "xtype" : "Row",
              "$ xns" : "Roo.form",
              "items" : [
               {
-               "fieldLabel" : "Test Class <BR/> (for system reference only)",
+               "$ xns" : "Roo.form",
                "Boolean readOnly" : true,
-               "xtype" : "TextField",
                "allowBlank" : true,
+               "fieldLabel" : "Test Class <BR/> (for system reference only)",
+               "name" : "test_class",
                "width" : 300,
-               "$ xns" : "Roo.form",
-               "name" : "test_class"
+               "xtype" : "TextField"
               }
-             ]
+             ],
+             "xtype" : "Row"
             },
             {
-             "xtype" : "Hidden",
              "$ xns" : "Roo.form",
-             "name" : "id"
+             "name" : "id",
+             "xtype" : "Hidden"
             }
-           ]
+           ],
+           "labelAlign" : "right",
+           "labelWidth" : 120,
+           "listeners" : {
+            "|actioncomplete" : [
+             "function(_self,action)",
+             "{",
+             "   ",
+             "    if (action.type == 'setdata') {",
+             "    ",
+             "        setInterval(_this.form.findField('bodytext').autosave, 5000);",
+             "        ",
+             "        _this.data.module = _this.data.module || 'crm_mailing_list_message';",
+             "        ",
+             "        _this.form.url = baseURL + '/Roo/' + _this.data.module;",
+             "        ",
+             "        _this.html_preview.hide();",
+             "        _this.preview_btn.hide();",
+             "            ",
+             "        if(_this.data.id*1 > 0){",
+             "            _this.dialog.el.mask(\"Loading\");",
+             "            this.load({ method: 'GET', params: { '_id' : _this.data.id }});",
+             "            _this.html_preview.show();",
+             "            _this.preview_btn.show();",
+             "            ",
+             "        } else {",
+             "            _this.form.setValues({",
+             "                'from_name' : Pman.Login.authUser.name,",
+             "                'from_email' : Pman.Login.authUser.email",
+             "            });",
+             "        }",
+             "       return;",
+             "    }",
+             "    if (action.type == 'load') {",
+             "        _this.dialog.el.unmask();",
+             "        ",
+             "        _this.form.findField('bodytext').originalValue = _this.form.findField('bodytext').getValue();",
+             "        ",
+             "        return;",
+             "    }",
+             "    if (action.type =='submit') {",
+             "    ",
+             "        _this.dialog.el.unmask();",
+             "        _this.dialog.hide();",
+             "    ",
+             "         if (_this.callback) {",
+             "            _this.callback.call(_this, action.result.data);",
+             "         }",
+             "         _this.form.reset();",
+             "         return;",
+             "    }",
+             "}",
+             ""
+            ],
+            "|rendered" : [
+             "function (form)",
+             "{",
+             "    _this.form= form;",
+             "}",
+             ""
+            ]
+           },
+           "method" : "POST",
+           "style" : "margin:10px",
+           "xtype" : "Form"
           }
-         ]
+         ],
+         "listeners" : {
+          "render" : [
+           "function (_self, width, height)",
+           "{",
+           "    ",
+           "      Roo.log(\"RESIZE, \" + width + ',' + height);",
+           "    ",
+           "    var ew = Math.max(250, width-50);",
+           "    var eh = Math.max(250,height-50) ;",
+           "    ",
+           "   ",
+           "",
+           "}"
+          ],
+          "resize" : [
+           "function (_self, width, height)\r",
+           "{\r",
+           "   var ew = Math.max(250, width-50);\r",
+           "    var eh = Math.max(250,height-50) ;",
+           "    ",
+           "    if (!_this.form) {\r",
+           "        return;\r",
+           "    }\r",
+           "    var bdtext = _this.form.findField('bodytext');\r",
+           "    var ptext = _this.form.findField('plaintext');\r",
+           "    if(bdtext.resizeEl){\r",
+           "        bdtext.width = ew-50;\r",
+           "        bdtext.resizeEl.resizeTo.defer(110, bdtext.resizeEl,[ bdtext.width, bdtext.height  ] );\r",
+           "        ptext.setSize(bdtext.width , bdtext.height);\r",
+           "    }\r\r",
+           "\r",
+           "}"
+          ]
+         },
+         "region" : "center",
+         "title" : "Message",
+         "xtype" : "ContentPanel"
         }
-       ]
+       ],
+       "xtype" : "BorderLayout"
       }
-     ]
+     ],
+     "region" : "center",
+     "xtype" : "NestedLayoutPanel"
     },
     {
-     "listeners" : {
-      "|activate" : "function() {\n    _this.ipanel = this;\n    if (_this.igrid) {\n       _this.igrid.ds.load({});\n    }\n}"
-     },
+     "$ xns" : "Roo",
      "autoScroll" : false,
      "background" : false,
-     "fitToframe" : true,
-     "region" : "east",
-     "title" : "Images / Attachments",
-     "xtype" : "GridPanel",
      "fitContainer" : true,
-     "$ xns" : "Roo",
-     "tableName" : "Images",
+     "fitToframe" : true,
      "items" : [
       {
-       "listeners" : {
-        "|render" : "function() \n{\n    _this.igrid = this; \n    //_this.dialog = Pman.Dialog.FILL_IN\n    if (_this.ipanel.active) {\n   //    _this.igrid.ds.load({});\n    }\n}"
-       },
-       "autoExpandColumn" : "filename",
-       "xtype" : "Grid",
-       "loadMask" : true,
        "$ xns" : "Roo.grid",
        "* prop" : "grid",
+       "autoExpandColumn" : "filename",
        "items" : [
         {
-         "listeners" : {
-          "beforeload" : "function (_self, options)\n{\n    options.params = options.params || {};\n    if (typeof(_this.data) == 'undefined') {\n        return false;\n    }\n    if(_this.data.id * 1 >= 0)\n    {\n        options.params.onid = _this.data.id;\n\n        options.params.ontable = (_this.data.module) ? _this.data.module : 'crm_mailing_list_message';\n    }\n}"
-         },
-         "xtype" : "Store",
-         "remoteSort" : true,
          "$ sortInfo" : "{ field : 'filename', direction: 'ASC' }",
          "$ xns" : "Roo.data",
          "* prop" : "dataSource",
          "items" : [
           {
            "$ url" : "baseURL + '/Roo/Images.php'",
-           "method" : "GET",
-           "xtype" : "HttpProxy",
            "$ xns" : "Roo.data",
-           "* prop" : "proxy"
+           "* prop" : "proxy",
+           "method" : "GET",
+           "xtype" : "HttpProxy"
           },
           {
-           "id" : "id",
-           "root" : "data",
-           "xtype" : "JsonReader",
-           "$ fields" : "[\n    {\n        'name': 'id',\n        'type': 'int'\n    },\n    {\n        'name': 'filename',\n        'type': 'string'\n    },\n    {\n        'name': 'ontable',\n        'type': 'string'\n    },\n    {\n        'name': 'onid',\n        'type': 'int'\n    },\n    {\n        'name': 'mimetype',\n        'type': 'string'\n    },\n    {\n        'name': 'width',\n        'type': 'int'\n    },\n    {\n        'name': 'height',\n        'type': 'int'\n    },\n    {\n        'name': 'filesize',\n        'type': 'int'\n    },\n    {\n        'name': 'displayorder',\n        'type': 'int'\n    },\n    {\n        'name': 'language',\n        'type': 'string'\n    },\n    {\n        'name': 'parent_image_id',\n        'type': 'int'\n    },\n    {\n        'name': 'created',\n        'type': 'date',\n        'dateFormat': 'Y-m-d'\n    },\n    {\n        'name': 'imgtype',\n        'type': 'string'\n    },\n    {\n        'name': 'linkurl',\n        'type': 'string'\n    },\n    {\n        'name': 'descript',\n        'type': 'string'\n    },\n    {\n        'name': 'title',\n        'type': 'string'\n    },\n    {\n        'name': 'parent_image_id_id',\n        'type': 'int'\n    },\n    {\n        'name': 'parent_image_id_filename',\n        'type': 'string'\n    },\n    {\n        'name': 'parent_image_id_ontable',\n        'type': 'string'\n    },\n    {\n        'name': 'parent_image_id_onid',\n        'type': 'int'\n    },\n    {\n        'name': 'parent_image_id_mimetype',\n        'type': 'string'\n    },\n    {\n        'name': 'parent_image_id_width',\n        'type': 'int'\n    },\n    {\n        'name': 'parent_image_id_height',\n        'type': 'int'\n    },\n    {\n        'name': 'parent_image_id_filesize',\n        'type': 'int'\n    },\n    {\n        'name': 'parent_image_id_displayorder',\n        'type': 'int'\n    },\n    {\n        'name': 'parent_image_id_language',\n        'type': 'string'\n    },\n    {\n        'name': 'parent_image_id_parent_image_id',\n        'type': 'int'\n    },\n    {\n        'name': 'parent_image_id_created',\n        'type': 'date'\n    },\n    {\n        'name': 'parent_image_id_imgtype',\n        'type': 'string'\n    },\n    {\n        'name': 'parent_image_id_linkurl',\n        'type': 'string'\n    },\n    {\n        'name': 'parent_image_id_descript',\n        'type': 'string'\n    },\n    {\n        'name': 'parent_image_id_title',\n        'type': 'string'\n    }\n]",
+           "$ fields" : [
+            "[",
+            "    {",
+            "        'name': 'id',",
+            "        'type': 'int'",
+            "    },",
+            "    {",
+            "        'name': 'filename',",
+            "        'type': 'string'",
+            "    },",
+            "    {",
+            "        'name': 'ontable',",
+            "        'type': 'string'",
+            "    },",
+            "    {",
+            "        'name': 'onid',",
+            "        'type': 'int'",
+            "    },",
+            "    {",
+            "        'name': 'mimetype',",
+            "        'type': 'string'",
+            "    },",
+            "    {",
+            "        'name': 'width',",
+            "        'type': 'int'",
+            "    },",
+            "    {",
+            "        'name': 'height',",
+            "        'type': 'int'",
+            "    },",
+            "    {",
+            "        'name': 'filesize',",
+            "        'type': 'int'",
+            "    },",
+            "    {",
+            "        'name': 'displayorder',",
+            "        'type': 'int'",
+            "    },",
+            "    {",
+            "        'name': 'language',",
+            "        'type': 'string'",
+            "    },",
+            "    {",
+            "        'name': 'parent_image_id',",
+            "        'type': 'int'",
+            "    },",
+            "    {",
+            "        'name': 'created',",
+            "        'type': 'date',",
+            "        'dateFormat': 'Y-m-d'",
+            "    },",
+            "    {",
+            "        'name': 'imgtype',",
+            "        'type': 'string'",
+            "    },",
+            "    {",
+            "        'name': 'linkurl',",
+            "        'type': 'string'",
+            "    },",
+            "    {",
+            "        'name': 'descript',",
+            "        'type': 'string'",
+            "    },",
+            "    {",
+            "        'name': 'title',",
+            "        'type': 'string'",
+            "    },",
+            "    {",
+            "        'name': 'parent_image_id_id',",
+            "        'type': 'int'",
+            "    },",
+            "    {",
+            "        'name': 'parent_image_id_filename',",
+            "        'type': 'string'",
+            "    },",
+            "    {",
+            "        'name': 'parent_image_id_ontable',",
+            "        'type': 'string'",
+            "    },",
+            "    {",
+            "        'name': 'parent_image_id_onid',",
+            "        'type': 'int'",
+            "    },",
+            "    {",
+            "        'name': 'parent_image_id_mimetype',",
+            "        'type': 'string'",
+            "    },",
+            "    {",
+            "        'name': 'parent_image_id_width',",
+            "        'type': 'int'",
+            "    },",
+            "    {",
+            "        'name': 'parent_image_id_height',",
+            "        'type': 'int'",
+            "    },",
+            "    {",
+            "        'name': 'parent_image_id_filesize',",
+            "        'type': 'int'",
+            "    },",
+            "    {",
+            "        'name': 'parent_image_id_displayorder',",
+            "        'type': 'int'",
+            "    },",
+            "    {",
+            "        'name': 'parent_image_id_language',",
+            "        'type': 'string'",
+            "    },",
+            "    {",
+            "        'name': 'parent_image_id_parent_image_id',",
+            "        'type': 'int'",
+            "    },",
+            "    {",
+            "        'name': 'parent_image_id_created',",
+            "        'type': 'date'",
+            "    },",
+            "    {",
+            "        'name': 'parent_image_id_imgtype',",
+            "        'type': 'string'",
+            "    },",
+            "    {",
+            "        'name': 'parent_image_id_linkurl',",
+            "        'type': 'string'",
+            "    },",
+            "    {",
+            "        'name': 'parent_image_id_descript',",
+            "        'type': 'string'",
+            "    },",
+            "    {",
+            "        'name': 'parent_image_id_title',",
+            "        'type': 'string'",
+            "    }",
+            "]"
+           ],
            "$ xns" : "Roo.data",
            "* prop" : "reader",
-           "totalProperty" : "total"
+           "id" : "id",
+           "root" : "data",
+           "totalProperty" : "total",
+           "xtype" : "JsonReader"
           }
-         ]
+         ],
+         "listeners" : {
+          "beforeload" : [
+           "function (_self, options)",
+           "{",
+           "    options.params = options.params || {};",
+           "    if (typeof(_this.data) == 'undefined') {",
+           "        return false;",
+           "    }",
+           "    if(_this.data.id * 1 >= 0)",
+           "    {",
+           "        options.params.onid = _this.data.id;",
+           "",
+           "        options.params.ontable = (_this.data.module) ? _this.data.module : 'crm_mailing_list_message';",
+           "    }",
+           "}"
+          ]
+         },
+         "remoteSort" : true,
+         "xtype" : "Store"
         },
         {
-         "xtype" : "Toolbar",
          "$ xns" : "Roo",
          "* prop" : "toolbar",
          "items" : [
           {
+           "$ icon" : "Roo.rootURL + 'images/default/dd/drop-add.gif'",
+           "$ xns" : "Roo.Toolbar",
+           "cls" : "x-btn-text-icon",
            "listeners" : {
-            "|click" : "function()\n{\n    var id = _this.form.findField('id').getValue();\n    \n    if(id*1 < 1){\n        Roo.MessageBox.alert('Error', 'Please save the email template first');\n        return;\n    }\n    \n    var ontable = (_this.data.module) ? _this.data.module : 'crm_mailing_list_message';\n    \n    Pman.Dialog.Image.show( { id : 0, onid: id, ontable: ontable }, function() {\n        _this.igrid.getDataSource().load({});\n    });\n}\n"
+            "|click" : [
+             "function()",
+             "{",
+             "    var id = _this.form.findField('id').getValue();",
+             "    ",
+             "    if(id*1 < 1){",
+             "        Roo.MessageBox.alert('Error', 'Please save the email template first');",
+             "        return;",
+             "    }",
+             "    ",
+             "    var ontable = (_this.data.module) ? _this.data.module : 'crm_mailing_list_message';",
+             "    ",
+             "    Pman.Dialog.Image.show( { id : 0, onid: id, ontable: ontable }, function() {",
+             "        _this.igrid.getDataSource().load({});",
+             "    });",
+             "}",
+             ""
+            ]
            },
            "text" : "Add",
-           "xtype" : "Button",
-           "cls" : "x-btn-text-icon",
-           "$ icon" : "Roo.rootURL + 'images/default/dd/drop-add.gif'",
-           "$ xns" : "Roo.Toolbar"
+           "xtype" : "Button"
           },
           {
+           "$ icon" : "rootURL + '/Pman/templates/images/trash.gif'",
+           "$ xns" : "Roo.Toolbar",
+           "cls" : "x-btn-text-icon",
            "listeners" : {
-            "|click" : "function()\n{\n    var s = _this.igrid.getSelectionModel().getSelected();\n    if (!s || isNaN(s.id *1)) {\n        Roo.MessageBox.alert(\"Error\", \"Select a image\"); \n        return;\n    }\n    Roo.MessageBox.confirm(\"Confirm\", \"Are sure you want to delete this image?\", function (v){\n        if (v != 'yes') {\n            return;\n        }\n        \n        new Pman.Request({\n            url : baseURL + '/Roo/Images.php',\n            method: 'POST',\n            params : {\n                _delete : s.id\n            },\n            success : function()\n            {\n                Roo.log('Got Success!!');\n               _this.igrid.ds.load({});\n            }\n        });\n    });\n}\n        "
+            "|click" : [
+             "function()",
+             "{",
+             "           Pman.genericDelete({grid: _this.igrid}, 'Images');",
+             "}",
+             "        "
+            ]
            },
            "text" : "Delete",
-           "xtype" : "Button",
-           "cls" : "x-btn-text-icon",
-           "$ icon" : "rootURL + '/Pman/templates/images/trash.gif'",
-           "$ xns" : "Roo.Toolbar"
+           "xtype" : "Button"
           }
-         ]
+         ],
+         "xtype" : "Toolbar"
         },
         {
-         "xtype" : "ColumnModel",
-         "header" : "Filename",
-         "width" : 300,
-         "$ renderer" : "function(v,x,r)\n{\n    var width = r.data.width;\n    var height = r.data.height;\n    \n    if(width > 50){\n        height = Math.round(height * 50 / width);\n        width = 50;\n    }\n    \n   return '<img src=\"' + baseURL + '/Images/' + r.data.id + '/' + r.data.filename + '\" width=\"' + width + '\" height=\"' + height + '\" />';\n}",
+         "$ renderer" : [
+          "function(v,x,r)",
+          "{",
+          "    var width = r.data.width;",
+          "    var height = r.data.height;",
+          "    ",
+          "    if(width > 50){",
+          "        height = Math.round(height * 50 / width);",
+          "        width = 50;",
+          "    }",
+          "    ",
+          "   return '<img src=\"' + baseURL + '/Images/' + r.data.id + '/' + r.data.filename + '\" width=\"' + width + '\" height=\"' + height + '\" />';",
+          "}"
+         ],
          "$ xns" : "Roo.grid",
          "* prop" : "colModel[]",
-         "dataIndex" : "filename"
+         "dataIndex" : "filename",
+         "header" : "Filename",
+         "width" : 300,
+         "xtype" : "ColumnModel"
         },
         {
-         "xtype" : "ColumnModel",
-         "width" : 75,
-         "header" : "Displayorder",
          "$ renderer" : "function(v) { return String.format('{0}', v); }",
          "$ xns" : "Roo.grid",
          "* prop" : "colModel[]",
-         "dataIndex" : "displayorder"
+         "dataIndex" : "displayorder",
+         "header" : "Displayorder",
+         "width" : 75,
+         "xtype" : "ColumnModel"
         },
         {
-         "xtype" : "ColumnModel",
-         "header" : "Title",
-         "width" : 75,
          "$ renderer" : "function(v) { return String.format('{0}', v); }",
          "$ xns" : "Roo.grid",
          "* prop" : "colModel[]",
-         "dataIndex" : "title"
+         "dataIndex" : "title",
+         "header" : "Title",
+         "width" : 75,
+         "xtype" : "ColumnModel"
         }
-       ]
+       ],
+       "listeners" : {
+        "|render" : [
+         "function() ",
+         "{",
+         "    _this.igrid = this; ",
+         "    //_this.dialog = Pman.Dialog.FILL_IN",
+         "    if (_this.ipanel.active) {",
+         "   //    _this.igrid.ds.load({});",
+         "    }",
+         "}"
+        ]
+       },
+       "loadMask" : true,
+       "xtype" : "Grid"
       }
-     ]
+     ],
+     "listeners" : {
+      "|activate" : [
+       "function() {",
+       "    _this.ipanel = this;",
+       "    if (_this.igrid) {",
+       "       _this.igrid.ds.load({});",
+       "    }",
+       "}"
+      ]
+     },
+     "region" : "east",
+     "tableName" : "Images",
+     "title" : "Images / Attachments",
+     "xtype" : "GridPanel"
     },
     {
+     "$ xns" : "Roo",
+     "* prop" : "buttons[]",
      "listeners" : {
-      "render" : "function (_self)\n{\n    _this.preview_btn = _self;\n}",
-      "click" : "function (_self, e)\n{\n    //_this.dialog.hide();\n    Roo.log(_this.data.module);\n    Pman.Dialog.CoreEmailPreview.show({ id : _this.form.findField('id').getValue(), module : _this.data.module });\n}"
+      "click" : [
+       "function (_self, e)",
+       "{",
+       "    //_this.dialog.hide();",
+       "    Roo.log(_this.data.module);",
+       "    Pman.Dialog.CoreEmailPreview.show({ id : _this.form.findField('id').getValue(), module : _this.data.module });",
+       "}"
+      ],
+      "render" : [
+       "function (_self)",
+       "{",
+       "    _this.preview_btn = _self;",
+       "}"
+      ]
      },
      "text" : "Preview",
-     "xtype" : "Button",
-     "$ xns" : "Roo",
-     "* prop" : "buttons[]"
+     "xtype" : "Button"
     },
     {
+     "$ xns" : "Roo",
+     "* prop" : "buttons[]",
      "listeners" : {
-      "render" : "function (_self)\n{\n    _this.html_preview = _self;\n}",
-      "click" : "function (_self, e)\n{\n    //_this.dialog.hide();\n\n    var id = _this.form.findField('id').getValue();\n    \n    if(id*1 < 1){\n        Roo.MessageBox.alert('Error', 'Please save the message frist!');\n        return;\n    }\n   \n    new Pman.Request({\n        url : baseURL + '/Core/MessagePreview',\n        method : 'POST',\n        mask: 'Sending',\n        params : {\n            _id : id,\n            _table : _this.data.module\n        }, \n        success : function(res) { \n            if(res.data == 'SUCCESS'){\n                Roo.MessageBox.alert(\"Email Sent\", 'The report was sent to your email (HTML format).');\n            }\n        }\n    });\n}"
+      "click" : [
+       "function (_self, e)",
+       "{",
+       "    //_this.dialog.hide();",
+       "",
+       "    var id = _this.form.findField('id').getValue();",
+       "    ",
+       "    if(id*1 < 1){",
+       "        Roo.MessageBox.alert('Error', 'Please save the message frist!');",
+       "        return;",
+       "    }",
+       "   ",
+       "    new Pman.Request({",
+       "        url : baseURL + '/Core/MessagePreview',",
+       "        method : 'POST',",
+       "        mask: 'Sending',",
+       "        params : {",
+       "            _id : id,",
+       "            _table : _this.data.module",
+       "        }, ",
+       "        success : function(res) { ",
+       "            if(res.data == 'SUCCESS'){",
+       "                Roo.MessageBox.alert(\"Email Sent\", 'The report was sent to your email (HTML format).');",
+       "            }",
+       "        }",
+       "    });",
+       "}"
+      ],
+      "render" : [
+       "function (_self)",
+       "{",
+       "    _this.html_preview = _self;",
+       "}"
+      ]
      },
      "text" : "Send me a test copy",
-     "xtype" : "Button",
-     "$ xns" : "Roo",
-     "* prop" : "buttons[]"
+     "xtype" : "Button"
     },
     {
+     "$ xns" : "Roo",
+     "* prop" : "buttons[]",
      "listeners" : {
-      "click" : "function (_self, e)\n{\n    _this.dialog.hide();\n}"
+      "click" : [
+       "function (_self, e)",
+       "{",
+       "    _this.dialog.hide();",
+       "}"
+      ]
      },
      "text" : "Cancel",
-     "xtype" : "Button",
-     "$ xns" : "Roo",
-     "* prop" : "buttons[]"
+     "xtype" : "Button"
     },
     {
+     "$ xns" : "Roo",
+     "* prop" : "buttons[]",
      "listeners" : {
-      "click" : "function (_self, e)\n{\n\n    // do some checks?\n    _this.form.preValidate(function(res) {\n        if (!res) {\n            return; //failed.\n        }\n         _this.form.doAction(\"submit\");\n    });\n\n}"
+      "click" : [
+       "function (_self, e)",
+       "{",
+       "",
+       "    // do some checks?",
+       "    _this.form.preValidate(function(res) {",
+       "        if (!res) {",
+       "            return; //failed.",
+       "        }",
+       "         _this.form.doAction(\"submit\");",
+       "    });",
+       "",
+       "}"
+      ]
      },
      "text" : "Save",
-     "xtype" : "Button",
-     "$ xns" : "Roo",
-     "* prop" : "buttons[]"
+     "xtype" : "Button"
     }
-   ]
+   ],
+   "listeners" : {
+    "show" : [
+     "function (_self)",
+     "{",
+     "    ",
+     "    _self.layout.getRegion('center').showPanel(0);",
+     "    var w = Roo.lib.Dom.getViewWidth();\r",
+     "    var h = Roo.lib.Dom.getViewHeight();    \r    this.resizeTo(w-50, h-50);\r",
+     "    this.center();\r    ",
+     "    var ew = Math.max(250, w-320);\r",
+     "    var eh = Math.max(250, h-350) ;\r",
+     "    var e = _this.dialog.layout.getRegion('east');",
+     "    if (e.visible) {",
+     "        e.hide();",
+     "    }",
+     "    ",
+     "    var el = _self.getEl();",
+     "    var elw = el.dom.clientWidth;",
+     "    ",
+     "    var bdtext = _this.form.findField('bodytext');",
+     "    var ptext = _this.form.findField('plaintext');",
+     "    if(bdtext.resizeEl){",
+     "        bdtext.width = elw-100;",
+     "        bdtext.resizeEl.resizeTo.defer(110, bdtext.resizeEl,[ bdtext.width, bdtext.height  ] );",
+     "        ptext.setSize(bdtext.width , bdtext.height);",
+     "    }",
+     "    ",
+     "}"
+    ]
+   },
+   "modal" : true,
+   "resizable" : true,
+   "title" : "Edit / Create Message",
+   "width" : 800,
+   "xtype" : "LayoutDialog"
   }
- ]
+ ],
+ "modOrder" : "001",
+ "name" : "Pman.Dialog.CoreEmail",
+ "named_strings" : {
+  "active_boxLabel" : "28690be026c0bb9003aa58e45e5662ca",
+  "active_value" : "c4ca4238a0b923820dcc509a6f75849b",
+  "bcc_group_id_name_emptyText" : "2c466a2c159463f1d9ef5a7b57b52827",
+  "bcc_group_id_name_fieldLabel" : "68b00d723d37122f64da8d9939f836f0",
+  "bcc_group_id_name_loadingText" : "1243daf593fa297e07ab03bf06d925af",
+  "bcc_group_id_name_qtip" : "2c466a2c159463f1d9ef5a7b57b52827",
+  "from_email_fieldLabel" : "b357b524e740bc85b9790a0712d84a30",
+  "from_name_fieldLabel" : "5da618e8e4b89c66fe86e32cdafde142",
+  "language_name_fieldLabel" : "4994a8ffeba4ac3140beb89e8d41f174",
+  "name_fieldLabel" : "b20a8b77b05d53b4e695738731400c85",
+  "subject_fieldLabel" : "c7892ebbb139886662c6f2fc8c450710",
+  "template_emptyText" : "31bb2f6e9b8fb11cbb7fb63c6025223f",
+  "template_fieldLabel" : "278c491bdd8a53618c149c4ac790da34",
+  "template_loadingText" : "1243daf593fa297e07ab03bf06d925af",
+  "template_qtip" : "31bb2f6e9b8fb11cbb7fb63c6025223f",
+  "test_class_fieldLabel" : "b337c8a67244afb6551ee1f8f9717676"
+ },
+ "parent" : "",
+ "path" : "/home/alan/gitlive/Pman.Core/Pman.Dialog.CoreEmail.bjs",
+ "permname" : "",
+ "strings" : {
+  "1243daf593fa297e07ab03bf06d925af" : "Searching...",
+  "1351017ac6423911223bc19a8cb7c653" : "Filename",
+  "1bd18d39370b7f26c1c5e18067b74c6f" : "Html File",
+  "2393ad754ba179442d85e415d1d5167c" : "Displayorder",
+  "278c491bdd8a53618c149c4ac790da34" : "Template",
+  "28690be026c0bb9003aa58e45e5662ca" : "Enabled - will be sent out",
+  "2c466a2c159463f1d9ef5a7b57b52827" : "Select BCC Group",
+  "2f26e35d61be90501e099089dc533638" : "Select Images",
+  "308f2757bfc9ce92fb00ff93fdffd279" : "Images / Attachments",
+  "31bb2f6e9b8fb11cbb7fb63c6025223f" : "Select Template",
+  "31fde7b05ac8952dacf4af8a704074ec" : "Preview",
+  "396ecabf0cd1f9503e591418851ef406" : "Edit / Create Message",
+  "4994a8ffeba4ac3140beb89e8d41f174" : "Language",
+  "4c2a8fe7eaf24721cc7a9f0175115bd4" : "Message",
+  "5b8ef4e762c00a15a41cfc26dc3ef99c" : "Send me a test copy",
+  "5da618e8e4b89c66fe86e32cdafde142" : "From",
+  "5feb9bf3c03b32635135006cbacb9542" : "Insert Field",
+  "68b00d723d37122f64da8d9939f836f0" : "BCC Group",
+  "6f16a5f8ff5d75ab84c018adacdfcbb7" : "Field",
+  "72d6d7a1885885bb55a565fd1070581a" : "Import",
+  "884df8e413319ff51a3f5f528606238a" : "Use template",
+  "962b90039a542a29cedd51d87a9f28a1" : "Html Editor",
+  "b20a8b77b05d53b4e695738731400c85" : "Mailout Name",
+  "b337c8a67244afb6551ee1f8f9717676" : "Test Class <BR/> (for system reference only)",
+  "b357b524e740bc85b9790a0712d84a30" : "Email address",
+  "b78a3223503896721cca1303f776159b" : "Title",
+  "b9c49611cfda3259a2b837b39489e650" : "Add Image",
+  "bd88a20b53a47f7b5704a83a15ff5506" : "Saved Version",
+  "c4ca4238a0b923820dcc509a6f75849b" : "1",
+  "c7892ebbb139886662c6f2fc8c450710" : "Subject",
+  "c9cc8cce247e49bae79f15173ce97354" : "Save",
+  "dc0de523c25be298ba751c63c694109e" : "Responsive Email (1)",
+  "e44b145bd8b49b06e0ad2ced1ad56466" : "Plain Text",
+  "e6b391a8d2c4d45902a23a8b6585703d" : "URL",
+  "e9968623956c15023d54335ea3699855" : "Convert Html to Text",
+  "ea30b40c3caf28acb29198d20d243e54" : "Images / Attachments >>",
+  "ea4788705e6873b424c65e91c2846b19" : "Cancel",
+  "ec211f7c20af43e742bf2570c3cb84f9" : "Add",
+  "f2a6c498fb90ee345d997f888fce3b18" : "Delete",
+  "fff0d600f8a0b5e19e88bfb821dd1157" : "Images"
+ },
+ "title" : ""
 }
\ No newline at end of file
index fb2be9a..0c83f95 100644 (file)
@@ -13,14 +13,15 @@ Pman.Dialog.CoreEmail = {
   'b357b524e740bc85b9790a0712d84a30' :"Email address",
   '962b90039a542a29cedd51d87a9f28a1' :"Html Editor",
   '72d6d7a1885885bb55a565fd1070581a' :"Import",
+  '28690be026c0bb9003aa58e45e5662ca' :"Enabled - will be sent out",
   'ea30b40c3caf28acb29198d20d243e54' :"Images / Attachments >>",
   '31fde7b05ac8952dacf4af8a704074ec' :"Preview",
   'b337c8a67244afb6551ee1f8f9717676' :"Test Class <BR/> (for system reference only)",
   '884df8e413319ff51a3f5f528606238a' :"Use template",
   'e6b391a8d2c4d45902a23a8b6585703d' :"URL",
-  '2393ad754ba179442d85e415d1d5167c' :"Displayorder",
   '6f16a5f8ff5d75ab84c018adacdfcbb7' :"Field",
   'ec211f7c20af43e742bf2570c3cb84f9' :"Add",
+  '2393ad754ba179442d85e415d1d5167c' :"Displayorder",
   'e9968623956c15023d54335ea3699855' :"Convert Html to Text",
   '1243daf593fa297e07ab03bf06d925af' :"Searching...",
   '5b8ef4e762c00a15a41cfc26dc3ef99c' :"Send me a test copy",
@@ -31,6 +32,7 @@ Pman.Dialog.CoreEmail = {
   'ea4788705e6873b424c65e91c2846b19' :"Cancel",
   '68b00d723d37122f64da8d9939f836f0' :"BCC Group",
   'c4ca4238a0b923820dcc509a6f75849b' :"1",
+  '4994a8ffeba4ac3140beb89e8d41f174' :"Language",
   'bd88a20b53a47f7b5704a83a15ff5506' :"Saved Version",
   'b20a8b77b05d53b4e695738731400c85' :"Mailout Name",
   '1bd18d39370b7f26c1c5e18067b74c6f' :"Html File",
@@ -39,13 +41,31 @@ Pman.Dialog.CoreEmail = {
   '31bb2f6e9b8fb11cbb7fb63c6025223f' :"Select Template",
   'b78a3223503896721cca1303f776159b' :"Title",
   '278c491bdd8a53618c149c4ac790da34' :"Template",
-  '1351017ac6423911223bc19a8cb7c653' :"Filename",
   '308f2757bfc9ce92fb00ff93fdffd279' :"Images / Attachments",
+  '1351017ac6423911223bc19a8cb7c653' :"Filename",
   'c9cc8cce247e49bae79f15173ce97354' :"Save",
   '5feb9bf3c03b32635135006cbacb9542' :"Insert Field",
   '4c2a8fe7eaf24721cc7a9f0175115bd4' :"Message",
   'fff0d600f8a0b5e19e88bfb821dd1157' :"Images"
  },
+ _named_strings : {
+  'active_boxLabel' : '28690be026c0bb9003aa58e45e5662ca' /* Enabled - will be sent out */ ,
+  'template_fieldLabel' : '278c491bdd8a53618c149c4ac790da34' /* Template */ ,
+  'name_fieldLabel' : 'b20a8b77b05d53b4e695738731400c85' /* Mailout Name */ ,
+  'bcc_group_id_name_qtip' : '2c466a2c159463f1d9ef5a7b57b52827' /* Select BCC Group */ ,
+  'bcc_group_id_name_emptyText' : '2c466a2c159463f1d9ef5a7b57b52827' /* Select BCC Group */ ,
+  'language_name_fieldLabel' : '4994a8ffeba4ac3140beb89e8d41f174' /* Language */ ,
+  'template_qtip' : '31bb2f6e9b8fb11cbb7fb63c6025223f' /* Select Template */ ,
+  'template_loadingText' : '1243daf593fa297e07ab03bf06d925af' /* Searching... */ ,
+  'from_email_fieldLabel' : 'b357b524e740bc85b9790a0712d84a30' /* Email address */ ,
+  'template_emptyText' : '31bb2f6e9b8fb11cbb7fb63c6025223f' /* Select Template */ ,
+  'active_value' : 'c4ca4238a0b923820dcc509a6f75849b' /* 1 */ ,
+  'from_name_fieldLabel' : '5da618e8e4b89c66fe86e32cdafde142' /* From */ ,
+  'bcc_group_id_name_loadingText' : '1243daf593fa297e07ab03bf06d925af' /* Searching... */ ,
+  'bcc_group_id_name_fieldLabel' : '68b00d723d37122f64da8d9939f836f0' /* BCC Group */ ,
+  'subject_fieldLabel' : 'c7892ebbb139886662c6f2fc8c450710' /* Subject */ ,
+  'test_class_fieldLabel' : 'b337c8a67244afb6551ee1f8f9717676' /* Test Class <BR/> (for system reference only) */ 
+ },
 
  dialog : false,
  callback:  false,
@@ -58,7 +78,7 @@ Pman.Dialog.CoreEmail = {
 
   this.callback = cb;
   this.data = data;
-  this.dialog.show(this.data._el);
+  this.dialog.show.apply(this.dialog,  Array.prototype.slice.call(arguments).slice(2));
   if (this.form) {
    this.form.reset();
    this.form.setValues(data);
@@ -538,6 +558,21 @@ Pman.Dialog.CoreEmail = {
                    });
                   
                }
+               
+               if (!_this.form.findField('bodytext').getValue().match(/unsubscribe/i)) {
+                   Roo.MessageBox.confirm("Missing unusubscribe",
+                       "There is no unsubscribe link on the email  are you sure you want to save it",
+                       function(res) {
+                           if (res == 'no') {
+                               return;
+                           }
+                           mkimg();
+                       }
+                   );
+           
+                   return;
+               }
+               
                mkimg();
            },
            style : 'margin:10px',
@@ -614,13 +649,14 @@ Pman.Dialog.CoreEmail = {
               },
               {
                xtype : 'Column',
-               hideLabels : true,
+               labelSeparator : ' ',
+               labelWidth : 0,
                xns : Roo.form,
                '|xns' : 'Roo.form',
                items  : [
                 {
                  xtype : 'Checkbox',
-                 boxLabel : 'Enabled - will be sent out',
+                 boxLabel : _this._strings['28690be026c0bb9003aa58e45e5662ca'] /* Enabled - will be sent out */,
                  checked : true,
                  name : 'active',
                  value : 1,
@@ -724,13 +760,44 @@ Pman.Dialog.CoreEmail = {
              ]
             },
             {
-             xtype : 'TextField',
-             allowBlank : false,
-             fieldLabel : _this._strings['c7892ebbb139886662c6f2fc8c450710'] /* Subject */,
-             name : 'subject',
-             width : 600,
+             xtype : 'Row',
              xns : Roo.form,
-             '|xns' : 'Roo.form'
+             '|xns' : 'Roo.form',
+             items  : [
+              {
+               xtype : 'TextField',
+               allowBlank : false,
+               fieldLabel : _this._strings['c7892ebbb139886662c6f2fc8c450710'] /* Subject */,
+               name : 'subject',
+               width : 600,
+               xns : Roo.form,
+               '|xns' : 'Roo.form'
+              },
+              {
+               xtype : 'ComboBox',
+               allowBlank : false,
+               displayField : 'title',
+               editable : false,
+               fieldLabel : _this._strings['4994a8ffeba4ac3140beb89e8d41f174'] /* Language */,
+               hiddenName : 'language',
+               listWidth : 200,
+               mode : 'local',
+               name : 'language_name',
+               tpl : '<div class=\"x-grid-cell-text x-btn button\"><b>{title}</b> </div>',
+               triggerAction : 'all',
+               valueField : 'code',
+               width : 200,
+               xns : Roo.form,
+               '|xns' : 'Roo.form',
+               store : {
+                xtype : 'SimpleStore',
+                data : (function() {return typeof(Pman) == 'object'  ? Pman.I18n.simpleStoreData('l') : []})(),
+                fields : ['code', 'title'],
+                xns : Roo.data,
+                '|xns' : 'Roo.data'
+               }
+              }
+             ]
             },
             {
              xtype : 'Row',
@@ -748,6 +815,8 @@ Pman.Dialog.CoreEmail = {
                items  : [
                 {
                  xtype : 'HtmlEditor',
+                 allowComments : true,
+                 autoClean : false,
                  autosave : function() {
                      
                      var body = _this.form.findField('bodytext');
@@ -764,43 +833,64 @@ Pman.Dialog.CoreEmail = {
                  },
                  clearUp : false,
                  cwhite : [ 
-                     'margin',
-                     'padding',
-                     'text-align',
                      'background',
-                     'height',
-                     'width',
                      'background-color',
+                     'border',
+                     'border-radius',
+                     'border-bottom',
+                     'border-left',
+                     'border-right',
+                     'border-top',
+                     'border-collapse',
+                      'border-color',
+                      'border-style',
+                     'border-width',
+                 
+                     
+                     'box-shadow',
+                     'clear',
+                     'color',
+                     'cursor',
+                     'display',
+                     'float' ,
+                     'font-family',
                      'font-size',
+                     'font-style',        
+                     'font-weight',
+                 
+                     'height',
+                     'left',
                      'line-height',
-                     'color',
-                     'outline',
-                     'text-decoration',
-                     'position',
-                     'clear',
-                     'overflow',
-                     'margin-top',
-                     'border-bottom',
-                     'top',
                      'list-style',
+                     'margin',
+                     'margin-bottom',
                      'margin-left',
-                     'border',
-                     'float' ,
                      'margin-right',
-                     'padding-top',
+                     'margin-top',
+                     'max-width',
                      'min-height',
-                     'left',
-                     'padding-left',
-                     'font-weight',
-                     'font-family',
-                     'display',
-                     'margin-bottom',
+                     '-ms-interpolation-mode',
+                     'mso-table-rspace',
+                     '-ms-text-size-adjust',
+                     'outline',
+                     'overflow',
+                     'padding',
                      'padding-bottom',
+                     'padding-left',
+                     'padding-right',
+                     'padding-top',
+                     'position',
+                     'right',
+                     'text-align',
+                     'text-decoration',
+                     'top',
                      'vertical-align',
-                     'cursor',
-                     'z-index',
-                     'right'
+                     '-webkit-text-size-adjust',
+                     'width',
+                     'width',
+                     'z-index'
                   ],
+                 enableBlocks : false,
                  height : 250,
                  name : 'bodytext',
                  resizable : 's',
@@ -1235,29 +1325,7 @@ Pman.Dialog.CoreEmail = {
           listeners : {
            click : function()
             {
-                var s = _this.igrid.getSelectionModel().getSelected();
-                if (!s || isNaN(s.id *1)) {
-                    Roo.MessageBox.alert("Error", "Select a image"); 
-                    return;
-                }
-                Roo.MessageBox.confirm("Confirm", "Are sure you want to delete this image?", function (v){
-                    if (v != 'yes') {
-                        return;
-                    }
-                    
-                    new Pman.Request({
-                        url : baseURL + '/Roo/Images.php',
-                        method: 'POST',
-                        params : {
-                            _delete : s.id
-                        },
-                        success : function()
-                        {
-                            Roo.log('Got Success!!');
-                           _this.igrid.ds.load({});
-                        }
-                    });
-                });
+                       Pman.genericDelete({grid: _this.igrid}, 'Images');
             }
           },
           xns : Roo.Toolbar,
index addc15a..1bea89d 100644 (file)
 {
- "name" : "Pman.Dialog.CoreEmailPreview",
- "parent" : "",
- "title" : "",
- "path" : "/home/johns/gitlive/Pman.Core/Pman.Dialog.CoreEmailPreview.bjs",
- "permname" : "",
- "modOrder" : "001",
- "strings" : {
-  "4cd8413207629a963225f4314b53adcd" : "Plain",
-  "4c4ad5fca2e7a3f74dbb1ced00381aa4" : "HTML",
-  "006c82ffdd63692a84a259c4f8732842" : "Email Preview",
-  "e0aa021e21dddbd6d8cecec71e9cf564" : "OK"
- },
  "items" : [
   {
-   "listeners" : {
-    "show" : "function (_self)\n{\n    \n    _self.layout.getRegion('center').showPanel(0);\n    _this.panel.load({ \n        url: baseURL + '/Core/MessagePreview', \n        params  : {\n            _id : _this.data.id,\n            _table : _this.data.module\n        },\n        method : 'GET'\n    });\n    _this.hpanel.load({ \n        url: baseURL + '/Core/MessagePreview', \n        params  : {\n            _as_html : 1,\n            _id : _this.data.id,\n            _table : _this.data.module\n        },\n        method : 'GET'\n    });\n        \n}"
-   },
-   "shadow" : true,
-   "autoScroll" : true,
-   "title" : "Email Preview",
-   "xtype" : "LayoutDialog",
-   "width" : 1200,
    "$ xns" : "Roo",
+   "autoScroll" : true,
    "closable" : true,
    "height" : 800,
    "items" : [
     {
+     "$ xns" : "Roo",
+     "* prop" : "center",
      "autoScroll" : true,
-     "xtype" : "LayoutRegion",
      "tabPosition" : "top",
-     "$ xns" : "Roo",
-     "* prop" : "center"
+     "xtype" : "LayoutRegion"
     },
     {
+     "$ xns" : "Roo",
+     "fitContainer" : true,
+     "fitToFrame" : true,
      "listeners" : {
-      "render" : "function (_self)\n{\n    _this.panel = _self;\n}"
+      "render" : [
+       "function (_self)",
+       "{",
+       "    _this.hpanel = _self;",
+       "}"
+      ]
      },
      "region" : "center",
-     "fitToFrame" : true,
-     "title" : "Plain",
-     "xtype" : "ContentPanel",
-     "fitContainer" : true,
-     "$ xns" : "Roo"
+     "title" : "HTML",
+     "xtype" : "ContentPanel"
     },
     {
+     "$ xns" : "Roo",
+     "fitContainer" : true,
+     "fitToFrame" : true,
      "listeners" : {
-      "render" : "function (_self)\n{\n    _this.hpanel = _self;\n}"
+      "render" : [
+       "function (_self)",
+       "{",
+       "    _this.panel = _self;",
+       "}"
+      ]
      },
      "region" : "center",
-     "fitToFrame" : true,
-     "title" : "HTML",
-     "xtype" : "ContentPanel",
-     "fitContainer" : true,
-     "$ xns" : "Roo"
+     "title" : "Plain",
+     "xtype" : "ContentPanel"
     },
     {
+     "$ xns" : "Roo",
+     "* prop" : "buttons[]",
      "listeners" : {
-      "click" : "function (_self, e)\n{\n    _this.dialog.hide();\n}"
+      "click" : [
+       "function (_self, e)",
+       "{",
+       "    _this.dialog.hide();",
+       "}"
+      ]
      },
      "text" : "OK",
-     "xtype" : "Button",
-     "$ xns" : "Roo",
-     "* prop" : "buttons[]"
+     "xtype" : "Button"
     }
-   ]
+   ],
+   "listeners" : {
+    "show" : [
+     "function (_self)",
+     "{",
+     "    ",
+     "    _self.layout.getRegion('center').showPanel(0);",
+     "    _this.panel.load({ ",
+     "        url: baseURL + '/Core/MessagePreview', ",
+     "        params  : {",
+     "            _id : _this.data.id || '',",
+     "            template_name : _this.data.template_name || '',            ",
+     "            _table : _this.data.module,",
+     "            ontable : _this.data.ontable || '',",
+     "            onid : _this.data.onid || '',",
+     "            evtype : _this.data.evtype  || ''",
+     "        },",
+     "        method : 'GET'",
+     "    });",
+     "    _this.hpanel.load({ ",
+     "        url: baseURL + '/Core/MessagePreview', ",
+     "        params  : {",
+     "            _as_html : 1,",
+     "            _id : _this.data.id || '',",
+     "            template_name : _this.data.template_name || '',",
+     "            _table : _this.data.module,",
+     "            ontable : _this.data.ontable || '',",
+     "            onid : _this.data.onid  || '',",
+     "            evtype : _this.data.evtype || ''",
+     "        },",
+     "        method : 'GET'",
+     "    });",
+     "        ",
+     "}"
+    ]
+   },
+   "shadow" : true,
+   "title" : "Email Preview",
+   "width" : 1200,
+   "xtype" : "LayoutDialog"
   }
- ]
+ ],
+ "modOrder" : "001",
+ "name" : "Pman.Dialog.CoreEmailPreview",
+ "parent" : "",
+ "path" : "/home/alan/gitlive/Pman.Core/Pman.Dialog.CoreEmailPreview.bjs",
+ "permname" : "",
+ "strings" : {
+  "006c82ffdd63692a84a259c4f8732842" : "Email Preview",
+  "4c4ad5fca2e7a3f74dbb1ced00381aa4" : "HTML",
+  "4cd8413207629a963225f4314b53adcd" : "Plain",
+  "e0aa021e21dddbd6d8cecec71e9cf564" : "OK"
+ },
+ "title" : ""
 }
\ No newline at end of file
index c045eb0..5acb548 100644 (file)
@@ -24,7 +24,7 @@ Pman.Dialog.CoreEmailPreview = {
 
   this.callback = cb;
   this.data = data;
-  this.dialog.show(this.data._el);
+  this.dialog.show.apply(this.dialog,  Array.prototype.slice.call(arguments).slice(2));
   if (this.form) {
    this.form.reset();
    this.form.setValues(data);
@@ -52,8 +52,12 @@ Pman.Dialog.CoreEmailPreview = {
           _this.panel.load({ 
               url: baseURL + '/Core/MessagePreview', 
               params  : {
-                  _id : _this.data.id,
-                  _table : _this.data.module
+                  _id : _this.data.id || '',
+                  template_name : _this.data.template_name || '',            
+                  _table : _this.data.module,
+                  ontable : _this.data.ontable || '',
+                  onid : _this.data.onid || '',
+                  evtype : _this.data.evtype  || ''
               },
               method : 'GET'
           });
@@ -61,8 +65,12 @@ Pman.Dialog.CoreEmailPreview = {
               url: baseURL + '/Core/MessagePreview', 
               params  : {
                   _as_html : 1,
-                  _id : _this.data.id,
-                  _table : _this.data.module
+                  _id : _this.data.id || '',
+                  template_name : _this.data.template_name || '',
+                  _table : _this.data.module,
+                  ontable : _this.data.ontable || '',
+                  onid : _this.data.onid  || '',
+                  evtype : _this.data.evtype || ''
               },
               method : 'GET'
           });
@@ -98,11 +106,11 @@ Pman.Dialog.CoreEmailPreview = {
       fitContainer : true,
       fitToFrame : true,
       region : 'center',
-      title : _this._strings['4cd8413207629a963225f4314b53adcd'] /* Plain */,
+      title : _this._strings['4c4ad5fca2e7a3f74dbb1ced00381aa4'] /* HTML */,
       listeners : {
        render : function (_self)
         {
-            _this.panel = _self;
+            _this.hpanel = _self;
         }
       },
       xns : Roo,
@@ -113,11 +121,11 @@ Pman.Dialog.CoreEmailPreview = {
       fitContainer : true,
       fitToFrame : true,
       region : 'center',
-      title : _this._strings['4c4ad5fca2e7a3f74dbb1ced00381aa4'] /* HTML */,
+      title : _this._strings['4cd8413207629a963225f4314b53adcd'] /* Plain */,
       listeners : {
        render : function (_self)
         {
-            _this.hpanel = _self;
+            _this.panel = _self;
         }
       },
       xns : Roo,
index a13189f..6dd5f21 100644 (file)
@@ -45,9 +45,9 @@
      "* prop" : "center"
     },
     {
+     "region" : "center",
      "fitToFrame" : true,
      "background" : true,
-     "region" : "center",
      "xtype" : "ContentPanel",
      "$ xns" : "Roo",
      "items" : [
@@ -57,8 +57,8 @@
         "|rendered" : "function (form)\n{\n   _this.form = form;\n}"
        },
        "$ url" : "baseURL + '/Roo/core_enum.php'",
-       "method" : "POST",
        "xtype" : "Form",
+       "method" : "POST",
        "style" : "margin: 5px",
        "$ xns" : "Roo.form",
        "items" : [
     },
     {
      "listeners" : {
-      "|click" : "function() {\n\n    var name =     _this.form.findField('name').getValue();\n    name = name.toUpperCase().replace(/[^A-Z]+/g, '');\n    if (!name.length) {\n        Roo.MessageBox.alert(\"Error\",\"Please fill in a valid name\");\n        return;\n    }\n    _this.form.findField('name').setValue(name);\n \n    _this.form.doAction('submit');\n    \n}"
+      "|click" : "function() {\n\n    var name =     _this.form.findField('name').getValue();\n    name = name.toUpperCase().replace(/[^A-Z0-9]+/g, '');\n    if (!name.length) {\n        Roo.MessageBox.alert(\"Error\",\"Please fill in a valid name\");\n        return;\n    }\n    _this.form.findField('name').setValue(name);\n \n    _this.form.doAction('submit');\n    \n}"
      },
      "text" : "OK",
      "xtype" : "Button",
index 273763a..aed333c 100644 (file)
@@ -35,7 +35,7 @@ Pman.Dialog.CoreEnum = {
 
   this.callback = cb;
   this.data = data;
-  this.dialog.show(this.data._el);
+  this.dialog.show.apply(this.dialog,  Array.prototype.slice.call(arguments).slice(2));
   if (this.form) {
    this.form.reset();
    this.form.setValues(data);
@@ -91,7 +91,7 @@ Pman.Dialog.CoreEnum = {
        click : function() {
         
             var name =     _this.form.findField('name').getValue();
-            name = name.toUpperCase().replace(/[^A-Z]+/g, '');
+            name = name.toUpperCase().replace(/[^A-Z0-9]+/g, '');
             if (!name.length) {
                 Roo.MessageBox.alert("Error","Please fill in a valid name");
                 return;
index f9c58b2..163dda0 100644 (file)
@@ -2,7 +2,7 @@
  "name" : "Pman.Dialog.CoreEnumMerge",
  "parent" : "",
  "title" : "",
- "path" : "/home/benny/gitlive/web.hhyc_membership_system/Pman.Core/Pman.Dialog.CoreEnumMerge.bjs",
+ "path" : "/home/alan/gitlive/Pman.Core/Pman.Dialog.CoreEnumMerge.bjs",
  "permname" : "",
  "modOrder" : "001",
  "strings" : {
   "266459bee8ed1ca2e0464899e1ef0994" : "And replace with",
   "ea4788705e6873b424c65e91c2846b19" : "Cancel"
  },
+ "named_strings" : {
+  "_merge_id_name_emptyText" : "bf8691517ce00a09186a05cd65863091",
+  "_merge_id_name_loadingText" : "1243daf593fa297e07ab03bf06d925af",
+  "_merge_id_name_qtip" : "bf8691517ce00a09186a05cd65863091",
+  "_merge_id_name_fieldLabel" : "266459bee8ed1ca2e0464899e1ef0994",
+  "_names_fieldLabel" : "8324cdec05065c4bd7d8c5effdf43edf"
+ },
  "items" : [
   {
    "listeners" : {
       {
        "listeners" : {
         "actionfailed" : "function (_self, action)\n{\n \n    Pman.standardActionFailed(_self, action);\n}\n",
-        "actioncomplete" : "function (_self, action)\n{\n\n   if (action.type =='submit') {\n       \n         _this.dialog.hide();\n       \n        if (_this.callback) {\n           _this.callback.call(_this, _this.form.getValues());\n        }\n        _this.form.reset();\n        return;\n    }\n    if (action.type == 'setdata') {\n        \n         var title = _this.data.title  || _this.data.etype;\n        _this.dialog.setTitle(\"Delete selected \" + title + \" and merge data with\");\n        \n\n        if(typeof(_this.data._ids) == \"undefined\"){\n            this.load({ method: 'GET', params: { '_id' : _this.data.id }});  \n            return;\n        }\n        _this.form.findField('_names').setValue(_this.data._names);\n        _this.form.findField('_ids').setValue(_this.data._ids);\n        return;\n    }\n    \n}\n",
-        "rendered" : "function (form)\n{\n   _this.form = form;\n}"
+        "rendered" : "function (form)\n{\n   _this.form = form;\n}",
+        "actioncomplete" : "function (_self, action)\n{\n\n   if (action.type =='submit') {\n       \n         _this.dialog.hide();\n       \n        if (_this.callback) {\n           _this.callback.call(_this, _this.form.getValues());\n        }\n        _this.form.reset();\n        return;\n    }\n    if (action.type == 'setdata') {\n        \n         var title = _this.data.title  || _this.data.etype;\n        _this.dialog.setTitle(\"Delete selected \" + title + \" and merge data with\");\n        \n\n        if(typeof(_this.data._ids) == \"undefined\"){\n            this.load({ method: 'GET', params: { '_id' : _this.data.id }});  \n            return;\n        }\n        _this.form.findField('_names').setValue(_this.data._names);\n        _this.form.findField('_ids').setValue(_this.data._ids);\n        return;\n    }\n    \n}\n"
        },
        "$ url" : "baseURL + '/Roo/Core_enum.php'",
-       "method" : "POST",
        "xtype" : "Form",
+       "method" : "POST",
        "style" : "margin: 10px;",
        "$ xns" : "Roo.form",
        "Number labelWidth" : 120,
        "items" : [
         {
          "String name" : "_names",
-         "Number width" : 250,
          "Boolean readOnly" : true,
+         "Number width" : 250,
          "xtype" : "TextField",
          "String fieldLabel" : "Delete this",
          "$ xns" : "Roo.form"
@@ -86,7 +93,7 @@
          "items" : [
           {
            "listeners" : {
-            "|beforeload" : "function (_self, o){\n    o.params = o.params || {};\n    \n    o.params['etype'] = _this.data.etype;\n    \n    o.params['!id'] = _this.form.findField('id').getValue();\n    // set more here\n}\n"
+            "|beforeload" : "function (_self, o){\n    o.params = o.params || {};\n    \n    o.params['etype'] = _this.data.etype;\n    \n    var ids = _this.form.findField('_ids').getValue();\n    if (ids.length) {\n        var xids = ids.split(',');\n        for(var i =0;i < xids.length; i++) {\n            o.params['!id[' + i + ']'] = xids[i];\n        }\n    } else {\n        o.params['!id'] = _this.form.findField('id').getValue();\n    } \n    // set more here\n}\n"
            },
            "xtype" : "Store",
            "remoteSort" : true,
            "items" : [
             {
              "$ url" : "baseURL + '/Roo/Core_enum'",
-             "xtype" : "HttpProxy",
              "method" : "GET",
+             "xtype" : "HttpProxy",
              "$ xns" : "Roo.data",
              "* prop" : "proxy"
             },
index 3e8d841..2850db2 100644 (file)
@@ -34,7 +34,7 @@ Pman.Dialog.CoreEnumMerge = {
 
   this.callback = cb;
   this.data = data;
-  this.dialog.show(this.data._el);
+  this.dialog.show.apply(this.dialog,  Array.prototype.slice.call(arguments).slice(2));
   if (this.form) {
    this.form.reset();
    this.form.setValues(data);
@@ -197,7 +197,15 @@ Pman.Dialog.CoreEnumMerge = {
                  
                  o.params['etype'] = _this.data.etype;
                  
-                 o.params['!id'] = _this.form.findField('id').getValue();
+                 var ids = _this.form.findField('_ids').getValue();
+                 if (ids.length) {
+                     var xids = ids.split(',');
+                     for(var i =0;i < xids.length; i++) {
+                         o.params['!id[' + i + ']'] = xids[i];
+                     }
+                 } else {
+                     o.params['!id'] = _this.form.findField('id').getValue();
+                 } 
                  // set more here
              }
            },
index a35c7ff..e455e0d 100644 (file)
@@ -2,7 +2,7 @@
  "name" : "Pman.Dialog.CorePersonContact",
  "parent" : "",
  "title" : "",
- "path" : "/home/johns/gitlive/Pman.Core/Pman.Dialog.CorePersonContact.bjs",
+ "path" : "/home/leon/gitlive/web.MediaOutreach/Pman/Core/Pman.Dialog.CorePersonContact.bjs",
  "permname" : "",
  "modOrder" : "001",
  "strings" : {
   "c9cc8cce247e49bae79f15173ce97354" : "Save",
   "9810aa2b9f44401be4bf73188ef2b67d" : "Fax"
  },
+ "named_strings" : {
+  "company_id_code_loadingText" : "1243daf593fa297e07ab03bf06d925af",
+  "role_fieldLabel" : "bbbabdbe1b262f75d99d62880b953be1",
+  "fax_fieldLabel" : "9810aa2b9f44401be4bf73188ef2b67d",
+  "office_id_name_emptyText" : "c373dd4bd4ba0b5d3e0c7522c5629880",
+  "name_fieldLabel" : "49ee3087348e8d44e1feda1917443987",
+  "phone_fieldLabel" : "bcc254b55c4a1babdf1dcb82c207506b",
+  "office_id_name_fieldLabel" : "df814135652a5a308fea15bff37ea284",
+  "office_id_name_loadingText" : "1243daf593fa297e07ab03bf06d925af",
+  "company_id_code_qtip" : "9675747b5ab12d05f18518761e68a533",
+  "office_id_name_qtip" : "c373dd4bd4ba0b5d3e0c7522c5629880",
+  "email_fieldLabel" : "ce8ae9da5b7cd6c3df2929543a9af92d",
+  "company_id_code_emptyText" : "9675747b5ab12d05f18518761e68a533",
+  "company_id_code_fieldLabel" : "1c76cbfe21c6f44c1d1e59d54f3e4420"
+ },
  "items" : [
   {
    "collapsible" : false,
-   "title" : "Edit / Create Contact Details",
    "xtype" : "LayoutDialog",
+   "title" : "Edit / Create Contact Details",
    "width" : 450,
    "$ xns" : "Roo",
    "closable" : false,
@@ -47,8 +62,8 @@
         "|rendered" : "function (form)\n{\n    _this.form= form;\n}\n"
        },
        "$ url" : "baseURL + '/Roo/core_person'",
-       "xtype" : "Form",
        "method" : "POST",
+       "xtype" : "Form",
        "style" : "margin:10px;",
        "$ xns" : "Roo.form",
        "items" : [
            "items" : [
             {
              "$ url" : "baseURL + '/Roo/core_company.php'",
-             "method" : "GET",
              "xtype" : "HttpProxy",
+             "method" : "GET",
              "$ xns" : "Roo.data",
              "* prop" : "proxy"
             },
            "items" : [
             {
              "$ url" : "baseURL + '/Roo/Office.php'",
-             "method" : "GET",
              "xtype" : "HttpProxy",
+             "method" : "GET",
              "$ xns" : "Roo.data",
              "* prop" : "proxy"
             },
index 1bd6e46..2dae25e 100644 (file)
@@ -21,6 +21,21 @@ Pman.Dialog.CorePersonContact = {
   'c9cc8cce247e49bae79f15173ce97354' :"Save",
   '9810aa2b9f44401be4bf73188ef2b67d' :"Fax"
  },
+ _named_strings : {
+  'company_id_code_loadingText' : '1243daf593fa297e07ab03bf06d925af' /* Searching... */ ,
+  'role_fieldLabel' : 'bbbabdbe1b262f75d99d62880b953be1' /* Role */ ,
+  'fax_fieldLabel' : '9810aa2b9f44401be4bf73188ef2b67d' /* Fax */ ,
+  'office_id_name_emptyText' : 'c373dd4bd4ba0b5d3e0c7522c5629880' /* Select Office */ ,
+  'name_fieldLabel' : '49ee3087348e8d44e1feda1917443987' /* Name */ ,
+  'phone_fieldLabel' : 'bcc254b55c4a1babdf1dcb82c207506b' /* Phone */ ,
+  'office_id_name_fieldLabel' : 'df814135652a5a308fea15bff37ea284' /* Office */ ,
+  'office_id_name_loadingText' : '1243daf593fa297e07ab03bf06d925af' /* Searching... */ ,
+  'company_id_code_qtip' : '9675747b5ab12d05f18518761e68a533' /* Select Companies */ ,
+  'office_id_name_qtip' : 'c373dd4bd4ba0b5d3e0c7522c5629880' /* Select Office */ ,
+  'email_fieldLabel' : 'ce8ae9da5b7cd6c3df2929543a9af92d' /* Email */ ,
+  'company_id_code_emptyText' : '9675747b5ab12d05f18518761e68a533' /* Select Companies */ ,
+  'company_id_code_fieldLabel' : '1c76cbfe21c6f44c1d1e59d54f3e4420' /* Company */ 
+ },
 
  dialog : false,
  callback:  false,
index 118820e..773d1a8 100644 (file)
@@ -79,8 +79,8 @@
         "|rendered" : "function (form)\n{\n    _this.form= form;\n}\n"
        },
        "$ url" : "baseURL + '/Roo/core_project'",
-       "method" : "POST",
        "xtype" : "Form",
+       "method" : "POST",
        "style" : "margin:10px;",
        "$ xns" : "Roo.form",
        "items" : [
            "items" : [
             {
              "$ url" : "baseURL + '/Roo/core_company'",
-             "xtype" : "HttpProxy",
              "method" : "GET",
+             "xtype" : "HttpProxy",
              "$ xns" : "Roo.data",
              "* prop" : "proxy"
             },
            "* prop" : "store",
            "items" : [
             {
-             "$ url" : "baseURL + '/Roo/Groups.php'",
-             "xtype" : "HttpProxy",
+             "$ url" : "baseURL + '/Roo/core_group'",
              "method" : "GET",
+             "xtype" : "HttpProxy",
              "$ xns" : "Roo.data",
              "* prop" : "proxy"
             },
              "items" : [
               {
                "$ url" : "baseURL + '/Roo/core_person'",
-               "xtype" : "HttpProxy",
                "method" : "GET",
+               "xtype" : "HttpProxy",
                "$ xns" : "Roo.data",
                "* prop" : "proxy"
               },
index f63ff82..9be1ab0 100644 (file)
@@ -64,7 +64,7 @@ Pman.Dialog.CoreProject = {
 
   this.callback = cb;
   this.data = data;
-  this.dialog.show(this.data._el);
+  this.dialog.show.apply(this.dialog,  Array.prototype.slice.call(arguments).slice(2));
   if (this.form) {
    this.form.reset();
    this.form.setValues(data);
@@ -329,7 +329,7 @@ Pman.Dialog.CoreProject = {
            proxy : {
             xtype : 'HttpProxy',
             method : 'GET',
-            url : baseURL + '/Roo/Groups.php',
+            url : baseURL + '/Roo/core_group',
             xns : Roo.data,
             '|xns' : 'Roo.data'
            },
index 32f560f..7e770d8 100644 (file)
 {
- "name" : "Pman.Dialog.Image",
- "parent" : "",
- "title" : "",
- "path" : "/home/edward/gitlive/Pman.Core/Pman.Dialog.Image.bjs",
- "permname" : "",
- "modOrder" : "001",
- "strings" : {
-  "eb5d45750c7ab13aa8e6bacc80315a30" : "32M",
-  "2859a4ae58ae4e25abdfc530f814e42f" : "Upload an Image or File",
-  "1243daf593fa297e07ab03bf06d925af" : "Searching...",
-  "ea4788705e6873b424c65e91c2846b19" : "Cancel",
-  "8e16a71b3d8217eb80b39b7d8dec4296" : "Image Type",
-  "dff0c70e4c11953e4e3ee1cf268fb96d" : "Select image type",
-  "91412465ea9169dfd901dd5e7c96dd99" : "Upload",
-  "ea72bacd2fdfa818907bb9559e6905a1" : "Upload Image or File"
- },
- "named_strings" : {
-  "imgtype_name_fieldLabel" : "8e16a71b3d8217eb80b39b7d8dec4296",
-  "imgtype_name_loadingText" : "1243daf593fa297e07ab03bf06d925af",
-  "imgtype_name_emptyText" : "dff0c70e4c11953e4e3ee1cf268fb96d",
-  "upload_max_filesize_value" : "eb5d45750c7ab13aa8e6bacc80315a30",
-  "imgtype_name_qtip" : "dff0c70e4c11953e4e3ee1cf268fb96d",
-  "post_max_size_value" : "eb5d45750c7ab13aa8e6bacc80315a30",
-  "imageUpload_fieldLabel" : "ea72bacd2fdfa818907bb9559e6905a1"
- },
+ "gen_extended" : false,
  "items" : [
   {
-   "listeners" : {
-    "show" : "function (_self)\n{\n\n    // this does not really work - escape on the borders works..\n    // resize to fit.. if we have styled stuff...\n    \n    \n    \n    \n    var d = this;\n    \n    var pad =     d.el.getSize().height - (d.header.getSize().height +\n        d.footer.getSize().height +        \n        d.layout.getRegion('center').getPanel(0).el.getSize().height\n        );\n    \n    var height = (\n        pad + \n        d.header.getSize().height +\n        d.footer.getSize().height +        \n        d.layout.getRegion('center').getPanel(0).el.child('div').getSize().height\n    );\n    this.resizeTo(d.el.getSize().width, height);\n    \n    if (this.keylistener) {\n        return;\n    }\n    this.keylistener = this.addKeyListener(27, this.hide, this);\n    \n}"
-   },
-   "modal" : true,
-   "shadow" : true,
-   "collapsible" : false,
-   "title" : "Upload an Image or File",
-   "xtype" : "LayoutDialog",
-   "uploadComplete" : false,
-   "width" : 500,
+   "$ uploadProgress" : [
+    "function()",
+    "{",
+    "    var dlg = this;",
+    "   if (!dlg.haveProgress) {",
+    "        Roo.MessageBox.progress(\"Uploading\", \"Uploading\");",
+    "    }",
+    "    ",
+    "    if (dlg.haveProgress == 2) {",
+    "        // it's been closed elsewhere..",
+    "        return;",
+    "    }",
+    "    if (dlg.uploadComplete) {",
+    "        Roo.MessageBox.hide();",
+    "        return;",
+    "    }",
+    "    ",
+    "    dlg.haveProgress = 1;",
+    "",
+    "    var uid = _this.form.findField('UPLOAD_IDENTIFIER').getValue();",
+    "    new Pman.Request({",
+    "        url : baseURL + '/Core/UploadProgress.php',",
+    "        params: {",
+    "            id : uid",
+    "        },",
+    "        method: 'GET',",
+    "        success : function(res){",
+    "            //console.log(data);",
+    "            var data = res.data;",
+    "            if (dlg.haveProgress == 2) {",
+    "                // it's been closed elsewhere..",
+    "                return;",
+    "            }",
+    "            ",
+    "            if (dlg.uploadComplete) {",
+    "                Roo.MessageBox.hide();",
+    "                return;",
+    "            }",
+    "                ",
+    "            if (data){",
+    "                Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,",
+    "                    Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'",
+    "                );",
+    "            } else {",
+    "                Roo.MessageBox.updateProgress(1,",
+    "                    \"Upload Complete - processing\"",
+    "                );",
+    "                return;",
+    "            }",
+    "            dlg.uploadProgress.defer(2000,dlg);",
+    "        },",
+    "        failure: function(data) {",
+    "          //  console.log('fail');",
+    "         //   console.log(data);",
+    "        }",
+    "    })",
+    "    ",
+    "}",
+    ""
+   ],
    "$ xns" : "Roo",
    "closable" : false,
-   "resizable" : false,
+   "collapsible" : false,
    "haveProgress" : false,
    "height" : 140,
-   "$ uploadProgress" : "function()\n{\n    var dlg = this;\n   if (!dlg.haveProgress) {\n        Roo.MessageBox.progress(\"Uploading\", \"Uploading\");\n    }\n    \n    if (dlg.haveProgress == 2) {\n        // it's been closed elsewhere..\n        return;\n    }\n    if (dlg.uploadComplete) {\n        Roo.MessageBox.hide();\n        return;\n    }\n    \n    dlg.haveProgress = 1;\n\n    var uid = _this.form.findField('UPLOAD_IDENTIFIER').getValue();\n    new Pman.Request({\n        url : baseURL + '/Core/UploadProgress.php',\n        params: {\n            id : uid\n        },\n        method: 'GET',\n        success : function(res){\n            //console.log(data);\n            var data = res.data;\n            if (dlg.haveProgress == 2) {\n                // it's been closed elsewhere..\n                return;\n            }\n            \n            if (dlg.uploadComplete) {\n                Roo.MessageBox.hide();\n                return;\n            }\n                \n            if (data){\n                Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,\n                    Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'\n                );\n            } else {\n                Roo.MessageBox.updateProgress(1,\n                    \"Upload Complete - processing\"\n                );\n                return;\n            }\n            dlg.uploadProgress.defer(2000,dlg);\n        },\n        failure: function(data) {\n          //  console.log('fail');\n         //   console.log(data);\n        }\n    })\n    \n}\n",
    "items" : [
     {
-     "xtype" : "LayoutRegion",
      "$ xns" : "Roo",
-     "* prop" : "center"
+     "* prop" : "center",
+     "xtype" : "LayoutRegion"
     },
     {
-     "fitToFrame" : true,
-     "region" : "center",
-     "Boolean fitContainer" : true,
-     "xtype" : "ContentPanel",
      "$ xns" : "Roo",
+     "Boolean fitContainer" : true,
+     "fitToFrame" : true,
      "items" : [
       {
-       "listeners" : {
-        "actionfailed" : "function (_self, act)\n{\n   \n   \n    _this.dialog.uploadComplete = true;\n   // _this.dialog.el.unmask();\n    // error msg???\n     _this.dialog.haveProgress = 2; \n    if (act.type == 'submit') {\n        Roo.log(\"Upload error\");\n        Roo.log(act);\n        \n        try {\n            Roo.MessageBox.alert(\"Error\", act.result.errorMsg.split(/\\n/).join('<BR/>'));\n        } catch(e) {\n          //  Roo.log(e);\n            Roo.MessageBox.alert(\"Error\", \"Saving failed = fix errors and try again\");        \n        }\n        return;\n    }\n    \n    // what about load failing..\n    Roo.MessageBox.alert(\"Error\", \"Error loading details\"); \n}",
-        "|actioncomplete" : "function(_self,act)\n{\n    _this.dialog.uploadComplete = true;\n    _this.dialog.haveProgress = 2; \n    Roo.MessageBox.hide(); // force hiding\n    //_this.dialog.el.unmask();\n     \n    if (act.type == 'setdata') { \n    \n        _this.form.findField('imgtype').hide();\n        \n        _this.dialog.resizeTo(500, 140);\n        \n        if(_this.data._show_image_type){\n            _this.form.findField('imgtype').show();\n            _this.dialog.resizeTo(500, 170);\n        }\n        \n        this.url = _this.data._url ? _this.data._url : baseURL + '/Roo/Images.php';\n        this.el.dom.action = this.url;\n        if (typeof(_this.data.timeout) != 'undefined') {\n            this.timeout = _this.data.timeout;\n        }\n        \n        this.findField('UPLOAD_IDENTIFIER').setValue(\n            (new Date() * 1) + '' + Math.random());\n            \n        return;\n    }\n     \n   \n    if (act.type == 'load') {\n      // should this happen?  \n        _this.data = act.result.data;\n       // _this.loaded();\n        return;\n    }\n    \n    \n    if (act.type == 'submit') { // only submitted here if we are \n        _this.dialog.hide();\n        Roo.log(\"Upload success\");\n        Roo.log(act);\n        //console.log(act);\n        if (_this.callback) {\n            _this.callback.call(this, act.result.data, act.result.extra);\n        }\n        return; \n    }\n \n\n    \n}\n",
-        "|rendered" : "function (form)\n{\n    _this.form= form;\n}\n"
-       },
        "$ url" : "baseURL + '/Roo/Images.php'",
-       "fileUpload" : true,
-       "method" : "POST",
-       "style" : "margin:10px;",
-       "xtype" : "Form",
-       "labelWidth" : 140,
-       "timeout" : 300,
        "$ xns" : "Roo.form",
+       "fileUpload" : true,
        "items" : [
         {
-         "xtype" : "Hidden",
          "$ xns" : "Roo.form",
-         "name" : "UPLOAD_IDENTIFIER"
+         "name" : "UPLOAD_IDENTIFIER",
+         "xtype" : "Hidden"
         },
         {
-         "xtype" : "Hidden",
-         "value" : "32M",
          "$ xns" : "Roo.form",
-         "name" : "post_max_size"
+         "name" : "post_max_size",
+         "value" : "32M",
+         "xtype" : "Hidden"
         },
         {
-         "xtype" : "Hidden",
-         "value" : "32M",
          "$ xns" : "Roo.form",
-         "name" : "upload_max_filesize"
+         "name" : "upload_max_filesize",
+         "value" : "32M",
+         "xtype" : "Hidden"
         },
         {
-         "inputType" : "file",
+         "$ xns" : "Roo.form",
+         "Boolean allowBlank" : false,
          "fieldLabel" : "Upload Image or File",
-         "xtype" : "TextField",
+         "inputType" : "file",
+         "name" : "imageUpload",
          "width" : 200,
-         "$ xns" : "Roo.form",
-         "name" : "imageUpload"
+         "xtype" : "TextField"
         },
         {
-         "listWidth" : 400,
+         "$ xns" : "Roo.form",
          "String actionMode" : "fieldEl",
+         "allowBlank" : true,
          "alwaysQuery" : true,
-         "triggerAction" : "all",
-         "fieldLabel" : "Image Type",
-         "forceSelection" : true,
-         "selectOnFocus" : true,
-         "pageSize" : 20,
          "displayField" : "display_name",
          "emptyText" : "Select image type",
+         "fieldLabel" : "Image Type",
+         "forceSelection" : true,
          "hiddenName" : "imgtype",
-         "minChars" : 2,
-         "valueField" : "name",
-         "xtype" : "ComboBox",
-         "allowBlank" : true,
-         "typeAhead" : true,
-         "width" : 250,
-         "$ xns" : "Roo.form",
-         "name" : "imgtype_name",
-         "qtip" : "Select image type",
-         "queryParam" : "query[search]",
-         "tpl" : "<div class=\"x-grid-cell-text x-btn button\"><b>{display_name}</b> {name}</div>",
-         "loadingText" : "Searching...",
          "items" : [
           {
-           "listeners" : {
-            "|beforeload" : "function (_self, o){\n    o.params = o.params || {};\n    \n    o.params.etype = 'ImageType';\n    \n    o.params.active = 1;\n}\n"
-           },
-           "xtype" : "Store",
-           "remoteSort" : true,
            "$ sortInfo" : "{ direction : 'ASC', field: 'name' }",
            "$ xns" : "Roo.data",
            "* prop" : "store",
            "items" : [
             {
              "$ url" : "baseURL + '/Roo/Core_enum'",
-             "xtype" : "HttpProxy",
-             "method" : "GET",
              "$ xns" : "Roo.data",
-             "* prop" : "proxy"
+             "* prop" : "proxy",
+             "method" : "GET",
+             "xtype" : "HttpProxy"
             },
             {
-             "id" : "id",
-             "root" : "data",
-             "xtype" : "JsonReader",
              "$ fields" : "[{\"name\":\"id\",\"type\":\"int\"},{\"name\":\"name\",\"type\":\"string\"}]",
              "$ xns" : "Roo.data",
              "* prop" : "reader",
-             "totalProperty" : "total"
+             "id" : "id",
+             "root" : "data",
+             "totalProperty" : "total",
+             "xtype" : "JsonReader"
             }
-           ]
+           ],
+           "listeners" : {
+            "|beforeload" : [
+             "function (_self, o){",
+             "    o.params = o.params || {};",
+             "    ",
+             "    o.params.etype = 'ImageType';",
+             "    ",
+             "    o.params.active = 1;",
+             "}",
+             ""
+            ]
+           },
+           "remoteSort" : true,
+           "xtype" : "Store"
           }
-         ]
+         ],
+         "listWidth" : 400,
+         "loadingText" : "Searching...",
+         "minChars" : 2,
+         "name" : "imgtype_name",
+         "pageSize" : 20,
+         "qtip" : "Select image type",
+         "queryParam" : "query[search]",
+         "selectOnFocus" : true,
+         "tpl" : "<div class=\"x-grid-cell-text x-btn button\"><b>{display_name}</b> {name}</div>",
+         "triggerAction" : "all",
+         "typeAhead" : true,
+         "valueField" : "name",
+         "width" : 250,
+         "xtype" : "ComboBox"
         },
         {
-         "xtype" : "Hidden",
          "$ xns" : "Roo.form",
-         "name" : "ontable"
+         "name" : "ontable",
+         "xtype" : "Hidden"
         },
         {
-         "xtype" : "Hidden",
          "$ xns" : "Roo.form",
-         "name" : "onid"
+         "name" : "onid",
+         "xtype" : "Hidden"
         },
         {
-         "xtype" : "Hidden",
          "$ xns" : "Roo.form",
-         "name" : "id"
+         "name" : "id",
+         "xtype" : "Hidden"
         }
-       ]
+       ],
+       "labelWidth" : 140,
+       "listeners" : {
+        "actionfailed" : [
+         "function (_self, act)",
+         "{",
+         "   ",
+         "   ",
+         "    _this.dialog.uploadComplete = true;",
+         "   // _this.dialog.el.unmask();",
+         "    // error msg???",
+         "     _this.dialog.haveProgress = 2; ",
+         "    if (act.type == 'submit') {",
+         "        Roo.log(\"Upload error\");",
+         "        Roo.log(act);",
+         "        ",
+         "        try {",
+         "            Roo.MessageBox.alert(\"Error\", act.result.errorMsg.split(/\\n/).join('<BR/>'));",
+         "        } catch(e) {",
+         "          //  Roo.log(e);",
+         "            Roo.MessageBox.alert(\"Error\", \"Saving failed = fix errors and try again\");        ",
+         "        }",
+         "        return;",
+         "    }",
+         "    ",
+         "    // what about load failing..",
+         "    Roo.MessageBox.alert(\"Error\", \"Error loading details\"); ",
+         "}"
+        ],
+        "|actioncomplete" : [
+         "function(_self,act)",
+         "{",
+         "    _this.dialog.uploadComplete = true;",
+         "    _this.dialog.haveProgress = 2; ",
+         "    Roo.MessageBox.hide(); // force hiding",
+         "    //_this.dialog.el.unmask();",
+         "     ",
+         "    if (act.type == 'setdata') { ",
+         "    ",
+         "        _this.form.findField('imgtype').hide();",
+         "        ",
+         "        _this.dialog.resizeTo(500, 140);",
+         "        ",
+         "        if(_this.data._show_image_type){",
+         "            _this.form.findField('imgtype').show();",
+         "            _this.dialog.resizeTo(500, 170);",
+         "        }",
+         "        ",
+         "        this.url = _this.data._url ? _this.data._url : baseURL + '/Roo/Images.php';",
+         "        this.el.dom.action = this.url;",
+         "        if (typeof(_this.data.timeout) != 'undefined') {",
+         "            this.timeout = _this.data.timeout;",
+         "        }",
+         "        ",
+         "        this.findField('UPLOAD_IDENTIFIER').setValue(",
+         "            (new Date() * 1) + '' + Math.random());",
+         "            ",
+         "        return;",
+         "    }",
+         "     ",
+         "   ",
+         "    if (act.type == 'load') {",
+         "      // should this happen?  ",
+         "        _this.data = act.result.data;",
+         "       // _this.loaded();",
+         "        return;",
+         "    }",
+         "    ",
+         "    ",
+         "    if (act.type == 'submit') { // only submitted here if we are ",
+         "        _this.dialog.hide();",
+         "        Roo.log(\"Upload success\");",
+         "        Roo.log(act);",
+         "        //console.log(act);",
+         "        if (_this.callback) {",
+         "            _this.callback.call(this, act.result.data, act.result.extra);",
+         "        }",
+         "        return; ",
+         "    }",
+         " ",
+         "",
+         "    ",
+         "}",
+         ""
+        ],
+        "|rendered" : [
+         "function (form)",
+         "{",
+         "    _this.form= form;",
+         "}",
+         ""
+        ]
+       },
+       "method" : "POST",
+       "style" : "margin:10px;",
+       "timeout" : 300,
+       "xtype" : "Form"
       }
-     ]
+     ],
+     "region" : "center",
+     "xtype" : "ContentPanel"
     },
     {
+     "$ xns" : "Roo",
+     "* prop" : "buttons[]",
      "listeners" : {
-      "click" : "function (_self, e)\n{\n    _this.dialog.hide();\n}"
+      "click" : [
+       "function (_self, e)",
+       "{",
+       "    _this.dialog.hide();",
+       "}"
+      ]
      },
      "text" : "Cancel",
-     "xtype" : "Button",
-     "$ xns" : "Roo",
-     "* prop" : "buttons[]"
+     "xtype" : "Button"
     },
     {
+     "$ xns" : "Roo",
+     "* prop" : "buttons[]",
      "listeners" : {
-      "click" : "function (_self, e)\n{\n    // do some checks?\n     \n    //_this.dialog.el.mask(\"Sending\");\n    _this.dialog.uploadComplete = false;\n    _this.form.doAction('submit', {\n        params: {\n            ts : Math.random()\n        }\n    });\n    _this.dialog.haveProgress = 0; // set to show..\n    _this.dialog.uploadProgress.defer(1000, _this.dialog);\n\n}"
+      "click" : [
+       "function (_self, e)",
+       "{",
+       "    // do some checks?",
+       "     ",
+       "    //_this.dialog.el.mask(\"Sending\");",
+       "    _this.dialog.uploadComplete = false;",
+       "    _this.form.doAction('submit', {",
+       "        params: {",
+       "            ts : Math.random()",
+       "        }",
+       "    });",
+       "    _this.dialog.haveProgress = 0; // set to show..",
+       "    _this.dialog.uploadProgress.defer(1000, _this.dialog);",
+       "",
+       "}"
+      ]
      },
      "text" : "Upload",
-     "xtype" : "Button",
-     "$ xns" : "Roo",
-     "* prop" : "buttons[]"
+     "xtype" : "Button"
     }
-   ]
+   ],
+   "listeners" : {
+    "show" : [
+     "function (_self)",
+     "{",
+     "",
+     "    // this does not really work - escape on the borders works..",
+     "    // resize to fit.. if we have styled stuff...",
+     "    ",
+     "    ",
+     "    ",
+     "    ",
+     "    var d = this;",
+     "    ",
+     "    var pad =     d.el.getSize().height - (d.header.getSize().height +",
+     "        d.footer.getSize().height +        ",
+     "        d.layout.getRegion('center').getPanel(0).el.getSize().height",
+     "        );",
+     "    ",
+     "    var height = (",
+     "        pad + ",
+     "        d.header.getSize().height +",
+     "        d.footer.getSize().height +        ",
+     "        d.layout.getRegion('center').getPanel(0).el.child('div').getSize().height",
+     "    );",
+     "    this.resizeTo(d.el.getSize().width, height);",
+     "    ",
+     "    if (this.keylistener) {",
+     "        return;",
+     "    }",
+     "    this.keylistener = this.addKeyListener(27, this.hide, this);",
+     "    ",
+     "}"
+    ]
+   },
+   "modal" : true,
+   "resizable" : false,
+   "shadow" : true,
+   "title" : "Upload an Image or File",
+   "uploadComplete" : false,
+   "width" : 500,
+   "xtype" : "LayoutDialog"
   }
- ]
+ ],
+ "modOrder" : "001",
+ "name" : "Pman.Dialog.Image",
+ "named_strings" : {
+  "imageUpload_fieldLabel" : "ea72bacd2fdfa818907bb9559e6905a1",
+  "imgtype_name_emptyText" : "dff0c70e4c11953e4e3ee1cf268fb96d",
+  "imgtype_name_fieldLabel" : "8e16a71b3d8217eb80b39b7d8dec4296",
+  "imgtype_name_loadingText" : "1243daf593fa297e07ab03bf06d925af",
+  "imgtype_name_qtip" : "dff0c70e4c11953e4e3ee1cf268fb96d",
+  "post_max_size_value" : "eb5d45750c7ab13aa8e6bacc80315a30",
+  "upload_max_filesize_value" : "eb5d45750c7ab13aa8e6bacc80315a30"
+ },
+ "parent" : "",
+ "permname" : "",
+ "strings" : {
+  "1243daf593fa297e07ab03bf06d925af" : "Searching...",
+  "2859a4ae58ae4e25abdfc530f814e42f" : "Upload an Image or File",
+  "8e16a71b3d8217eb80b39b7d8dec4296" : "Image Type",
+  "91412465ea9169dfd901dd5e7c96dd99" : "Upload",
+  "dff0c70e4c11953e4e3ee1cf268fb96d" : "Select image type",
+  "ea4788705e6873b424c65e91c2846b19" : "Cancel",
+  "ea72bacd2fdfa818907bb9559e6905a1" : "Upload Image or File",
+  "eb5d45750c7ab13aa8e6bacc80315a30" : "32M"
+ },
+ "title" : ""
 }
\ No newline at end of file
index 50a667b..e6d58ed 100644 (file)
@@ -37,7 +37,7 @@ Pman.Dialog.Image = {
 
   this.callback = cb;
   this.data = data;
-  this.dialog.show(this.data._el);
+  this.dialog.show.apply(this.dialog,  Array.prototype.slice.call(arguments).slice(2));
   if (this.form) {
    this.form.reset();
    this.form.setValues(data);
@@ -319,6 +319,7 @@ Pman.Dialog.Image = {
          },
          {
           xtype : 'TextField',
+          allowBlank : false,
           fieldLabel : _this._strings['ea72bacd2fdfa818907bb9559e6905a1'] /* Upload Image or File */,
           inputType : 'file',
           name : 'imageUpload',
index 2cee8c0..8349841 100644 (file)
@@ -31,7 +31,7 @@ Pman.Dialog.PersonEditor.prototype = {
             return;
         }
         var _this = this;
-        this.dialog = new Ext.LayoutDialog(Ext.get(document.body).createChild({tag:'div'}),  
+        this.dialog = new Roo.LayoutDialog(Roo.get(document.body).createChild({tag:'div'}),  
             Roo.apply({ 
                 autoCreated: true,
                 title: 'Edit Contact Details',
@@ -69,7 +69,7 @@ Pman.Dialog.PersonEditor.prototype = {
         this.layout.beginUpdate();
         
          
-        this.form = new Ext.form.Form({
+        this.form = new Roo.form.Form({
             labelWidth: 120,
             listeners : {
                 actionfailed : function(f, act) {
@@ -189,7 +189,7 @@ Pman.Dialog.PersonEditor.prototype = {
          
         this.form.render(ef.dom);
 
-        var vp = this.dialog.getLayout().add('center', new Ext.ContentPanel(ef, {
+        var vp = this.dialog.getLayout().add('center', new Roo.ContentPanel(ef, {
             autoCreate : true,
             //title: 'Org Details',
             //toolbar: this.tb,
@@ -259,7 +259,7 @@ Pman.Dialog.PersonEditor.prototype = {
                 forceSelection: true,
                 //mode: 'local',
                 triggerAction: 'all',
-                tpl: new Ext.Template(
+                tpl: new Roo.Template(
                     '<div class="x-grid-cell-text x-btn button">',
                         '<b>{name}</b> {address}',
                     '</div>'
@@ -337,7 +337,7 @@ Pman.Dialog.PersonEditor.prototype = {
                         if (_this.type == 'new') {
                             data = _this.form.findField('company_id').lastData;
                             if (!data.id ) {
-                                Ext.MessageBox.alert("Error", "Select An Company First");
+                                Roo.MessageBox.alert("Error", "Select An Company First");
                                 return false
                             }
                             
@@ -372,7 +372,7 @@ Pman.Dialog.PersonEditor.prototype = {
                     beforequery : function (qe) {
                         var coid = _this.form.findField('company_id').getValue();
                         if (coid < 1 ) {
-                            Ext.MessageBox.alert("Error", "Select An Company First");
+                            Roo.MessageBox.alert("Error", "Select An Company First");
                             return false;
                         }
                     }
@@ -384,7 +384,7 @@ Pman.Dialog.PersonEditor.prototype = {
                 forceSelection: true,
                 //mode: 'local',
                 triggerAction: 'all',
-                tpl: new Ext.Template(
+                tpl: new Roo.Template(
                     '<div class="x-grid-cell-text x-btn button">',
                         '<b>{name}</b> {address}',
                     '</div>'
@@ -561,7 +561,7 @@ Pman.Dialog.PersonEditor.prototype = {
                         width: 50,
                         
                         
-                        store: new Ext.data.SimpleStore({
+                        store: new Roo.data.SimpleStore({
                               // load using HTTP
                             fields: [ 'code', 'desc' ],
                             data:  [[ 'ACTION_REQUIRED', "Yes"] , [ 'NOTIFY', "No"] ]
@@ -613,7 +613,7 @@ Pman.Dialog.PersonEditor.prototype = {
             
         }
         if (this.form.findField('company_id') && !this.form.findField('company_id').getValue()) {
-            Ext.MessageBox.alert("Error", "Select a Company");
+            Roo.MessageBox.alert("Error", "Select a Company");
             return;
         }
         
@@ -623,19 +623,19 @@ Pman.Dialog.PersonEditor.prototype = {
             var p2 = this.form.findField('passwd2').getValue();
             
             if (this.sendAfterSave && !p1.length) {
-                Ext.MessageBox.alert("Error", "You must create a password to send introduction mail");
+                Roo.MessageBox.alert("Error", "You must create a password to send introduction mail");
                 return;
             }
             
             if (Pman.Login.authUser.id < 0 && !p1.length) {
-                Ext.MessageBox.alert("Error", "You must create a password for the admin account");
+                Roo.MessageBox.alert("Error", "You must create a password for the admin account");
                 return;
             }
             
             
             if (p1.length || p2.length) {
                 if (p1 != p2) {
-                    Ext.MessageBox.alert("Error", "Passwords do not match");
+                    Roo.MessageBox.alert("Error", "Passwords do not match");
                     return;
                 }
             }
index 2f16b24..f4584d2 100644 (file)
@@ -18,15 +18,16 @@ var t = new Pman.Download({
 * 
 * @constructor
 * @param {Object} cfg   Configuration object.
+* @cfg {Object}  params  params to send
 * @cfg {String} url     Location to download from.
-* @cfg {String} method     GET or POST (default GET), POST will create a form, and post that into the hidden frame.
+* @cfg {String} method (GET|POST)    GET or POST (default GET), POST will create a form, and post that into the hidden frame.
 * @cfg {Boolean} newWindow (optional) download to new window
 * @cfg {String} doctype (optional) download PDF to new window
 * @cfg {Boolean} limit (optional) limit for grid downloads.
+* @cfg {Boolean} showDownloading default false - show a dialog indicating that the file is downloading
  * @cfg {String} csvCols  - use '*' to override grid coluns
  * @cfg {String} csvTitles - use '*' to override grid coluns
-
+ * @cfg {String} hiddenCols - default 'show'  (use 'hide' to not display them on download)
  
  
 * @cfg {Function} success (optional) MAY fire on download completed (fails on attachments)..
@@ -163,7 +164,9 @@ Pman.Download = function(cfg)
         }
         
     }
-    
+    if (this.showDownloading) {
+        Roo.MessageBox.alert("Downloading", "The file should download shortly");
+    }
     req.send(this.form);
     /*
     (function() {
@@ -196,6 +199,9 @@ Roo.apply(Pman.Download.prototype, {
     success : false,
     failure : false,
     
+    hiddenCols : 'show', // set to 'hide' to hide them..
+    
+    showDownloading : false,
     // private..
     //used by simple GET method.
     createCsvFrame: function()
@@ -305,7 +311,7 @@ Roo.apply(Pman.Download.prototype, {
             
         });
         
-         if(ds.sortInfo && ds.remoteSort){
+        if(ds.sortInfo && ds.remoteSort){
             var pn = ds.paramNames;
             this.params[pn["sort"]] = ds.sortInfo.field;
             this.params[pn["dir"]] = ds.sortInfo.direction;
@@ -328,6 +334,11 @@ Roo.apply(Pman.Download.prototype, {
         } else {
             
             Roo.each(this.grid.cm.config, function(c,i) {
+                
+                if (t.hiddenCols != 'show' && t.grid.cm.isHidden(i)) {
+                    return;
+                }
+                
                 t.params['csvCols['+i+']'] = c.dataIndex;
                 t.params['csvTitles['+i+']'] = c.header;
                 
index d581916..a346fba 100644 (file)
@@ -218,7 +218,7 @@ Roo.extend(Pman.Gnumeric, Roo.util.Observable, {
         // we wil only support AA not AAA
         var top = Math.floor(c/26);
         var bot = c % 26;
-        var cc = top > 0 ? String.fromCharCode('A'.charCodeAt(0) + top) : '';
+        var cc = top > 0 ? String.fromCharCode('A'.charCodeAt(0) + (top-1)) : '';
         cc += String.fromCharCode('A'.charCodeAt(0)  + bot);
         return cc+'' +r;
         
@@ -1716,10 +1716,10 @@ Roo.extend(Pman.Gnumeric, Roo.util.Observable, {
         }
         
         var ser = new XMLSerializer();
-       Roo.get(document.body).mask("Downloading");
+               Roo.get(document.body).mask("Downloading");
         var x = new Pman.Download({
             method: 'POST',
-            timeout : 120000, // quite a long wait.. 2 minutes.
+            timeout :240000, // quite a long wait.. 2 minutes.
             params : {
                xml : ser.serializeToString(this.doc),
                format : this.format,
@@ -1728,16 +1728,16 @@ Roo.extend(Pman.Gnumeric, Roo.util.Observable, {
             },
             url : (this.downloadURL || (baseURL + '/GnumericToExcel/')) + name + '.xls',
             success : function() {
-               Roo.get(document.body).unmask();
+                               Roo.get(document.body).unmask();
                 Roo.MessageBox.alert("Alert", "File should have downloaded now");
                 if (callback) {
                     callback();
                 }
             },
-           failure : function() {
-               Roo.get(document.body).unmask();
-               Roo.MessageBox.alert("Alert", "Download failed");
-           }
+                       failure : function() {
+                               Roo.get(document.body).unmask();
+                               Roo.MessageBox.alert("Alert", "Download failed");
+                       }
         });
          
     }
index b44696d..9636ada 100644 (file)
@@ -97,11 +97,12 @@ Roo.apply(Pman.Lock.prototype, {
     },
     
     
-    unlock : function() {
+    unlock : function(id) {
+        id = id || this.id;
         new Pman.Request({
             url : baseURL + '/Core/Lock/unlock',
             params : {
-                id : this.id
+                id : id
             },
             failure : function() {
                 Roo.MessageBox.alert("Error", "UnLock Request failed, you may get a warning when trying to edit again");
index 234b9c0..a7b77e2 100644 (file)
@@ -132,7 +132,9 @@ Pman.Login =  new Roo.util.Observable({
         var res = Pman.processResponse(response);
         //console.log(res);
         if ( Pman.Login.checkFails > 2) {
-            Pman.Preview.disable();
+            if (typeof(Pman.Preview) != 'undefined') {
+                Pman.Preview.disable(); // not sure why this was added - but MO chrome does not have it.
+            }
             Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg : 
                 "Error getting authentication status. - try reloading"); 
             return;
@@ -348,9 +350,8 @@ Pman.Login =  new Roo.util.Observable({
                 autoCreate : {tag: "input", type: "text", size: "20"}
             }),
 
-            new Roo.form.TextField({
+            new Roo.form.Password({
                 fieldLabel: "Password",
-                inputType: 'password',
                 name: 'password',
                 width:200,
                 autoCreate : {tag: "input", type: "text", size: "20"},
index cf2c313..8ee3fb1 100644 (file)
@@ -564,8 +564,27 @@ Pman.Tab.PersonList.prototype = {
                 }
             
                      
-            }
+            },
+            '->',
             
+              {
+               
+                xtype : 'Button',
+                xns : Roo.Toolbar,
+               
+                text: "Bulk Change Passwords",
+                hidden : _this.permName != 'Core.Staff' || !Pman.hasPerm('Core.Staff', 'E'),
+                listeners : {
+                    click : function () {
+                        Pman.Dialog.AdminBulkPassword.show({}, function() { 
+                          refreshPager();
+                        });
+                        
+                    }
+                }
+            
+                     
+            }
 
         );
         
diff --git a/Process/FixMysqlCharset.php b/Process/FixMysqlCharset.php
new file mode 100644 (file)
index 0000000..128bc92
--- /dev/null
@@ -0,0 +1,152 @@
+<?php
+
+require_once 'Pman/Core/Cli.php';
+
+class Pman_Core_Process_FixMysqlCharset extends Pman_Core_Cli {
+    
+    static $cli_desc = "Base class for CLI only commands";
+    static $cli_opts = array(
+        'table' => array(
+            'desc' => 'Database Table',
+            'short' => 't',
+            'min' => 1,
+            'max' => 1,
+            
+        ),
+        /*
+        'field' => array(
+            'desc' => 'Table Column Name',
+            'short' => 'f',
+            'min' => 1,
+            'max' => 1,
+            
+        ),
+        */
+    );
+    
+    
+    // bugs: 'PICUT, MAËPPE' << strips out chars..
+    
+    
+    /*
+     *
+     * should we do it in PHP - not using the lating stuff?
+     */
+    
+    function get($req , $opts=array())
+    {
+       // DB_DataObject::debugLevel(1);
+       
+        if (file_exists('/tmp/fix_mysql_charset_'. $opts['table'])) {
+            echo "Conversion for {$opts['table']} has already been done - doing it again will mess things up.. - delete the /tmp/fix_mysql_charset file if you really want to do this\n\n";
+            exit;
+        }
+        touch('/tmp/fix_mysql_charset_'. $opts['table']);
+        
+        $this->disableTriggers($opts['table']);
+        
+        $t = DB_DataObject::factory($opts['table']);
+        $cols = $t->tableColumns();
+        $t->selectAdd();
+        $t->selectAdd("id");
+        
+        $conv = array();
+        $w = array();
+        foreach($cols as $k=>$v) {
+            if (!($v & 2)) {
+                continue;
+            }
+            if (($v & 4)) { // date?
+                continue;
+            }
+            $conv[] = $k;
+            $t->selectAdd($k);
+            $t->selectAdd("COALESCE(convert(cast(convert({$k} using  latin1) as binary) using utf8), '') as zz_{$k}");
+            $w[] = " convert(cast(convert({$k} using  latin1) as binary) using utf8) != $k";
+        }
+        $t->whereAdd(implode(" OR ", $w));
+        //$t->whereAdd('id=4555');
+       // $t->limit(100);
+        $t->orderBy('id ASC');
+        $all = $t->fetchAll();
+        foreach($all as $t) {
+            $up =false;
+            $tt = clone($t);
+            //print_r($tt); exit;
+            foreach($conv as $k) {
+               if ($t->{$k} != $t->{'zz_'.$k}) {
+                    if (strpos($t->{'zz_'. $k}, '?') !== false) {
+                        $up = false;
+                        continue;
+                    }
+                
+                    $t->{$k} = $t->{'zz_'.$k};
+                    $up =true;
+               }
+               
+               
+            }
+            if ($up) {
+                echo "UPDATE $t->id\n";
+                $t->_skip_write_xml= true;
+                //DB_DataObject::debugLevel(1);
+                $t->update($tt);
+                //DB_DataObject::debugLevel(0);
+               //  print_r($t);exit;; 
+            }
+        }
+        $this->enableTriggers($opts['table']);
+
+        
+         
+        exit;
+    }
+    
+    var $triggers = array();
+    function disabletriggers($tbl)
+    {
+        
+        $t = DB_DataObject::factory($tbl);
+        // DB_DataObject::debugLevel(1);
+        $t->query("SHOW TRIGGERS FROM {$t->databaseNickname()} where `table` = '{$tbl}'");
+        $this->triggers = array();
+        while ($t->fetch()) {
+            $this->triggers[] = $t->toArray('%s', true);
+            $d = DB_DataObject::factory($tbl);
+            $d->query("DROP TRIGGER {$t->Trigger}");
+        }
+        
+        
+    }
+    /*
+     [Trigger] => account_transaction_before_delete
+    [Event] => DELETE
+    [Table] => account_transaction
+    [Statement] => BEGIN
+            
+            UPDATE `Error: Not allow to delete transaction` SET x = 1;
+
+        END
+    [Timing] => BEFORE
+   */
+    function enabletriggers($tbl)
+    {
+        
+        
+        //DB_DataObject::debugLevel(1);
+        foreach($this->triggers as $tr) {
+            $t = DB_DataObject::factory($tbl);
+            $t->query("
+                CREATE TRIGGER {$tr['Trigger']} 
+                {$tr['Timing']} {$tr['Event']} ON {$tbl}
+                FOR EACH ROW
+                {$tr['Statement']}
+            ");
+            
+            
+            
+        } 
+    }
+    
+    
+}
index 2994e1b..d574edd 100644 (file)
@@ -29,7 +29,7 @@ class Pman_Core_RefreshDatabaseCache extends Pman
         parent::getAuth(); // load company!
         $au = $this->getAuthUser();
         if (!$au || $au->company()->comptype != 'OWNER') {
-            $this->jerr("Not authenticated", array('authFailure' => true));
+            $this->jerror("LOGIN-NOAUTH", "Not authenticated", array('authFailure' => true));
         }
         $this->authUser = $au;
         return true;
index 162ebce..4815b3c 100644 (file)
@@ -256,6 +256,7 @@ trait Pman_Core_RooGetTrait {
         if (!empty($_REQUEST['_requestMeta']) &&  count($ret)) {
             $meta = $this->meta($x, $ret);
             if ($meta) {
+                $extra = $extra ? $extra: array();
                 $extra['metaData'] = $meta;
             }
         }
index 456aa7a..3389036 100644 (file)
@@ -2,6 +2,8 @@
 
 trait Pman_Core_RooPostTrait {
     
+    var $old;
+    
     /**
      * POST method   Roo/TABLENAME  
      * -- creates, updates, or deletes data.
@@ -187,8 +189,13 @@ trait Pman_Core_RooPostTrait {
        // echo '<PRE>';print_r($affects);exit;
        // DB_Dataobject::debugLevel(1);
        
-        
-        $clean = create_function('$v', 'return (int)$v;');
+        if (function_exists('create_function')) {
+            $clean = create_function('$v', 'return (int)$v;');
+        } else {
+            $clean = function($v) {
+                return (int)$v;
+            };
+        }
         
         $bits = array_map($clean, explode(',', $req['_delete']));
         
index 9a929f1..b00112a 100644 (file)
@@ -10,9 +10,23 @@ trait Pman_Core_RooTrait {
     
     var $debugEnabled = true;
     
+    var $appName;
+    var $appNameShort;
+    var $appModules;
+    var $isDev;
+    var $appDisable;
+    var $appDisabled;
+    var $version ;
+    var $uiConfig ;
+      
+    var $cols = array();
+    var $countWhat;
+    var $colsJname;    
+    var $_hasInit;
+    
     function init() 
     {
-        if (isset($this->_hasInit)) {
+        if (!empty($this->_hasInit)) {
             return;
         }
         
@@ -143,7 +157,7 @@ trait Pman_Core_RooTrait {
         
     }
     
-    var $cols = array();
+    
     
     function loadMap($do, $cfg =array())
     {
index 3a4516a..3911255 100644 (file)
@@ -56,7 +56,7 @@ class Pman_Core_RunGenerator extends Pman
         parent::getAuth(); // load company!
         $au = $this->getAuthUser();
         if (!$au || $au->company()->comptype != 'OWNER') {
-            $this->jerr("Not authenticated", array('authFailure' => true));
+            $this->jerror("LOGIN-NOAUTH", "Not authenticated", array('authFailure' => true));
         }
         $this->authUser = $au;
         return true;
index c3187f1..6108d49 100644 (file)
@@ -28,7 +28,7 @@ class Pman_Core_SendIntro extends Pman
         
         $au = $this->getAuthUser();
         if (!$au) {
-            $this->jerr("Not authenticated", array('authFailure' => true));
+            $this->jerror("LOGIN-NOAUTH", "Not authenticated", array('authFailure' => true));
         }
         $this->authUser = $au;
         // check that it's a supplier!!!! 
index 6c36750..0ca12fc 100644 (file)
@@ -47,7 +47,7 @@ new Pman_Core_SimpleExcel($data_array, array(
             workbook => '....' // ???
     ),
     'leave_open' => false,  // if you call addrows?? later..
-            
+    'nonspacer' => false, // should add line between head and header row.     
 ));
 
     callbacks: renderer
@@ -75,6 +75,7 @@ class Pman_Core_SimpleExcel extends Pman
     var $workbook = false;
     var $worksheet= false;
     var $postRender = array();
+    var $outfile2;
      
     function __construct($data,$cfg)
     {
@@ -394,7 +395,7 @@ class Pman_Core_SimpleExcel extends Pman
           //  print_R(array($start_row+$r, $c, $v, $format));exit;
           // handle 0 prefixes..
           
-            if (preg_match('/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/', $v)) {
+            if ($dataFormat == 'date' || preg_match('/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/', $v)) {
                 $dataFormat = 'date';
                 $format = empty($format) ? $this->formats['_default_date_format_']: $format;
                 $ut_to_ed_diff = 86400 * 25569;
@@ -409,9 +410,10 @@ class Pman_Core_SimpleExcel extends Pman
             if ( (is_numeric($v) &&  strlen($v) > 1 && substr($v,0,1) == '0' && substr($v,1,1) != '.' )
                     || 
                     $dataFormat == 'string' ) {
+                //var_dump("Write ( {$r}, {$c} ) = " . $v);
                 $worksheet->writeString($start_row+$r, $c, $v, $format);
             } else {
-          
+                //var_dump("Write String ( {$r}, {$c} ) = " . $v);
                 $worksheet->write($start_row+$r, $c, $v, $format);
             }
             
diff --git a/TimeZone.php b/TimeZone.php
new file mode 100644 (file)
index 0000000..bdad4cf
--- /dev/null
@@ -0,0 +1,268 @@
+<?php
+require_once 'Pman.php';
+
+class Pman_Core_TimeZone extends Pman
+{
+    function getAuth()
+    {
+        parent::getAuth();
+        
+        if (!$this->getAuthUser()) {  
+            $this->jerr("Not authenticated", array('authFailure' => true));
+        }
+        
+        return true;
+    }
+
+    function get($base, $opts=array())
+    {
+        $this->lang = !empty($_REQUEST['lang']) && in_array($_REQUEST['lang'], array('en', 'zh_CN')) ? $_REQUEST['lang'] : 'en';
+        self::getTimezones($this->lang);
+
+        $data = array();
+
+        foreach(self::$timezones as $tz => $o) {
+            if(!empty($_REQUEST['region']) && $_REQUEST['region'] != $o['region']) {
+                continue;
+            }
+
+            if(
+                !empty($_REQUEST['query']['area_start']) 
+                && 
+                substr(strtolower($o['area']), 0, strlen($_REQUEST['query']['area_start'])) != strtolower($_REQUEST['query']['area_start'])
+            ){
+                continue;
+            }
+            $data[] = array(
+                'region' => $o['region'],
+                'area' => $o['area'],
+                'displayRegion' => $o['displayRegion'],
+                'displayArea' => $o['displayArea']
+            );
+        }
+
+        echo json_encode(array(
+            'data' => $data,
+            'metaData' => array(
+                'root' => 'data',
+                'successProperty' => 'success',
+                'totalProperty' => 'total',
+                'fields' => array(
+                    'region',
+                    'area',
+                    'displayRegion',
+                    'displayArea'
+                )
+            ),
+            'success' => true,
+            'total' => count($data),
+            
+        ));
+        exit;
+    }
+
+    function post($base) {
+        die('Invalid post');
+    }
+
+    static $timezones = array();
+
+    static function getTimezones($lang)
+    {
+        if(!empty(self::$timezones)) {
+            return self::$timezones;
+        }
+         $ce = DB_DataObject::factory('core_enum');
+        $ce->query("
+            SELECT
+                *, TIME_FORMAT(TIMEDIFF(NOW(), CONVERT_TZ(NOW(), Name, 'UTC')), '%H:%i') as timeOffset
+            FROM
+                mysql.time_zone_name
+            WHERE
+                Name LIKE '%/%'
+                AND
+                Name NOT LIKE '%/%/%'
+                AND
+                Name NOT LIKE 'right%'
+                AND
+                Name NOT LIKE 'posix%'
+                AND
+                Name NOT LIKE 'Etc%'
+            ORDER BY
+                SUBSTRING_INDEX(Name, '/', 1) ASC,
+                timeoffset ASC,
+                Name ASC
+        ");
+
+        $regions = DB_DataObject::factory('core_enum');
+        $regions->setFrom(array(
+            'etype' => 'Timezone.Region',
+            'active' => 1
+        ));
+        $regionIds = $regions->fetchAll('display_name', 'id');
+
+        $areas = DB_DataObject::factory('core_enum');
+        $areas->setFrom(array(
+            'etype' => 'Timezone.Area',
+            'active' => 1
+        ));
+        $areaIds = $areas->fetchAll('display_name', 'id');
+
+
+        $ct = DB_DataObject::factory('core_templatestr');
+        $ct->lang = $lang;
+        $ct->on_table = 'core_enum';
+        $ct->active = 1;
+        $translations = array();
+        foreach($ct->fetchAll() as $t) {
+            if(empty($t->txt)) {
+                continue;
+            }
+            $translations[$t->on_id][$t->on_col] = $t->txt;
+        }
+
+        while($ce->fetch()) {
+            // ignroe timezone such as 'CET' and 'America/Argentina/Buenos_Aires'
+           
+
+            $ar = explode('/', $ce->Name);
+            // ignore timezone such as 'Etc/GMT+8'
+
+            $region = $displayRegion = $ar[0];
+
+            if(!empty($translations[$regionIds[$region]]['display_name'])) {
+                $displayRegion = $translations[$regionIds[$region]]['display_name'];
+            }
+
+            $area =  $ar[1];
+            $displayArea = str_replace('_', ' ', $area);
+
+            if(!empty($translations[$areaIds[$displayArea]]['display_name'])) {
+                $displayArea = $translations[$areaIds[$displayArea]]['display_name'];
+            }
+
+            $timeOffset = ((substr($ce->timeOffset, 0, 1) == '-') ? '' : '+') . $ce->timeOffset;
+            $displayOffset = '(GMT ' . $timeOffset . ')';
+
+            self::$timezones[$ce->Name] = array(
+                'region' => $region,
+                'area' => $area,
+                'displayName' => $ar[0] . '/' . $displayArea . ' ' . $displayOffset,
+                'displayRegion' => $displayRegion,
+                'displayArea' => $displayArea . ' ' . $displayOffset
+            );
+        }
+
+        return self::$timezones;
+    }
+
+    static function isValidTimeZone($tz) {
+        try {
+            new DateTimeZone($tz);
+        }
+        catch (Exception $e) {
+            return false;
+        }
+
+        return true;
+    }
+
+    static function toRegion($tz)
+    {
+        if(!self::isValidTimeZone($tz)) {
+            return '';
+        }
+        
+        return explode('/', $tz)[0];
+    }
+
+    static function toArea($tz)
+    {
+        if(!self::isValidTimeZone($tz)) {
+            return '';
+        }
+
+        return explode('/', $tz)[1];
+    }
+    
+    static function toTimeOffset($dt, $tz)
+    {
+        if(!self::isValidTimeZone($tz)) {
+            return '';
+        }
+
+        if($dt == '0000-00-00 00:00:00' || $dt == '') {
+            $dt = 'NOW';
+        }
+
+        $date = new DateTime($dt, new DateTimeZone($tz));
+        return $date->format('P');
+    }
+
+    static function toDisplayRegion($lang, $tz) 
+    {
+        $region = explode('/', $tz)[0];
+
+        $ce = DB_DataObject::factory('core_enum');
+        $ce->setFrom(array(
+            'etype' => 'Timezone.Region',
+            'active' => 1,
+            'name' => $region,
+            'display_name' => $region
+        ));
+        if(!$ce->find(true)) {
+            return $region;
+        }
+
+        $ct = DB_DataObject::factory('core_templatestr');
+        $ct->setFrom(array(
+            'lang' => $lang,
+            'on_table' => 'core_enum',
+            'on_id' => $ce->id,
+            'on_col' => 'display_name',
+            'active' => 1
+        ));
+        if(!$ct->find(true) || empty($ct->txt)) {
+            return $region;
+        }
+        return $ct->txt;
+    }
+
+    static function toDisplayArea($lang, $dt, $tz)
+    {
+        $displayArea = str_replace('_', ' ', self::toArea($tz));
+        $displayOffset = '(GMT ' . self::toTimeOffset($dt,$tz) . ')';
+
+        $ce = DB_DataObject::factory('core_enum');
+        $ce->setFrom(array(
+            'etype' => 'Timezone.Area',
+            'active' => 1,
+            'name' => $displayArea,
+            'display_name' => $displayArea
+        ));
+
+        if(!$ce->find(true)) {
+            return $displayArea . ' ' . $displayOffset;
+        }
+
+        $ct = DB_DataObject::factory('core_templatestr');
+        $ct->setFrom(array(
+            'lang' => $lang,
+            'on_table' => 'core_enum',
+            'on_id' => $ce->id,
+            'on_col' => 'display_name',
+            'active' => 1
+        ));
+        if(!$ct->find(true) || empty($ct->txt)) {
+            return $displayArea . ' ' . $displayOffset;
+        }
+
+        return $ct->txt . ' ' . $displayOffset;
+
+    }
+
+    static function toDisplayName($lang, $dt, $tz)
+    {
+        return self::toDisplayRegion($lang, $tz) . '/' . self::toDisplayArea($lang, $dt, $tz);
+    }
+}
\ No newline at end of file
index f2f1663..6973f56 100644 (file)
@@ -154,14 +154,14 @@ class Pman_Core_UpdateDatabase extends Pman
             'active' => 1,
             'description' => '9.1 Management System Password Reset',
             'template_dir' => '/Pman/Core/templates/mail/'
-
-            
         )
     );
     
     var $required_extensions = array(
         'curl',
-        'gd'
+        'gd',
+        'mbstring'
     );
     
     function getAuth() {
@@ -176,7 +176,7 @@ class Pman_Core_UpdateDatabase extends Pman
         parent::getAuth(); // load company!
         $au = $this->getAuthUser();
         if (!$au || $au->company()->comptype != 'OWNER') {
-            $this->jerr("Not authenticated", array('authFailure' => true));
+            $this->jerror("LOGIN-NOAUTH", "Not authenticated", array('authFailure' => true));
         }
         $this->authUser = $au;
         return true;
@@ -613,7 +613,10 @@ class Pman_Core_UpdateDatabase extends Pman
                 $extra[]  =   "create sequence {$tbl}_seq;";
               
             }
-            
+            if ($tbl && preg_match('#engine=\S+#i',  $l, $m)) {
+                $l = preg_replace('#engine=\S+#i', '', $l);
+                
+            }
             if (preg_match('#alter\s+table\s+(\`[a-z0-9_]+\`)#i',  $l, $m)){
                 $l = preg_replace('#alter\s+table\s+(\`[a-z0-9_]+\`)#i', "ALTER TABLE {$tbl}", $l);
             }
@@ -767,6 +770,7 @@ class Pman_Core_UpdateDatabase extends Pman
             if(!method_exists($x, 'updateData')){
                 continue;
             };
+            $x->rootDir =  $this->rootDir;
             echo "$module\n";
             $x->updateData();
         }
@@ -849,21 +853,25 @@ class Pman_Core_UpdateDatabase extends Pman
             array(
                 'name' => 'bcc-email', // group who are bcc'ed on all requests.
                 'type' => 0, // system
+                'is_system' => 1,
                 'display_name' => 'Standard BCC Group'
             ),
             array(
                 'name' => 'system-email-from',
                 'type' => 0, // system
+                'is_system' => 1,
                 'display_name' => 'Standard System Email From Group'
             ),
             array(
                 'name' => 'core-person-signup-bcc',
                 'type' => 0, // system
+                'is_system' => 1,
                 'display_name' => 'Standard Person Signup BCC Group'
             ),
             array(
                 'name' => 'Empty Group', // use for no bcc emails.
                 'type' => 0,
+                'is_system' => 1,
                 'display_name' => 'Standard Empty Group'
             )
 
@@ -921,10 +929,8 @@ class Pman_Core_UpdateDatabase extends Pman
         }
         foreach ($this->emailTemplates as $k => $mail) {
             
-            $mail_dir = "{$this->rootDir}{$mail['template_dir']}";
-
             $this->initEmails(
-                $mail_dir,
+                !empty($mail['template_dir']) ? "{$this->rootDir}{$mail['template_dir']}" : '',
                 array($k => $mail),
                 false
             );
@@ -948,11 +954,11 @@ class Pman_Core_UpdateDatabase extends Pman
                 
                 $g = DB_DataObject::Factory('core_group')->lookup('name',$data['bcc_group']);
                 
-                if (empty($g->id)) {
+                if (empty($g->id)) { // Admin group as bcc will not have any member at initialization.
                     $this->jerr("bcc_group {$data['bcc_group']} does not exist when importing template $name");
                 }
                 
-                if (!$g->members('email') && $g->name != 'Empty Group') {
+                if (!$g->members('email') && $g->name != 'Empty Group' &&  $g->name != 'Administrators') {
                     $this->jerr("bcc_group {$data['bcc_group']} does not have any members");
                 }
                 
@@ -1024,9 +1030,14 @@ class Pman_Core_UpdateDatabase extends Pman
             
             $opts = array(
                 'update' => 1,
-                'file' => $templateDir. $name .'.html'
             );
-            
+            if (!empty($templateDir)) {
+                $opts['file'] = $templateDir. $name .'.html';
+            }
+            if (!empty($data['raw_content'])) {
+                $opts['raw_content'] = $data['raw_content'];
+                $opts['name'] = $name;
+            }
             if (!empty($data['master'])) {
                 $opts['master'] = $templateDir . $master .'.html';
             }
@@ -1255,17 +1266,16 @@ class Pman_Core_UpdateDatabase extends Pman
             'gifsicle', // used for gif conversions
         );
          
-         
-         
+          
         // these are prefered - but may have complicated depenacies
         $pref = $pref !== false ? $pref :  array(
             'abiword',
-            'faad',
+            //'faad',
             'ffmpeg',
             'html2text', // not availabe in debian squeeze
             'pdftocairo',  //poppler-utils - not available in debian squeeze.
 
-            'lame',
+            //'lame',
             'ssconvert',
             'unoconv',
             'wkhtmltopdf',
index 83b9634..0bdd508 100644 (file)
@@ -167,7 +167,7 @@ class Pman_Core_UpdateDatabase_MysqlLinks {
         }
         
         $q = DB_DAtaObject::factory('core_enum');
-        $q->query("ALTER TABLE $tbl COMMENT = '{$q->escape($fkstr)}'");
+        $q->query("ALTER TABLE `$tbl` COMMENT = '{$q->escape($fkstr)}'");
         
         
         
index 7616fbf..a0b144d 100644 (file)
@@ -7,7 +7,7 @@ class Pman_Core_UploadProgress extends Pman
         
         $au = $this->getAuthUser();
         if (!$au) {
-             $this->jerr("Not authenticated", array('authFailure' => true));
+             $this->jerror("LOGIN-NOAUTH", "Not authenticated", array('authFailure' => true));
         }
         $this->authUser = $au;
         // check that it's a supplier!!!! 
index 81de637..7d714f4 100644 (file)
@@ -10,7 +10,7 @@ CREATE TRIGGER core_notify_trigger_after_delete AFTER DELETE on core_notify
     FOR EACH ROW
         BEGIN
             -- I think we changed it so that sent is not null, deafult '0000....'
-            if old.sent is not null AND old.sent > '0001-01-01 00:00:00' THEN 
+            if old.sent is not null AND old.sent > '1500-01-01 00:00:00' THEN 
                 UPDATE `Error: Can not delete core_notify after it is sent` SET x = 1;
             END IF;
         END;
index 4297371..07bdc83 100644 (file)
@@ -10,7 +10,7 @@ CREATE TRIGGER core_notify_trigger_after_update
         FOR EACH ROW
         BEGIN
             -- make sure that act_start does not get modified if sent is set.
-            IF (OLD.sent IS NOT NULL AND  OLD.sent != '0000-00-00 00:00:00')
+            IF (OLD.sent IS NOT NULL AND  OLD.sent > '1500-01-01 00:00:00')
                 AND  ( NEW.act_start != OLD.act_start  OR NEW.act_when != OLD.act_when )  THEN
                   UPDATE `Error: Can not update core_notify action dates  after its sent` SET x = 1;
             END IF;
index 75bc7b4..6498b67 100644 (file)
@@ -14,13 +14,19 @@ RETURNS TEXT NOT DETERMINISTIC READS SQL DATA
 
         DECLARE v_ret TEXT;
         DECLARE v_id INT(11);
+        DECLARE v_src_id INT(11);
+               DECLARE s_id INT(11);
+
+        IF LENGTH(in_default) < 1 THEN
+            RETURN in_default;
+        END IF;
         
         SET v_id = 0;
         
         SELECT
-            id , txt
+            id , txt, src_id
             INTO
-            v_id, v_ret
+            v_id, v_ret, v_src_id
         FROM
             core_templatestr
         WHERE
@@ -38,6 +44,21 @@ RETURNS TEXT NOT DETERMINISTIC READS SQL DATA
         IF v_id < 1 OR LENGTH(v_ret) < 1 THEN
             RETURN in_default;
         END IF;
+
+               SELECT 
+                       id
+                       INTO
+                       s_id
+               FROM
+                       core_templatestr
+               WHERE
+                       id = v_src_id
+                       AND
+                       mdsum = MD5(in_default);
+               
+               IF s_id IS NULL THEN
+                       RETURN in_default;
+               END IF;
         
         RETURN v_ret;
 
index 23c287c..b2106c8 100644 (file)
@@ -1,6 +1,8 @@
 
 DROP FUNCTION IF EXISTS i18n_translate;
+
 DELIMITER $$
+
 CREATE FUNCTION i18n_translate(in_ltype  varchar(1) , in_lkey varchar(8), in_inlang varchar(8)) 
         RETURNS VARCHAR(64) DETERMINISTIC
     BEGIN
@@ -11,4 +13,5 @@ CREATE FUNCTION i18n_translate(in_ltype  varchar(1) , in_lkey varchar(8), in_inl
         RETURN ret;
         
     END $$
-DELIMITER ;
\ No newline at end of file
+    
+DELIMITER ; 
index e40f77f..e577390 100644 (file)
@@ -4,7 +4,7 @@ CREATE TABLE  i18n (
   id int(11)  NOT NULL AUTO_INCREMENT,
   PRIMARY KEY (id)
 
-) ENGINE=InnoDB;
+);
 
 ALTER TABLE  i18n ADD COLUMN   ltype varchar(1)  NOT NULL DEFAULT '';
 ALTER TABLE  i18n ADD COLUMN   lkey varchar(8)  NOT NULL DEFAULT '';
diff --git a/sql/core_column_settings.sql b/sql/core_column_settings.sql
new file mode 100644 (file)
index 0000000..e69de29
index 60e7f51..1df8d9f 100644 (file)
@@ -4,8 +4,11 @@ CREATE TABLE core_company (
 );
 
 
-ALTER TABLE core_company ADD COLUMN    code varchar(32)  NOT NULL DEFAULT '';;
-ALTER TABLE core_company ADD COLUMN    name varchar(128)  default NULL ;
+ALTER TABLE core_company CHANGE COLUMN  code  code varchar(128)  NOT NULL DEFAULT '';
+ALTER TABLE core_company ADD COLUMN    code varchar(128)  NOT NULL DEFAULT '';
+ALTER TABLE core_company CHANGE COLUMN    name name varchar(254)  default NULL ;
+
+ALTER TABLE core_company ADD COLUMN    name varchar(254)  default NULL ;
 ALTER TABLE core_company ADD COLUMN    remarks text ;
 ALTER TABLE core_company ADD COLUMN    owner_id int(11) NOT NULL DEFAULT 0 ;
 ALTER TABLE core_company ADD COLUMN    address text ;
@@ -31,25 +34,35 @@ ALTER TABLE core_company ADD COLUMN    comptype varchar(32)  NOT NULL DEFAULT ''
 -- not sure if this needs to change.. << there is code in core/update that fills this in??
 ALTER TABLE core_company ADD COLUMN    comptype_id INT(11) DEFAULT 0;
 
+ALTER TABLE core_company ADD COLUMN  parent_id INT NOT NULL DEFAULT 0;
+
 
 ALTER TABLE core_company CHANGE COLUMN isOwner isOwner int(11);
+
 ALTER TABLE core_company CHANGE COLUMN comptype comptype  VARCHAR(32) DEFAULT '';
+
 -- postres
 -- ALTER TABLE core_company ALTER isOwner TYPE int(11);
 ALTER TABLE core_company ALTER owner_id SET DEFAULT 0;
 ALTER TABLE core_company ALTER url SET DEFAULT '';
 
+
 ALTER TABLE core_company ADD COLUMN    address1 text ;
 ALTER TABLE core_company ADD COLUMN    address2 text ;
 ALTER TABLE core_company ADD COLUMN    address3 text ;
 ALTER TABLE core_company ADD COLUMN is_system INT(2) NOT NULL DEFAULT 0;-- #2028
 
-ALTER TABLE core_company ADD INDEX name_lookup (name);
 
 ALTER TABLE core_company ADD COLUMN deleted_by INT(11)  NOT NULL DEFAULT 0;
+alter table core_company CHANGE COLUMN  deleted_dt deleted_dt datetime NOT NULL DEFAULT '1000-01-01 00:00:00';
+ALTER TABLE core_company ADD COLUMN deleted_dt DATETIME  NOT NULL DEFAULT '1000-00-00'; 
 
-ALTER TABLE core_company ADD COLUMN deleted_dt DATETIME  NOT NULL DEFAULT '0000-00-00'; 
+-- indexs
 
+
+ALTER TABLE core_company ADD INDEX name_lookup (name);
 ALTER TABLE core_company ADD INDEX lookup_owner_id (owner_id);
 
 -- our new code should have this fixed now..
index b7e582f..fe30275 100644 (file)
@@ -34,5 +34,7 @@ ALTER TABLE core_email ADD COLUMN description VARCHAR(254) NOT NULL DEFAULT '';
 
 ALTER TABLE core_email ADD INDEX lookup_owner_id (owner_id);
 
+ALTER TABLE core_email ADD COLUMN language varchar(5)  NOT NULL DEFAULT 'en';
+
 UPDATE core_email SET updated_dt = NOW() where updated_dt IS NULL;
 
index 05e0087..57603e3 100644 (file)
@@ -14,4 +14,7 @@ ALTER TABLE core_group ADD COLUMN type  int(11)  NOT NULL DEFAULT 0;
 ALTER TABLE core_group ADD COLUMN leader int(11)  NOT NULL default 0;
 ALTER TABLE core_group ADD COLUMN is_system int(2) NOT NULL default 0;
 
+UPDATE core_group SET  display_name = name WHERE display_name = '';
+UPDATE core_group SET  is_system = 1 WHERE name = 'Administrators';
+
 ALTER TABLE core_group ADD INDEX lookup_leader (leader);
\ No newline at end of file
index f0449bb..4880851 100644 (file)
@@ -7,3 +7,4 @@ ALTER TABLE core_holiday ADD COLUMN holiday_date DATE NOT NULL DEFAULT '0000-00-
 ALTER TABLE core_holiday ADD COLUMN country VARCHAR(4) NOT NULL DEFAULT '';
 
 
+alter table core_holiday add index lookup (holiday_date, country);
index 6f79c56..9751443 100644 (file)
@@ -28,6 +28,8 @@ ALTER TABLE core_notify ADD COLUMN person_table VARCHAR(256) NOT NULL DEFAULT ''
 
 -- ?? why added???  - probably need to document this..
 ALTER TABLE core_notify ADD COLUMN domain_id INT(11)  NOT NULL  DEFAULT 0;
+ALTER TABLE core_notify ADD COLUMN server_id INT(11) NOT NULL DEFAULT -1;
+
 
 ALTER TABLE core_notify ADD   INDEX lookup(act_when, msgid);
 
@@ -41,6 +43,8 @@ ALTER TABLE core_notify add   index lookup_d (person_id, msgid, ontable);
 ALTER TABLE core_notify ADD   INDEX lookup_e (onid, ontable, person_id, act_when);
 ALTER TABLE core_notify ADD   INDEX lookup_f (to_email);
 alter table core_notify add index lookup_g(sent, act_start, act_when);
+alter table core_notify add   INDEX lookup_h (sent, event_id, server_id, msgid, ontable);
+
 
 ALTER TABLE core_notify ADD INDEX lookup_person_id (person_id);
 ALTER TABLE core_notify ADD INDEX lookup_trigger_person_id (trigger_person_id);
diff --git a/sql/core_notify_blacklist.sql b/sql/core_notify_blacklist.sql
new file mode 100644 (file)
index 0000000..e2aa7f5
--- /dev/null
@@ -0,0 +1,11 @@
+CREATE  TABLE core_notify_blacklist (
+    id INT(11) NOT NULL AUTO_INCREMENT ,
+    server_id INT(11) NOT NULL DEFAULT 0,
+    domain_id INT(11) NOT NULL DEFAULT 0,
+    added_dt DATETIME NOT NULL DEFAULT '1000-01-01 00:00:00',
+    error_str TEXT NOT NULL DEFAULT '',
+    
+    PRIMARY KEY (id)
+) ENGINE=InnoDB;;
+
+ALTER TABLE core_notify_blacklist ADD INDEX lookup (server_id,domain_id);
diff --git a/sql/core_notify_sender.sql b/sql/core_notify_sender.sql
new file mode 100644 (file)
index 0000000..3e3efd5
--- /dev/null
@@ -0,0 +1,10 @@
+CREATE  TABLE core_notify_sender (
+    id INT(11) NOT NULL AUTO_INCREMENT ,
+    email VARCHAR(254) NOT NULL DEFAULT '',
+    is_active INT(4) NOT NULL DEFAULT 0,
+    poolname VARCHAR(128) NOT NULL DEFAULT '',
+    priority INT NOT NULL DEFAULT 0,
+    PRIMARY KEY (id)
+) ENGINE=InnoDB;
+
+ALTER TABLE core_notify_sender ADD INDEX lookup (email,poolname,is_active);
diff --git a/sql/core_notify_sender_blacklist.sql b/sql/core_notify_sender_blacklist.sql
new file mode 100644 (file)
index 0000000..e191f5f
--- /dev/null
@@ -0,0 +1,11 @@
+CREATE  TABLE core_notify_sender_blacklist (
+    id INT(11) NOT NULL AUTO_INCREMENT ,
+    domain_id INT(11) NOT NULL DEFAULT 0,
+    sender_id INT(11) NOT NULL DEFAULT 0,
+    added_dt DATETIME NOT NULL DEFAULT '1000-01-01 00:00:00',
+    error_str TEXT NOT NULL DEFAULT '',
+    
+    PRIMARY KEY (id)
+) ENGINE=InnoDB; 
+
+ALTER TABLE core_notify_sender_blacklist ADD INDEX lookup (sender_id,domain_id);
diff --git a/sql/core_notify_server.sql b/sql/core_notify_server.sql
new file mode 100644 (file)
index 0000000..a7a8daf
--- /dev/null
@@ -0,0 +1,12 @@
+CREATE  TABLE core_notify_server (
+    id INT(11) NOT NULL AUTO_INCREMENT ,
+    hostname VARCHAR(128) NOT NULL DEFAULT '',
+    helo VARCHAR(128) NOT NULL DEFAULT '',
+    poolname VARCHAR(128) NOT NULL DEFAULT '',
+    is_active INT(4) NOT NULL DEFAULT 0,
+    last_send DATETIME NOT NULL DEFAULT '1000-01-01 00:00:00',
+    
+    PRIMARY KEY (id)
+) ENGINE=InnoDB;;
+
+ALTER TABLE core_notify_server ADD INDEX lookup (hostname,poolname,is_active);
index 2044aad..00dee63 100644 (file)
@@ -14,7 +14,7 @@ ALTER TABLE core_person ADD COLUMN   lastname_alt varchar(128) NOT NULL DEFAULT
 
 -- chose title is like a nickname 
 
-ALTER TABLE core_person ADD COLUMN   chosen_title TEXT NOT NULL; 
+ALTER TABLE core_person ADD COLUMN   chosen_title TEXT NOT NULL DEFAULT ''
 
 
 ALTER TABLE core_person ADD COLUMN   role varchar(254)  NOT NULL DEFAULT '';
@@ -55,7 +55,7 @@ ALTER TABLE core_person ADD COLUMN   no_reset_sent int(11) default '0';
 
 
 ALTER TABLE core_person ADD COLUMN   deleted_by INT(11) NOT NULL default 0 ;
-ALTER TABLE core_person ADD COLUMN   deleted_dt DATETIME ;
+ALTER TABLE core_person ADD COLUMN   deleted_dt DATETIME NOT null default '1000-01-01 00:00:00';
 
 
 -- social
@@ -64,9 +64,9 @@ ALTER TABLE core_person ADD COLUMN   url_blog VARCHAR(256) NULL ;
 ALTER TABLE core_person ADD COLUMN   url_twitter VARCHAR(256) NULL ;
 ALTER TABLE core_person ADD COLUMN   linkedin_id VARCHAR(256) NULL ;
 ALTER TABLE core_person ADD COLUMN   url_linkedin VARCHAR(256) NULL ;
-ALTER TABLE core_person ADD COLUMN url_google_plus TEXT NOT NULL
-ALTER TABLE core_person ADD COLUMN url_blog2 TEXT NOT NULL
-ALTER TABLE core_person ADD COLUMN url_blog3 TEXT NOT NULL
+ALTER TABLE core_person ADD COLUMN url_google_plus TEXT NOT NULL DEFAULT '';
+ALTER TABLE core_person ADD COLUMN url_blog2 TEXT NOT NULL  DEFAULT '';
+ALTER TABLE core_person ADD COLUMN url_blog3 TEXT NOT NULL  DEFAULT '';
 
 
 
index b4a7417..8c9ef07 100644 (file)
@@ -16,9 +16,14 @@ ALTER TABLE  core_project  ADD COLUMN   type varchar(1)  NOT NULL default 'P';
 ALTER TABLE  core_project  ADD COLUMN   client_id int(11) NOT NULL default '0';
 ALTER TABLE  core_project  ADD COLUMN   team_id int(11) NOT NULL default '0';
 ALTER TABLE  core_project  ADD COLUMN file_location varchar(254)    NOT NULL default '';
-ALTER TABLE  core_project  ADD COLUMN open_date date default NULL;
-ALTER TABLE  core_project  ADD COLUMN open_by int(11) NOT NULL default '0';
-ALTER TABLE  core_project  ADD COLUMN updated_dt DATETIME NOT NULL;
+ALTER TABLE  core_project  ADD COLUMN open_date date NOT NULL DEFAULT '1000-01-01';
+ALTER TABLE  core_project  ADD COLUMN open_by int(11) NOT NULL default 0;
+
+ALTER TABLE  core_project  ADD COLUMN updated_dt DATETIME NOT NULL DEFAULT '1000-01-01 00:00:00';
+ALTER TABLE  core_project  ADD COLUMN deleted_by INT NOT NULL DEFAULT 0;
+ALTER TABLE  core_project  ADD COLUMN deleted_dt DATETIME NOT NULL DEFAULT '1000-01-01 00:00:00';
+
+
 
 -- these should be removed, as they are code specific..
 ALTER TABLE core_project ADD COLUMN countries varchar(128)  NOT NULL DEFAULT '';
@@ -32,4 +37,4 @@ ALTER TABLE core_project ADD INDEX lookup_agency_id (agency_id);
 
 ALTER TABLE core_project ADD INDEX lookup_open_by (open_by);
 ALTER TABLE core_project ADD INDEX lookup_owner_id (owner_id);
\ No newline at end of file
+
diff --git a/sql/core_project_group.sql b/sql/core_project_group.sql
new file mode 100644 (file)
index 0000000..e52f5f5
--- /dev/null
@@ -0,0 +1,9 @@
+
+CREATE TABLE core_project_group (
+  id int(11) NOT NULL auto_increment,
+  PRIMARY KEY  (id)
+  
+);
+
+ALTER TABLE  core_project_group  ADD COLUMN   group_id int(11) default NULL default 0;
+ALTER TABLE  core_project_group  ADD COLUMN   project_id int(11) default NULL default 0;
index 15bf3c3..5bc8cd8 100644 (file)
@@ -23,3 +23,4 @@ ALTER TABLE core_templatestr ADD COLUMN on_col VARCHAR(64) DEFAULT '';
 
 ALTER TABLE core_templatestr ADD INDEX lookup_a(active, lang, on_table, on_id, on_col);
 
+alter table core_templatestr add index lookup_b(src_id, lang, mdsum, template_id);
index 7998e17..b81c281 100644 (file)
@@ -1,6 +1,6 @@
 
 CREATE TABLE Events (
-  id int(11) NOT NULL auto_increment,
+  id bigint NOT NULL auto_increment,
   
   PRIMARY KEY  (id)
 ) ;
@@ -36,6 +36,11 @@ ALTER TABLE Events CHANGE COLUMN Container on_table VARCHAR(64);
 -- make action larger..
 ALTER TABLE Events CHANGE COLUMN action action varchar(64)  default NULL;
 
+-- id needs more space..
+ALTER TABLE Events change COLUMN id id bigint  NOT NULL AUTO_INCREMENT;
+
+
+
 ALTER TABLE Events ADD INDEX lookupf (on_id, action, on_table, person_id, event_when, person_table);
 
 ALTER TABLE Events ADD INDEX lookup_person_id (person_id);
index a9c54b5..3c355b1 100644 (file)
@@ -18,10 +18,11 @@ ALTER TABLE Images    ADD COLUMN   parent_image_id int(11) NOT NULL default '0';
 ALTER TABLE  Images ADD COLUMN created datetime ;
 ALTER TABLE  Images ADD COLUMN imgtype VARCHAR(32) DEFAULT '' NOT NULL;
 ALTER TABLE  Images ADD COLUMN linkurl VARCHAR(254) DEFAULT '' NOT NULL;
-ALTER TABLE  Images ADD COLUMN descript TEXT NOT NULL;
+ALTER TABLE  Images ADD COLUMN descript TEXT DEFAULT '' NOT NULL;
 ALTER TABLE  Images ADD COLUMN title VARCHAR(128) DEFAULT '' NOT NULL;
 
 ALTER TABLE Images    CHANGE COLUMN   mimetype mimetype  varchar(128) NOT NULL default '';
+ALTER TABLE Images    CHANGE COLUMN   descript descript  TEXT NOT NULL default '';
 
 -- postgres (need better way to support this..)
 -- ALTER TABLE Images    ALTER COLUMN   mimetype  TYPE  varchar(128) ;
index 757c105..1dcd636 100644 (file)
@@ -1,7 +1,11 @@
-<code>From : "{msg.from_name}" &lt;{msg.from_email}&gt;</code>
-<br/>
-<code>Subject : {msg.subject}</code>
-<br/>
+<div class="undoreset" style="margin:10px">
+
+<code><B>From:</B> "{msg.from_name}" &lt;{msg.from_email}&gt;<br/>
+<B>Subject:</B> {msg.subject}<br/>
+<B>To:</B> {msg.rcpts}<br/>
+</code>
 {if:!showHtml}
 <br>
 <code>{msg.plaintext:b}</code>
@@ -9,4 +13,4 @@
 <br/>
 {msg.bodytext:h}
 {end:}
-    
+</div>
index 0009f8c..e65df15 100644 (file)
@@ -15,7 +15,8 @@
         
         <link rel="stylesheet" type="text/css" href="{rootURL}/roojs1/css/roojs.css" />  
         <link rel="stylesheet" type="text/css" href="{rootURL}/roojs1/css/xtheme-slate.css" />  
+        <link rel="stylesheet" type="text/css" href="{rootURL}/roojs1/fonts/font-awesome.css" />
+
         {outputCSSIncludes()}
       
      </head>
         <div id="loading">
             <div class="loading-indicator" id="loading-text">&#160;Loading...(This may take a few seconds)</div>
         </div>
-       
         
-{if:bootLoader.Pman[roo_debug]}                  
-        <script type="text/javascript" src="{rootURL}/roojs1/roojs-debug.js?ts={version}"></script>
+   
+   {if:isDev}                  
+     <script type="text/javascript" src="{rootURL}/roojs1/roojs-debug.js?ts={version}"></script>
         <script type="text/javascript" src="{rootURL}/roojs1/roojs-calendar-debug.js?ts={version}"></script>
-        <!-- <script type="text/javascript" src="{rootURL}/roojs1/ux/Iscroll.js"></script>  -->
-         
-{else:}                  
+    {else:}
+
         <script type="text/javascript" src="{rootURL}/roojs1/roojs-all.js?ts={version}"></script>
-                 
-{end:}                  
+    {end:}              
+
         <flexy:toJSON 
             baseURL="baseURL" 
             rootURL="rootURL" 
index 732db5b..b1bfde4 100644 (file)
@@ -2,7 +2,7 @@
 //<script type="text/Javascript">
 
 
-Ext.form.SecurePass = function (config) {
+Roo.form.SecurePass = function (config) {
     // these go here, so the translation tool can replace them..
     this.errors = {
         PwdEmpty: "Please type a password, and then retype it to confirm.",
@@ -16,10 +16,10 @@ Ext.form.SecurePass = function (config) {
     },
     this.meterLabel = "Password strength:";
     this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
-    Ext.form.SecurePass.superclass.constructor.call(this, config);
+    Roo.form.SecurePass.superclass.constructor.call(this, config);
 }
 
-Ext.extend(Ext.form.SecurePass, Ext.form.TextField, {
+Roo.extend(Roo.form.SecurePass, Roo.form.TextField, {
     /**
      * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
      * {
@@ -65,7 +65,7 @@ Ext.extend(Ext.form.SecurePass, Ext.form.TextField, {
     insecure: false,
     // private
     initEvents: function () {
-        Ext.form.SecurePass.superclass.initEvents.call(this);
+        Roo.form.SecurePass.superclass.initEvents.call(this);
 
         if (this.el.is('input[type=password]') && Roo.isSafari) {
             this.el.on('keydown', this.SafariOnKeyDown, this);
@@ -75,7 +75,7 @@ Ext.extend(Ext.form.SecurePass, Ext.form.TextField, {
     },
     // private
     onRender: function (ct, position) {
-        Ext.form.SecurePass.superclass.onRender.call(this, ct, position);
+        Roo.form.SecurePass.superclass.onRender.call(this, ct, position);
         this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
         this.trigger = this.wrap.createChild({tag: 'div', cls: 'roo-strength-meter ' + this.triggerClass});
 
@@ -122,7 +122,7 @@ Ext.extend(Ext.form.SecurePass, Ext.form.TextField, {
         if (this.wrap) {
             this.wrap.remove();
         }
-        Ext.form.TriggerField.superclass.onDestroy.call(this);
+        Roo.form.TriggerField.superclass.onDestroy.call(this);
     },
     // private
     checkStrength: function () {
@@ -153,7 +153,7 @@ Ext.extend(Ext.form.SecurePass, Ext.form.TextField, {
         this._lastPwd = pwd;
     },
     reset: function () {
-        Ext.form.SecurePass.superclass.reset.call(this);
+        Roo.form.SecurePass.superclass.reset.call(this);
         this._lastPwd = '';
         var pm = this.trigger.child('div/div/div').dom;
         pm.style.width = 0;
@@ -162,7 +162,7 @@ Ext.extend(Ext.form.SecurePass, Ext.form.TextField, {
     // private
     validateValue: function (value) {
         
-        if (!Ext.form.TextField.superclass.validateValue.call(this, value)) {
+        if (!Roo.form.TextField.superclass.validateValue.call(this, value)) {
             return false;
         }
         if (value.length == 0) {