]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - modules/Schedulers/_AddJobsHere.php
Release 6.5.16
[Github/sugarcrm.git] / modules / Schedulers / _AddJobsHere.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-2013 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  * Set up an array of Jobs with the appropriate metadata
41  * 'jobName' => array (
42  *              'X' => 'name',
43  * )
44  * 'X' should be an increment of 1
45  * 'name' should be the EXACT name of your function
46  *
47  * Your function should not be passed any parameters
48  * Always  return a Boolean. If it does not the Job will not terminate itself
49  * after completion, and the webserver will be forced to time-out that Job instance.
50  * DO NOT USE sugar_cleanup(); in your function flow or includes.  this will
51  * break Schedulers.  That function is called at the foot of cron.php
52  */
53
54 /**
55  * This array provides the Schedulers admin interface with values for its "Job"
56  * dropdown menu.
57  */
58 $job_strings = array (
59         0 => 'refreshJobs',
60         1 => 'pollMonitoredInboxes',
61         2 => 'runMassEmailCampaign',
62     5 => 'pollMonitoredInboxesForBouncedCampaignEmails',
63         3 => 'pruneDatabase',
64         4 => 'trimTracker',
65         /*4 => 'securityAudit()',*/
66     12 => 'sendEmailReminders',
67     14 => 'cleanJobQueue',
68     15 => 'removeDocumentsFromFS',
69     16 => 'trimSugarFeeds',
70
71 );
72
73 /**
74  * Job 0 refreshes all job schedulers at midnight
75  * DEPRECATED
76  */
77 function refreshJobs() {
78         return true;
79 }
80
81
82 /**
83  * Job 1
84  */
85 function pollMonitoredInboxes() {
86
87     $_bck_up = array('team_id' => $GLOBALS['current_user']->team_id, 'team_set_id' => $GLOBALS['current_user']->team_set_id);
88         $GLOBALS['log']->info('----->Scheduler fired job of type pollMonitoredInboxes()');
89         global $dictionary;
90         global $app_strings;
91
92
93         require_once('modules/Emails/EmailUI.php');
94
95         $ie = new InboundEmail();
96         $emailUI = new EmailUI();
97         $r = $ie->db->query('SELECT id, name FROM inbound_email WHERE is_personal = 0 AND deleted=0 AND status=\'Active\' AND mailbox_type != \'bounce\'');
98         $GLOBALS['log']->debug('Just got Result from get all Inbounds of Inbound Emails');
99
100         while($a = $ie->db->fetchByAssoc($r)) {
101                 $GLOBALS['log']->debug('In while loop of Inbound Emails');
102                 $ieX = new InboundEmail();
103                 $ieX->retrieve($a['id']);
104         $GLOBALS['current_user']->team_id = $ieX->team_id;
105         $GLOBALS['current_user']->team_set_id = $ieX->team_set_id;
106                 $mailboxes = $ieX->mailboxarray;
107                 foreach($mailboxes as $mbox) {
108                         $ieX->mailbox = $mbox;
109                         $newMsgs = array();
110                         $msgNoToUIDL = array();
111                         $connectToMailServer = false;
112                         if ($ieX->isPop3Protocol()) {
113                                 $msgNoToUIDL = $ieX->getPop3NewMessagesToDownloadForCron();
114                                 // get all the keys which are msgnos;
115                                 $newMsgs = array_keys($msgNoToUIDL);
116                         }
117                         if($ieX->connectMailserver() == 'true') {
118                                 $connectToMailServer = true;
119                         } // if
120
121                         $GLOBALS['log']->debug('Trying to connect to mailserver for [ '.$a['name'].' ]');
122                         if($connectToMailServer) {
123                                 $GLOBALS['log']->debug('Connected to mailserver');
124                                 if (!$ieX->isPop3Protocol()) {
125                                         $newMsgs = $ieX->getNewMessageIds();
126                                 }
127                                 if(is_array($newMsgs)) {
128                                         $current = 1;
129                                         $total = count($newMsgs);
130                                         require_once("include/SugarFolders/SugarFolders.php");
131                                         $sugarFolder = new SugarFolder();
132                                         $groupFolderId = $ieX->groupfolder_id;
133                                         $isGroupFolderExists = false;
134                                         $users = array();
135                                         if ($groupFolderId != null && $groupFolderId != "") {
136                                                 $sugarFolder->retrieve($groupFolderId);
137                                                 $isGroupFolderExists = true;
138                                         } // if
139                                         $messagesToDelete = array();
140                                         if ($ieX->isMailBoxTypeCreateCase()) {
141                                                 $users[] = $sugarFolder->assign_to_id;
142                                                 $distributionMethod = $ieX->get_stored_options("distrib_method", "");
143                                                 if ($distributionMethod != 'roundRobin') {
144                                                         $counts = $emailUI->getAssignedEmailsCountForUsers($users);
145                                                 } else {
146                                                         $lastRobin = $emailUI->getLastRobin($ieX);
147                                                 }
148                                                 $GLOBALS['log']->debug('distribution method id [ '.$distributionMethod.' ]');
149                                         }
150                                         foreach($newMsgs as $k => $msgNo) {
151                                                 $uid = $msgNo;
152                                                 if ($ieX->isPop3Protocol()) {
153                                                         $uid = $msgNoToUIDL[$msgNo];
154                                                 } else {
155                                                         $uid = imap_uid($ieX->conn, $msgNo);
156                                                 } // else
157                                                 if ($isGroupFolderExists) {
158                                                         if ($ieX->importOneEmail($msgNo, $uid)) {
159                                                                 // add to folder
160                                                                 $sugarFolder->addBean($ieX->email);
161                                                                 if ($ieX->isPop3Protocol()) {
162                                                                         $messagesToDelete[] = $msgNo;
163                                                                 } else {
164                                                                         $messagesToDelete[] = $uid;
165                                                                 }
166                                                                 if ($ieX->isMailBoxTypeCreateCase()) {
167                                                                         $userId = "";
168                                                                         if ($distributionMethod == 'roundRobin') {
169                                                                                 if (sizeof($users) == 1) {
170                                                                                         $userId = $users[0];
171                                                                                         $lastRobin = $users[0];
172                                                                                 } else {
173                                                                                         $userIdsKeys = array_flip($users); // now keys are values
174                                                                                         $thisRobinKey = $userIdsKeys[$lastRobin] + 1;
175                                                                                         if(!empty($users[$thisRobinKey])) {
176                                                                                                 $userId = $users[$thisRobinKey];
177                                                                                                 $lastRobin = $users[$thisRobinKey];
178                                                                                         } else {
179                                                                                                 $userId = $users[0];
180                                                                                                 $lastRobin = $users[0];
181                                                                                         }
182                                                                                 } // else
183                                                                         } else {
184                                                                                 if (sizeof($users) == 1) {
185                                                                                         foreach($users as $k => $value) {
186                                                                                                 $userId = $value;
187                                                                                         } // foreach
188                                                                                 } else {
189                                                                                         asort($counts); // lowest to highest
190                                                                                         $countsKeys = array_flip($counts); // keys now the 'count of items'
191                                                                                         $leastBusy = array_shift($countsKeys); // user id of lowest item count
192                                                                                         $userId = $leastBusy;
193                                                                                         $counts[$leastBusy] = $counts[$leastBusy] + 1;
194                                                                                 }
195                                                                         } // else
196                                                                         $GLOBALS['log']->debug('userId [ '.$userId.' ]');
197                                                                         $ieX->handleCreateCase($ieX->email, $userId);
198                                                                 } // if
199                                                         } // if
200                                                 } else {
201                                                                 if($ieX->isAutoImport()) {
202                                                                         $ieX->importOneEmail($msgNo, $uid);
203                                                                 } else {
204                                                                         /*If the group folder doesn't exist then download only those messages
205                                                                          which has caseid in message*/
206                                                                         $ieX->getMessagesInEmailCache($msgNo, $uid);
207                                                                         $email = new Email();
208                                                                         $header = imap_headerinfo($ieX->conn, $msgNo);
209                                                                         $email->name = $ieX->handleMimeHeaderDecode($header->subject);
210                                                                         $email->from_addr = $ieX->convertImapToSugarEmailAddress($header->from);
211                                                                         $email->reply_to_email  = $ieX->convertImapToSugarEmailAddress($header->reply_to);
212                                                                         if(!empty($email->reply_to_email)) {
213                                                                                 $contactAddr = $email->reply_to_email;
214                                                                         } else {
215                                                                                 $contactAddr = $email->from_addr;
216                                                                         }
217                                                                         $mailBoxType = $ieX->mailbox_type;
218                                                                                 $ieX->handleAutoresponse($email, $contactAddr);
219                                                                 } // else
220                                                 } // else
221                                                 $GLOBALS['log']->debug('***** On message [ '.$current.' of '.$total.' ] *****');
222                                                 $current++;
223                                         } // foreach
224                                         // update Inbound Account with last robin
225                                         if ($ieX->isMailBoxTypeCreateCase() && $distributionMethod == 'roundRobin') {
226                                                 $emailUI->setLastRobin($ieX, $lastRobin);
227                                         } // if
228
229                                 } // if
230                                 if ($isGroupFolderExists)        {
231                                         $leaveMessagesOnMailServer = $ieX->get_stored_options("leaveMessagesOnMailServer", 0);
232                                         if (!$leaveMessagesOnMailServer) {
233                                                 if ($ieX->isPop3Protocol()) {
234                                                         $ieX->deleteMessageOnMailServerForPop3(implode(",", $messagesToDelete));
235                                                 } else {
236                                                         $ieX->deleteMessageOnMailServer(implode($app_strings['LBL_EMAIL_DELIMITER'], $messagesToDelete));
237                                                 }
238                                         }
239                                 }
240                         } else {
241                                 $GLOBALS['log']->fatal("SCHEDULERS: could not get an IMAP connection resource for ID [ {$a['id']} ]. Skipping mailbox [ {$a['name']} ].");
242                                 // cn: bug 9171 - continue while
243                         } // else
244                 } // foreach
245                 imap_expunge($ieX->conn);
246                 imap_close($ieX->conn, CL_EXPUNGE);
247         } // while
248     $GLOBALS['current_user']->team_id = $_bck_up['team_id'];
249     $GLOBALS['current_user']->team_set_id = $_bck_up['team_set_id'];
250         return true;
251 }
252
253 /**
254  * Job 2
255  */
256 function runMassEmailCampaign() {
257         if (!class_exists('LoggerManager')){
258
259         }
260         $GLOBALS['log'] = LoggerManager::getLogger('emailmandelivery');
261         $GLOBALS['log']->debug('Called:runMassEmailCampaign');
262
263         if (!class_exists('DBManagerFactory')){
264                 require('include/database/DBManagerFactory.php');
265         }
266
267         global $beanList;
268         global $beanFiles;
269         require("config.php");
270         require('include/modules.php');
271         if(!class_exists('AclController')) {
272                 require('modules/ACL/ACLController.php');
273         }
274
275         require('modules/EmailMan/EmailManDelivery.php');
276         return true;
277 }
278
279 /**
280  *  Job 3
281  */
282 function pruneDatabase() {
283         $GLOBALS['log']->info('----->Scheduler fired job of type pruneDatabase()');
284         $backupDir      = sugar_cached('backups');
285         $backupFile     = 'backup-pruneDatabase-GMT0_'.gmdate('Y_m_d-H_i_s', strtotime('now')).'.php';
286
287         $db = DBManagerFactory::getInstance();
288         $tables = $db->getTablesArray();
289     $queryString = array();
290
291         if(!empty($tables)) {
292                 foreach($tables as $kTable => $table) {
293                         // find tables with deleted=1
294                         $columns = $db->get_columns($table);
295                         // no deleted - won't delete
296                         if(empty($columns['deleted'])) continue;
297
298                         $custom_columns = array();
299                         if(array_search($table.'_cstm', $tables)) {
300                             $custom_columns = $db->get_columns($table.'_cstm');
301                             if(empty($custom_columns['id_c'])) {
302                                 $custom_columns = array();
303                             }
304                         }
305
306                         $qDel = "SELECT * FROM $table WHERE deleted = 1";
307                         $rDel = $db->query($qDel);
308
309                         // make a backup INSERT query if we are deleting.
310                         while($aDel = $db->fetchByAssoc($rDel, false)) {
311                                 // build column names
312
313                                 $queryString[] = $db->insertParams($table, $columns, $aDel, null, false);
314
315                                 if(!empty($custom_columns) && !empty($aDel['id'])) {
316                     $qDelCstm = 'SELECT * FROM '.$table.'_cstm WHERE id_c = '.$db->quoted($aDel['id']);
317                     $rDelCstm = $db->query($qDelCstm);
318
319                     // make a backup INSERT query if we are deleting.
320                     while($aDelCstm = $db->fetchByAssoc($rDelCstm)) {
321                         $queryString[] = $db->insertParams($table, $custom_columns, $aDelCstm, null, false);
322                     } // end aDel while()
323
324                     $db->query('DELETE FROM '.$table.'_cstm WHERE id_c = '.$db->quoted($aDel['id']));
325                 }
326                         } // end aDel while()
327                         // now do the actual delete
328                         $db->query('DELETE FROM '.$table.' WHERE deleted = 1');
329                 } // foreach() tables
330
331                 if(!file_exists($backupDir) || !file_exists($backupDir.'/'.$backupFile)) {
332                         // create directory if not existent
333                         mkdir_recursive($backupDir, false);
334                 }
335                 // write cache file
336
337                 write_array_to_file('pruneDatabase', $queryString, $backupDir.'/'.$backupFile);
338                 return true;
339         }
340         return false;
341 }
342
343
344 ///**
345 // * Job 4
346 // */
347
348 //function securityAudit() {
349 //      // do something
350 //      return true;
351 //}
352
353 function trimTracker()
354 {
355     global $sugar_config, $timedate;
356         $GLOBALS['log']->info('----->Scheduler fired job of type trimTracker()');
357         $db = DBManagerFactory::getInstance();
358
359         $admin = new Administration();
360         $admin->retrieveSettings('tracker');
361         require('modules/Trackers/config.php');
362         $trackerConfig = $tracker_config;
363
364     require_once('include/utils/db_utils.php');
365     $prune_interval = !empty($admin->settings['tracker_prune_interval']) ? $admin->settings['tracker_prune_interval'] : 30;
366         foreach($trackerConfig as $tableName=>$tableConfig) {
367
368                 //Skip if table does not exist
369                 if(!$db->tableExists($tableName)) {
370                    continue;
371                 }
372
373             $timeStamp = db_convert("'". $timedate->asDb($timedate->getNow()->get("-".$prune_interval." days")) ."'" ,"datetime");
374                 if($tableName == 'tracker_sessions') {
375                    $query = "DELETE FROM $tableName WHERE date_end < $timeStamp";
376                 } else {
377                    $query = "DELETE FROM $tableName WHERE date_modified < $timeStamp";
378                 }
379
380             $GLOBALS['log']->info("----->Scheduler is about to trim the $tableName table by running the query $query");
381                 $db->query($query);
382         } //foreach
383     return true;
384 }
385
386 /* Job 5
387  *
388  */
389 function pollMonitoredInboxesForBouncedCampaignEmails() {
390         $GLOBALS['log']->info('----->Scheduler job of type pollMonitoredInboxesForBouncedCampaignEmails()');
391         global $dictionary;
392
393
394         $ie = new InboundEmail();
395         $r = $ie->db->query('SELECT id FROM inbound_email WHERE deleted=0 AND status=\'Active\' AND mailbox_type=\'bounce\'');
396
397         while($a = $ie->db->fetchByAssoc($r)) {
398                 $ieX = new InboundEmail();
399                 $ieX->retrieve($a['id']);
400                 $ieX->connectMailserver();
401         $ieX->importMessages();
402         }
403
404         return true;
405 }
406
407
408
409
410 /**
411  * Job 12
412  */
413 function sendEmailReminders(){
414         $GLOBALS['log']->info('----->Scheduler fired job of type sendEmailReminders()');
415         require_once("modules/Activities/EmailReminder.php");
416         $reminder = new EmailReminder();
417         return $reminder->process();
418 }
419
420 function removeDocumentsFromFS()
421 {
422     $GLOBALS['log']->info('Starting removal of documents if they are not present in DB');
423
424     /**
425      * @var DBManager $db
426      * @var SugarBean $bean
427      */
428     global $db;
429
430     // temp table to store id of files without memory leak
431     $tableName = 'cron_remove_documents';
432
433     $resource = $db->limitQuery("SELECT * FROM cron_remove_documents WHERE 1=1 ORDER BY date_modified ASC", 0, 100);
434     $return = true;
435     while ($row = $db->fetchByAssoc($resource)) {
436         $bean = BeanFactory::getBean($row['module']);
437         $bean->retrieve($row['bean_id'], true, false);
438         if (empty($bean->id)) {
439             $isSuccess = true;
440             $bean->id = $row['bean_id'];
441             $directory = $bean->deleteFileDirectory();
442             if (!empty($directory) && is_dir('upload://deleted/' . $directory)) {
443                 if ($isSuccess = rmdir_recursive('upload://deleted/' . $directory)) {
444                     $directory = explode('/', $directory);
445                     while (!empty($directory)) {
446                         $path = 'upload://deleted/' . implode('/', $directory);
447                         if (is_dir($path)) {
448                             $directoryIterator = new DirectoryIterator($path);
449                             $empty = true;
450                             foreach ($directoryIterator as $item) {
451                                 if ($item->getFilename() == '.' || $item->getFilename() == '..') {
452                                     continue;
453                                 }
454                                 $empty = false;
455                                 break;
456                             }
457                             if ($empty) {
458                                 rmdir($path);
459                             }
460                         }
461                         array_pop($directory);
462                     }
463                 }
464             }
465             if ($isSuccess) {
466                 $db->query('DELETE FROM ' . $tableName . ' WHERE id=' . $db->quoted($row['id']));
467             } else {
468                 $return = false;
469             }
470         } else {
471             $db->query('UPDATE ' . $tableName . ' SET date_modified=' . $db->convert($db->quoted(TimeDate::getInstance()->nowDb()), 'datetime') . ' WHERE id=' . $db->quoted($row['id']));
472         }
473     }
474
475     return $return;
476 }
477
478
479 /**
480 + * Job 16
481 + * this will trim all records in sugarfeeds table that are older than 30 days or specified interval
482 + */
483
484 function trimSugarFeeds()
485 {
486     global $sugar_config, $timedate;
487     $GLOBALS['log']->info('----->Scheduler fired job of type trimSugarFeeds()');
488     $db = DBManagerFactory::getInstance();
489
490     //get the pruning interval from globals if it's specified
491     $prune_interval = !empty($GLOBALS['sugar_config']['sugarfeed_prune_interval']) && is_numeric($GLOBALS['sugar_config']['sugarfeed_prune_interval']) ? $GLOBALS['sugar_config']['sugarfeed_prune_interval'] : 30;
492
493
494     //create and run the query to delete the records
495     $timeStamp = $db->convert("'". $timedate->asDb($timedate->getNow()->get("-".$prune_interval." days")) ."'" ,"datetime");
496     $query = "DELETE FROM sugarfeed WHERE date_modified < $timeStamp";
497
498
499     $GLOBALS['log']->info("----->Scheduler is about to trim the sugarfeed table by running the query $query");
500     $db->query($query);
501
502     return true;
503 }
504
505
506
507 function cleanJobQueue($job)
508 {
509     $td = TimeDate::getInstance();
510     // soft delete all jobs that are older than cutoff
511     $soft_cutoff = 7;
512     if(isset($GLOBALS['sugar_config']['jobs']['soft_lifetime'])) {
513         $soft_cutoff = $GLOBALS['sugar_config']['jobs']['soft_lifetime'];
514     }
515     $soft_cutoff_date = $job->db->quoted($td->getNow()->modify("- $soft_cutoff days")->asDb());
516     $job->db->query("UPDATE {$job->table_name} SET deleted=1 WHERE status='done' AND date_modified < ".$job->db->convert($soft_cutoff_date, 'datetime'));
517     // hard delete all jobs that are older than hard cutoff
518     $hard_cutoff = 21;
519     if(isset($GLOBALS['sugar_config']['jobs']['hard_lifetime'])) {
520         $hard_cutoff = $GLOBALS['sugar_config']['jobs']['hard_lifetime'];
521     }
522     $hard_cutoff_date = $job->db->quoted($td->getNow()->modify("- $hard_cutoff days")->asDb());
523     $job->db->query("DELETE FROM {$job->table_name} WHERE status='done' AND date_modified < ".$job->db->convert($hard_cutoff_date, 'datetime'));
524     return true;
525 }
526
527 if (file_exists('custom/modules/Schedulers/_AddJobsHere.php')) {
528         require('custom/modules/Schedulers/_AddJobsHere.php');
529 }
530
531 if (file_exists('custom/modules/Schedulers/Ext/ScheduledTasks/scheduledtasks.ext.php'))
532 {
533         require('custom/modules/Schedulers/Ext/ScheduledTasks/scheduledtasks.ext.php');
534 }
535 ?>