]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/externalAPI/ExternalAPIFactory.php
Release 6.4.0
[Github/sugarcrm.git] / include / externalAPI / ExternalAPIFactory.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 require_once('include/connectors/utils/ConnectorUtils.php');
40 require_once('include/connectors/sources/SourceFactory.php');
41 /**
42  * Provides a factory to list, discover and create external API calls
43  *
44  * Main features are to list available external API's by supported features, modules and which ones have access for the user.
45  * @api
46  */
47 class ExternalAPIFactory
48 {
49     /**
50      * Filter the list of APIs, removing disabled ones
51      * @param array $apiFullList
52      * @return array Filtered list
53      */
54     public static function filterAPIList($apiFullList)
55     {
56         $filteredList = array();
57         foreach($apiFullList as $name => $data) {
58             if(isset($data['connector'])) {
59                 if(ConnectorUtils::eapmEnabled($data['connector'])) {
60                      if(isset($data['authMethod']) && $data['authMethod'] == 'oauth'){
61                         $connector = SourceFactory::getSource($data['connector'], false);
62                         if(!empty($connector) && $connector->propertyExists('oauth_consumer_key')
63                             && $connector->propertyExists('oauth_consumer_secret')) {
64                                 $filteredList[$name] = $data;
65                         }
66                      }else{
67                         $filteredList[$name] = $data;
68                      }
69                 }
70             }else {
71                 $filteredList[$name] = $data;
72             }
73         }
74         return $filteredList;
75     }
76
77     /**
78      * Get the list of available APIs
79      * @param bool $forceRebuild
80      * @param bool $ignoreDisabled Should we ignore disabled status?
81      * @return array
82      */
83     public static function loadFullAPIList($forceRebuild=false, $ignoreDisabled = false) {
84         if ( isset($GLOBALS['sugar_config']['developerMode']) && $GLOBALS['sugar_config']['developerMode'] ) {
85             static $beenHereBefore = false;
86             if ( !$beenHereBefore ) {
87                 $forceRebuild = true;
88                 $beenHereBefore = true;
89             }
90         }
91         $cached=sugar_cached('include/externalAPI.cache.php');
92         if (!$forceRebuild && file_exists($cached) ) {
93             // Already have a cache file built, no need to rebuild
94             require $cached;
95
96             return $ignoreDisabled?$fullAPIList:self::filterAPIList($fullAPIList);
97         }
98
99         $apiFullList = array();
100         $meetingPasswordList = array();
101         $needUrlList = array();
102
103         $baseDirList = array('include/externalAPI/','custom/include/externalAPI/');
104         foreach ( $baseDirList as $baseDir ) {
105             $dirList = glob($baseDir.'*',GLOB_ONLYDIR);
106             foreach($dirList as $dir) {
107                 if ( $dir == $baseDir.'.' || $dir == $baseDir.'..' || $dir == $baseDir.'Base' ) {
108                     continue;
109                 }
110
111                 $apiName = str_replace($baseDir,'',$dir);
112                 if ( file_exists($dir.'/ExtAPI'.$apiName.'.php') ) {
113                     $apiFullList[$apiName]['className'] = 'ExtAPI'.$apiName;
114                     $apiFullList[$apiName]['file'] = $dir.'/'.$apiFullList[$apiName]['className'].'.php';
115                 }
116                 if ( file_exists($dir.'/ExtAPI'.$apiName.'_cstm.php') ) {
117                     $apiFullList[$apiName]['className'] = 'ExtAPI'.$apiName.'_cstm';
118                     $apiFullList[$apiName]['file_cstm'] = $dir.'/'.$apiFullList[$apiName]['className'].'.php';
119                 }
120             }
121         }
122
123         $optionList = array('supportedModules','useAuth','requireAuth','supportMeetingPassword','docSearch', 'authMethod', 'oauthFixed','needsUrl','canInvite','sendsInvites','sharingOptions','connector', 'oauthParams','restrictUploadsByExtension');
124         foreach ( $apiFullList as $apiName => $apiOpts ) {
125             require_once($apiOpts['file']);
126             if ( !empty($apiOpts['file_cstm']) ) {
127                 require_once($apiOpts['file_cstm']);
128             }
129             $className = $apiOpts['className'];
130             $apiClass = new $className();
131             foreach ( $optionList as $opt ) {
132                 if ( isset($apiClass->$opt) ) {
133                     $apiFullList[$apiName][$opt] = $apiClass->$opt;
134                 }
135             }
136
137             // Special handling for the show/hide of the Meeting Password field, we need to create a dropdown for the Sugar Logic code.
138             if ( isset($apiClass->supportMeetingPassword) && $apiClass->supportMeetingPassword == true ) {
139                 $meetingPasswordList[$apiName] = $apiName;
140             }
141
142         }
143
144         create_cache_directory('/include/');
145         $cached_tmp = sugar_cached('include/externalAPI.cache-tmp.php');
146         $fd = fopen($cached_tmp,'w');
147         fwrite($fd,"<"."?php\n//This file is auto generated by ".__FILE__."\n\$fullAPIList = ".var_export($apiFullList,true).";\n\n");
148         fclose($fd);
149         rename($cached_tmp, $cached);
150
151         $fd = fopen(sugar_cached('include/externalAPI.cache-tmp.js'),'w');
152         fwrite($fd,"//This file is auto generated by ".__FILE__."\nSUGAR.eapm = ".json_encode($apiFullList).";\n\n");
153         fclose($fd);
154         rename(sugar_cached('include/externalAPI.cache-tmp.js'),sugar_cached('include/externalAPI.cache.js'));
155
156
157         if (!isset($GLOBALS['app_list_strings']['extapi_meeting_password']) || (is_array($GLOBALS['app_list_strings']['extapi_meeting_password']) && count(array_diff($meetingPasswordList,$GLOBALS['app_list_strings']['extapi_meeting_password'])) != 0 )) {
158             // Our meeting password list is different... we need to do something about this.
159             require_once('modules/Administration/Common.php');
160             $languages = get_languages();
161             foreach( $languages as $lang => $langLabel ) {
162                 $contents = return_custom_app_list_strings_file_contents($lang);
163                 $new_contents = replace_or_add_dropdown_type('extapi_meeting_password', $meetingPasswordList, $contents);
164                 save_custom_app_list_strings_contents($new_contents, $lang);
165             }
166         }
167
168         return $ignoreDisabled?$apiFullList:self::filterAPIList($apiFullList);
169     }
170
171         /**
172         * Clear API cache file
173         */
174     public static function clearCache() {
175         $cached=sugar_cached('include/externalAPI.cache.php');
176         if ( file_exists($cached) ) {
177             unlink($cached);
178         }
179         $cached=sugar_cached('include/externalAPI.cache.js');
180         if ( file_exists($cached) ) {
181             unlink($cached);
182         }
183     }
184
185
186     /**
187      * This will hand back an initialized class for the requested external API, it will also load in the external API password information into the bean.
188      * @param string $apiName The name of the requested API ( known API's can be listed by the listAPI() call )
189      * @param bool $apiName Ignore authentication requirements (optional)
190      * @return ExternalAPIBase API plugin
191      */
192     public static function loadAPI($apiName, $ignoreAuth=false)
193     {
194         $apiList = self::loadFullAPIList();
195         if ( ! isset($apiList[$apiName]) ) {
196             return false;
197         }
198
199         $myApi = $apiList[$apiName];
200         require_once($myApi['file']);
201         if ( !empty($myApi['file_cstm']) ) {
202             require_once($myApi['file_cstm']);
203         }
204
205         $apiClassName = $myApi['className'];
206
207         $apiClass = new $apiClassName();
208         if ($ignoreAuth) {
209             return $apiClass;
210         }
211
212         if ($myApi['useAuth']) {
213             $eapmBean = EAPM::getLoginInfo($apiName);
214
215             if (!isset($eapmBean->application) && $myApi['requireAuth']) {
216                 // We need authentication, and they don't have it, don't load the API
217                 return false;
218             }
219         }
220
221         if ( $myApi['useAuth'] && isset($eapmBean->application) ) {
222             $apiClass->loadEAPM($eapmBean);
223         }
224
225         return $apiClass;
226     }
227
228     /**
229      * Lists the available API's for a module or all modules, and possibly ignoring if the user has auth information for that API even if it is required
230      * @param string $module Which module name you are searching for, leave blank to find all API's
231      * @param bool $ignoreAuth Ignore API's demands for authentication (used to get a complete list of modules
232      * @return API class
233      */
234     public static function listAPI($module = '', $ignoreAuth = false) {
235         $apiList = self::loadFullAPIList();
236
237         if ( $module == '' && $ignoreAuth == true ) {
238             // Simplest case, return everything.
239             return($apiList);
240         }
241
242         $apiFinalList = array();
243
244         // Not such an easy case, we need to limit to specific modules and see if we have authentication (or not)
245         foreach ( $apiList as $apiName => $apiOpts ) {
246             if ( $module == '' || in_array($module,$apiOpts['supportedModules']) ) {
247                 // This matches the module criteria
248                 if ( $ignoreAuth || !$apiOpts['useAuth'] || !$apiOpts['requireAuth'] ) {
249                     // Don't need to worry about authentication
250                     $apiFinalList[$apiName] = $apiOpts;
251                 } else {
252                     // We need to worry about authentication
253                     $eapmBean = EAPM::getLoginInfo($apiName);
254                     if ( isset($eapmBean->application) ) {
255                         // We have authentication
256                         $apiFinalList[$apiName] = $apiOpts;
257                     }
258                 }
259             }
260         }
261
262         return $apiFinalList;
263     }
264
265     /**
266      * Get the array of API names available for cetain module
267      * @param string $moduleName
268      * @param bool $ignoreAuth Ignore if we have authentication details or not
269      * @param bool $addEmptyEntry Add empty entry?
270      */
271      public static function getModuleDropDown($moduleName, $ignoreAuth = false, $addEmptyEntry = false) {
272         global $app_list_strings;
273
274         $apiList = self::listAPI($moduleName,$ignoreAuth);
275
276         $apiDropdown = array();
277         if($addEmptyEntry){
278             $apiDropdown[''] = '';
279         }
280
281         foreach ( $apiList as $apiName => $ignore ) {
282             $appStringTranslKey = 'eapm_list_' .strtolower($moduleName);
283             if ( isset($app_list_strings[$appStringTranslKey]) && !empty($app_list_strings[$appStringTranslKey][$apiName]) ) {
284                 $apiDropdown[$apiName] = $app_list_strings[$appStringTranslKey][$apiName];
285             }
286             else if ( !empty($app_list_strings['eapm_list'][$apiName]) ) {
287                 $apiDropdown[$apiName] = $app_list_strings['eapm_list'][$apiName];
288             }
289             else {
290                 $apiDropdown[$apiName] = $apiName;
291             }
292         }
293
294         return $apiDropdown;
295
296     }
297 }