]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/SugarFolders/SugarFolders.php
Release 6.4.0
[Github/sugarcrm.git] / include / SugarFolders / SugarFolders.php
1 <?php
2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4  * SugarCRM Community Edition is a customer relationship management program developed by
5  * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc.
6  * 
7  * This program is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU Affero General Public License version 3 as published by the
9  * Free Software Foundation with the addition of the following permission added
10  * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11  * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12  * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
13  * 
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
17  * details.
18  * 
19  * You should have received a copy of the GNU Affero General Public License along with
20  * this program; if not, see http://www.gnu.org/licenses or write to the Free
21  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22  * 02110-1301 USA.
23  * 
24  * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25  * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
26  * 
27  * The interactive user interfaces in modified source and object code versions
28  * of this program must display Appropriate Legal Notices, as required under
29  * Section 5 of the GNU Affero General Public License version 3.
30  * 
31  * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32  * these Appropriate Legal Notices must retain the display of the "Powered by
33  * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34  * technical reasons, the Appropriate Legal Notices must display the words
35  * "Powered by SugarCRM".
36  ********************************************************************************/
37
38 /*********************************************************************************
39
40  * Description:
41  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. All Rights
42  * Reserved. Contributor(s): ______________________________________..
43  *********************************************************************************/
44
45 require_once("include/ytree/Tree.php");
46 require_once("include/ytree/ExtNode.php");
47
48 /**
49  * Polymorphic buckets - place any item in a folder
50  */
51 class SugarFolder {
52
53         // public attributes
54         var $id;
55         var $name;
56         var $parent_folder;
57         var $has_child = 0; // flag node has child
58         var $is_group = 0;
59         var $is_dynamic = 0;
60         var $dynamic_query = '';
61         var $assign_to_id;
62         var $created_by;
63         var $modified_by;
64         var $date_created;
65         var $date_modified;
66         var $deleted;
67         var $folder_type;
68
69         var $db;
70         var $new_with_id = false;
71
72         // core queries
73         var $core = "SELECT f.id, f.name, f.has_child, f.is_group, f.is_dynamic, f.dynamic_query, f.folder_type, f.created_by, i.deleted FROM folders f left join inbound_email i on f.id = i.groupfolder_id ";
74         var $coreSubscribed = "SELECT f.id, f.name, f.has_child, f.is_group, f.is_dynamic, f.dynamic_query, f.folder_type, f.created_by, i.deleted FROM folders f LEFT JOIN folders_subscriptions fs ON f.id = fs.folder_id LEFT JOIN inbound_email i on  i.groupfolder_id = f.id ";
75         var $coreWhere = "WHERE f.deleted = 0 ";
76         var $coreWhereSubscribed = "WHERE f.deleted = 0 AND fs.assigned_user_id = ";
77         var $coreOrderBy = " ORDER BY f.is_dynamic, f.is_group, f.name ASC ";
78
79         var $hrSortLocal = array(
80             'flagged' => 'type',
81             'status'  => 'reply_to_status',
82             'from'    => 'emails_text.from_addr',
83             'subject' => 'name',
84             'date'    => 'date_sent',
85             'AssignedTo' => 'assigned_user_id',
86             'flagged' => 'flagged'
87         );
88     var $defaultSort = 'date';
89     var $defaultDirection = "DESC";
90
91         // private attributes
92         var $_depth;
93
94         /**
95          * Sole constructor
96          */
97         function SugarFolder() {
98                 $this->db = DBManagerFactory::getInstance();
99         }
100
101         function deleteEmailFromAllFolder($id) {
102                 $q = "delete from folders_rel where polymorphic_module = 'Emails' AND polymorphic_id = '{$id}' ";
103                 $r = $this->db->query($q);
104         }
105
106         function deleteEmailFromFolder($id) {
107                 $q = "delete from folders_rel where polymorphic_module = 'Emails' AND polymorphic_id = '{$id}' AND folder_id = '{$this->id}'";
108                 $r = $this->db->query($q);
109         }
110
111         function checkEmailExistForFolder($id) {
112                 $q = "SELECT COUNT(*) c from folders_rel where polymorphic_module = 'Emails' AND polymorphic_id = '{$id}' AND folder_id = '{$this->id}'";
113                 $r = $this->db->query($q);
114                 $a = $this->db->fetchByAssoc($r);
115                 if ($a['c'] > 0) {
116                         return true;
117                 } else {
118                         return false;
119                 } // else
120         }
121         /**
122          * Moves beans from one folder to another folder
123          * @param string fromFolder GUID of source folder
124          * @param string toFolder GUID of destination folder
125          * @param string beanId GUID of SugarBean being moved
126          */
127         function move($fromFolder, $toFolder, $beanId) {
128                 $q = "UPDATE folders_rel SET folder_id = '{$toFolder}' WHERE folder_id = '{$fromFolder}' AND polymorphic_id = '{$beanId}' AND deleted = 0";
129                 $r = $this->db->query($q);
130         }
131
132         /**
133          * Copies one bean from one folder to another
134          */
135         function copyBean($fromFolder, $toFolder, $beanId, $module) {
136                 $q = "INSERT INTO folders_rel (id, folder_id, polymorphic_module, polymorphic_id, deleted)
137                                 VALUES('{$guid}', '{$toFolder}', '{$module}', '{$beanId}', 0)";
138                 $r = $this->db->query($q);
139         }
140
141         /**
142          * Creates a new group Folder from the passed fields
143          * @param array fields
144          */
145         function setFolder($fields) {
146
147                 global $current_user;
148                 if(empty($fields['groupFoldersUser'])) {
149                         $fields['groupFoldersUser'] = $current_user->id;
150                 }
151
152                 $this->name = $fields['name'];
153                 $this->parent_folder = $fields['parent_folder'];
154                 $this->has_child = 0;
155                 $this->is_group = 1;
156                 $this->assign_to_id = $fields['groupFoldersUser'];
157
158                 $this->save();
159         }
160
161         /**
162          * Returns GUIDs of folders that the user in focus is subscribed to
163          * @param object user User object in focus
164          * @return array
165          */
166         function getSubscriptions($user) {
167                 if(empty($user)) {
168                         global $current_user;
169                         $user = $current_user;
170                 }
171
172                 $q = "SELECT folder_id FROM folders_subscriptions WHERE assigned_user_id = '{$user->id}'";
173                 $r = $this->db->query($q);
174                 $ret = array();
175                 while($a = $this->db->fetchByAssoc($r)) {
176                         $ret[] = $a['folder_id'];
177                 }
178                 return $ret;
179         }
180
181         /**
182          * Sets a user's preferences for subscribe folders (Sugar only)
183          * @param array subs Array of IDs for subscribed folders
184          */
185         function setSubscriptions($subs) {
186                 global $current_user;
187
188                 if(empty($current_user->id)) {
189                         $GLOBALS['log']->fatal("*** FOLDERS: tried to update folder subscriptions for a user with no ID");
190                         return false;
191                 }
192
193                 $cleanSubscriptions = array();
194
195                 // ensure parent folders are selected, regardless.
196                 foreach($subs as $id) {
197                         $id = trim($id);
198                         if(!empty($id)) {
199                                 $cleanSubscriptions[] = $id;
200                                 $qChk = "SELECT parent_folder FROM folders WHERE id = '{$id}'";
201                                 $rChk = $this->db->query($qChk);
202                                 $aChk = $this->db->fetchByAssoc($rChk);
203
204                                 if(!empty($aChk['parent_folder'])) {
205                                         $cleanSubscriptions = $this->getParentIDRecursive($aChk['parent_folder'], $cleanSubscriptions);
206                                 }
207                         }
208                 }
209
210                 $this->clearSubscriptions();
211
212                 foreach($cleanSubscriptions as $id) {
213                     $this->insertFolderSubscription($id, $current_user->id);
214                 }
215         }
216
217         /**
218          * Given a folder id and user id, create a folder subscription entry.
219          *
220          * @param String $folderId
221          * @param String $userID
222          * @return String The id of the newly created folder subscription.
223          */
224         function insertFolderSubscription($folderId, $userID)
225         {
226             $guid = create_guid();
227                 $query = "INSERT INTO folders_subscriptions (id, folder_id, assigned_user_id) VALUES ('{$guid}', '{$folderId}', '{$userID}')";
228                 $r = $this->db->query($query);
229                 return $guid;
230         }
231         /**
232          * Recursively finds parent node until it hits root
233          * @param string id Starting id to follow up
234          * @param array ret collected ids
235          * @return array of IDs
236          */
237         function getParentIDRecursive($id, $ret=array()) {
238                 $q = "SELECT * FROM folders WHERE id = '{$id}' AND deleted = 0";
239                 $r = $this->db->query($q);
240                 $a = $this->db->fetchByAssoc($r);
241
242                 if(!in_array($id, $ret)) {
243                         $ret[] = $id;
244                 }
245
246                 if($a['parent_folder'] != '') {
247                         $qChk = "SELECT parent_folder FROM folders WHERE id = '{$id}'";
248                         $rChk = $this->db->query($qChk);
249                         $aChk = $this->db->fetchByAssoc($rChk);
250
251                         if(!empty($aChk['parent_folder'])) {
252                                 $ret = $this->getParentIDRecursive($aChk['parent_folder'], $ret);
253                         }
254                 }
255
256                 return $ret;
257         }
258
259         /**
260          * Deletes subscriptions to folders in preparation for reset
261          */
262         function clearSubscriptions() {
263                 global $current_user;
264
265                 if(!empty($current_user->id)) {
266                         $q = "DELETE FROM folders_subscriptions WHERE assigned_user_id = '{$current_user->id}'";
267                         $r = $this->db->query($q);
268                 }
269         }
270
271
272         /**
273          * Deletes all subscriptions for a particular folder id
274          *
275          * @return unknown
276          */
277         function clearSubscriptionsForFolder($folderID)
278         {
279             $query = "DELETE FROM folders_subscriptions WHERE folder_id = '$folderID'";
280             $r = $this->db->query($query);
281         }
282
283         function generateSugarsDynamicFolderQuery() {
284                 global $current_user;
285                 $type = $this->folder_type;
286                 $status = $type;
287                 if($type == "sent") {
288                         $type = "out";
289                 }
290                 if($type == 'inbound') {
291                         $ret = " AND status NOT IN ('sent', 'archived', 'draft') AND type NOT IN ('out', 'archived', 'draft')";
292                 } else {
293                         $ret = " AND status NOT IN ('archived') AND type NOT IN ('archived')";
294                 }
295                 $q = "SELECT emails.id , emails.name, emails.date_sent, emails.status, emails.type, emails.flagged, emails.reply_to_status, emails_text.from_addr, emails_text.to_addrs, 'Emails' polymorphic_module FROM emails" .
296                                                                    " JOIN emails_text on emails.id = emails_text.email_id
297                                    WHERE (type = '{$type}' OR status = '{$status}') AND assigned_user_id = '{$current_user->id}' AND emails.deleted = '0'";
298                 return $q . $ret;
299         } // fn
300
301
302         /**
303          * returns array of items for listView display in yui-ext Grid
304          */
305         function getListItemsForEmailXML($folderId, $page = 1, $pageSize = 10, $sort = '', $direction='') {
306                 require_once('include/TimeDate.php');
307                 global $timedate;
308                 global $current_user;
309                 global $beanList;
310                 global $sugar_config;
311                 global $app_strings;
312
313                 $this->retrieve($folderId);
314                 $start = ($page - 1) * $pageSize;
315
316                 $sort = (empty($sort)) ? $this->defaultSort : $sort;
317         $direction = (empty($direction)) ? $this->defaultDirection : $direction;
318         $order = " ORDER BY {$this->hrSortLocal[$sort]} {$direction}";
319
320                 if($this->is_dynamic) {
321                         $r = $this->db->limitQuery(from_html($this->generateSugarsDynamicFolderQuery() . $order), $start, $pageSize);
322                 } else {
323                         // get items and iterate through them
324                         $q = "SELECT emails.id , emails.name, emails.date_sent, emails.status, emails.type, emails.flagged, emails.reply_to_status, emails_text.from_addr, emails_text.to_addrs, 'Emails' polymorphic_module FROM emails JOIN folders_rel ON emails.id = folders_rel.polymorphic_id" .
325                                   " JOIN emails_text on emails.id = emails_text.email_id
326                   WHERE folders_rel.folder_id = '{$folderId}' AND folders_rel.deleted = 0 AND emails.deleted = 0";
327                         if ($this->is_group) {
328                                 $q = $q . " AND emails.assigned_user_id is null";
329                         }
330                         $r = $this->db->limitQuery($q . $order, $start, $pageSize);
331                 }
332
333                 $return = array();
334
335                 $email = new Email(); //Needed for email specific functions.
336
337                 while($a = $this->db->fetchByAssoc($r)) {
338
339                         $temp = array();
340                         $temp['flagged'] = (is_null($a['flagged']) || $a['flagged'] == '0') ? '' : 1;
341                         $temp['status'] = (is_null($a['reply_to_status']) || $a['reply_to_status'] == '0') ? '' : 1;
342                         $temp['from']   = preg_replace('/[\x00-\x08\x0B-\x1F]/', '', $a['from_addr']);
343                         $temp['subject'] = $a['name'];
344                         $temp['date']   = $timedate->to_display_date_time($this->db->fromConvert($a['date_sent'], 'datetime'));
345                         $temp['uid'] = $a['id'];
346                         $temp['mbox'] = 'sugar::'.$a['polymorphic_module'];
347                         $temp['ieId'] = $folderId;
348                         $temp['site_url'] = $sugar_config['site_url'];
349                         $temp['seen'] = ($a['status'] == 'unread') ? 0 : 1;
350                         $temp['type'] = $a['type'];
351                         $temp['hasAttach'] = $email->doesImportedEmailHaveAttachment($a['id']);
352                         $temp['to_addrs'] = preg_replace('/[\x00-\x08\x0B-\x1F]/', '', $a['to_addrs']);
353                         $return[] = $temp;
354                 }
355
356
357                 $metadata = array();
358                 $metadata['mbox'] = $app_strings['LBL_EMAIL_SUGAR_FOLDER'].': '.$this->name;
359                 $metadata['ieId'] = $folderId;
360                 $metadata['name'] = $this->name;
361                 $metadata['unreadChecked'] = ($current_user->getPreference('showUnreadOnly', 'Emails') == 1) ? 'CHECKED' : '';
362                 $metadata['out'] = $return;
363
364                 return $metadata;
365         }
366
367         function getCountItems ( $folderId ) {
368                 global $current_user ;
369                 global $beanList ;
370                 global $sugar_config ;
371                 global $app_strings ;
372
373                 $this->retrieve ( $folderId ) ;
374                 if ($this->is_dynamic) {
375                 $pattern = '/SELECT(.*?)(\s){1}FROM(\s){1}/is';  // ignores the case
376                 $replacement = 'SELECT count(*) c FROM ';
377                 $modified_select_query = preg_replace($pattern, $replacement, $this->generateSugarsDynamicFolderQuery(), 1);
378                 $r = $this->db->query ( from_html ( $modified_select_query )) ;
379                 } else {
380                         // get items and iterate through them
381                         $q = "SELECT count(*) c FROM folders_rel JOIN emails ON emails.id = folders_rel.polymorphic_id" .
382                         " WHERE folder_id = '{$folderId}' AND folders_rel.deleted = 0 AND emails.deleted = 0" ;
383                         if ($this->is_group) {
384                                 $q .= " AND emails.assigned_user_id IS null";
385                         }
386                         $r = $this->db->query ( $q ) ;
387                 }
388
389                 $a = $this->db->fetchByAssoc($r);
390                 return $a['c'];
391         }
392
393     function getCountUnread ( $folderId ) {
394         global $current_user ;
395         global $beanList ;
396         global $sugar_config ;
397         global $app_strings ;
398
399         $this->retrieve ( $folderId ) ;
400         if ($this->is_dynamic) {
401                 $pattern = '/SELECT(.*?)(\s){1}FROM(\s){1}/is';  // ignores the case
402                 $replacement = 'SELECT count(*) c FROM ';
403                 $modified_select_query = preg_replace($pattern, $replacement, $this->generateSugarsDynamicFolderQuery(), 1);
404                 $r = $this->db->query (from_html($modified_select_query) . " AND emails.status = 'unread'") ;
405         } else {
406             // get items and iterate through them
407             $q = "SELECT count(*) c FROM folders_rel fr JOIN emails on fr.folder_id = '{$folderId}' AND fr.deleted = 0 " .
408                "AND fr.polymorphic_id = emails.id AND emails.status = 'unread' AND emails.deleted = 0" ;
409             if ($this->is_group) {
410                 $q .= " AND emails.assigned_user_id IS null";
411             }
412             $r = $this->db->query ( $q ) ;
413         }
414
415                 $a = $this->db->fetchByAssoc($r);
416         return $a['c'];
417     }
418
419
420         /**
421          * Convenience method, pass a SugarBean and User to this to add anything to a given folder
422          */
423         function addBean($bean, $user=null) {
424                 if(empty($bean->id) || empty($bean->module_dir)) {
425                         $GLOBALS['log']->fatal("*** FOLDERS: addBean() got empty bean - not saving");
426                         return false;
427                 } elseif(empty($this->id)) {
428                         $GLOBALS['log']->fatal("*** FOLDERS: addBean() is trying to save to a non-saved or non-existent folder");
429                         return false;
430                 }
431
432                 global $current_user;
433                 if($user == null) {
434                         $user = $current_user;
435                 }
436
437                 $guid = create_guid();
438
439                 $q = "INSERT INTO folders_rel (id, folder_id, polymorphic_module, polymorphic_id, deleted)
440                                 VALUES('{$guid}', '{$this->id}', '{$bean->module_dir}', '{$bean->id}', 0)";
441                 $r = $this->db->query($q);
442                 return true;
443         }
444
445         /**
446          * Builds up a metacollection of user/group folders to be passed to processor methods
447          * @param object User object, defaults to $current_user
448          * @return array Array of abstract folder objects
449          */
450         function retrieveFoldersForProcessing($user, $subscribed=true) {
451                 global $sugar_config;
452                 global $current_language, $current_user;
453
454                 $emails_mod_strings = return_module_language($current_language, "Emails");
455                 $myEmailTypeString = 'inbound';
456                 $myDraftsTypeString = 'draft';
457                 $mySentEmailTypeString = 'sent';
458
459                 if(empty($user)) {
460                         global $current_user;
461                         $user = $current_user;
462                 }
463                 $rootWhere = '';
464         $teamSecurityClause = '';
465
466
467
468         $rootWhere .= "AND (f.parent_folder IS NULL OR f.parent_folder = '')";
469
470                 if($subscribed) {
471                         $q = $this->coreSubscribed.$teamSecurityClause.$this->coreWhereSubscribed."'{$user->id}' ".$rootWhere.$this->coreOrderBy;
472                 } else {
473                         $q = $this->core.$teamSecurityClause.$this->coreWhere.$rootWhere.$this->coreOrderBy;
474                 }
475                 $r = $this->db->query($q);
476                 $return = array();
477
478                 $found = array();
479                 while($a = $this->db->fetchByAssoc($r)) {
480                         if ((($a['folder_type'] == $myEmailTypeString) ||
481                                 ($a['folder_type'] == $myDraftsTypeString) ||
482                                 ($a['folder_type'] == $mySentEmailTypeString)) &&
483                                 ($a['created_by'] != $current_user->id)) {
484
485                                 continue;
486                         } // if
487                         if (!isset($found[$a['id']])) {
488                 $found[$a['id']] = true;
489                             $return[] = $a;
490                         }
491                 }
492                 return $return;
493         }
494     /**
495          * Preps object array for async call from user's Settings->Folders
496          */
497         function getGroupFoldersForSettings($focusUser=null) {
498                 global $app_strings;
499
500                 $grp = array();
501
502                 $folders = $this->retrieveFoldersForProcessing($focusUser, false);
503                 $subscriptions = $this->getSubscriptions($focusUser);
504
505                 foreach($folders as $a) {
506                         $a['selected'] = (in_array($a['id'], $subscriptions)) ? true : false;
507             $a['origName'] = $a['name'];
508
509                         if($a['is_group'] == 1)
510                                 if ($a['deleted'] != 1)
511                                         $grp[] = $a;
512                 }
513
514                 return $grp;
515         }
516         /**
517          * Preps object array for async call from user's Settings->Folders
518          */
519         function getFoldersForSettings($focusUser=null) {
520                 global $app_strings;
521
522                 $user = array();
523                 $grp = array();
524                 $user[] = array('id' => '', 'name' => $app_strings['LBL_NONE'], 'has_child' => 0, 'is_group' => 0, 'selected' => false);
525                 $grp[] = array('id' => '', 'name' => $app_strings['LBL_NONE'], 'has_child' => 0, 'is_group' => 1, 'selected' => false, 'origName' => "");
526
527                 $folders = $this->retrieveFoldersForProcessing($focusUser, false);
528                 $subscriptions = $this->getSubscriptions($focusUser);
529
530                 foreach($folders as $a) {
531                         $a['selected'] = (in_array($a['id'], $subscriptions)) ? true : false;
532             $a['origName'] = $a['name'];
533             if( isset($a['dynamic_query']) )
534                 unset($a['dynamic_query']);
535                         if($a['is_group'] == 1) {
536                                 $grp[] = $a;
537                         } else {
538                                 $user[] = $a;
539                         }
540
541                         if($a['has_child'] == 1) {
542                                 $qGetChildren = $this->core.$this->coreWhere."AND parent_folder = '{$a['id']}'";
543                                 $rGetChildren = $this->db->query($qGetChildren);
544
545                                 while($aGetChildren = $this->db->fetchByAssoc($rGetChildren)) {
546                                         if($a['is_group']) {
547                                                 $this->_depth = 1;
548                                                 $grp = $this->getFoldersChildForSettings($aGetChildren, $grp, $subscriptions);
549                                         } else {
550                                                 $this->_depth = 1;
551                                                 $user = $this->getFoldersChildForSettings($aGetChildren, $user, $subscriptions);
552                                         }
553                                 }
554                         }
555                 }
556
557                 $ret = array(
558                         'userFolders'   => $user,
559                         'groupFolders'  => $grp,
560                 );
561                 return $ret;
562         }
563
564         function getFoldersChildForSettings($a, $collection, $subscriptions) {
565                 $a['selected'] = (in_array($a['id'], $subscriptions)) ? true : false;
566                 $a['origName'] = $a['name'];
567
568                 if(isset($a['dynamic_query']))
569                 {
570                    unset($a['dynamic_query']);
571                 }
572                 
573                 for($i=0; $i<$this->_depth; $i++) 
574                 {
575                         $a['name'] = ".".$a['name'];
576                 }
577                 
578                 $collection[] = $a;
579
580                 if($a['has_child'] == 1) {
581                         $this->_depth++;
582                         $qGetChildren = $this->core.$this->coreWhere."AND parent_folder = '{$a['id']}'";
583                         $rGetChildren = $this->db->query($qGetChildren);
584                         while($aGetChildren = $this->db->fetchByAssoc($rGetChildren)) {
585                                 $collection = $this->getFoldersChildForSettings($aGetChildren, $collection, $subscriptions);
586                         }
587                 }
588
589                 return $collection;
590         }
591
592         /**
593          * Returns the number of "new" items (based on passed criteria)
594          * @param string id ID of folder
595          * @param array criteria
596          *              expected:
597          *              array('field' => 'status',
598          *                              'value' => 'unread');
599          * @param array
600          * @return int
601          */
602         function getCountNewItems($id, $criteria, $folder) {
603                 global $current_user;
604
605                 $sugarFolder = new SugarFolder();
606                 return $sugarFolder->getCountUnread($id);
607         }
608
609         /**
610          * Collects, sorts, and builds tree of user's folders
611          * @param objec $rootNode Reference to tree root node
612          * @param array $folderStates User pref folder open/closed states
613          * @param object $user Optional User in focus, default current_user
614          * @return array
615          */
616         function getUserFolders(&$rootNode, $folderStates, $user=null, $forRefresh=false) {
617                 if(empty($user)) {
618                         global $current_user;
619                         $user = $current_user;
620                 }
621                 global $mod_strings;
622                 $folders = $this->retrieveFoldersForProcessing($user, true);
623                 $subscriptions = $this->getSubscriptions($user);
624
625                 $refresh = ($forRefresh) ? array() : null;
626
627                 if(!is_array($folderStates)) {
628                         $folderStates = array();
629                 }
630
631                 foreach($folders as $a) {
632                         if ($a['deleted'] == 1)
633                                 continue;
634                         $label = ($a['name'] == 'My Email' ? $mod_strings['LNK_MY_INBOX'] : $a['name']);
635
636                         $unseen = $this->getCountNewItems($a['id'], array('field' => 'status', 'value' => 'unread'), $a);
637
638                         $folderNode = new ExtNode($a['id'], $label);
639                         $folderNode->dynamicloadfunction = '';
640                         $folderNode->expanded = false;
641
642                         if(array_key_exists('Home::'.$a['id'], $folderStates)) {
643                                 if($folderStates['Home::'.$a['id']] == 'open') {
644                                         $folderNode->expanded = true;
645                                 }
646                         }
647                         $nodePath = "Home::".$folderNode->_properties['id'];
648
649                         $folderNode->dynamic_load = true;
650                 //$folderNode->set_property('click', " SUGAR.email2.listView.populateListFrameSugarFolder(YAHOO.namespace('frameFolders').selectednode, '{$a['id']}', 'false');");
651                 $folderNode->set_property('ieId', 'folder');
652                 $folderNode->set_property('is_group', ($a['is_group'] == 1) ? 'true' : 'false');
653                 $folderNode->set_property('is_dynamic', ($a['is_dynamic'] == 1) ? 'true' : 'false');
654                 $folderNode->set_property('mbox', $folderNode->_properties['id']);
655                 $folderNode->set_property('unseen', $unseen);
656                 $folderNode->set_property('id', $a['id']);
657                 $folderNode->set_property('folder_type', $a['folder_type']);
658                 $folderNode->set_property('children', array());
659
660                         if(in_array($a['id'], $subscriptions) && $a['has_child'] == 1) {
661                                 $qGetChildren = $this->core.$this->coreWhere."AND parent_folder = '{$a['id']}'";
662                                 $rGetChildren = $this->db->query($qGetChildren);
663
664                                 while($aGetChildren = $this->db->fetchByAssoc($rGetChildren)) {
665                                         if(in_array($aGetChildren['id'], $subscriptions)) {
666                                                 $folderNode->add_node($this->buildTreeNodeFolders($aGetChildren, $nodePath, $folderStates, $subscriptions));
667                                         }
668                                 }
669                         }
670                         $rootNode->add_node($folderNode);
671                 }
672
673                 /* the code below is called only by Settings->Folders when selecting folders to subscribe to */
674                 if($forRefresh) {
675                         $metaNode = array();
676
677                         if(!empty($rootNode->nodes)) {
678                                 foreach($rootNode->nodes as $node) {
679                                         $metaNode[] = $this->buildTreeNodeRefresh($node, $subscriptions);
680                                 }
681                         }
682                         return $metaNode;
683                 }
684         }
685
686         /**
687          * Builds up a metanode for folder refresh (Sugar folders only)
688          */
689         function buildTreeNodeRefresh($folderNode, $subscriptions) {
690                 $metaNode = $folderNode->_properties;
691                 $metaNode['expanded'] = $folderNode->expanded;
692                 $metaNode['text'] = $folderNode->_label;
693                 if($metaNode['is_group'] == 'true') {
694                         $metaNode['cls'] = 'groupFolder';
695                 } else {
696                     $metaNode['cls'] = 'sugarFolder';
697                 }
698                 $metaNode['id'] = $folderNode->_properties['id'];
699                 $metaNode['children'] = array();
700                 $metaNode['type'] = 1;
701                 $metaNode['leaf'] = false;
702                 $metaNode['isTarget'] = true;
703                 $metaNode['allowChildren'] = true;
704
705                 if(!empty($folderNode->nodes)) {
706                         foreach($folderNode->nodes as $node) {
707                                 if(in_array($node->_properties['id'], $subscriptions))
708                                         $metaNode['children'][] = $this->buildTreeNodeRefresh($node, $subscriptions);
709                         }
710                 }
711                 return $metaNode;
712         }
713
714         /**
715          * Builds children nodes for folders for TreeView
716          * @return $folderNode TreeView node
717          */
718         function buildTreeNodeFolders($a, $nodePath, $folderStates, $subscriptions) {
719                 $label = $a['name'];
720                 global $mod_strings;
721                 if($a['name'] == 'My Drafts') {
722                         $label = $mod_strings['LBL_LIST_TITLE_MY_DRAFTS'];
723                 }
724                 if($a['name'] == 'Sent Emails') {
725                         $label = $mod_strings['LBL_LIST_TITLE_MY_SENT'];
726                 }
727                 $unseen = $this->getCountNewItems($a['id'], array('field' => 'status', 'value' => 'unread'), $a);
728
729                 $folderNode = new ExtNode($a['id'], $label);
730                 $folderNode->dynamicloadfunction = '';
731                 $folderNode->expanded = false;
732
733                 $nodePath .= "::{$a['id']}";
734
735                 if(array_key_exists($nodePath, $folderStates)) {
736                         if($folderStates[$nodePath] == 'open') {
737                                 $folderNode->expanded = true;
738                         }
739                 }
740
741                 $folderNode->dynamic_load = true;
742         $folderNode->set_property('click', "SUGAR.email2.listView.populateListFrameSugarFolder(YAHOO.namespace('frameFolders').selectednode, '{$a['id']}', 'false');");
743         $folderNode->set_property('ieId', 'folder');
744         $folderNode->set_property('mbox', $a['id']);
745                 $folderNode->set_property('is_group', ($a['is_group'] == 1) ? 'true' : 'false');
746         $folderNode->set_property('is_dynamic', ($a['is_dynamic'] == 1) ? 'true' : 'false');
747         $folderNode->set_property('unseen', $unseen);
748             $folderNode->set_property('folder_type', $a['folder_type']);
749
750                 if(in_array($a['id'], $subscriptions) && $a['has_child'] == 1) {
751                         $qGetChildren = $this->core.$this->coreWhere."AND parent_folder = '{$a['id']}' ".$this->coreOrderBy;
752                         $rGetChildren = $this->db->query($qGetChildren);
753
754                         while($aGetChildren = $this->db->fetchByAssoc($rGetChildren)) {
755                                 $folderNode->add_node($this->buildTreeNodeFolders($aGetChildren, $nodePath, $folderStates, $subscriptions));
756                         }
757                 }
758                 return $folderNode;
759         }
760
761         /**
762          * Flags a folder as deleted
763          * @return bool True on success
764          */
765         function delete() {
766                 global $current_user;
767
768                 if(!empty($this->id)) {
769                         if($this->has_child) {
770                                 $this->deleteChildrenCascade($this->id);
771                         }
772
773                         $ownerCheck = ($current_user->is_admin == 0) ? " AND created_by = '{$current_user->id}'" : "";
774                         $q = "UPDATE folders SET deleted = 1 WHERE id = '{$this->id}'{$ownerCheck}";
775                         $r = $this->db->query($q);
776                         return true;
777                 }
778                 return false;
779         }
780
781         /**
782          * Deletes all children in a cascade
783          * @param string $id ID of parent
784          * @return bool True on success
785          */
786         function deleteChildrenCascade($id) {
787                 global $current_user;
788
789                 $canContinue = true;
790                 $checkInboundQuery = "SELECT count(*) c FROM inbound_email WHERE groupfolder_id = '{$id}' and deleted = 0";
791                 $resultSet = $this->db->query($checkInboundQuery);
792                 $a = $this->db->fetchByAssoc($resultSet);
793                 if ($a['c'] > 0) {
794                         return false;
795                 } // if
796
797                 $q = "SELECT COUNT(*) c from folders_rel where polymorphic_module = 'Emails' AND polymorphic_id = '{$id}' AND folder_id = '{$this->id}'";
798
799                 $checkEmailQuery = "SELECT count(*) c FROM folders_rel where polymorphic_module = 'Emails' and folder_id = '{$id}' and deleted = 0";
800                 $resultSet = $this->db->query($checkEmailQuery);
801                 $a = $this->db->fetchByAssoc($resultSet);
802                 if ($a['c'] > 0) {
803                         return false;
804                 } // if
805
806                 $q = "SELECT * FROM folders WHERE id = '{$id}'";
807                 $r = $this->db->query($q);
808                 $a = $this->db->fetchByAssoc($r);
809
810                 if($a['has_child'] == 1) {
811                         $q2 = "SELECT id FROM folders WHERE parent_folder = '{$id}'";
812                         $r2 = $this->db->query($q2);
813
814                         while($a2 = $this->db->fetchByAssoc($r2)) {
815                                 $canContinue = $this->deleteChildrenCascade($a2['id']);
816                         }
817                 }
818
819                 if ($canContinue) {
820                         // flag deleted
821                         $ownerCheck = ($current_user->is_admin == 0) ? " AND created_by = '{$current_user->id}'" : "";
822                         $q3 = "UPDATE folders SET deleted = 1 WHERE id = '{$id}'{$ownerCheck}";
823                         $r3 = $this->db->query($q3);
824
825                         // flag rels
826                         $qRel = "UPDATE folders_rel SET deleted = 1 WHERE folder_id = '{$id}'";
827                         $rRel = $this->db->query($qRel);
828
829                         // delete subscriptions
830                         $qSub = "DELETE FROM folders_subscriptions WHERE folder_id = '{$id}'";
831                         $rSub = $this->db->query($qSub);
832                 }
833                 return $canContinue;
834                 //_pp($q3);_pp($qRel);_pp($qSub);
835         }
836
837
838         /**
839          * Saves folder
840          * @return bool
841          */
842         function save($addSubscriptions = TRUE) {
843                 global $current_user;
844
845                 $this->dynamic_query = $this->db->quote($this->dynamic_query);
846
847                 if((empty($this->id) && $this->new_with_id == false) || (!empty($this->id) && $this->new_with_id == true))
848                 {
849
850                     if( empty($this->id) )
851                     {
852                             $guid = create_guid();
853                             $this->id = $guid;
854                     }
855
856                         $q = "INSERT INTO folders(id, name, folder_type, parent_folder, has_child, is_group, is_dynamic, dynamic_query, assign_to_id, ".
857                                 "created_by, modified_by, deleted)".
858
859                                 " VALUES('{$this->id}', '{$this->name}', '{$this->folder_type}', '{$this->parent_folder}', {$this->has_child}, {$this->is_group}, {$this->is_dynamic}, '{$this->dynamic_query}', '{$this->assign_to_id}', " .
860                                 "'{$current_user->id}', '{$current_user->id}', 0)";
861
862
863                         if($addSubscriptions)
864                         {
865                             // create default subscription
866                             $this->addSubscriptionsToGroupFolder();
867                         }
868
869                         // if parent_id is set, update parent's has_child flag
870                         $q3 = "UPDATE folders SET has_child = 1 WHERE id = '{$this->parent_folder}'";
871                         $r3 = $this->db->query($q3);
872                 }
873                 else {
874                         $q = "UPDATE folders SET name = '{$this->name}', parent_folder = '{$this->parent_folder}', dynamic_query = '{$this->dynamic_query}', assign_to_id = '{$this->assign_to_id}', " .
875                                 "modified_by = '{$current_user->id}' WHERE id = '{$this->id}'";
876                 }
877
878                 $this->db->query($q, true);
879
880                 return true;
881         }
882
883         /**
884          * Add subscriptions to this group folder.
885          *
886          */
887         function addSubscriptionsToGroupFolder()
888         {
889             global $current_user;
890
891             $this->createSubscriptionForUser($current_user->id);
892
893         }
894
895
896
897     /**
898          * Add subscriptions to this group folder.
899          *
900          */
901         function createSubscriptionForUser($user_id)
902         {
903            $guid2 = create_guid();
904            $query = "INSERT INTO folders_subscriptions VALUES('{$guid2}', '{$this->id}', '{$user_id}')";
905            $this->db->query($query);
906         }
907
908
909         function updateFolder($fields) {
910                 global $current_user;
911
912                 $this->dynamic_query = $this->db->quote($this->dynamic_query);
913                 $id = $fields['record'];
914                 $name = $fields['name'];
915                 $parent_folder = $fields['parent_folder'];
916                 // first do the retrieve
917                 $this->retrieve($id);
918                 if ($this->has_child) {
919                         $childrenArray = array();
920                         $this->findAllChildren($id, $childrenArray);
921                         if (in_array($parent_folder, $childrenArray)) {
922                                 return array('status' => "failed", 'message' => "Can not add this folder to its children");
923                         }
924                 }
925                 // update has_child to 0 for this parent folder if this is the only child it has
926                 $q1 = "select count(*) count from folders where deleted = 0 AND parent_folder = '{$this->parent_folder}'";
927                 $r1 = $this->db->query($q1);
928                 $a1 = $this->db->fetchByAssoc($r1);
929                 if ($a1['count'] == 1) {
930                         $q1 = "UPDATE folders SET has_child = 0 WHERE id = '{$this->parent_folder}'";
931                         $r1 = $this->db->query($q1);
932                 } // if
933
934
935                 $this->name = $name;
936                 $this->parent_folder = $parent_folder;
937                 $q2 = "UPDATE folders SET name = '{$this->name}', parent_folder = '{$this->parent_folder}',                     dynamic_query = '{$this->dynamic_query}', " .
938                         "modified_by = '{$current_user->id}' WHERE id = '{$this->id}'";
939                 $r2 = $this->db->query($q2);
940                 if (!empty($this->parent_folder)) {
941                         $q3 = "UPDATE folders SET has_child = 1 WHERE id = '{$this->parent_folder}'";
942                         $r3 = $this->db->query($q3);
943                 } // if
944                 return array('status' => "done");
945
946         } // fn
947
948         function findAllChildren($folderId, &$childrenArray) {
949                 $q = "SELECT * FROM folders WHERE id = '{$folderId}'";
950                 $r = $this->db->query($q);
951                 $a = $this->db->fetchByAssoc($r);
952
953                 if($a['has_child'] == 1) {
954                         $q2 = "SELECT id FROM folders WHERE deleted = 0 AND parent_folder = '{$folderId}'";
955                         $r2 = $this->db->query($q2);
956
957                         while($a2 = $this->db->fetchByAssoc($r2)) {
958                                 $childrenArray[] = $a2['id'];
959                                 $this->findAllChildren($a2['id'], $childrenArray);
960                         } // while
961                 } // if
962
963         } // fn
964
965         /**
966          * Retrieves and populates object
967          * @param string $id ID of folder
968          * @return bool True on success
969          */
970         function retrieve($id) {
971                 $q = "SELECT * FROM folders WHERE id = '{$id}' AND deleted = 0";
972                 $r = $this->db->query($q);
973                 $a = $this->db->fetchByAssoc($r);
974
975                 if(!empty($a)) {
976                         foreach($a as $k => $v) {
977                                 if($k == 'dynamic_query') {
978                                         $v = from_html($v);
979                                 }
980                                 $this->$k = $v;
981                         }
982                         return true;
983                 }
984
985                 return false;
986         }
987 } // end class def