]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - modules/SugarFeed/SugarFeed.php
Release 6.4.0
[Github/sugarcrm.git] / modules / SugarFeed / SugarFeed.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 class SugarFeed extends Basic {
40         var $new_schema = true;
41         var $module_dir = 'SugarFeed';
42         var $object_name = 'SugarFeed';
43         var $table_name = 'sugarfeed';
44         var $importable = false;
45
46                 var $id;
47                 var $name;
48                 var $date_entered;
49                 var $date_modified;
50                 var $modified_user_id;
51                 var $modified_by_name;
52                 var $created_by;
53                 var $created_by_name;
54                 var $description;
55                 var $deleted;
56                 var $created_by_link;
57                 var $modified_user_link;
58                 var $assigned_user_id;
59                 var $assigned_user_name;
60                 var $assigned_user_link;
61
62         function SugarFeed(){
63                 parent::Basic();
64         }
65
66     static function activateModuleFeed( $module, $updateDB = true ) {
67         if ( $module != 'UserFeed' ) {
68             // UserFeed is a fake module, used for the user postings to the feed
69             // Don't try to load up any classes for it
70             $fileList = SugarFeed::getModuleFeedFiles($module);
71
72             foreach ( $fileList as $fileName ) {
73                 $feedClass = substr(basename($fileName),0,-4);
74
75                 require_once($fileName);
76                 $tmpClass = new $feedClass();
77                 $tmpClass->installHook($fileName,$feedClass);
78             }
79         }
80         if ( $updateDB == true ) {
81
82             $admin = new Administration();
83             $admin->saveSetting('sugarfeed','module_'.$admin->db->quote($module),'1');
84         }
85     }
86
87     static function disableModuleFeed( $module, $updateDB = true ) {
88         if ( $module != 'UserFeed' ) {
89             // UserFeed is a fake module, used for the user postings to the feed
90             // Don't try to load up any classes for it
91             $fileList = SugarFeed::getModuleFeedFiles($module);
92
93             foreach ( $fileList as $fileName ) {
94                 $feedClass = substr(basename($fileName),0,-4);
95
96                 require_once($fileName);
97                 $tmpClass = new $feedClass();
98                 $tmpClass->removeHook($fileName,$feedClass);
99             }
100         }
101
102         if ( $updateDB == true ) {
103
104             $admin = new Administration();
105             $admin->saveSetting('sugarfeed','module_'.$admin->db->quote($module),'0');
106         }
107     }
108
109     static function flushBackendCache( ) {
110         // This function will flush the cache files used for the module list and the link type lists
111         sugar_cache_clear('SugarFeedModules');
112         if ( file_exists($cachefile = sugar_cached('modules/SugarFeed/moduleCache.php'))) {
113             unlink($cachefile);
114         }
115
116         sugar_cache_clear('SugarFeedLinkType');
117         if ( file_exists($cachefile = sugar_cached('modules/SugarFeed/linkTypeCache.php'))) {
118             unlink($cachefile);
119         }
120     }
121
122
123     static function getModuleFeedFiles( $module ) {
124         $baseDirList = array('modules/'.$module.'/SugarFeeds/', 'custom/modules/'.$module.'/SugarFeeds/');
125
126         // We store the files in a list sorted by the filename so you can override a default feed by
127         // putting your replacement feed in the custom directory with the same filename
128         $fileList = array();
129
130         foreach ( $baseDirList as $baseDir ) {
131             if ( ! file_exists($baseDir) ) {
132                 continue;
133             }
134             $d = dir($baseDir);
135             while ( $file = $d->read() ) {
136                 if ( $file{0} == '.' ) { continue; }
137                 if ( substr($file,-4) == '.php' ) {
138                     // We found one
139                     $fileList[$file] = $baseDir.$file;
140                 }
141             }
142         }
143
144         return($fileList);
145     }
146
147     static function getActiveFeedModules( ) {
148         // Stored in a cache somewhere
149         $feedModules = sugar_cache_retrieve('SugarFeedModules');
150         if ( $feedModules != null ) {
151             return($feedModules);
152         }
153
154         // Already stored in a file
155         if ( file_exists($cachefile = sugar_cached('modules/SugarFeed/moduleCache.php'))) {
156             require_once($cachefile);
157             sugar_cache_put('SugarFeedModules',$feedModules);
158             return $feedModules;
159         }
160
161         // Gotta go looking for it
162
163         $admin = new Administration();
164         $admin->retrieveSettings();
165
166         $feedModules = array();
167         if ( isset($admin->settings['sugarfeed_enabled']) && $admin->settings['sugarfeed_enabled'] == '1' ) {
168             // Only enable modules if the feed system is enabled
169             foreach ( $admin->settings as $key => $value ) {
170                 if ( strncmp($key,'sugarfeed_module_',17) === 0 ) {
171                     // It's a module setting
172                     if ( $value == '1' ) {
173                         $moduleName = substr($key,17);
174                         $feedModules[$moduleName] = $moduleName;
175                     }
176                 }
177             }
178         }
179
180
181         sugar_cache_put('SugarFeedModules',$feedModules);
182         if ( ! file_exists($cachedir = sugar_cached('modules/SugarFeed')))  {
183             mkdir_recursive($cachedir);
184         }
185         $fd = fopen("$cachedir/moduleCache.php",'w');
186         fwrite($fd,'<'."?php\n\n".'$feedModules = '.var_export($feedModules,true).';');
187         fclose($fd);
188
189         return $feedModules;
190     }
191
192     static function getAllFeedModules( ) {
193         // Uncached, only used from the admin panel and during installation currently
194         $feedModules = array('UserFeed'=>'UserFeed');
195
196         $baseDirList = array('modules/', 'custom/modules/');
197         foreach ( $baseDirList as $baseDir ) {
198             if ( ! file_exists($baseDir) ) {
199                 continue;
200             }
201             $d = dir($baseDir);
202             while ( $module = $d->read() ) {
203                 if ( file_exists($baseDir.$module.'/SugarFeeds/') ) {
204                     $dFeed = dir($baseDir.$module.'/SugarFeeds/');
205                     while ( $file = $dFeed->read() ) {
206                         if ( $file{0} == '.' ) { continue; }
207                         if ( substr($file,-4) == '.php' ) {
208                             // We found one
209                             $feedModules[$module] = $module;
210                         }
211                     }
212                 }
213             }
214         }
215
216         return($feedModules);
217     }
218
219     /**
220      * pushFeed2
221      * This method is a wrapper to pushFeed
222      *
223      * @param $text String value of the feed's description
224      * @param $bean The SugarBean that is triggering the feed
225      * @param $link_type boolean value indicating whether or not feed is a link type
226      * @param $link_url String value of the URL (for link types only)
227      */
228     static function pushFeed2($text, $bean, $link_type=false, $link_url=false) {
229             self::pushFeed($text, $bean->module_dir, $bean->id
230                                                                 ,$bean->assigned_user_id
231                                                                 ,$link_type
232                                                                 ,$link_url
233             );
234     }
235
236         static function pushFeed($text, $module, $id,
237                 $record_assigned_user_id=false,
238                 $link_type=false,
239                 $link_url=false
240                 ) {
241                 $feed = new SugarFeed();
242                 if((empty($text) && empty($link_url)) || !$feed->ACLAccess('save', true) )
243                 {
244                         $GLOBALS['log']->error('Unable to save SugarFeed record (missing data or no ACL access)');
245                         return;
246                 }
247                 
248                 if(!empty($link_url)){
249             $linkClass = SugarFeed::getLinkClass($link_type);
250             if ( $linkClass !== FALSE ) {
251                 $linkClass->handleInput($feed,$link_type,$link_url);
252             }
253         }
254         $text = strip_tags(from_html($text));
255                 $text = '<b>{this.CREATED_BY}</b> ' . $text;
256                 $feed->name = substr($text, 0, 255);
257                 if(strlen($text) > 255){
258                         $feed->description = substr($text, 255, 510);
259                 }
260
261                 if ( $record_assigned_user_id === false ) {
262                         $feed->assigned_user_id = $GLOBALS['current_user']->id;
263                 } else {
264                         $feed->assigned_user_id = $record_assigned_user_id;
265                 }
266                 $feed->related_id = $id;
267                 $feed->related_module = $module;
268                 $feed->save();
269         }
270
271     static function getLinkTypes() {
272         static $linkTypeList = null;
273
274         // Fastest, already stored in the static variable
275         if ( $linkTypeList != null ) {
276             return $linkTypeList;
277         }
278
279         // Second fastest, stored in a cache somewhere
280         $linkTypeList = sugar_cache_retrieve('SugarFeedLinkType');
281         if ( $linkTypeList != null ) {
282             return($linkTypeList);
283         }
284
285         // Third fastest, already stored in a file
286         if ( file_exists($cachedfile = sugar_cached('modules/SugarFeed/linkTypeCache.php'))) {
287             require_once($cachedfile);
288             sugar_cache_put('SugarFeedLinkType',$linkTypeList);
289             return $linkTypeList;
290         }
291
292         // Slow, have to actually collect the data
293         $baseDirs = array('custom/modules/SugarFeed/linkHandlers/','modules/SugarFeed/linkHandlers');
294
295         $linkTypeList = array();
296
297         foreach ( $baseDirs as $dirName ) {
298             if ( !file_exists($dirName) ) { continue; }
299             $d = dir($dirName);
300             while ( $file = $d->read() ) {
301                 if ( $file{0} == '.' ) { continue; }
302                 if ( substr($file,-4) == '.php' ) {
303                     // We found one
304                     $typeName = substr($file,0,-4);
305                     $linkTypeList[$typeName] = $typeName;
306                 }
307             }
308         }
309
310         sugar_cache_put('SugarFeedLinkType',$linkTypeList);
311         if ( ! file_exists($cachedir = sugar_cached('modules/SugarFeed')) ) {
312             mkdir_recursive($cachedir);
313         }
314         $fd = fopen("$cachedir/linkTypeCache.php",'w');
315         fwrite($fd,'<'."?php\n\n".'$linkTypeList = '.var_export($linkTypeList,true).';');
316         fclose($fd);
317
318         return $linkTypeList;
319     }
320
321     static function getLinkClass( $linkName ) {
322         $linkTypeList = SugarFeed::getLinkTypes();
323
324         // Have to make sure the linkName is on the list, so they can't pass in linkName's like ../../config.php ... not that they could get anywhere if they did
325         if ( ! isset($linkTypeList[$linkName]) ) {
326             // No class by this name...
327             return FALSE;
328         }
329
330         if ( file_exists('custom/modules/SugarFeed/linkHandlers/'.$linkName.'.php') ) {
331             require_once('custom/modules/SugarFeed/linkHandlers/'.$linkName.'.php');
332         } else {
333             require_once('modules/SugarFeed/linkHandlers/'.$linkName.'.php');
334         }
335
336         $linkClassName = 'FeedLinkHandler'.$linkName;
337
338         $linkClass = new $linkClassName();
339
340         return($linkClass);
341     }
342
343         function get_list_view_data(){
344                 $data = parent::get_list_view_data();
345                 $delete = '';
346                 if (ACLController::moduleSupportsACL($data['RELATED_MODULE']) && !ACLController::checkAccess($data['RELATED_MODULE'], 'view', $data['CREATED_BY'] == $GLOBALS['current_user']->id) && !ACLController::checkAccess($data['RELATED_MODULE'], 'list', $data['CREATED_BY'] == $GLOBALS['current_user']->id)){
347                         $data['NAME'] = '';
348                         return $data;
349                 }
350         if(is_admin($GLOBALS['current_user']) || (isset($data['CREATED_BY']) && $data['CREATED_BY'] == $GLOBALS['current_user']->id) ) {
351             $delete = ' - <a id="sugarFeedDeleteLink'.$data['ID'].'" href="#" onclick=\'SugarFeed.deleteFeed("'. $data['ID'] . '", "{this.id}"); return false;\'>'. $GLOBALS['app_strings']['LBL_DELETE_BUTTON_LABEL'].'</a>';
352         }
353                 $data['NAME'] .= $data['DESCRIPTION'];
354                 $data['NAME'] =  '<div style="padding:3px">' . html_entity_decode($data['NAME']);
355                 if(!empty($data['LINK_URL'])){
356             $linkClass = SugarFeed::getLinkClass($data['LINK_TYPE']);
357             if ( $linkClass !== FALSE ) {
358                 $data['NAME'] .= $linkClass->getDisplay($data);
359             }
360                 }
361         $data['NAME'] .= '<div class="byLineBox"><span class="byLineLeft">';
362                 $data['NAME'] .= $this->getTimeLapse($data['DATE_ENTERED']) . '&nbsp;</span><div class="byLineRight"><a id="sugarFeedReplyLink'.$data['ID'].'" href="#" onclick=\'SugarFeed.buildReplyForm("'.$data['ID'].'", "{this.id}", this); return false;\'>'.$GLOBALS['app_strings']['LBL_EMAIL_REPLY'].'</a>' .$delete. '</div></div>';
363
364         $data['NAME'] .= $this->fetchReplies($data);
365                 return  $data ;
366         }
367
368     function fetchReplies($data) {
369         $seedBean = new SugarFeed;
370
371         $replies = $seedBean->get_list('date_entered',"related_module = 'SugarFeed' AND related_id = '".$data['ID']."'");
372
373         if ( count($replies['list']) < 1 ) {
374             return '';
375         }
376
377
378         $replyHTML = '<div class="clear"></div><blockquote>';
379
380         foreach ( $replies['list'] as $reply ) {
381             // Setup the delete link
382             $delete = '';
383             if(is_admin($GLOBALS['current_user']) || $data['CREATED_BY'] == $GLOBALS['current_user']->id) {
384                 $delete = '<a id="sugarFieldDeleteLink'.$reply->id.'" href="#" onclick=\'SugarFeed.deleteFeed("'. $reply->id . '", "{this.id}"); return false;\'>'. $GLOBALS['app_strings']['LBL_DELETE_BUTTON_LABEL'].'</a>';
385             }
386
387             $image_url = 'include/images/default_user_feed_picture.png';
388             if ( isset($reply->created_by) ) {
389                 $user = loadBean('Users');
390                 $user->retrieve($reply->created_by);
391                 if ( !empty($user->picture) ) {
392                     $image_url = 'index.php?entryPoint=download&id='.$user->picture.'&type=SugarFieldImage&isTempFile=1';
393                 }
394             }
395             $replyHTML .= '<div style="float: left; margin-right: 3px; width: 50px; height: 50px;"><!--not_in_theme!--><img src="'.$image_url.'" style="max-width: 50px; max-height: 50px;"></div> ';
396             $replyHTML .= str_replace("{this.CREATED_BY}",get_assigned_user_name($reply->created_by),html_entity_decode($reply->name)).'<br>';
397             $replyHTML .= '<div class="byLineBox"><span class="byLineLeft">'. $this->getTimeLapse($reply->date_entered) . '&nbsp;</span><div class="byLineRight">  &nbsp;' .$delete. '</div></div><div class="clear"></div>';
398         }
399
400         $replyHTML .= '</blockquote>';
401         return $replyHTML;
402
403     }
404
405         static function getTimeLapse($startDate)
406         {
407                 $seconds = $GLOBALS['timedate']->getNow()->ts - $GLOBALS['timedate']->fromUser($startDate)->ts;
408                 $minutes =   $seconds/60;
409                 $seconds = $seconds % 60;
410                 $hours = floor( $minutes / 60);
411                 $minutes = $minutes % 60;
412                 $days = floor( $hours / 24);
413                 $hours = $hours % 24;
414                 $weeks = floor( $days / 7);
415                 $days = $days % 7;
416                 $result = '';
417                 if($weeks == 1){
418                         $result = translate('LBL_TIME_LAST_WEEK','SugarFeed').' ';
419                         return $result;
420                 }else if($weeks > 1){
421                         $result .= $weeks . ' '.translate('LBL_TIME_WEEKS','SugarFeed').' ';
422                         if($days > 0) {
423                 $result .= $days . ' '.translate('LBL_TIME_DAYS','SugarFeed').' ';
424             }
425                 }else{
426                         if($days == 1){
427                                 $result = translate('LBL_TIME_YESTERDAY','SugarFeed').' ';
428                                 return $result;
429                         }else if($days > 1){
430                                 $result .= $days . ' '. translate('LBL_TIME_DAYS','SugarFeed').' ';
431                         }else{
432                                 if($hours == 1) {
433                     $result .= $hours . ' '.translate('LBL_TIME_HOUR','SugarFeed').' ';
434                 } else {
435                     $result .= $hours . ' '.translate('LBL_TIME_HOURS','SugarFeed').' ';
436                 }
437                                 if($hours < 6){
438                                         if($minutes == 1) {
439                         $result .= $minutes . ' ' . translate('LBL_TIME_MINUTE','SugarFeed'). ' ';
440                     } else {
441                         $result .= $minutes . ' ' . translate('LBL_TIME_MINUTES','SugarFeed'). ' ';
442                     }
443                                 }
444                                 if($hours == 0 && $minutes == 0) {
445                     if($seconds == 1 ) {
446                         $result = $seconds . ' ' . translate('LBL_TIME_SECOND','SugarFeed');
447                     } else {
448                         $result = $seconds . ' ' . translate('LBL_TIME_SECONDS','SugarFeed');
449                     }
450                 }
451                         }
452                 }
453                 return $result . ' ' . translate('LBL_TIME_AGO','SugarFeed');
454     }
455
456     /**
457      * Parse a piece of text and replace with proper display tags.
458      * @static
459      * @param  $input
460      * @return void
461      */
462     public static function parseMessage($input){
463         $urls = getUrls($input);
464         foreach($urls as $url){
465                         $output = "<a href='$url' target='_blank'>".$url."</a>";
466                         $input = str_replace($url, $output, $input);
467                 }
468                 return $input;
469     }
470
471
472 }