|
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: