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-2013 SugarCRM Inc.
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.
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
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
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.
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.
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 ********************************************************************************/
38 /*********************************************************************************
41 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. All Rights
42 * Reserved. Contributor(s): ______________________________________..
43 *********************************************************************************/
45 require_once("include/ytree/Tree.php");
46 require_once("include/ytree/ExtNode.php");
49 * Polymorphic buckets - place any item in a folder
57 var $has_child = 0; // flag node has child
60 var $dynamic_query = '';
70 var $new_with_id = false;
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 ";
79 var $hrSortLocal = array(
81 'status' => 'reply_to_status',
82 'from' => 'emails_text.from_addr',
84 'date' => 'date_sent',
85 'AssignedTo' => 'assigned_user_id',
86 'flagged' => 'flagged'
88 var $defaultSort = 'date';
89 var $defaultDirection = "DESC";
97 function SugarFolder() {
98 $this->db = DBManagerFactory::getInstance();
101 function deleteEmailFromAllFolder($id) {
102 $q = "delete from folders_rel where polymorphic_module = 'Emails' AND polymorphic_id = '{$id}' ";
103 $r = $this->db->query($q);
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);
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);
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
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);
133 * Copies one bean from one folder to another
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);
142 * Creates a new group Folder from the passed fields
143 * @param array fields
145 function setFolder($fields) {
147 global $current_user;
148 if(empty($fields['groupFoldersUser'])) {
149 $fields['groupFoldersUser'] = $current_user->id;
152 $this->name = $fields['name'];
153 $this->parent_folder = $fields['parent_folder'];
154 $this->has_child = 0;
156 $this->assign_to_id = $fields['groupFoldersUser'];
162 * Returns GUIDs of folders that the user in focus is subscribed to
163 * @param object user User object in focus
166 function getSubscriptions($user) {
168 global $current_user;
169 $user = $current_user;
172 $q = "SELECT folder_id FROM folders_subscriptions WHERE assigned_user_id = '{$user->id}'";
173 $r = $this->db->query($q);
175 while($a = $this->db->fetchByAssoc($r)) {
176 $ret[] = $a['folder_id'];
182 * Sets a user's preferences for subscribe folders (Sugar only)
183 * @param array subs Array of IDs for subscribed folders
185 function setSubscriptions($subs) {
186 global $current_user;
188 if(empty($current_user->id)) {
189 $GLOBALS['log']->fatal("*** FOLDERS: tried to update folder subscriptions for a user with no ID");
193 $cleanSubscriptions = array();
195 // ensure parent folders are selected, regardless.
196 foreach($subs as $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);
204 if(!empty($aChk['parent_folder'])) {
205 $cleanSubscriptions = $this->getParentIDRecursive($aChk['parent_folder'], $cleanSubscriptions);
210 $this->clearSubscriptions();
212 foreach($cleanSubscriptions as $id) {
213 $this->insertFolderSubscription($id, $current_user->id);
218 * Given a folder id and user id, create a folder subscription entry.
220 * @param String $folderId
221 * @param String $userID
222 * @return String The id of the newly created folder subscription.
224 function insertFolderSubscription($folderId, $userID)
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);
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
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);
242 if(!in_array($id, $ret)) {
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);
251 if(!empty($aChk['parent_folder'])) {
252 $ret = $this->getParentIDRecursive($aChk['parent_folder'], $ret);
260 * Deletes subscriptions to folders in preparation for reset
262 function clearSubscriptions() {
263 global $current_user;
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);
273 * Deletes all subscriptions for a particular folder id
277 function clearSubscriptionsForFolder($folderID)
279 $query = "DELETE FROM folders_subscriptions WHERE folder_id = '$folderID'";
280 $r = $this->db->query($query);
283 protected function generateArchiveFolderQuery()
285 global $current_user;
287 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
288 JOIN emails_text on emails.id = emails_text.email_id
289 WHERE emails.deleted=0 AND emails.type NOT IN ('out', 'draft') AND emails.status NOT IN ('sent', 'draft') AND emails.id IN (
290 SELECT eear.email_id FROM emails_email_addr_rel eear
291 JOIN email_addr_bean_rel eabr ON eabr.email_address_id=eear.email_address_id AND eabr.bean_id = '{$current_user->id}' AND eabr.bean_module = 'Users'
298 function generateSugarsDynamicFolderQuery()
300 global $current_user;
301 $type = $this->folder_type;
302 if($type == 'archived') {
303 return $this->generateArchiveFolderQuery();
306 if($type == "sent") {
309 if($type == 'inbound') {
310 $ret = " AND emails.status NOT IN ('sent', 'archived', 'draft') AND emails.type NOT IN ('out', 'archived', 'draft')";
312 $ret = " AND emails.status NOT IN ('archived') AND emails.type NOT IN ('archived')";
314 $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" .
315 " JOIN emails_text on emails.id = emails_text.email_id
316 WHERE (type = '{$type}' OR status = '{$status}') AND assigned_user_id = '{$current_user->id}' AND emails.deleted=0";
322 * returns array of items for listView display in yui-ext Grid
324 function getListItemsForEmailXML($folderId, $page = 1, $pageSize = 10, $sort = '', $direction='') {
325 require_once('include/TimeDate.php');
327 global $current_user;
329 global $sugar_config;
332 $this->retrieve($folderId);
333 $start = ($page - 1) * $pageSize;
335 $sort = (empty($sort)) ? $this->defaultSort : $sort;
336 if (!in_array(strtolower($direction), array('asc', 'desc'))) {
337 $direction = $this->defaultDirection;
340 if (!empty($this->hrSortLocal[$sort])) {
341 $order = " ORDER BY {$this->hrSortLocal[$sort]} {$direction}";
346 if($this->is_dynamic) {
347 $r = $this->db->limitQuery(from_html($this->generateSugarsDynamicFolderQuery() . $order), $start, $pageSize);
349 // get items and iterate through them
350 $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" .
351 " JOIN emails_text on emails.id = emails_text.email_id
352 WHERE folders_rel.folder_id = '{$folderId}' AND folders_rel.deleted = 0 AND emails.deleted = 0";
353 if ($this->is_group) {
354 $q = $q . " AND (emails.assigned_user_id is null or emails.assigned_user_id = '')";
356 $r = $this->db->limitQuery($q . $order, $start, $pageSize);
361 $email = new Email(); //Needed for email specific functions.
363 while($a = $this->db->fetchByAssoc($r)) {
366 $temp['flagged'] = (is_null($a['flagged']) || $a['flagged'] == '0') ? '' : 1;
367 $temp['status'] = (is_null($a['reply_to_status']) || $a['reply_to_status'] == '0') ? '' : 1;
368 $temp['from'] = preg_replace('/[\x00-\x08\x0B-\x1F]/', '', $a['from_addr']);
369 $temp['subject'] = $a['name'];
370 $temp['date'] = $timedate->to_display_date_time($this->db->fromConvert($a['date_sent'], 'datetime'));
371 $temp['uid'] = $a['id'];
372 $temp['mbox'] = 'sugar::'.$a['polymorphic_module'];
373 $temp['ieId'] = $folderId;
374 $temp['site_url'] = $sugar_config['site_url'];
375 $temp['seen'] = ($a['status'] == 'unread') ? 0 : 1;
376 $temp['type'] = $a['type'];
377 $temp['hasAttach'] = $email->doesImportedEmailHaveAttachment($a['id']);
378 $temp['to_addrs'] = preg_replace('/[\x00-\x08\x0B-\x1F]/', '', $a['to_addrs']);
384 $metadata['mbox'] = $app_strings['LBL_EMAIL_SUGAR_FOLDER'].': '.$this->name;
385 $metadata['ieId'] = $folderId;
386 $metadata['name'] = $this->name;
387 $metadata['unreadChecked'] = ($current_user->getPreference('showUnreadOnly', 'Emails') == 1) ? 'CHECKED' : '';
388 $metadata['out'] = $return;
393 function getCountItems ( $folderId ) {
394 global $current_user ;
396 global $sugar_config ;
397 global $app_strings ;
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 )) ;
406 // get items and iterate through them
407 $q = "SELECT count(*) c FROM folders_rel JOIN emails ON emails.id = folders_rel.polymorphic_id" .
408 " WHERE folder_id = '{$folderId}' AND folders_rel.deleted = 0 AND emails.deleted = 0" ;
409 if ($this->is_group) {
410 $q .= " AND (emails.assigned_user_id is null or emails.assigned_user_id = '')";
412 $r = $this->db->query ( $q ) ;
415 $a = $this->db->fetchByAssoc($r);
419 function getCountUnread ( $folderId ) {
420 global $current_user ;
422 global $sugar_config ;
423 global $app_strings ;
425 $this->retrieve ( $folderId ) ;
426 if ($this->is_dynamic) {
427 $pattern = '/SELECT(.*?)(\s){1}FROM(\s){1}/is'; // ignores the case
428 $replacement = 'SELECT count(*) c FROM ';
429 $modified_select_query = preg_replace($pattern, $replacement, $this->generateSugarsDynamicFolderQuery(), 1);
430 $r = $this->db->query (from_html($modified_select_query) . " AND emails.status = 'unread'") ;
432 // get items and iterate through them
433 $q = "SELECT count(*) c FROM folders_rel fr JOIN emails on fr.folder_id = '{$folderId}' AND fr.deleted = 0 " .
434 "AND fr.polymorphic_id = emails.id AND emails.status = 'unread' AND emails.deleted = 0" ;
435 if ($this->is_group) {
436 $q .= " AND (emails.assigned_user_id is null or emails.assigned_user_id = '')";
438 $r = $this->db->query ( $q ) ;
441 $a = $this->db->fetchByAssoc($r);
447 * Convenience method, pass a SugarBean and User to this to add anything to a given folder
449 function addBean($bean, $user=null) {
450 if(empty($bean->id) || empty($bean->module_dir)) {
451 $GLOBALS['log']->fatal("*** FOLDERS: addBean() got empty bean - not saving");
453 } elseif(empty($this->id)) {
454 $GLOBALS['log']->fatal("*** FOLDERS: addBean() is trying to save to a non-saved or non-existent folder");
458 global $current_user;
460 $user = $current_user;
463 $guid = create_guid();
465 $q = "INSERT INTO folders_rel (id, folder_id, polymorphic_module, polymorphic_id, deleted)
466 VALUES('{$guid}', '{$this->id}', '{$bean->module_dir}', '{$bean->id}', 0)";
467 $r = $this->db->query($q);
472 * Builds up a metacollection of user/group folders to be passed to processor methods
473 * @param object User object, defaults to $current_user
474 * @return array Array of abstract folder objects
476 function retrieveFoldersForProcessing($user, $subscribed=true) {
477 global $sugar_config;
478 global $current_language, $current_user;
480 $emails_mod_strings = return_module_language($current_language, "Emails");
481 $myEmailTypeString = 'inbound';
482 $myDraftsTypeString = 'draft';
483 $mySentEmailTypeString = 'sent';
486 global $current_user;
487 $user = $current_user;
490 $teamSecurityClause = '';
494 $rootWhere .= "AND (f.parent_folder IS NULL OR f.parent_folder = '')";
497 $q = $this->coreSubscribed.$teamSecurityClause.$this->coreWhereSubscribed."'{$user->id}' ".$rootWhere.$this->coreOrderBy;
499 $q = $this->core.$teamSecurityClause.$this->coreWhere.$rootWhere.$this->coreOrderBy;
501 $r = $this->db->query($q);
505 while($a = $this->db->fetchByAssoc($r)) {
506 if ((($a['folder_type'] == $myEmailTypeString) ||
507 ($a['folder_type'] == $myDraftsTypeString) ||
508 ($a['folder_type'] == $mySentEmailTypeString)) &&
509 ($a['created_by'] != $current_user->id)) {
513 if (!isset($found[$a['id']])) {
514 $found[$a['id']] = true;
521 * Preps object array for async call from user's Settings->Folders
523 function getGroupFoldersForSettings($focusUser=null) {
528 $folders = $this->retrieveFoldersForProcessing($focusUser, false);
529 $subscriptions = $this->getSubscriptions($focusUser);
531 foreach($folders as $a) {
532 $a['selected'] = (in_array($a['id'], $subscriptions)) ? true : false;
533 $a['origName'] = $a['name'];
535 if($a['is_group'] == 1)
536 if ($a['deleted'] != 1)
543 * Preps object array for async call from user's Settings->Folders
545 function getFoldersForSettings($focusUser=null) {
550 $user[] = array('id' => '', 'name' => $app_strings['LBL_NONE'], 'has_child' => 0, 'is_group' => 0, 'selected' => false);
551 $grp[] = array('id' => '', 'name' => $app_strings['LBL_NONE'], 'has_child' => 0, 'is_group' => 1, 'selected' => false, 'origName' => "");
553 $folders = $this->retrieveFoldersForProcessing($focusUser, false);
554 $subscriptions = $this->getSubscriptions($focusUser);
556 foreach($folders as $a) {
557 $a['selected'] = (in_array($a['id'], $subscriptions)) ? true : false;
558 $a['origName'] = $a['name'];
559 if( isset($a['dynamic_query']) )
560 unset($a['dynamic_query']);
561 if($a['is_group'] == 1) {
567 if($a['has_child'] == 1) {
568 $qGetChildren = $this->core.$this->coreWhere."AND parent_folder = '{$a['id']}'";
569 $rGetChildren = $this->db->query($qGetChildren);
571 while($aGetChildren = $this->db->fetchByAssoc($rGetChildren)) {
574 $grp = $this->getFoldersChildForSettings($aGetChildren, $grp, $subscriptions);
577 $user = $this->getFoldersChildForSettings($aGetChildren, $user, $subscriptions);
584 'userFolders' => $user,
585 'groupFolders' => $grp,
590 function getFoldersChildForSettings($a, $collection, $subscriptions) {
591 $a['selected'] = (in_array($a['id'], $subscriptions)) ? true : false;
592 $a['origName'] = $a['name'];
594 if(isset($a['dynamic_query']))
596 unset($a['dynamic_query']);
599 for($i=0; $i<$this->_depth; $i++)
601 $a['name'] = ".".$a['name'];
606 if($a['has_child'] == 1) {
608 $qGetChildren = $this->core.$this->coreWhere."AND parent_folder = '{$a['id']}'";
609 $rGetChildren = $this->db->query($qGetChildren);
610 while($aGetChildren = $this->db->fetchByAssoc($rGetChildren)) {
611 $collection = $this->getFoldersChildForSettings($aGetChildren, $collection, $subscriptions);
619 * Returns the number of "new" items (based on passed criteria)
620 * @param string id ID of folder
621 * @param array criteria
623 * array('field' => 'status',
624 * 'value' => 'unread');
628 function getCountNewItems($id, $criteria, $folder) {
629 global $current_user;
631 $sugarFolder = new SugarFolder();
632 return $sugarFolder->getCountUnread($id);
636 * Collects, sorts, and builds tree of user's folders
637 * @param objec $rootNode Reference to tree root node
638 * @param array $folderStates User pref folder open/closed states
639 * @param object $user Optional User in focus, default current_user
642 function getUserFolders(&$rootNode, $folderStates, $user=null, $forRefresh=false) {
644 global $current_user;
645 $user = $current_user;
648 $folders = $this->retrieveFoldersForProcessing($user, true);
649 $subscriptions = $this->getSubscriptions($user);
651 $refresh = ($forRefresh) ? array() : null;
653 if(!is_array($folderStates)) {
654 $folderStates = array();
657 foreach($folders as $a) {
658 if ($a['deleted'] == 1)
660 $label = ($a['name'] == 'My Email' ? $mod_strings['LNK_MY_INBOX'] : $a['name']);
662 $unseen = $this->getCountNewItems($a['id'], array('field' => 'status', 'value' => 'unread'), $a);
664 $folderNode = new ExtNode($a['id'], $label);
665 $folderNode->dynamicloadfunction = '';
666 $folderNode->expanded = false;
668 if(array_key_exists('Home::'.$a['id'], $folderStates)) {
669 if($folderStates['Home::'.$a['id']] == 'open') {
670 $folderNode->expanded = true;
673 $nodePath = "Home::".$folderNode->_properties['id'];
675 $folderNode->dynamic_load = true;
676 //$folderNode->set_property('click', " SUGAR.email2.listView.populateListFrameSugarFolder(YAHOO.namespace('frameFolders').selectednode, '{$a['id']}', 'false');");
677 $folderNode->set_property('ieId', 'folder');
678 $folderNode->set_property('is_group', ($a['is_group'] == 1) ? 'true' : 'false');
679 $folderNode->set_property('is_dynamic', ($a['is_dynamic'] == 1) ? 'true' : 'false');
680 $folderNode->set_property('mbox', $folderNode->_properties['id']);
681 $folderNode->set_property('unseen', $unseen);
682 $folderNode->set_property('id', $a['id']);
683 $folderNode->set_property('folder_type', $a['folder_type']);
684 $folderNode->set_property('children', array());
686 if(in_array($a['id'], $subscriptions) && $a['has_child'] == 1) {
687 $qGetChildren = $this->core.$this->coreWhere."AND parent_folder = '{$a['id']}'";
688 $rGetChildren = $this->db->query($qGetChildren);
690 while($aGetChildren = $this->db->fetchByAssoc($rGetChildren)) {
691 if(in_array($aGetChildren['id'], $subscriptions)) {
692 $folderNode->add_node($this->buildTreeNodeFolders($aGetChildren, $nodePath, $folderStates, $subscriptions));
696 $rootNode->add_node($folderNode);
699 /* the code below is called only by Settings->Folders when selecting folders to subscribe to */
703 if(!empty($rootNode->nodes)) {
704 foreach($rootNode->nodes as $node) {
705 $metaNode[] = $this->buildTreeNodeRefresh($node, $subscriptions);
713 * Builds up a metanode for folder refresh (Sugar folders only)
715 function buildTreeNodeRefresh($folderNode, $subscriptions) {
716 $metaNode = $folderNode->_properties;
717 $metaNode['expanded'] = $folderNode->expanded;
718 $metaNode['text'] = $folderNode->_label;
719 if($metaNode['is_group'] == 'true') {
720 $metaNode['cls'] = 'groupFolder';
722 $metaNode['cls'] = 'sugarFolder';
724 $metaNode['id'] = $folderNode->_properties['id'];
725 $metaNode['children'] = array();
726 $metaNode['type'] = 1;
727 $metaNode['leaf'] = false;
728 $metaNode['isTarget'] = true;
729 $metaNode['allowChildren'] = true;
731 if(!empty($folderNode->nodes)) {
732 foreach($folderNode->nodes as $node) {
733 if(in_array($node->_properties['id'], $subscriptions))
734 $metaNode['children'][] = $this->buildTreeNodeRefresh($node, $subscriptions);
741 * Builds children nodes for folders for TreeView
742 * @return $folderNode TreeView node
744 function buildTreeNodeFolders($a, $nodePath, $folderStates, $subscriptions) {
747 if($a['name'] == 'My Drafts') {
748 $label = $mod_strings['LBL_LIST_TITLE_MY_DRAFTS'];
750 if($a['name'] == 'Sent Emails') {
751 $label = $mod_strings['LBL_LIST_TITLE_MY_SENT'];
753 $unseen = $this->getCountNewItems($a['id'], array('field' => 'status', 'value' => 'unread'), $a);
755 $folderNode = new ExtNode($a['id'], $label);
756 $folderNode->dynamicloadfunction = '';
757 $folderNode->expanded = false;
759 $nodePath .= "::{$a['id']}";
761 if(array_key_exists($nodePath, $folderStates)) {
762 if($folderStates[$nodePath] == 'open') {
763 $folderNode->expanded = true;
767 $folderNode->dynamic_load = true;
768 $folderNode->set_property('click', "SUGAR.email2.listView.populateListFrameSugarFolder(YAHOO.namespace('frameFolders').selectednode, '{$a['id']}', 'false');");
769 $folderNode->set_property('ieId', 'folder');
770 $folderNode->set_property('mbox', $a['id']);
771 $folderNode->set_property('is_group', ($a['is_group'] == 1) ? 'true' : 'false');
772 $folderNode->set_property('is_dynamic', ($a['is_dynamic'] == 1) ? 'true' : 'false');
773 $folderNode->set_property('unseen', $unseen);
774 $folderNode->set_property('folder_type', $a['folder_type']);
776 if(in_array($a['id'], $subscriptions) && $a['has_child'] == 1) {
777 $qGetChildren = $this->core.$this->coreWhere."AND parent_folder = '{$a['id']}' ".$this->coreOrderBy;
778 $rGetChildren = $this->db->query($qGetChildren);
780 while($aGetChildren = $this->db->fetchByAssoc($rGetChildren)) {
781 $folderNode->add_node($this->buildTreeNodeFolders($aGetChildren, $nodePath, $folderStates, $subscriptions));
788 * Flags a folder as deleted
789 * @return bool True on success
792 global $current_user;
794 if(!empty($this->id)) {
795 if($this->has_child) {
796 $this->deleteChildrenCascade($this->id);
799 $ownerCheck = ($current_user->is_admin == 0) ? " AND created_by = '{$current_user->id}'" : "";
800 $q = "UPDATE folders SET deleted = 1 WHERE id = '{$this->id}'{$ownerCheck}";
801 $r = $this->db->query($q);
808 * Deletes all children in a cascade
809 * @param string $id ID of parent
810 * @return bool True on success
812 function deleteChildrenCascade($id) {
813 global $current_user;
816 $checkInboundQuery = "SELECT count(*) c FROM inbound_email WHERE groupfolder_id = '{$id}' and deleted = 0";
817 $resultSet = $this->db->query($checkInboundQuery);
818 $a = $this->db->fetchByAssoc($resultSet);
823 $q = "SELECT COUNT(*) c from folders_rel where polymorphic_module = 'Emails' AND polymorphic_id = '{$id}' AND folder_id = '{$this->id}'";
825 $checkEmailQuery = "SELECT count(*) c FROM folders_rel where polymorphic_module = 'Emails' and folder_id = '{$id}' and deleted = 0";
826 $resultSet = $this->db->query($checkEmailQuery);
827 $a = $this->db->fetchByAssoc($resultSet);
832 $q = "SELECT * FROM folders WHERE id = '{$id}'";
833 $r = $this->db->query($q);
834 $a = $this->db->fetchByAssoc($r);
836 if($a['has_child'] == 1) {
837 $q2 = "SELECT id FROM folders WHERE parent_folder = '{$id}'";
838 $r2 = $this->db->query($q2);
840 while($a2 = $this->db->fetchByAssoc($r2)) {
841 $canContinue = $this->deleteChildrenCascade($a2['id']);
847 $ownerCheck = ($current_user->is_admin == 0) ? " AND created_by = '{$current_user->id}'" : "";
848 $q3 = "UPDATE folders SET deleted = 1 WHERE id = '{$id}'{$ownerCheck}";
849 $r3 = $this->db->query($q3);
852 $qRel = "UPDATE folders_rel SET deleted = 1 WHERE folder_id = '{$id}'";
853 $rRel = $this->db->query($qRel);
855 // delete subscriptions
856 $qSub = "DELETE FROM folders_subscriptions WHERE folder_id = '{$id}'";
857 $rSub = $this->db->query($qSub);
860 //_pp($q3);_pp($qRel);_pp($qSub);
868 function save($addSubscriptions = TRUE) {
869 global $current_user;
871 $this->dynamic_query = $this->db->quote($this->dynamic_query);
873 if((empty($this->id) && $this->new_with_id == false) || (!empty($this->id) && $this->new_with_id == true))
876 if( empty($this->id) )
878 $guid = create_guid();
882 $q = "INSERT INTO folders(id, name, folder_type, parent_folder, has_child, is_group, is_dynamic, dynamic_query, assign_to_id, ".
883 "created_by, modified_by, deleted)".
885 " 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}', " .
886 "'{$current_user->id}', '{$current_user->id}', 0)";
889 if($addSubscriptions)
891 // create default subscription
892 $this->addSubscriptionsToGroupFolder();
895 // if parent_id is set, update parent's has_child flag
896 $q3 = "UPDATE folders SET has_child = 1 WHERE id = '{$this->parent_folder}'";
897 $r3 = $this->db->query($q3);
900 $q = "UPDATE folders SET name = '{$this->name}', parent_folder = '{$this->parent_folder}', dynamic_query = '{$this->dynamic_query}', assign_to_id = '{$this->assign_to_id}', " .
901 "modified_by = '{$current_user->id}' WHERE id = '{$this->id}'";
904 $this->db->query($q, true);
910 * Add subscriptions to this group folder.
913 function addSubscriptionsToGroupFolder()
915 global $current_user;
917 $this->createSubscriptionForUser($current_user->id);
924 * Add subscriptions to this group folder.
927 function createSubscriptionForUser($user_id)
929 $guid2 = create_guid();
930 $query = "INSERT INTO folders_subscriptions VALUES('{$guid2}', '{$this->id}', '{$user_id}')";
931 $this->db->query($query);
935 function updateFolder($fields) {
936 global $current_user;
938 $this->dynamic_query = $this->db->quote($this->dynamic_query);
939 $id = $fields['record'];
940 $name = $fields['name'];
941 $parent_folder = $fields['parent_folder'];
942 // first do the retrieve
943 $this->retrieve($id);
944 if ($this->has_child) {
945 $childrenArray = array();
946 $this->findAllChildren($id, $childrenArray);
947 if (in_array($parent_folder, $childrenArray)) {
948 return array('status' => "failed", 'message' => "Can not add this folder to its children");
951 // update has_child to 0 for this parent folder if this is the only child it has
952 $q1 = "select count(*) count from folders where deleted = 0 AND parent_folder = '{$this->parent_folder}'";
953 $r1 = $this->db->query($q1);
954 $a1 = $this->db->fetchByAssoc($r1);
955 if ($a1['count'] == 1) {
956 $q1 = "UPDATE folders SET has_child = 0 WHERE id = '{$this->parent_folder}'";
957 $r1 = $this->db->query($q1);
962 $this->parent_folder = $parent_folder;
963 $q2 = "UPDATE folders SET name = '{$this->name}', parent_folder = '{$this->parent_folder}', dynamic_query = '{$this->dynamic_query}', " .
964 "modified_by = '{$current_user->id}' WHERE id = '{$this->id}'";
965 $r2 = $this->db->query($q2);
966 if (!empty($this->parent_folder)) {
967 $q3 = "UPDATE folders SET has_child = 1 WHERE id = '{$this->parent_folder}'";
968 $r3 = $this->db->query($q3);
970 return array('status' => "done");
974 function findAllChildren($folderId, &$childrenArray) {
975 $q = "SELECT * FROM folders WHERE id = '{$folderId}'";
976 $r = $this->db->query($q);
977 $a = $this->db->fetchByAssoc($r);
979 if($a['has_child'] == 1) {
980 $q2 = "SELECT id FROM folders WHERE deleted = 0 AND parent_folder = '{$folderId}'";
981 $r2 = $this->db->query($q2);
983 while($a2 = $this->db->fetchByAssoc($r2)) {
984 $childrenArray[] = $a2['id'];
985 $this->findAllChildren($a2['id'], $childrenArray);
992 * Retrieves and populates object
993 * @param string $id ID of folder
994 * @return bool True on success
996 function retrieve($id) {
997 $q = "SELECT * FROM folders WHERE id = '{$id}' AND deleted = 0";
998 $r = $this->db->query($q);
999 $a = $this->db->fetchByAssoc($r);
1002 foreach($a as $k => $v) {
1003 if($k == 'dynamic_query') {