]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/externalAPI/ExternalAPIFactory.php
Release 6.2.0beta4
[Github/sugarcrm.git] / include / externalAPI / ExternalAPIFactory.php
1 <?php
2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4  * SugarCRM 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  **/
46 class ExternalAPIFactory
47 {
48     /**
49      * Filter the list of APIs, removing disabled ones
50      * @param array $apiFullList
51      * @return array Filtered list
52      */
53     public static function filterAPIList($apiFullList)
54     {
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;
66                             }
67                         }
68                      }else{
69                         $filteredList[$name] = $data;
70                      }
71                 }
72             }else {
73                 $filteredList[$name] = $data;
74             }
75         }
76         return $filteredList;
77     }
78
79     /**
80      * Get the list of available APIs
81      * @param bool $forceRebuild
82      * @param bool $ignoreDisabled Should we ignore disabled status?
83      * @return array
84      */
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 ) {
89                 $forceRebuild = true;
90                 $beenHereBefore = true;
91             }
92         }
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');
96
97             return $ignoreDisabled?$fullAPIList:self::filterAPIList($fullAPIList);
98         }
99
100         $apiFullList = array();
101         $meetingPasswordList = array();
102         $needUrlList = array();
103
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' ) {
109                     continue;
110                 }
111
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';
116                 }
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';
120                 }
121             }
122         }
123
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']);
129             }
130             $className = $apiOpts['className'];
131             $apiClass = new $className();
132             foreach ( $optionList as $opt ) {
133                 if ( isset($apiClass->$opt) ) {
134                     $apiFullList[$apiName][$opt] = $apiClass->$opt;
135                 }
136             }
137
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;
141             }
142
143         }
144
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");
148         fclose($fd);
149         rename('cache/include/externalAPI.cache-tmp.php','cache/include/externalAPI.cache.php');
150
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");
153         fclose($fd);
154         rename('cache/include/externalAPI.cache-tmp.js','cache/include/externalAPI.cache.js');
155
156
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);
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         if ( file_exists('cache/include/externalAPI.cache.php') ) {
176             unlink('cache/include/externalAPI.cache.php');
177         }
178         if ( file_exists('cache/include/externalAPI.cache.js') ) {
179             unlink('cache/include/externalAPI.cache.js');
180         }
181     }
182
183
184     /**
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
189      */
190     public static function loadAPI($apiName, $ignoreAuth=false)
191     {
192         $apiList = self::loadFullAPIList();
193         if ( ! isset($apiList[$apiName]) ) {
194             return false;
195         }
196
197         $myApi = $apiList[$apiName];
198         require_once($myApi['file']);
199         if ( !empty($myApi['file_cstm']) ) {
200             require_once($myApi['file_cstm']);
201         }
202
203         $apiClassName = $myApi['className'];
204
205         $apiClass = new $apiClassName();
206         if ($ignoreAuth) {
207             return $apiClass;
208         }
209
210         if ($myApi['useAuth']) {
211             $eapmBean = EAPM::getLoginInfo($apiName);
212
213             if (!isset($eapmBean->application) && $myApi['requireAuth']) {
214                 // We need authentication, and they don't have it, don't load the API
215                 return false;
216             }
217         }
218
219         if ( $myApi['useAuth'] && isset($eapmBean->application) ) {
220             $apiClass->loadEAPM($eapmBean);
221         }
222
223         return $apiClass;
224     }
225
226     /**
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
230      * @return API class
231      */
232     public static function listAPI($module = '', $ignoreAuth = false) {
233         $apiList = self::loadFullAPIList();
234
235         if ( $module == '' && $ignoreAuth == true ) {
236             // Simplest case, return everything.
237             return($apiList);
238         }
239
240         $apiFinalList = array();
241
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;
249                 } else {
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;
255                     }
256                 }
257             }
258         }
259
260         return $apiFinalList;
261     }
262
263     /**
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?
268      */
269      public static function getModuleDropDown($moduleName, $ignoreAuth = false, $addEmptyEntry = false) {
270         global $app_list_strings;
271
272         $apiList = self::listAPI($moduleName,$ignoreAuth);
273
274         $apiDropdown = array();
275         if($addEmptyEntry){
276             $apiDropdown[''] = '';
277         }
278
279         foreach ( $apiList as $apiName => $ignore ) {
280
281             if ( !empty($app_list_strings['eapm_list'][$apiName]) ) {
282                 $apiDropdown[$apiName] = $app_list_strings['eapm_list'][$apiName];
283             } else {
284                 $apiDropdown[$apiName] = $apiName;
285             }
286         }
287
288         return $apiDropdown;
289
290     }
291 }