1
|
|
|
<?php if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); |
2
|
|
|
/********************************************************************************* |
3
|
|
|
* SugarCRM Community Edition is a customer relationship management program developed by |
4
|
|
|
* SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc. |
5
|
|
|
|
6
|
|
|
* SuiteCRM is an extension to SugarCRM Community Edition developed by Salesagility Ltd. |
7
|
|
|
* Copyright (C) 2011 - 2014 Salesagility Ltd. |
8
|
|
|
* |
9
|
|
|
* This program is free software; you can redistribute it and/or modify it under |
10
|
|
|
* the terms of the GNU Affero General Public License version 3 as published by the |
11
|
|
|
* Free Software Foundation with the addition of the following permission added |
12
|
|
|
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK |
13
|
|
|
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY |
14
|
|
|
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. |
15
|
|
|
* |
16
|
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT |
17
|
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
18
|
|
|
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more |
19
|
|
|
* details. |
20
|
|
|
* |
21
|
|
|
* You should have received a copy of the GNU Affero General Public License along with |
22
|
|
|
* this program; if not, see http://www.gnu.org/licenses or write to the Free |
23
|
|
|
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
24
|
|
|
* 02110-1301 USA. |
25
|
|
|
* |
26
|
|
|
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, |
27
|
|
|
* SW2-130, Cupertino, CA 95014, USA. or at email address [email protected]. |
28
|
|
|
* |
29
|
|
|
* The interactive user interfaces in modified source and object code versions |
30
|
|
|
* of this program must display Appropriate Legal Notices, as required under |
31
|
|
|
* Section 5 of the GNU Affero General Public License version 3. |
32
|
|
|
* |
33
|
|
|
* In accordance with Section 7(b) of the GNU Affero General Public License version 3, |
34
|
|
|
* these Appropriate Legal Notices must retain the display of the "Powered by |
35
|
|
|
* SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not |
36
|
|
|
* reasonably feasible for technical reasons, the Appropriate Legal Notices must |
37
|
|
|
* display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM". |
38
|
|
|
********************************************************************************/ |
39
|
|
|
|
40
|
|
|
|
41
|
|
|
require_once('soap/SoapHelperFunctions.php'); |
42
|
|
|
$GLOBALS['log']->debug("JSON_SERVER:"); |
43
|
|
|
$global_registry_var_name = 'GLOBAL_REGISTRY'; |
44
|
|
|
|
45
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
46
|
|
|
//// SUPPORTED METHODS |
47
|
|
|
/* |
48
|
|
|
* ADD NEW METHODS TO THIS ARRAY: |
49
|
|
|
* then create a function called "function json_$method($request_id, &$params)" |
50
|
|
|
* where $method is the method name |
51
|
|
|
*/ |
52
|
|
|
$SUPPORTED_METHODS = array( |
53
|
|
|
'retrieve', |
54
|
|
|
'query', |
55
|
|
|
); |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* Generic retrieve for getting data from a sugarbean |
59
|
|
|
*/ |
60
|
|
|
function json_retrieve($request_id, $params) { |
61
|
|
|
global $current_user; |
62
|
|
|
global $beanFiles,$beanList; |
63
|
|
|
$json = getJSONobj(); |
64
|
|
|
|
65
|
|
|
$record = $params[0]['record']; |
66
|
|
|
|
67
|
|
|
require_once($beanFiles[$beanList[$params[0]['module']]]); |
68
|
|
|
$focus = new $beanList[$params[0]['module']]; |
69
|
|
|
$focus->retrieve($record); |
70
|
|
|
|
71
|
|
|
// to get a simplified version of the sugarbean |
72
|
|
|
$module_arr = populateBean($focus); |
73
|
|
|
|
74
|
|
|
$response = array(); |
75
|
|
|
$response['id'] = $request_id; |
76
|
|
|
$response['result'] = array("status"=>"success","record"=>$module_arr); |
77
|
|
|
$json_response = $json->encode($response, true); |
78
|
|
|
print $json_response; |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
function json_query($request_id, $params) { |
82
|
|
|
global $response, $sugar_config; |
83
|
|
|
global $beanFiles, $beanList; |
84
|
|
|
$json = getJSONobj(); |
85
|
|
|
|
86
|
|
|
if($sugar_config['list_max_entries_per_page'] < 31) // override query limits |
87
|
|
|
$sugar_config['list_max_entries_per_page'] = 31; |
88
|
|
|
|
89
|
|
|
$args = $params[0]; |
90
|
|
|
|
91
|
|
|
//decode condition parameter values.. |
92
|
|
|
if(is_array($args['conditions'])) { |
93
|
|
|
foreach($args['conditions'] as $key=>$condition) { |
94
|
|
|
if(!empty($condition['value'])) { |
95
|
|
|
$where = $json->decode(utf8_encode($condition['value'])); |
96
|
|
|
// cn: bug 12693 - API change due to CSRF security changes. |
97
|
|
|
$where = empty($where) ? $condition['value'] : $where; |
98
|
|
|
$args['conditions'][$key]['value'] = $where; |
99
|
|
|
} |
100
|
|
|
} |
101
|
|
|
} |
102
|
|
|
|
103
|
|
|
$list_return = array(); |
104
|
|
|
|
105
|
|
|
if(! empty($args['module'])) { |
106
|
|
|
$args['modules'] = array($args['module']); |
107
|
|
|
} |
108
|
|
|
|
109
|
|
|
foreach($args['modules'] as $module) { |
110
|
|
|
require_once($beanFiles[$beanList[$module]]); |
111
|
|
|
$focus = new $beanList[$module]; |
112
|
|
|
|
113
|
|
|
$query_orderby = ''; |
114
|
|
|
if(!empty($args['order'])) { |
115
|
|
|
$query_orderby = preg_replace('/[^\w_.-]+/i', '', $args['order']['by']); |
116
|
|
|
if(!empty($args['order']['desc'])) { |
117
|
|
|
$query_orderby .= " DESC"; |
118
|
|
|
} else { |
119
|
|
|
$query_orderby .= " ASC"; |
120
|
|
|
} |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
$query_limit = ''; |
124
|
|
|
if(!empty($args['limit'])) { |
125
|
|
|
$query_limit = (int)$args['limit']; |
126
|
|
|
} |
127
|
|
|
$query_where = construct_where($args, $focus->table_name,$module); |
128
|
|
|
$list_arr = array(); |
129
|
|
|
if($focus->ACLAccess('ListView', true)) { |
130
|
|
|
$focus->ungreedy_count=false; |
131
|
|
|
$curlist = $focus->get_list($query_orderby, $query_where, 0, $query_limit, -1, 0); |
132
|
|
|
$list_return = array_merge($list_return,$curlist['list']); |
133
|
|
|
} |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
$app_list_strings = null; |
137
|
|
|
|
138
|
|
|
for($i = 0;$i < count($list_return);$i++) { |
|
|
|
|
139
|
|
|
if(isset($list_return[$i]->emailAddress) && is_object($list_return[$i]->emailAddress)) { |
140
|
|
|
$list_return[$i]->emailAddress->handleLegacyRetrieve($list_return[$i]); |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
$list_arr[$i]= array(); |
144
|
|
|
$list_arr[$i]['fields']= array(); |
145
|
|
|
$list_arr[$i]['module']= $list_return[$i]->object_name; |
146
|
|
|
|
147
|
|
|
foreach($args['field_list'] as $field) { |
148
|
|
|
if(!empty($list_return[$i]->field_name_map[$field]['sensitive'])) { |
149
|
|
|
continue; |
150
|
|
|
} |
151
|
|
|
// handle enums |
152
|
|
|
if( (isset($list_return[$i]->field_name_map[$field]['type']) && $list_return[$i]->field_name_map[$field]['type'] == 'enum') || |
153
|
|
|
(isset($list_return[$i]->field_name_map[$field]['custom_type']) && $list_return[$i]->field_name_map[$field]['custom_type'] == 'enum')) { |
154
|
|
|
|
155
|
|
|
// get fields to match enum vals |
156
|
|
|
if(empty($app_list_strings)) { |
157
|
|
|
if(isset($_SESSION['authenticated_user_language']) && $_SESSION['authenticated_user_language'] != '') $current_language = $_SESSION['authenticated_user_language']; |
158
|
|
|
else $current_language = $sugar_config['default_language']; |
159
|
|
|
$app_list_strings = return_app_list_strings_language($current_language); |
160
|
|
|
} |
161
|
|
|
|
162
|
|
|
// match enum vals to text vals in language pack for return |
163
|
|
|
if(!empty($app_list_strings[$list_return[$i]->field_name_map[$field]['options']])) { |
164
|
|
|
$list_return[$i]->$field = $app_list_strings[$list_return[$i]->field_name_map[$field]['options']][$list_return[$i]->$field]; |
165
|
|
|
} |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
$list_arr[$i]['fields'][$field] = $list_return[$i]->$field; |
169
|
|
|
} |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
|
173
|
|
|
$response['id'] = $request_id; |
174
|
|
|
$response['result'] = array("list"=>$list_arr); |
175
|
|
|
$json_response = $json->encode($response, true); |
176
|
|
|
echo $json_response; |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
//// END SUPPORTED METHODS |
180
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
181
|
|
|
|
182
|
|
|
// ONLY USED FOR MEETINGS |
183
|
|
|
// HAS MEETING SPECIFIC CODE: |
184
|
|
|
function populateBean(&$focus) { |
185
|
|
|
$all_fields = $focus->column_fields; |
186
|
|
|
// MEETING SPECIFIC |
187
|
|
|
$all_fields = array_merge($all_fields,array('required','accept_status','name')); // need name field for contacts and users |
188
|
|
|
//$all_fields = array_merge($focus->column_fields,$focus->additional_column_fields); |
189
|
|
|
|
190
|
|
|
$module_arr = array(); |
191
|
|
|
|
192
|
|
|
$module_arr['module'] = $focus->object_name; |
193
|
|
|
|
194
|
|
|
$module_arr['fields'] = array(); |
195
|
|
|
|
196
|
|
|
foreach($all_fields as $field) |
197
|
|
|
{ |
198
|
|
|
if(isset($focus->$field) && !is_object($focus->$field)) |
199
|
|
|
{ |
200
|
|
|
$focus->$field = from_html($focus->$field); |
201
|
|
|
$focus->$field = preg_replace("/\r\n/","<BR>",$focus->$field); |
202
|
|
|
$focus->$field = preg_replace("/\n/","<BR>",$focus->$field); |
203
|
|
|
$module_arr['fields'][$field] = $focus->$field; |
204
|
|
|
} |
205
|
|
|
} |
206
|
|
|
$GLOBALS['log']->debug("JSON_SERVER:populate bean:"); |
207
|
|
|
return $module_arr; |
208
|
|
|
} |
209
|
|
|
|
210
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
211
|
|
|
//// UTILS |
212
|
|
|
function authenticate() { |
213
|
|
|
global $sugar_config; |
214
|
|
|
|
215
|
|
|
$user_unique_key =(isset($_SESSION['unique_key'])) ? $_SESSION['unique_key'] : ""; |
216
|
|
|
$server_unique_key =(isset($sugar_config['unique_key'])) ? $sugar_config['unique_key'] : ""; |
217
|
|
|
|
218
|
|
|
if($user_unique_key != $server_unique_key) { |
219
|
|
|
$GLOBALS['log']->debug("JSON_SERVER: user_unique_key:".$user_unique_key."!=".$server_unique_key); |
220
|
|
|
session_destroy(); |
221
|
|
|
return null; |
222
|
|
|
} |
223
|
|
|
|
224
|
|
|
if(!isset($_SESSION['authenticated_user_id'])) { |
225
|
|
|
$GLOBALS['log']->debug("JSON_SERVER: authenticated_user_id NOT SET. DESTROY"); |
226
|
|
|
session_destroy(); |
227
|
|
|
return null; |
228
|
|
|
} |
229
|
|
|
|
230
|
|
|
$current_user = new User(); |
231
|
|
|
|
232
|
|
|
$result = $current_user->retrieve($_SESSION['authenticated_user_id']); |
233
|
|
|
$GLOBALS['log']->debug("JSON_SERVER: retrieved user from SESSION"); |
234
|
|
|
|
235
|
|
|
|
236
|
|
|
if($result == null) { |
237
|
|
|
$GLOBALS['log']->debug("JSON_SERVER: could get a user from SESSION. DESTROY"); |
238
|
|
|
session_destroy(); |
239
|
|
|
return null; |
240
|
|
|
} |
241
|
|
|
|
242
|
|
|
return $result; |
243
|
|
|
} |
244
|
|
|
|
245
|
|
|
function construct_where(&$query_obj, $table='',$module=null) |
246
|
|
|
{ |
247
|
|
|
if(! empty($table)) { |
248
|
|
|
$table .= "."; |
249
|
|
|
} |
250
|
|
|
$cond_arr = array(); |
251
|
|
|
|
252
|
|
|
if(! is_array($query_obj['conditions'])) { |
253
|
|
|
$query_obj['conditions'] = array(); |
254
|
|
|
} |
255
|
|
|
|
256
|
|
|
foreach($query_obj['conditions'] as $condition) { |
257
|
|
|
if($condition['name'] == 'user_hash') { |
258
|
|
|
continue; |
259
|
|
|
} |
260
|
|
|
if ($condition['name']=='email1' or $condition['name']=='email2') { |
261
|
|
|
|
262
|
|
|
$email1_value=strtoupper($condition['value']); |
263
|
|
|
$email1_condition = " {$table}id in ( SELECT er.bean_id AS id FROM email_addr_bean_rel er, " . |
264
|
|
|
"email_addresses ea WHERE ea.id = er.email_address_id " . |
265
|
|
|
"AND ea.deleted = 0 AND er.deleted = 0 AND er.bean_module = '{$module}' AND email_address_caps LIKE '%{$email1_value}%' )"; |
266
|
|
|
|
267
|
|
|
array_push($cond_arr,$email1_condition); |
268
|
|
|
} |
269
|
|
|
else { |
270
|
|
|
if($condition['op'] == 'contains') { |
271
|
|
|
$cond_arr[] = $table.$GLOBALS['db']->getValidDBName($condition['name'])." like '%".$GLOBALS['db']->quote($condition['value'])."%'"; |
272
|
|
|
} |
273
|
|
|
if($condition['op'] == 'like_custom') { |
274
|
|
|
$like = ''; |
275
|
|
|
if(!empty($condition['begin'])) $like .= $GLOBALS['db']->quote($condition['begin']); |
276
|
|
|
$like .= $GLOBALS['db']->quote($condition['value']); |
277
|
|
|
if(!empty($condition['end'])) $like .= $GLOBALS['db']->quote($condition['end']); |
278
|
|
|
$cond_arr[] = $table.$GLOBALS['db']->getValidDBName($condition['name'])." like '$like'"; |
279
|
|
|
} else { // starts_with |
280
|
|
|
$cond_arr[] = $table.$GLOBALS['db']->getValidDBName($condition['name'])." like '".$GLOBALS['db']->quote($condition['value'])."%'"; |
281
|
|
|
} |
282
|
|
|
} |
283
|
|
|
} |
284
|
|
|
|
285
|
|
|
if($table == 'users.') { |
286
|
|
|
$cond_arr[] = $table."status='Active'"; |
287
|
|
|
} |
288
|
|
|
$group = strtolower(trim($query_obj['group'])); |
289
|
|
|
if($group != "and" && $group != "or") { |
290
|
|
|
$group = "and"; |
291
|
|
|
} |
292
|
|
|
|
293
|
|
|
return implode(" $group ",$cond_arr); |
294
|
|
|
} |
295
|
|
|
|
296
|
|
|
//// END UTILS |
297
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
298
|
|
|
|
299
|
|
|
|
300
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
301
|
|
|
//// JSON SERVER HANDLER LOGIC |
302
|
|
|
//ignore notices |
303
|
|
|
error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT); |
304
|
|
|
ob_start(); |
305
|
|
|
insert_charset_header(); |
306
|
|
|
global $sugar_config; |
307
|
|
|
if(!empty($sugar_config['session_dir'])) { |
308
|
|
|
session_save_path($sugar_config['session_dir']); |
309
|
|
|
$GLOBALS['log']->debug("JSON_SERVER:session_save_path:".$sugar_config['session_dir']); |
310
|
|
|
} |
311
|
|
|
|
312
|
|
|
session_start(); |
313
|
|
|
$GLOBALS['log']->debug("JSON_SERVER:session started"); |
314
|
|
|
|
315
|
|
|
$current_language = 'en_us'; // defaulting - will be set by user, then sys prefs |
316
|
|
|
|
317
|
|
|
// create json parser |
318
|
|
|
$json = getJSONobj(); |
319
|
|
|
|
320
|
|
|
// if the language is not set yet, then set it to the default language. |
321
|
|
|
if(isset($_SESSION['authenticated_user_language']) && $_SESSION['authenticated_user_language'] != '') { |
322
|
|
|
$current_language = $_SESSION['authenticated_user_language']; |
323
|
|
|
} else { |
324
|
|
|
$current_language = $sugar_config['default_language']; |
325
|
|
|
} |
326
|
|
|
|
327
|
|
|
$locale = new Localization(); |
328
|
|
|
|
329
|
|
|
$GLOBALS['log']->debug("JSON_SERVER: current_language:".$current_language); |
330
|
|
|
|
331
|
|
|
// if this is a get, than this is spitting out static javascript as if it was a file |
332
|
|
|
// wp: DO NOT USE THIS. Include the javascript inline using include/json_config.php |
333
|
|
|
// using <script src=json_server.php></script> does not cache properly on some browsers |
334
|
|
|
// resulting in 2 or more server hits per page load. Very bad for SSL. |
335
|
|
|
if(strtolower($_SERVER['REQUEST_METHOD'])== 'get') { |
336
|
|
|
echo "alert('DEPRECATED API\nPlease report as a bug.');"; |
337
|
|
|
} else { |
338
|
|
|
// else act as a JSON-RPC server for SugarCRM |
339
|
|
|
// create result array |
340
|
|
|
$response = array(); |
341
|
|
|
$response['result'] = null; |
342
|
|
|
$response['id'] = "-1"; |
343
|
|
|
|
344
|
|
|
// authenticate user |
345
|
|
|
$current_user = authenticate(); |
346
|
|
|
|
347
|
|
|
if(empty($current_user)) { |
348
|
|
|
$response['error'] = array("error_msg"=>"not logged in"); |
349
|
|
|
print $json->encode($response, true); |
350
|
|
|
print "not logged in"; |
351
|
|
|
} |
352
|
|
|
|
353
|
|
|
// extract request |
354
|
|
|
if(isset($GLOBALS['HTTP_RAW_POST_DATA'])) |
355
|
|
|
$request = $json->decode($GLOBALS['HTTP_RAW_POST_DATA'], true); |
356
|
|
|
else |
357
|
|
|
$request = $json->decode(file_get_contents("php://input"), true); |
358
|
|
|
|
359
|
|
|
|
360
|
|
|
if(!is_array($request)) { |
361
|
|
|
$response['error'] = array("error_msg"=>"malformed request"); |
362
|
|
|
print $json->encode($response, true); |
363
|
|
|
} |
364
|
|
|
|
365
|
|
|
// make sure required RPC fields are set |
366
|
|
|
if(empty($request['method']) || empty($request['id'])) { |
367
|
|
|
$response['error'] = array("error_msg"=>"missing parameters"); |
368
|
|
|
print $json->encode($response, true); |
369
|
|
|
} |
370
|
|
|
|
371
|
|
|
$response['id'] = $request['id']; |
372
|
|
|
|
373
|
|
|
if(in_array($request['method'], $SUPPORTED_METHODS)) { |
374
|
|
|
call_user_func('json_'.$request['method'],$request['id'],$request['params']); |
375
|
|
|
} else { |
376
|
|
|
$response['error'] = array("error_msg"=>"method:".$request["method"]." not supported"); |
377
|
|
|
print $json->encode($response, true); |
378
|
|
|
} |
379
|
|
|
} |
380
|
|
|
|
381
|
|
|
ob_end_flush(); |
382
|
|
|
sugar_cleanup(); |
383
|
|
|
exit(); |
384
|
|
|
|
If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration: