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.
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 ********************************************************************************/
39 require_once('include/connectors/utils/ConnectorUtils.php');
40 require_once('include/connectors/sources/SourceFactory.php');
42 * Provides a factory to list, discover and create external API calls
44 * Main features are to list available external API's by supported features, modules and which ones have access for the user.
46 class ExternalAPIFactory
49 * Filter the list of APIs, removing disabled ones
50 * @param array $apiFullList
51 * @return array Filtered list
53 public static function filterAPIList($apiFullList)
55 $filteredList = array();
56 foreach($apiFullList as $name => $data) {
57 if(isset($data['connector'])) {
58 if(ConnectorUtils::eapmEnabled($data['connector'])) {
59 if(isset($data['authMethod']) && $data['authMethod'] == 'oauth'){
60 $connector = SourceFactory::getSource($data['connector'], false);
61 if(!empty($connector)) {
62 $key = $connector->getProperty('oauth_consumer_key');
63 $secret = $connector->getProperty('oauth_consumer_secret');
64 if(!empty($key) && !empty($secret)){
65 $filteredList[$name] = $data;
69 $filteredList[$name] = $data;
73 $filteredList[$name] = $data;
80 * Get the list of available APIs
81 * @param bool $forceRebuild
82 * @param bool $ignoreDisabled Should we ignore disabled status?
85 public static function loadFullAPIList($forceRebuild=false, $ignoreDisabled = false) {
86 if ( isset($GLOBALS['sugar_config']['developer_mode']) && $GLOBALS['sugar_config']['developer_mode'] ) {
87 static $beenHereBefore = false;
88 if ( !$beenHereBefore ) {
90 $beenHereBefore = true;
93 if (!$forceRebuild && file_exists('cache/include/externalAPI.cache.php') ) {
94 // Already have a cache file built, no need to rebuild
95 require('cache/include/externalAPI.cache.php');
97 return $ignoreDisabled?$fullAPIList:self::filterAPIList($fullAPIList);
100 $apiFullList = array();
101 $meetingPasswordList = array();
102 $needUrlList = array();
104 $baseDirList = array('include/externalAPI/','custom/include/externalAPI');
105 foreach ( $baseDirList as $baseDir ) {
106 $dirList = glob($baseDir.'*',GLOB_ONLYDIR);
107 foreach($dirList as $dir) {
108 if ( $dir == $baseDir.'.' || $dir == $baseDir.'..' || $dir == $baseDir.'Base' ) {
112 $apiName = str_replace($baseDir,'',$dir);
113 if ( file_exists($dir.'/ExtAPI'.$apiName.'.php') ) {
114 $apiFullList[$apiName]['className'] = 'ExtAPI'.$apiName;
115 $apiFullList[$apiName]['file'] = $dir.'/'.$apiFullList[$apiName]['className'].'.php';
117 if ( file_exists($dir.'/ExtAPI'.$apiName.'_cstm.php') ) {
118 $apiFullList[$apiName]['className'] = 'ExtAPI'.$apiName.'_cstm';
119 $apiFullList[$apiName]['file_cstm'] = $dir.'/'.$apiFullList[$apiName]['className'].'.php';
124 $optionList = array('supportedModules','useAuth','requireAuth','supportMeetingPassword','docSearch', 'authMethod', 'oauthFixed','needsUrl','canInvite','sendsInvites','sharingOptions','connector', 'oauthParams','restrictUploadsByExtension');
125 foreach ( $apiFullList as $apiName => $apiOpts ) {
126 require_once($apiOpts['file']);
127 if ( !empty($apiOpts['file_cstm']) ) {
128 require_once($apiOpts['file_cstm']);
130 $className = $apiOpts['className'];
131 $apiClass = new $className();
132 foreach ( $optionList as $opt ) {
133 if ( isset($apiClass->$opt) ) {
134 $apiFullList[$apiName][$opt] = $apiClass->$opt;
138 // Special handling for the show/hide of the Meeting Password field, we need to create a dropdown for the Sugar Logic code.
139 if ( isset($apiClass->supportMeetingPassword) && $apiClass->supportMeetingPassword == true ) {
140 $meetingPasswordList[$apiName] = $apiName;
145 create_cache_directory('/include/');
146 $fd = fopen('cache/include/externalAPI.cache-tmp.php','w');
147 fwrite($fd,"<"."?php\n//This file is auto generated by ".__FILE__."\n\$fullAPIList = ".var_export($apiFullList,true).";\n\n");
149 rename('cache/include/externalAPI.cache-tmp.php','cache/include/externalAPI.cache.php');
151 $fd = fopen('cache/include/externalAPI.cache-tmp.js','w');
152 fwrite($fd,"//This file is auto generated by ".__FILE__."\nSUGAR.eapm = ".json_encode($apiFullList).";\n\n");
154 rename('cache/include/externalAPI.cache-tmp.js','cache/include/externalAPI.cache.js');
157 if (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);
168 return $ignoreDisabled?$apiFullList:self::filterAPIList($apiFullList);
172 * Clear API cache file
174 public static function clearCache() {
175 if ( file_exists('cache/include/externalAPI.cache.php') ) {
176 unlink('cache/include/externalAPI.cache.php');
178 if ( file_exists('cache/include/externalAPI.cache.js') ) {
179 unlink('cache/include/externalAPI.cache.js');
185 * 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.
186 * @param string $apiName The name of the requested API ( known API's can be listed by the listAPI() call )
187 * @param bool $apiName Ignore authentication requirements (optional)
188 * @return ExternalAPIBase API plugin
190 public static function loadAPI($apiName, $ignoreAuth=false)
192 $apiList = self::loadFullAPIList();
193 if ( ! isset($apiList[$apiName]) ) {
197 $myApi = $apiList[$apiName];
198 require_once($myApi['file']);
199 if ( !empty($myApi['file_cstm']) ) {
200 require_once($myApi['file_cstm']);
203 $apiClassName = $myApi['className'];
205 $apiClass = new $apiClassName();
210 if ($myApi['useAuth']) {
211 $eapmBean = EAPM::getLoginInfo($apiName);
213 if (!isset($eapmBean->application) && $myApi['requireAuth']) {
214 // We need authentication, and they don't have it, don't load the API
219 if ( $myApi['useAuth'] && isset($eapmBean->application) ) {
220 $apiClass->loadEAPM($eapmBean);
227 * 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
228 * @param string $module Which module name you are searching for, leave blank to find all API's
229 * @param bool $ignoreAuth Ignore API's demands for authentication (used to get a complete list of modules
232 public static function listAPI($module = '', $ignoreAuth = false) {
233 $apiList = self::loadFullAPIList();
235 if ( $module == '' && $ignoreAuth == true ) {
236 // Simplest case, return everything.
240 $apiFinalList = array();
242 // Not such an easy case, we need to limit to specific modules and see if we have authentication (or not)
243 foreach ( $apiList as $apiName => $apiOpts ) {
244 if ( $module == '' || in_array($module,$apiOpts['supportedModules']) ) {
245 // This matches the module criteria
246 if ( $ignoreAuth || !$apiOpts['useAuth'] || !$apiOpts['requireAuth'] ) {
247 // Don't need to worry about authentication
248 $apiFinalList[$apiName] = $apiOpts;
250 // We need to worry about authentication
251 $eapmBean = EAPM::getLoginInfo($apiName);
252 if ( isset($eapmBean->application) ) {
253 // We have authentication
254 $apiFinalList[$apiName] = $apiOpts;
260 return $apiFinalList;
264 * Get the array of API names available for cetain module
265 * @param string $moduleName
266 * @param bool $ignoreAuth Ignore if we have authentication details or not
267 * @param bool $addEmptyEntry Add empty entry?
269 public static function getModuleDropDown($moduleName, $ignoreAuth = false, $addEmptyEntry = false) {
270 global $app_list_strings;
272 $apiList = self::listAPI($moduleName,$ignoreAuth);
274 $apiDropdown = array();
276 $apiDropdown[''] = '';
279 foreach ( $apiList as $apiName => $ignore ) {
281 if ( !empty($app_list_strings['eapm_list'][$apiName]) ) {
282 $apiDropdown[$apiName] = $app_list_strings['eapm_list'][$apiName];
284 $apiDropdown[$apiName] = $apiName;