-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathrpclib.php
executable file
·296 lines (265 loc) · 10.2 KB
/
rpclib.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* @package mod_tracker
* @category mod
* @author Clifford Tham, Valery Fremaux > 1.8
* @date 02/12/2007
*
* Library of functions for rpc remote calls at tracker. All complex
* variables transport are performed using JSON format.
*/
defined('MOODLE_INTERNAL') || die();
require_once($CFG->dirroot.'/mod/tracker/locallib.php');
if (!function_exists('debug_trace')) {
function debug_trace($str) {
// Empty fake function if missing.
assert(1);
}
}
/*
* Constants
*
*/
if (!defined('RPC_SUCCESS')) {
define('RPC_TEST', 100);
define('RPC_SUCCESS', 200);
define('RPC_FAILURE', 500);
define('RPC_FAILURE_USER', 501);
define('RPC_FAILURE_CONFIG', 502);
define('RPC_FAILURE_DATA', 503);
define('RPC_FAILURE_CAPABILITY', 510);
}
define('CREATE_IF_MISSING', true);
/**
* checks an user has local identity and comes from a known host
* @param string $username the user's login
* @param string $remotehostroot the host he comes from
* @return a failure report if unchecked, null elsewhere.
*/
function tracker_rpc_check($remoteuser, &$localuser, $createmissing = false) {
global $DB;
// Get local identity for user.
if (!$remotehost = $DB->get_record('mnet_host', array('wwwroot' => $remoteuser->hostwwwroot))) {
$response->status = RPC_FAILURE;
$response->error[] = "Calling host is not registered. Check MNET configuration";
return json_encode($response);
}
$select = "username = ? AND mnethostid = ? AND deleted = 0";
if (!$localuser = $DB->get_record_select('user', $select, array($remoteuser->username, $remotehost->id))) {
if ($createmissing) {
// We create a minimalistic mnet user. Profile might be completed later.
$localuser = new StdClass();
$localuser->username = $remoteuser->username;
if (is_enabled_auth('multimnet')) {
$localuser->auth = 'multimnet';
} else {
$localuser->auth = 'mnet';
}
$localuser->timecreated = time();
$localuser->firstname = $remoteuser->firstname;
$localuser->lastname = $remoteuser->lastname;
$localuser->deleted = 0;
$localuser->email = $remoteuser->email;
$localuser->mnethostid = $remotehost->id;
try {
$localuser->id = $DB->insert_record('user', $localuser);
} catch (Exception $e) {
$response->status = RPC_FAILURE_USER;
$response->error[] = "User could not be created.";
$response->error[] = serialize($e);
return json_encode($response);
}
} else {
$response->status = RPC_FAILURE_USER;
$response->error[] = "Calling user has no local account. Register remote user first";
return json_encode($response);
}
}
return null;
}
/**
* sends tracker information to remote caller. This is intended for
* administrative binding GUIs.
* @param int $trackerid the id of the tracker instance
* @param boolean $nojson when true, avoids serializing through JSON syntax
* @return string a JSON encoded information structure.
*/
function tracker_rpc_get_infos($trackerid, $nojson = false) {
global $DB;
$tracker = $DB->get_record('tracker', array('id' => "$trackerid"));
$query = "
SELECT
te.name,
te.description,
te.type
FROM
{tracker_element} te,
{tracker_elementused} teu
WHERE
te.id = teu.elementid AND
teu.trackerid = {$trackerid}
";
$elementused = $DB->get_records_sql($query);
$tracker->elements = $elementused;
if ($nojson) {
return $tracker;
}
return json_encode($tracker);
}
/**
* sends an array of available trackers. Returns only trackers
* the remote user has capability to manage. Note that this
* RPC call can be used locally.
* @param string $username the user's login
* @param string $remotehostroot the host he comes from
* @return a stub of instance descriptions
*/
function tracker_rpc_get_instances($username, $remotehostroot) {
global $CFG, $DB;
$response->status = RPC_SUCCESS;
$trackers = $DB->get_records('tracker', null, 'name', 'id, name, networkable');
if (!empty($trackers)) {
foreach ($trackers as $id => $tracker) {
/*
* A networkable tracker is exposed at once the tracker
* ticket transport layer is enabled.
*/
if (!$tracker->networkable) {
/*
* Non networkable trackers will need the remote user
* has proper write capabilities to nbe able to link and post
*/
try {
$cm = get_coursemodule_from_instance('tracker', $id);
$modulecontext = context_module::instance($cm->id);
if (!has_capability('mod/tracker:report', $modulecontext, $localuser->id)) {
unset($trackers[$id]);
$response->report[] = "ignoring tracker $id for capability reasons";
}
} catch (Exception $e) {
$response->report[] = "No course module for tracker instance $id";
}
}
}
}
$response->trackers = $trackers;
return json_encode($response);
}
/**
* remote post an entry in a tracker
* @param object $remoteuser a user description
* @param int $trackerid the local trackerid where to post
* @param string $remoteissue a JSON encoded variable containing all
* information about an issue.
* @return the local issue record id
*/
function tracker_rpc_post_issue($remoteuser, $trackerid, $remoteissue, $islocalcall = false) {
global $DB, $USER;
$tracker = $DB->get_record('tracker', array('id' => $trackerid));
if (!$tracker) {
$response = new StdClass;
$response->status = RPC_FAILURE;
$response->error[] = 'Tracker not found';
return json_encode($response);
}
// Objectify received arrays.
$remoteuser = (object)$remoteuser;
// Clone is important here to unbind instances.
$newissue = clone((object)$remoteissue);
if (!$islocalcall) {
if ($tracker->networkable) {
/*
* If tracker is networkable, we consider service binding is enough to accept
* local user creation if missing.
*/
if ($failedcheck = tracker_rpc_check($remoteuser, $localuser, CREATE_IF_MISSING)) {
return $failedcheck;
}
} else {
// Simply checks user and returns $localuser record.
if ($failedcheck = tracker_rpc_check($remoteuser, $localuser)) {
return $failedcheck;
}
}
$originhostid = $DB->get_field('mnet_host', 'id', array('wwwroot' => $remoteuser->hostwwwroot));
} else {
$localuser = $USER;
$originhostid = 0;
}
$response = new StdClass;
$response->status = RPC_SUCCESS;
// Get additional data and cleanup the issue record for insertion.
if (isset($newissue->attributes)) {
$attributes = $newissue->attributes;
unset($newissue->attributes); // Clears attributes so we have an issue record.
}
$comment = $newissue->comment;
unset($newissue->comment);
unset($newissue->id); // Clears id, so it will be a new record.
$newissue->trackerid = $trackerid;
$newissue->status = POSTED;
$newissue->reportedby = $localuser->id;
$newissue->assignedto = 0;
if (!empty($tracker->defaultassignee)) {
$newissue->assignedto = $tracker->defaultassignee;
}
$newissue->bywhomid = $localuser->id;
$newissue->downlink = $originhostid.':'.$newissue->downlink;
$newissue->uplink = '';
try {
$followid = $DB->insert_record('tracker_issue', $newissue);
} catch (Exception $e) {
$response->status = RPC_FAILURE;
$response->error[] = "Remote error : Could not insert cascade issue record";
$response->error[] = $e->error;
return json_encode($response);
}
// TODO : rebind attributes and add them.
if (!empty($newissue->attributes)) {
$used = tracker_getelementsused_by_name($tracker);
foreach ($newissue->attributes as $attribute) {
// Cleanup and crossmap attribute records.
$attribute->elementid = $used[$attribute->elementname]->id;
unset($attribute->elementname);
unset($attribute->id);
$attribute->trackerid = $trackerid;
$attribute->issueid = $followid;
// Don't really worry if it fails.
try {
$DB->insert_record('tracker_issueattribute', $attribute);
} catch (Exception $e) {
assert(1);
}
}
}
// Get comment track and add starting comment backtrace.
$issuecomment = new StdClass;
$issuecomment->trackerid = $trackerid;
$issuecomment->issueid = $followid;
$issuecomment->userid = $localuser->id;
$issuecomment->comment = $comment;
$issuecomment->commentformat = FORMAT_HTML;
$issuecomment->datecreated = time();
try {
$DB->insert_record('tracker_issuecomment', $issuecomment);
} catch (Exception $e) {
$response->status = RPC_FAILURE;
$response->error[] = "Remote error : Could not insert cascade commment record";
}
$response->followid = $followid;
return json_encode($response);
}