BMLT Root Server
c_comdef_admin_xml_handler.class.php
Go to the documentation of this file.
1 <?php
2 /*
3  This file is part of the Basic Meeting List Toolbox (BMLT).
4 
5  Find out more at: https://bmlt.app
6 
7  BMLT is free software: you can redistribute it and/or modify
8  it under the terms of the MIT License.
9 
10  BMLT is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  MIT License for more details.
14 
15  You should have received a copy of the MIT License along with this code.
16  If not, see <https://opensource.org/licenses/MIT>.
17 */
18 defined('BMLT_EXEC') or die('Cannot Execute Directly'); // Makes sure that this file is in the correct context.
19 /***********************************************************************************************************//**
20  \class c_comdef_admin_xml_handler
21  \brief Controls handling of the admin semantic interface.
22 
23  This class should not even be instantiated unless the user has been authorized, and an authorized seesion
24  is in progress.
25 ***************************************************************************************************************/
26 // phpcs:disable PSR1.Classes.ClassDeclaration.MissingNamespace
27 // phpcs:disable Squiz.Classes.ValidClassName.NotCamelCaps
29 // phpcs:enable PSR1.Classes.ClassDeclaration.MissingNamespace
30 // phpcs:enable Squiz.Classes.ValidClassName.NotCamelCaps
31 {
32  public $http_vars; ///< This will hold the combined GET and POST parameters for this call.
33  public $server; ///< The BMLT server model instance.
34  public $my_localized_strings; ///< An array of localized strings.
35  public $handled_service_body_ids; ///< This is used to ensure that we respect the hierarchy when doing a hierarchical Service body request.
36 
37  /********************************************************************************************************//**
38  \brief The class constructor.
39  ************************************************************************************************************/
40  public function __construct(
41  $in_http_vars, ///< The combined GET and POST parameters.
42  $in_server ///< The BMLT server instance.
43  ) {
44  $this->http_vars = $in_http_vars;
45  $this->server = $in_server;
46  $this->my_localized_strings = c_comdef_server::GetLocalStrings();
47  $this->handled_service_body_ids = array();
48  }
49 
50  /********************************************************************************************************//**
51  \brief This returns the URL to the main server. It needs extra stripping, because we're depper than usual.
52 
53  \returns the URL.
54  ************************************************************************************************************/
55  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
56  public function getMainURL()
57  {
58  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
59  return dirname(dirname(GetURLToMainServerDirectory(false))).'/';
60  }
61 
62  /********************************************************************************************************//**
63  \brief This extracts a meeting's essential data as XML.
64 
65  \returns the XML for the meeting data.
66  ************************************************************************************************************/
67  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
68  public function get_meeting_data($meeting_id)
69  {
70  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
71  $ret = '';
72 
74 
75  if (($meeting_object instanceof c_comdef_meeting) && (intval($meeting_object->GetID()) == intval($meeting_id))) {
76  $localized_strings = c_comdef_server::GetLocalStrings();
77  $meeting_id = $meeting_object->GetID();
78  $weekday_tinyint = intval($meeting_object->GetMeetingDataValue('weekday_tinyint'));
79  $weekday_name = $localized_strings["comdef_server_admin_strings"]["meeting_search_weekdays_names"][$weekday_tinyint];
80  $start_time = $meeting_object->GetMeetingDataValue('start_time');
81  $meeting_name = str_replace('"', "'", str_replace("\n", " ", str_replace("\r", " ", $meeting_object->GetMeetingDataValue('meeting_name'))));
82  $meeting_borough = str_replace('"', "'", str_replace("\n", " ", str_replace("\r", " ", $meeting_object->GetMeetingDataValue('location_city_subsection'))));
83  $meeting_town = str_replace('"', "'", str_replace("\n", " ", str_replace("\r", " ", $meeting_object->GetMeetingDataValue('location_municipality'))));
84  $meeting_state = str_replace('"', "'", str_replace("\n", " ", str_replace("\r", " ", $meeting_object->GetMeetingDataValue('location_province'))));
85 
86  $ret = '"meeting_id","meeting_name","weekday_tinyint","weekday_name","start_time","location_city_subsection","location_municipality","location_province"'."\n";
87 
88  if ($meeting_id) {
89  $change_line['meeting_id'] = $meeting_id;
90  } else {
91  $change_line['meeting_id'] = 0;
92  }
93 
94  if ($meeting_name) {
95  $change_line['meeting_name'] = $meeting_name;
96  } else {
97  $change_line['meeting_name'] = '';
98  }
99 
100  if ($weekday_tinyint) {
101  $change_line['weekday_tinyint'] = $weekday_tinyint;
102  } else {
103  $change_line['weekday_tinyint'] = '';
104  }
105 
106  if ($weekday_name) {
107  $change_line['weekday_name'] = $weekday_name;
108  } else {
109  $change_line['weekday_name'] = '';
110  }
111 
112  if ($start_time) {
113  $change_line['start_time'] = $start_time;
114  } else {
115  $change_line['start_time'] = '';
116  }
117 
118  if ($meeting_borough) {
119  $change_line['location_city_subsection'] = $meeting_borough;
120  } else {
121  $change_line['location_city_subsection'] = '';
122  }
123 
124  if ($meeting_town) {
125  $change_line['location_municipality'] = $meeting_town;
126  } else {
127  $change_line['location_municipality'] = '';
128  }
129 
130  if ($meeting_state) {
131  $change_line['location_province'] = $meeting_state;
132  } else {
133  $change_line['location_province'] = '';
134  }
135 
136  $ret .= '"'.implode('","', $change_line).'"'."\n";
137  $ret = $this->TranslateCSVToXML($ret);
138  $ret = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<meeting xmlns=\"http://".c_comdef_htmlspecialchars($_SERVER['SERVER_NAME'])."\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"".$this->getMainURL()."client_interface/xsd/RestoreDeletedMeeting.php\">$ret</meeting>";
139  } else {
140  $ret = '<h1>PROGRAM ERROR (MEETING FETCH FAILED)</h1>';
141  }
142 
143  return $ret;
144  }
145 
146  /********************************************************************************************************//**
147  \brief This is called to process the input and generate the output. It is the "heart" of the class.
148 
149  \returns XML to be returned.
150  ************************************************************************************************************/
151  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
152  public function process_commands()
153  {
154  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
155  $ret = null;
156  // We make sure that we are allowed to access this level of functionality.
157  // This is "belt and suspenders." We will constantly check user credentials.
158  if ($this->basic_user_validation()) {
159  if (isset($this->http_vars['admin_action']) && trim($this->http_vars['admin_action'])) {
160  set_time_limit(120); // Some requests can take a loooong time...
161  switch (strtolower(trim($this->http_vars['admin_action']))) {
162  case 'get_permissions':
163  $ret = $this->process_capabilities_request();
164  break;
165 
166  case 'get_service_body_info':
167  $ret = $this->process_service_bodies_info_request();
168  break;
169 
170  case 'get_format_info':
171  $ret = $this->process_format_info();
172  break;
173 
174  case 'get_field_templates':
175  $ret = $this->process_get_field_templates();
176  break;
177 
178  case 'get_meetings':
179  $ret = $this->process_meeting_search();
180  break;
181 
182  case 'get_deleted_meetings':
183  $ret = $this->process_deleted_meetings();
184  break;
185 
186  case 'get_changes':
187  $ret = $this->process_changes();
188  break;
189 
190  case 'add_meeting':
191  $this->http_vars['meeting_id'] = 0;
192  unset($this->http_vars['meeting_id']); // Make sure that we have no meeting ID. This forces an add.
193  $ret = $this->process_meeting_modify();
194  break;
195 
196  case 'rollback_meeting_to_before_change':
197  if (intval($this->http_vars['meeting_id']) && intval($this->http_vars['change_id'])) { // Make sure that we are referring to a meeting and a change.
198  $ret = $this->process_rollback_meeting();
199  } else {
200  $ret = '<h1>BAD ADMIN ACTION</h1>';
201  }
202  break;
203 
204  case 'restore_deleted_meeting':
205  if (intval($this->http_vars['meeting_id'])) { // Make sure that we are referring to a meeting
206  $ret = $this->process_restore_deleted_meeting();
207  } else {
208  $ret = '<h1>BAD ADMIN ACTION</h1>';
209  }
210  break;
211 
212  case 'modify_meeting':
213  if (intval($this->http_vars['meeting_id'])) { // Make sure that we are referring to a meeting.
214  $ret = $this->process_meeting_modify();
215  } else {
216  $ret = '<h1>BAD ADMIN ACTION</h1>';
217  }
218  break;
219 
220  case 'delete_meeting':
221  if (intval($this->http_vars['meeting_id'])) { // Make sure that we are referring to a meeting
222  $ret = $this->process_meeting_delete();
223  } else {
224  $ret = '<h1>BAD ADMIN ACTION</h1>';
225  }
226  break;
227 
228  case 'get_user_info':
229  $ret = $this->process_user_info();
230  break;
231 
232  default:
233  $ret = '<h1>BAD ADMIN ACTION</h1>';
234  break;
235  }
236 
237  set_time_limit(30); // Probably unnecessary...
238  } else {
239  $ret = '<h1>BAD ADMIN ACTION</h1>';
240  }
241  } else {
242  $ret = '<h1>NOT AUTHORIZED</h1>';
243  }
244 
245  return $ret;
246  }
247 
248  /********************************************************************************************************//**
249  \brief This is a basic funtion that tests the current user, to see if they are basically valid.
250 
251  \returns TRUE, if the user is valid.
252  ************************************************************************************************************/
253  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
254  public function basic_user_validation()
255  {
256  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
257  $ret = false;
258 
259  $user_obj = $this->server->GetCurrentUserObj();
260  // First, make sure the use is of the correct general type.
261  if (isset($user_obj) && ($user_obj instanceof c_comdef_user) && ($user_obj->GetUserLevel() != _USER_LEVEL_DISABLED) && ($user_obj->GetUserLevel() != _USER_LEVEL_SERVER_ADMIN) && ($user_obj->GetID() > 1)) {
262  $ret = true;
263  }
264 
265  return $ret;
266  }
267 
268  /********************************************************************************************************//**
269  \brief This fulfills a user request to get change records.
270 
271  \returns the XML for the change data.
272  ************************************************************************************************************/
273  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
274  public function process_changes()
275  {
276  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
277  $ret = '<h1>NOT AUTHORIZED</h1>';
278 
279  // First, make sure the use is of the correct general type.
280  if ($this->basic_user_validation()) {
281  $start_date = (isset($this->http_vars['from_date']) && $this->http_vars['from_date']) ? strtotime($this->http_vars['from_date']) : (isset($this->http_vars['start_date']) && intval($this->http_vars['start_date']) ? intval($this->http_vars['start_date']) : null);
282  $end_date = (isset($this->http_vars['to_date']) && $this->http_vars['to_date']) ? strtotime($this->http_vars['to_date']) : (isset($this->http_vars['end_date']) && intval($this->http_vars['end_date']) ? intval($this->http_vars['end_date']) : null);
283  $meeting_id = isset($this->http_vars['meeting_id']) && intval($this->http_vars['meeting_id']) ? intval($this->http_vars['meeting_id']) : null;
284  $user_id = isset($this->http_vars['user_id']) && intval($this->http_vars['user_id']) ? intval($this->http_vars['user_id']) : null;
285  $service_body_id = null;
286 
287  if (isset($this->http_vars['service_body_id'])) {
288  $service_body_array = explode(",", $this->http_vars['service_body_id']);
289 
290  foreach ($service_body_array as $sb) {
291  $sb_int = intval($sb);
292 
293  if ($sb_int > 0) {
294  $sb_obj = c_comdef_server::GetServiceBodyByIDObj($sb_int);
295 
296  if ($sb_obj instanceof c_comdef_service_body) {
297  if ($sb_obj->UserCanObserve()) {
298  if (!isset($service_body_id)) {
299  $service_body_id = $sb_int;
300  } elseif (!is_array($service_body_id)) {
301  $service_body_id = array ( $service_body_id, $sb_int );
302  } else {
303  $service_body_id[] = $sb_int;
304  }
305  }
306  }
307  }
308  }
309  }
310 
311  // We get the changes as CSV, then immediately turn them into XML.
312  $ret = $this->TranslateCSVToXML($this->get_changes_as_csv($start_date, $end_date, $meeting_id, $user_id, $service_body_id));
313  $ret = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<changes xmlns=\"http://".c_comdef_htmlspecialchars($_SERVER['SERVER_NAME'])."\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"".$this->getMainURL()."client_interface/xsd/GetChanges.php\">$ret</changes>";
314  }
315 
316  return $ret;
317  }
318 
319  /********************************************************************************************************//**
320  \brief This fulfills a user request to restore a single deleted meeting.
321 
322  \returns the current meeting XML, if the rollback was successful.
323  ************************************************************************************************************/
324  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
325  public function process_rollback_meeting()
326  {
327  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
328  $ret = '<h1>NOT AUTHORIZED</h1>';
329 
330  // First, make sure the user is of the correct general type.
331  if ($this->basic_user_validation()) {
332  $ret = '<h1>PROGRAM ERROR (ROLLBACK FAILED)</h1>';
333 
334  $meeting_id = isset($this->http_vars['meeting_id']) && intval($this->http_vars['meeting_id']) ? intval($this->http_vars['meeting_id']) : null;
335  $change_id = isset($this->http_vars['change_id']) && intval($this->http_vars['change_id']) ? intval($this->http_vars['change_id']) : null;
336 
337  if ($meeting_id && $change_id) {
338  $change_objects = c_comdef_server::GetChangesFromIDAndType('c_comdef_meeting', $meeting_id);
339 
340  if ($change_objects instanceof c_comdef_changes) {
341  $obj_array = $change_objects->GetChangesObjects();
342 
343  if (is_array($obj_array) && count($obj_array)) {
344  foreach ($obj_array as $change) {
345  if ($change->GetID() == $change_id) {
346  $beforeMeetingObject = $change->GetBeforeObject();
347  if ($beforeMeetingObject) {
348  $currentMeetingObject = c_comdef_server::GetOneMeeting($meeting_id);
349 
350  if (($beforeMeetingObject instanceof c_comdef_meeting) && ($currentMeetingObject instanceof c_comdef_meeting)) {
351  if ($currentMeetingObject->UserCanEdit() && $beforeMeetingObject->UserCanEdit()) {
352  if ($change->Rollback()) {
353  $meeting_object = c_comdef_server::GetOneMeeting($meeting_id);
354 
355  $ret = $this->get_meeting_data($meeting_id);
356  }
357  }
358  }
359  }
360 
361  break;
362  }
363  }
364  }
365  }
366  }
367  }
368 
369  return $ret;
370  }
371 
372  /********************************************************************************************************//**
373  \brief This fulfills a user request to restore a single deleted meeting.
374 
375  \returns the XML for the meeting data.
376  ************************************************************************************************************/
377  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
379  {
380  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
381  $ret = '';
382 
383  // First, make sure the user is of the correct general type.
384  if ($this->basic_user_validation()) {
385  $meeting_id = isset($this->http_vars['meeting_id']) && intval($this->http_vars['meeting_id']) ? intval($this->http_vars['meeting_id']) : null;
386 
387  if ($meeting_id) {
388  $change_objects = c_comdef_server::GetChangesFromIDAndType('c_comdef_meeting', $meeting_id);
389 
390  if ($change_objects instanceof c_comdef_changes) {
391  $obj_array = $change_objects->GetChangesObjects();
392 
393  if (is_array($obj_array) && count($obj_array)) {
394  foreach ($obj_array as $change) {
395  if ($change instanceof c_comdef_change) {
396  if ($change->GetAfterObject()) {
397  continue;
398  }
399 
400  $unrestored_meeting_object = $change->GetBeforeObject();
401 
402  if ($unrestored_meeting_object->UserCanEdit()) {
403  $unrestored_meeting_object->SetPublished(false); // Newly restored meetings are always unpublished.
404  $unrestored_meeting_object->UpdateToDB();
405  $ret = $this->get_meeting_data($meeting_id);
406  } else {
407  $ret = '<h1>NOT AUTHORIZED</h1>';
408  }
409  } else {
410  $ret = '<h1>PROGRAM ERROR (NO VALID CHANGE RECORD)</h1>';
411  }
412  }
413  } else {
414  $ret = '<h1>NO MEETING AVAILABLE</h1>';
415  }
416  } else {
417  $ret = '<h1>NO MEETING AVAILABLE</h1>';
418  }
419  } else {
420  $ret = '<h1>NO MEETING SPECIFIED</h1>';
421  }
422  } else {
423  $ret = '<h1>NOT AUTHORIZED</h1>';
424  }
425 
426 
427  return $ret;
428  }
429 
430  /********************************************************************************************************//**
431  \brief This fulfills a user request to delete a meeting.
432 
433  \returns the XML for the meeting data.
434  ************************************************************************************************************/
435  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
436  public function process_deleted_meetings()
437  {
438  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
439  $ret = '';
440 
441  // First, make sure the user is of the correct general type.
442  if ($this->basic_user_validation()) {
443  $start_date = (isset($this->http_vars['from_date']) && $this->http_vars['from_date']) ? strtotime($this->http_vars['from_date']) : (isset($this->http_vars['start_date']) && intval($this->http_vars['start_date']) ? intval($this->http_vars['start_date']) : null);
444  $end_date = (isset($this->http_vars['to_date']) && $this->http_vars['to_date']) ? strtotime($this->http_vars['to_date']) : (isset($this->http_vars['end_date']) && intval($this->http_vars['end_date']) ? intval($this->http_vars['end_date']) : null);
445  $meeting_id = isset($this->http_vars['meeting_id']) && intval($this->http_vars['meeting_id']) ? intval($this->http_vars['meeting_id']) : null;
446  $user_id = isset($this->http_vars['user_id']) && intval($this->http_vars['user_id']) ? intval($this->http_vars['user_id']) : null;
447  $service_body_id = null;
448 
449  if (isset($this->http_vars['service_body_id'])) {
450  $service_body_array = explode(",", $this->http_vars['service_body_id']);
451 
452  foreach ($service_body_array as $sb) {
453  $sb_int = intval($sb);
454 
455  if ($sb_int > 0) {
456  $sb_obj = c_comdef_server::GetServiceBodyByIDObj($sb_int);
457 
458  if ($sb_obj instanceof c_comdef_service_body) {
459  if ($sb_obj->UserCanObserve()) {
460  if (!isset($service_body_id)) {
461  $service_body_id = $sb_int;
462  } elseif (!is_array($service_body_id)) {
463  $service_body_id = array ( $service_body_id, $sb_int );
464  } else {
465  $service_body_id[] = $sb_int;
466  }
467  }
468  }
469  }
470  }
471  }
472 
473  // We get the deleted meetings as CSV, then immediately turn them into XML.
474  $ret = $this->get_deleted_meetings_as_csv($start_date, $end_date, $meeting_id, $user_id, $service_body_id);
475  $ret = $this->TranslateCSVToXML($ret);
476  $ret = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<meetings xmlns=\"http://".c_comdef_htmlspecialchars($_SERVER['SERVER_NAME'])."\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"".$this->getMainURL()."client_interface/xsd/GetDeletedMeetings.php\">$ret</meetings>";
477  } else {
478  $ret = '<h1>NOT AUTHORIZED</h1>';
479  }
480 
481  return $ret;
482  }
483 
484  /*******************************************************************/
485  /**
486  \brief This returns deleted meeting records in CSV form (which we turn into XML).
487 
488  \returns CSV data, with the first row a key header.
489  */
490  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
492  $in_start_date = null, ///< Optional. A start date (In PHP time() format). If supplied, then only deletions on, or after this date will be returned.
493  $in_end_date = null, ///< Optional. An end date (In PHP time() format). If supplied, then only deletions that occurred on, or before this date will be returned.
494  $in_meeting_id = null, ///< Optional. If supplied, an ID for a particular meeting. Only deletion for that meeting will be returned.
495  $in_user_id = null, ///< Optional. If supplied, an ID for a particular user. Only deletions made by that user will be returned.
496  $in_sb_id = null ///< Optional. If supplied, an ID for a particular Service body. Only deletions for meetings in that Service body will be returned. If this is an array, then multiple Service bodies will be searched.
497  ) {
498  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
499  $ret = null;
500  try {
501  $change_objects = c_comdef_server::GetChangesFromIDAndType('c_comdef_meeting', null, $in_start_date, $in_end_date);
502  if ($change_objects instanceof c_comdef_changes) {
503  $obj_array = $change_objects->GetChangesObjects();
504 
505  if (is_array($obj_array) && count($obj_array)) {
506  set_time_limit(max(30, intval(count($obj_array) / 20))); // Change requests can take a loooong time...
507  $localized_strings = c_comdef_server::GetLocalStrings();
508  require_once(dirname(dirname(dirname(__FILE__))).'/server/config/get-config.php');
509  // These are our columns. This will be our header line.
510  $ret = '"deletion_date_int","deletion_date_string","user_id","user_name","service_body_id","service_body_name","meeting_id","meeting_name","weekday_tinyint","weekday_name","start_time","location_city_subsection","location_municipality","location_province"'."\n";
511 
512  // If they specify a Service body, we also look in "child" Service bodies, so we need to produce a flat array of IDs.
513  if (isset($in_sb_id) && $in_sb_id) {
514  // If this is not an array, then we check for children. If it is an array, then we just do exactly what is in the array, regardless of children.
515  if (!is_array($in_sb_id) || !count($in_sb_id)) {
516  global $bmlt_array_gather;
517 
518  $bmlt_array_gather = array();
519 
520  /************************************************//**
521  * This little internal function will simply fill *
522  * the $bmlt_array_gather array with a linear set of *
523  * Service body IDs that can be used for a quick *
524  * comparison, later on. It is a callback function. *
525  ****************************************************/
526  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
527  function bmlt_at_at(
528  $in_value,
529  $in_key
530  ) {
531  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
532  global $bmlt_array_gather;
533 
534  if ($in_value instanceof c_comdef_service_body) {
535  array_push($bmlt_array_gather, $in_value->GetID());
536  }
537  }
538 
539  $array_to_walk = c_comdef_server::GetServer()->GetNestedServiceBodyArray($in_sb_id);
540  array_walk_recursive($array_to_walk, 'bmlt_at_at');
541 
542  if (is_array($bmlt_array_gather) && count($bmlt_array_gather)) {
543  $in_sb_id = $bmlt_array_gather;
544  } else {
545  $in_sb_id = array ( $in_sb_id );
546  }
547  }
548  }
549 
550  $fetched_ids_array = array();
551 
552  foreach ($obj_array as $change) {
553  $date_int = intval($change->GetChangeDate());
554  $date_string = date("Y-m-d H:m:s", $date_int);
555 
556  if ($change instanceof c_comdef_change) {
557  $b_obj = $change->GetBeforeObject();
558 
559  if ($change->GetAfterObject()) { // We are only interested in deleted meetings. If After exists, it was not a deletion.
560  continue;
561  }
562 
563  $meeting_id = intval($change->GetBeforeObjectID()); // By default, we get the meeting ID from the "before" object.
564  $sb_b = intval(($b_obj instanceof c_comdef_meeting) ? $b_obj->GetServiceBodyID() : 0);
565 
567  if (($sb_obj instanceof c_comdef_service_body) && $sb_obj->UserCanObserve()) {
568  $sb_c = intval($change->GetServiceBodyID());
569 
570  if (in_array($meeting_id, $fetched_ids_array)) {
571  continue;
572  }
573 
574  // If this meeting currently exists, then it doesn't qualify.
576  continue;
577  }
578 
579  $fetched_ids_array[] = $meeting_id;
580 
581  // If we are looking for a particular meeting, and this is it, or we don't care, then go ahead.
582  if ((intval($in_meeting_id) && intval($in_meeting_id) == intval($meeting_id)) || !intval($in_meeting_id)) {
583  $meeting_name = '';
584  $user_name = '';
585  $meeting_town = '';
586  $meeting_state = '';
587 
588  // If we are looking for a particular Service body, and this is it, or we don't caer about the Service body, then go ahead.
589  if (!is_array($in_sb_id) || !count($in_sb_id) || in_array($sb_b, $in_sb_id) || in_array($sb_c, $in_sb_id)) {
590  $sb_id = (intval($sb_c) ? $sb_c : $sb_b);
591 
592  $user_id = intval($change->GetUserID());
593 
594  // If the user was specified, we look for changes by that user only. Otherwise, we don't care.
595  if ((isset($in_user_id) && $in_user_id && ($in_user_id == $user_id)) || !isset($in_user_id) || !$in_user_id) {
596  // Get the user that created this change.
597  $user = c_comdef_server::GetUserByIDObj($user_id);
598 
599  if ($user instanceof c_comdef_user) {
600  $user_name = $user->GetLocalName();
601  } else {
602  $user_name = '????'; // Otherwise, it's a mystery.
603  }
604 
605  // Using str_replace, because preg_replace is pretty expensive. However, I don't think this buys us much.
606  if ($b_obj instanceof c_comdef_meeting) {
607  $meeting_name = str_replace('"', "'", str_replace("\n", " ", str_replace("\r", " ", $b_obj->GetMeetingDataValue('meeting_name'))));
608  $meeting_borough = str_replace('"', "'", str_replace("\n", " ", str_replace("\r", " ", $b_obj->GetMeetingDataValue('location_city_subsection'))));
609  $meeting_town = str_replace('"', "'", str_replace("\n", " ", str_replace("\r", " ", $b_obj->GetMeetingDataValue('location_municipality'))));
610  $meeting_state = str_replace('"', "'", str_replace("\n", " ", str_replace("\r", " ", $b_obj->GetMeetingDataValue('location_province'))));
611  }
612 
613  $weekday_tinyint = intval($b_obj->GetMeetingDataValue('weekday_tinyint'));
614  $weekday_name = $localized_strings["comdef_server_admin_strings"]["meeting_search_weekdays_names"][$weekday_tinyint];
615 
616  $start_time = $b_obj->GetMeetingDataValue('start_time');
617 
619 
620  if ($sb instanceof c_comdef_service_body) {
621  $sb_name = $sb->GetLocalName();
622  } else {
623  $sb_name = '????';
624  }
625 
626  // We create an array, which we'll implode after we're done. Easy way to create a CSV row.
627  $change_line = array();
628 
629  // Create each column for this row.
630  if ($date_int) {
631  $change_line['deletion_date_int'] = $date_int;
632  } else {
633  $change_line['deletion_date_int'] = 0;
634  }
635 
636  if ($date_string) {
637  $change_line['deletion_date_string'] = $date_string;
638  } else {
639  $change_line['deletion_date_string'] = '';
640  }
641 
642  if ($user_id) {
643  $change_line['user_id'] = $user_id;
644  } else {
645  $change_line['user_id'] = 0;
646  }
647 
648  if ($user_name) {
649  $change_line['user_name'] = $user_name;
650  } else {
651  $change_line['user_name'] = '';
652  }
653 
654  if ($sb_id) {
655  $change_line['service_body_id'] = $sb_id;
656  } else {
657  $change_line['service_body_id'] = '';
658  }
659 
660  if ($sb_name) {
661  $change_line['service_body_name'] = $sb_name;
662  } else {
663  $change_line['service_body_name'] = '';
664  }
665 
666  if ($meeting_id) {
667  $change_line['meeting_id'] = $meeting_id;
668  } else {
669  $change_line['meeting_id'] = 0;
670  }
671 
672  if ($meeting_name) {
673  $change_line['meeting_name'] = $meeting_name;
674  } else {
675  $change_line['meeting_name'] = '';
676  }
677 
678  if ($weekday_tinyint) {
679  $change_line['weekday_tinyint'] = $weekday_tinyint;
680  } else {
681  $change_line['weekday_tinyint'] = '';
682  }
683 
684  if ($weekday_name) {
685  $change_line['weekday_name'] = $weekday_name;
686  } else {
687  $change_line['weekday_name'] = '';
688  }
689 
690  if ($start_time) {
691  $change_line['start_time'] = $start_time;
692  } else {
693  $change_line['start_time'] = '';
694  }
695 
696  if ($meeting_borough) {
697  $change_line['location_city_subsection'] = $meeting_borough;
698  } else {
699  $change_line['location_city_subsection'] = '';
700  }
701 
702  if ($meeting_town) {
703  $change_line['location_municipality'] = $meeting_town;
704  } else {
705  $change_line['location_municipality'] = '';
706  }
707 
708  if ($meeting_state) {
709  $change_line['location_province'] = $meeting_state;
710  } else {
711  $change_line['location_province'] = '';
712  }
713 
714  $ret .= '"'.implode('","', $change_line).'"'."\n";
715  }
716  }
717  }
718  }
719  }
720  }
721  }
722  }
723  } catch (Exception $e) {
724  $ret = '<h1>ERROR</h1>';
725  }
726 
727  return $ret;
728  }
729 
730  /*******************************************************************/
731  /**
732  \brief This returns change records in CSV form (which we turn into XML).
733 
734  \returns CSV data, with the first row a key header.
735  */
736  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
737  public function get_changes_as_csv(
738  $in_start_date = null, ///< Optional. A start date (In PHP time() format). If supplied, then only changes on, or after this date will be returned.
739  $in_end_date = null, ///< Optional. An end date (In PHP time() format). If supplied, then only changes that occurred on, or before this date will be returned.
740  $in_meeting_id = null, ///< Optional. If supplied, an ID for a particular meeting. Only changes for that meeting will be returned.
741  $in_user_id = null, ///< Optional. If supplied, an ID for a particular user. Only changes made by that user will be returned.
742  $in_sb_id = null, ///< Optional. If supplied, an ID for a particular Service body. Only changes for that Service body will be returned.
743  $in_change_type = 'c_comdef_meeting' ///< This is the change type. Default is meeting change (NOTE: This function needs work to handle other types, but I figured I'd put in a hook for later).
744  ) {
745  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
746  $ret = null;
747  try {
748  // Start by getting every meeting change between the given dates.
749  $change_objects = c_comdef_server::GetChangesFromIDAndType($in_change_type, null, $in_start_date, $in_end_date);
750  if ($change_objects instanceof c_comdef_changes) {
751  $obj_array = $change_objects->GetChangesObjects();
752 
753  if (is_array($obj_array) && count($obj_array)) {
754  set_time_limit(max(30, intval(count($obj_array) / 20))); // Change requests can take a loooong time...
755  $localized_strings = c_comdef_server::GetLocalStrings();
756  require_once(dirname(dirname(dirname(__FILE__))).'/server/config/get-config.php');
757  // These are our columns. This will be our header line.
758  $ret = '"new_meeting","change_id","date_int","date_string","change_type","meeting_id","meeting_name","user_id","user_name","service_body_id","service_body_name","meeting_exists","details"'."\n";
759 
760  // If they specify a Service body, we also look in "child" Service bodies, so we need to produce a flat array of IDs.
761  if (isset($in_sb_id) && $in_sb_id) {
762  // If this is not an array, then we check for children. If it is an array, then we just do exactly what is in the array, regardless of children.
763  if (!is_array($in_sb_id) || !count($in_sb_id)) {
764  global $bmlt_array_gather;
765 
766  $bmlt_array_gather = array();
767 
768  /************************************************//**
769  * This little internal function will simply fill *
770  * the $bmlt_array_gather array with a linear set of *
771  * Service body IDs that can be used for a quick *
772  * comparison, later on. It is a callback function. *
773  ****************************************************/
774  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
775  function bmlt_at_at(
776  $in_value,
777  $in_key
778  ) {
779  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
780  global $bmlt_array_gather;
781 
782  if ($in_value instanceof c_comdef_service_body) {
783  array_push($bmlt_array_gather, $in_value->GetID());
784  }
785  }
786 
787  $array_to_walk = c_comdef_server::GetServer()->GetNestedServiceBodyArray($in_sb_id);
788  array_walk_recursive($array_to_walk, 'bmlt_at_at');
789 
790  if (is_array($bmlt_array_gather) && count($bmlt_array_gather)) {
791  $in_sb_id = $bmlt_array_gather;
792  } else {
793  $in_sb_id = array ( $in_sb_id );
794  }
795  }
796  }
797 
798  foreach ($obj_array as $change) {
799  $change_type = $change->GetChangeType();
800  $date_int = intval($change->GetChangeDate());
801  $date_string = date("Y-m-d H:m:s", $date_int);
802 
803  if ($change instanceof c_comdef_change) {
804  $b_obj = $change->GetBeforeObject();
805  $a_obj = $change->GetAfterObject();
806  $meeting_id = intval($change->GetBeforeObjectID()); // By default, we get the meeting ID from the "before" object.
807  $sb_a = intval(($a_obj instanceof c_comdef_meeting) ? $a_obj->GetServiceBodyID() : 0);
808  $sb_b = intval(($b_obj instanceof c_comdef_meeting) ? $b_obj->GetServiceBodyID() : 0);
809  $sb_c = intval($change->GetServiceBodyID());
810 
811  // If the meeting was newly created, then we get the ID from the "after" object.
812  if (!$meeting_id) {
813  $meeting_id = intval($change->GetAfterObjectID());
814  }
815 
816  // If we are looking for a particular meeting, and this is it, or we don't care, then go ahead.
817  if ((intval($in_meeting_id) && intval($in_meeting_id) == intval($meeting_id)) || !intval($in_meeting_id)) {
818  $meeting_name = '';
819  $user_name = '';
820 
821  // If we are looking for a particular Service body, and this is it, or we don't caer about the Service body, then go ahead.
822  if (!is_array($in_sb_id) || !count($in_sb_id) || in_array($sb_a, $in_sb_id) || in_array($sb_b, $in_sb_id) || in_array($sb_c, $in_sb_id)) {
823  $sb_id = (intval($sb_c) ? $sb_c : (intval($sb_b) ? $sb_b : $sb_a));
824 
825  $user_id = intval($change->GetUserID());
826 
827  // If the user was specified, we look for changes by that user only. Otherwise, we don't care.
828  if ((isset($in_user_id) && $in_user_id && ($in_user_id == $user_id)) || !isset($in_user_id) || !$in_user_id) {
829  // Get the user that created this change.
830  $user = c_comdef_server::GetUserByIDObj($user_id);
831 
832  if ($user instanceof c_comdef_user) {
833  $user_name = $user->GetLocalName();
834  } else {
835  $user_name = '????'; // Otherwise, it's a mystery.
836  }
837 
838  // Using str_replace, because preg_replace is pretty expensive. However, I don't think this buys us much.
839  if ($b_obj instanceof c_comdef_meeting) {
840  $meeting_name = str_replace('"', "'", str_replace("\n", " ", str_replace("\r", " ", $b_obj->GetMeetingDataValue('meeting_name'))));
841  } elseif ($a_obj instanceof c_comdef_meeting) {
842  $meeting_name = str_replace('"', "'", str_replace("\n", " ", str_replace("\r", " ", $a_obj->GetMeetingDataValue('meeting_name'))));
843  }
844 
846 
847  if ($sb instanceof c_comdef_service_body) {
848  $sb_name = $sb->GetLocalName();
849  } else {
850  $sb_name = '????';
851  }
852 
853  // We see if the meeting currently exists.
854  $meeting_exists = 0;
855 
857  $meeting_exists = 1;
858  }
859 
860  // Get the details of the change.
861  $details = '';
862  $desc = $change->DetailedChangeDescription();
863 
864  if ($desc && isset($desc['details']) && is_array($desc['details'])) {
865  // We need to prevent double-quotes, as they are the string delimiters, so we replace them with single-quotes.
866  $details = htmlspecialchars_decode(str_replace('"', "'", str_replace("\n", " ", str_replace("\r", " ", implode(" ", $desc['details'])))), ENT_COMPAT);
867  } elseif ($desc && isset($desc['details'])) {
868  // We need to prevent double-quotes, as they are the string delimiters, so we replace them with single-quotes.
869  $details = htmlspecialchars_decode(str_replace('"', "'", str_replace("\n", " ", str_replace("\r", " ", $desc['details']))), ENT_COMPAT);
870  } else {
871  $details = htmlspecialchars_decode(str_replace('"', "'", str_replace("\n", " ", str_replace("\r", " ", $desc['overall']))), ENT_COMPAT);
872  }
873 
874  // We create an array, which we'll implode after we're done. Easy way to create a CSV row.
875  $change_line = array();
876 
877  // Create each column for this row.
878  $change_line["new_meeting"] = ($b_obj instanceof c_comdef_meeting) ? 0 : 1;
879 
880  $change_line['change_id'] = $change->GetID();
881 
882  if ($date_int) {
883  $change_line['date_int'] = $date_int;
884  } else {
885  $change_line['date_int'] = 0;
886  }
887 
888  if ($date_string) {
889  $change_line['date_string'] = $date_string;
890  } else {
891  $change_line['date_string'] = '';
892  }
893 
894  if ($change_type) {
895  $change_line['change_type'] = $change_type;
896  } else {
897  $change_line['change_type'] = '';
898  }
899 
900  if ($meeting_id) {
901  $change_line['meeting_id'] = $meeting_id;
902  } else {
903  $change_line['meeting_id'] = 0;
904  }
905 
906  if ($meeting_name) {
907  $change_line['meeting_name'] = $meeting_name;
908  } else {
909  $change_line['meeting_name'] = '';
910  }
911 
912  if ($user_id) {
913  $change_line['user_id'] = $user_id;
914  } else {
915  $change_line['user_id'] = 0;
916  }
917 
918  if ($user_name) {
919  $change_line['user_name'] = $user_name;
920  } else {
921  $change_line['user_name'] = '';
922  }
923 
924  if ($sb_id) {
925  $change_line['service_body_id'] = $sb_id;
926  } else {
927  $change_line['service_body_id'] = '';
928  }
929 
930  if ($sb_name) {
931  $change_line['service_body_name'] = $sb_name;
932  } else {
933  $change_line['service_body_name'] = '';
934  }
935 
936  $change_line['meeting_exists'] = $meeting_exists;
937 
938  if ($details) {
939  $change_line['details'] = $details;
940  } else {
941  $change_line['details'] = '';
942  }
943 
944  $ret .= '"'.implode('","', $change_line).'"'."\n";
945  }
946  }
947  }
948  }
949  }
950  }
951  }
952  } catch (Exception $e) {
953  $ret = '<h1>ERROR</h1>';
954  }
955 
956  return $ret;
957  }
958 
959  /********************************************************************************************************//**
960  \brief This fulfills a user request to get all the available fields for adding/modifying meeting data.
961 
962  \returns the XML for the template data.
963  ************************************************************************************************************/
964  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
965  public function process_get_field_templates()
966  {
967  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
968  $ret = '';
969 
970  // First, make sure the use is of the correct general type.
971  if ($this->basic_user_validation()) {
972  // Get the template data from the database.
974  $template_longdata = c_comdef_meeting::GetLongDataTableTemplate();
975 
976  // We merge the two tables (data and longdata).
977  if (is_array($template_data) && count($template_data) && is_array($template_longdata) && count($template_longdata)) {
978  $template_data = array_merge($template_data, $template_longdata);
979  }
980 
981  // $template_data now contains the templates for the meeting data. These are the available "slots" for new values. We need to convert to XML.
982 
983  foreach ($template_data as $template) {
984  $ret .= '<field_template>';
985  $ret .= '<key>'.c_comdef_htmlspecialchars($template['key']).'</key>';
986  $ret .= '<field_prompt>'.c_comdef_htmlspecialchars($template['field_prompt']).'</field_prompt>';
987  $ret .= '<lang_enum>'.c_comdef_htmlspecialchars($template['lang_enum']).'</lang_enum>';
988  $ret .= '<visibility>'.intval($template['visibility']).'</visibility>';
989 
990  if (isset($template['data_string'])) {
991  $ret .= '<data_string>'.c_comdef_htmlspecialchars($template['data_string']).'</data_string>';
992  }
993 
994  if (isset($template['data_bigint'])) {
995  $ret .= '<data_bigint>'.intval($template['data_bigint']).'</data_bigint>';
996  }
997 
998  if (isset($template['data_double'])) {
999  $ret .= '<data_double>'.intval($template['data_double']).'</data_double>';
1000  }
1001 
1002  if (isset($template['data_longtext'])) {
1003  $ret .= '<data_longtext>'.c_comdef_htmlspecialchars($template['data_longtext']).'</data_longtext>';
1004  }
1005 
1006  if (isset($template['data_blob'])) {
1007  $ret .= '<data_blob>'.c_comdef_htmlspecialchars(base64_encode($template['data_blob'])).'</data_blob>';
1008  }
1009  $ret .= '</field_template>';
1010  }
1011 
1012  $ret = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<field_templates xmlns=\"http://".c_comdef_htmlspecialchars($_SERVER['SERVER_NAME'])."\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"".$this->getMainURL()."client_interface/xsd/FieldTemplates.php\">$ret</field_templates>";
1013  } else {
1014  $ret = '<h1>NOT AUTHORIZED</h1>';
1015  }
1016 
1017  return $ret;
1018  }
1019 
1020  /********************************************************************************************************//**
1021  \brief This fulfills a user request to delete an existing meeting. $this->http_vars['meeting_id'] must be set to the meeting ID.
1022 
1023  \returns A very simple XML Report.
1024  ************************************************************************************************************/
1025  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
1026  public function process_meeting_delete()
1027  {
1028  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
1029  $ret = null;
1030 
1031  // First, make sure the use is of the correct general type.
1032  if ($this->basic_user_validation()) {
1033  $meeting_obj = $this->server->GetOneMeeting(intval($this->http_vars['meeting_id']));
1034  if ($meeting_obj instanceof c_comdef_meeting) { // Make sure we got a meeting.
1035  if ($meeting_obj->UserCanEdit($this->server->GetCurrentUserObj())) { // Make sure that we are allowed to edit this meeting.
1036  // Before we say goodbye, we take down the relevant details for the next of kin...
1037  $id = intval($meeting_obj->GetID());
1038  $service_body_id = intval($meeting_obj->GetServiceBodyID());
1039  $name = c_comdef_htmlspecialchars(str_replace('"', "'", str_replace("\n", " ", str_replace("\r", " ", $meeting_obj->GetMeetingDataValue('meeting_name')))));
1040  $weekday = intval($meeting_obj->GetMeetingDataValue('weekday_tinyint'));
1041  $start_time = c_comdef_htmlspecialchars($meeting_obj->GetMeetingDataValue('start_time'));
1042 
1043  $meeting_obj->DeleteFromDB(); // Delete the meeting.
1044 
1045  // Write out the death certificate.
1046  $ret = '<meetingId>'.$id.'</meetingId><meeting_id>'.$id.'</meeting_id><meetingName>'.$name.'</meetingName><meetingServiceBodyId>'.$service_body_id.'</meetingServiceBodyId><meetingStartTime>'.$start_time.'</meetingStartTime><meetingWeekday>'.$weekday.'</meetingWeekday>';
1047  $ret = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<deletedMeeting xmlns=\"http://".c_comdef_htmlspecialchars($_SERVER['SERVER_NAME'])."\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"".$this->getMainURL()."client_interface/xsd/DeletedMeeting.php\" id=\"$id\">$ret</deletedMeeting>";
1048  } else {
1049  $ret = '<h1>NOT AUTHORIZED</h1>';
1050  }
1051  } else {
1052  $ret = '<h1>ERROR</h1>';
1053  }
1054  } else {
1055  $ret = '<h1>NOT AUTHORIZED</h1>';
1056  }
1057 
1058  return $ret;
1059  }
1060 
1061  /********************************************************************************************************//**
1062  \brief This fulfills a user request to modify fields in a meeting (or create a new meeting).
1063  This requires that the following HTTP parameters be set:
1064  - meeting_id This is an integer that is the BMLT ID of the meeting being modified (the user must have edit rights to this meeting). If this is 0 (or unset), then we will be creating a new meeting.
1065  If we are creating a new meeting, the new meeting will start at 8:30PM on Sunday, unless new values for the 'weekday' and 'start_time' fields are provided.
1066  Once the meeting is created, we can set any of its fields as given.
1067  - meeting_field This is a string, or array of string, with the field name in the meeting search response.
1068  - new_value This is a string, or array of string, with the new value for the field. If the meeting_field parameter is an array, then each value here needs to be specified to correspond with the field.
1069 
1070  \returns XML, containing the fields modified.
1071  ************************************************************************************************************/
1072  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
1073  public function process_meeting_modify()
1074  {
1075  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
1076  $ret = null;
1077 
1078  $user_obj = $this->server->GetCurrentUserObj();
1079  // First, make sure the use is of the correct general type.
1080  if ($this->basic_user_validation()) {
1081  $closing_tag = '</changeMeeting>'; // We will usually be changing existing meetings.
1082  $my_editable_service_bodies = array();
1083  $thisIsANewMeeting = false; // Set to true for new meetings.
1084 
1085  $service_bodies = $this->server->GetServiceBodyArray();
1086 
1087  if ($user_obj->GetUserLevel() == _USER_LEVEL_SERVICE_BODY_ADMIN) { // Must be a Service Body Admin.
1088  // We cycle through all the Service bodies, and look for ones in which we have permissions.
1089  // We use the Service body IDs to key them in associative arrays.
1090  foreach ($service_bodies as $service_body) {
1091  if ($service_body->UserCanEditMeetings()) { // We are a full Service body editor, with rights to edit the Service body itself (as well as all its meetings).
1092  $my_editable_service_bodies['sb_'.$service_body->GetID()] = $service_body;
1093  }
1094  }
1095  }
1096 
1097  $new_meeting_id = 0;
1098  // Get the meeting object, itself.
1099  if (!intval($this->http_vars['meeting_id'])) { // Will we be creating a new meeting?
1100  $service_bodies = $this->server->GetServiceBodyArray();
1101 
1102  if ($user_obj->GetUserLevel() == _USER_LEVEL_SERVICE_BODY_ADMIN) { // Must be a Service Body Admin.
1103  if (isset($my_editable_service_bodies) && is_array($my_editable_service_bodies) && count($my_editable_service_bodies)) {
1104  $service_body_id = 0;
1105 
1106  // If we are allowed to edit more than one Service body, then we are given a choice. We must supply an ID for the new meeting.
1107  if (count($my_editable_service_bodies) > 1) {
1108  if (isset($this->http_vars['service_body_id']) && intval($this->http_vars['service_body_id'])) {
1109  $service_body_id = intval($this->http_vars['service_body_id']);
1110  } else {
1111  $meeting_fields = $this->http_vars['meeting_field'];
1112 
1113  foreach ($meeting_fields as $field) {
1114  list ( $key, $value ) = explode(',', $field);
1115 
1116  if ($key == 'service_body_bigint') {
1117  $service_body_id = intval($value);
1118  break;
1119  }
1120  }
1121  }
1122  } else // Otherwise, it is picked for us.
1123  {
1124  // We have to do this odd dance, because it's an associative array.
1125  $keys_1 = array_keys($my_editable_service_bodies);
1126 
1127  $service_body = $my_editable_service_bodies[$keys_1[0]];
1128 
1129  if ($service_body instanceof c_comdef_service_body) {
1130  $service_body_id = $service_body->GetID();
1131  }
1132  }
1133 
1134  $weekday = 1; // Default is Sunday
1135  $start_time = '20:30:00'; // Default is 8:30 PM
1136  $lang = c_comdef_server::GetServer()->GetLocalLang(); // We use whatever the server language is.
1137  if ($service_body_id) { // Can't create a new meeting without a Service body.
1138  $service_body = c_comdef_server::GetServer()->GetServiceBodyByIDObj($service_body_id);
1139 
1140  if ($service_body instanceof c_comdef_service_body) {
1141  if ($service_body->UserCanEditMeetings($user_obj)) {
1142  $new_meeting_id = c_comdef_server::AddNewMeeting($service_body_id, $weekday, $start_time, $lang);
1143  $meeting_obj = $this->server->GetOneMeeting(intval($new_meeting_id));
1144  $meeting_obj->SetPublished(false); // New meetings are always unpublished.
1145  $meeting_id = $new_meeting_id;
1146  $ret = '<newMeeting id="'.intval($meeting_obj->GetID()).'">';
1147  $thisIsANewMeeting = true;
1148  $closing_tag = '</newMeeting>';
1149  } else {
1150  $ret = '<h1>NOT AUTHORIZED</h1>';
1151  }
1152  } else {
1153  $ret = '<h1>ERROR</h1>';
1154  }
1155  } else {
1156  $ret = '<h1>ERROR</h1>';
1157  }
1158  } else {
1159  $ret = '<h1>NOT AUTHORIZED</h1>';
1160  }
1161  } else {
1162  $ret = '<h1>NOT AUTHORIZED</h1>';
1163  }
1164  } else {
1165  $meeting_obj = $this->server->GetOneMeeting(intval($this->http_vars['meeting_id']));
1166  $ret = '<changeMeeting id="'.intval($meeting_obj->GetID()).'">';
1167  }
1168 
1169  if ($meeting_obj instanceof c_comdef_meeting) {
1170  if ($meeting_obj->UserCanEdit($user_obj)) { // We next make sure that we are allowed to make changes to this meeting.
1171  $keys = c_comdef_meeting::GetAllMeetingKeys(); // Get all the available keys. The one passed in needs to match one of these.
1172  $localized_strings = c_comdef_server::GetLocalStrings();
1173 
1174  // In case we need to add a new field, we get the meeting data template.
1175  $template_data = c_comdef_meeting::GetDataTableTemplate();
1176  $template_longdata = c_comdef_meeting::GetLongDataTableTemplate();
1177 
1178  // We merge the two tables (data and longdata).
1179  if (is_array($template_data) && count($template_data) && is_array($template_longdata) && count($template_longdata)) {
1180  $template_data = array_merge($template_data, $template_longdata);
1181  }
1182 
1183  // If so, we take the field, and tweak its value.
1184  $meeting_fields = $this->http_vars['meeting_field'];
1185 
1186  if (!is_array($meeting_fields)) {
1187  $meeting_fields = array ( $meeting_fields );
1188  }
1189 
1190  // We change each of the fields passed in to the new values passed in.
1191  foreach ($meeting_fields as $field) {
1192  list ( $meeting_field, $value ) = explode(',', $field, 2);
1193  if (strpos($value, "##-##")) { // Look for our special flagged items.
1194  $temp = explode("##-##", $value);
1195  $value = $temp[count($temp) - 1];
1196  }
1197 
1198  if (isset($meeting_field) && in_array($meeting_field, $keys)) {
1199  switch ($meeting_field) {
1200  case 'id_bigint': // We don't currently let these get changed.
1201  case 'lang_enum':
1202  $value = null;
1203  $old_value = null;
1204  break;
1205 
1206  case 'service_body_bigint':
1207  if (isset($my_editable_service_bodies) && is_array($my_editable_service_bodies) && count($my_editable_service_bodies)) {
1208  $before_id = intval($meeting_obj->GetServiceBodyID());
1209  $after_id = intval($value);
1210 
1211  // Have to be allowed to edit both.
1212  if ($my_editable_service_bodies['sb_'.$before_id] && $my_editable_service_bodies['sb_'.$after_id]) {
1213  $old_value = $meeting_obj->GetServiceBodyID();
1214  $meeting_obj->SetServiceBodyID(intval($value));
1215  } else {
1216  $ret = '<h1>NOT AUTHORIZED</h1>';
1217  }
1218  } else {
1219  $ret = '<h1>NOT AUTHORIZED</h1>';
1220  }
1221  break;
1222 
1223  case 'email_contact':
1224  $old_value = $meeting_obj->GetEmailContact();
1225  $meeting_obj->SetEmailContact(intval($value));
1226  break;
1227 
1228  case 'published':
1229  if (!$new_meeting_id) { // New meetings are always unpublished.
1230  $old_value = $meeting_obj->IsPublished();
1231  $meeting_obj->SetPublished(intval($value) != 0 ? true : false);
1232  } else {
1233  $old_value = 0;
1234  $value = 0;
1235  }
1236  break;
1237 
1238  case 'weekday_tinyint':
1239  if ((intval($value) > 0) && (intval($value) < 8)) {
1240  $old_value = $meeting_obj->GetMeetingDataValue($meeting_field);
1241  $data =& $meeting_obj->GetMeetingData();
1242  $data[$meeting_field] = intval($value);
1243  }
1244  break;
1245 
1246  case 'longitude':
1247  case 'latitude':
1248  if (floatval($value) != 0.0) {
1249  $old_value = $meeting_obj->GetMeetingDataValue($meeting_field);
1250  $data =& $meeting_obj->GetMeetingData();
1251  $data[$meeting_field] = floatval($value);
1252  }
1253  break;
1254 
1255  case 'start_time':
1256  case 'duration_time':
1257  case 'time_zone':
1258  $old_value = $meeting_obj->GetMeetingDataValue($meeting_field);
1259  $data =& $meeting_obj->GetMeetingData();
1260  $data[$meeting_field] = $value;
1261  break;
1262 
1263  case 'formats':
1264  // Formats take some extra work, because we store them in the meeting as individual objects, so we create, sort and apply those objects.
1265  $old_value_array = $meeting_obj->GetMeetingDataValue($meeting_field);
1266  $lang = $this->server->GetLocalLang();
1267  $vals = array();
1268 
1269  foreach ($old_value_array as $format) {
1270  if ($format) {
1271  $vals[$format->GetSharedID()] = $format;
1272  }
1273  }
1274 
1275  uksort($vals, array ( 'c_comdef_meeting','format_sorter_simple' ));
1276 
1277  $keys_2 = array();
1278  foreach ($vals as $format) {
1279  $keys_2[] = $format->GetKey();
1280  }
1281 
1282  $old_value = implode(",", $keys_2);
1283 
1284  $formats = explode(",", $value);
1285  $formats_object = $this->server->GetFormatsObj();
1286 
1287  $newVals = array();
1288  foreach ($formats as $key) {
1289  $object = $formats_object->GetFormatByKeyAndLanguage($key, $lang);
1290  if ($object instanceof c_comdef_format) {
1291  $newVals[$object->GetSharedID()] = $object;
1292  }
1293  }
1294 
1295  uksort($newVals, array ( 'c_comdef_meeting','format_sorter_simple' ));
1296  $data =& $meeting_obj->GetMeetingData();
1297  $data[$meeting_field] = $newVals;
1298  break;
1299 
1300  case 'worldid_mixed':
1301  $old_value = $meeting_obj->GetMeetingDataValue($meeting_field);
1302  $data =& $meeting_obj->GetMeetingData();
1303  $data[$meeting_field] = $value;
1304  break;
1305 
1306  case 'meeting_name':
1307  $old_value = $meeting_obj->GetMeetingDataValue($meeting_field);
1308  if (!isset($value) || !$value) {
1309  $value = $localized_strings["comdef_server_admin_strings"]["Value_Prompts"]["generic"];
1310  }
1311  // Assuming fallthrough is intentional here, due to lack of break statement?
1312 
1313  default:
1314  $old_value = $meeting_obj->GetMeetingDataValue($meeting_field);
1315  $data =& $meeting_obj->GetMeetingData();
1316  $prompt = isset($data[$meeting_field]['field_prompt']) ? $data[$meeting_field]['field_prompt'] : $template_data[$meeting_field]['field_prompt'];
1317  $visibility = intval(isset($data[$meeting_field]['visibility']) ? $data[$meeting_field]['visibility'] : $template_data[$meeting_field]['visibility']);
1318  $meeting_obj->AddDataField($meeting_field, $prompt, $value, null, $visibility, true);
1319  break;
1320  }
1321 
1322  // We only indicate changes.
1323  if (isset($meeting_field) && $meeting_field && !($thisIsANewMeeting && !(isset($value) && $value)) && ((isset($old_value) && $old_value) || (isset($value) && $value)) && ($old_value != $value)) {
1324  $ret_temp = '';
1325  $ret_temp_internal = '';
1326  // New meetings have no old data.
1327  if (!$thisIsANewMeeting && isset($old_value) && $old_value) {
1328  $ret_temp_internal .= '<oldValue>'.c_comdef_htmlspecialchars($old_value).'</oldValue>';
1329  }
1330 
1331  if (isset($value) && $value) {
1332  $ret_temp_internal .= '<newValue>'.c_comdef_htmlspecialchars($value).'</newValue>';
1333  }
1334 
1335  $ret_temp .= '<field key="'.c_comdef_htmlspecialchars($meeting_field).'">'.$ret_temp_internal.'</field>';
1336 
1337  // We only send back changes that were actually made. This reduces empty response data.
1338  if ($ret_temp_internal) {
1339  $ret .= $ret_temp;
1340  }
1341  }
1342 
1343  $meeting_field = null;
1344  }
1345  }
1346 
1347  // This can short-circuit the operation.
1348  if ($ret != '<h1>NOT AUTHORIZED</h1>') {
1349  $meeting_obj->UpdateToDB(); // Save the new data. After this, the meeting has been changed.
1350 
1351  $ret .= $closing_tag;
1352 
1353  $ret = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<changeResponse xmlns=\"http://".c_comdef_htmlspecialchars($_SERVER['SERVER_NAME'])."\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"".$this->getMainURL()."client_interface/xsd/ChangeResponse.php\">$ret</changeResponse>";
1354  }
1355  } else {
1356  $ret = '<h1>NOT AUTHORIZED</h1>';
1357  }
1358  } else {
1359  $ret = '<h1>ERROR</h1>';
1360  }
1361  } else {
1362  $ret = '<h1>NOT AUTHORIZED</h1>';
1363  }
1364 
1365  return $ret;
1366  }
1367 
1368  /********************************************************************************************************//**
1369  \brief This fulfills a user request to return meeting information from a search.
1370 
1371  \returns XML, containing the answer.
1372  ************************************************************************************************************/
1373  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
1374  public function process_meeting_search()
1375  {
1376  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
1377  if (!( isset($this->http_vars['geo_width']) && $this->http_vars['geo_width'] ) && isset($this->http_vars['bmlt_search_type']) && ($this->http_vars['bmlt_search_type'] == 'advanced') && isset($this->http_vars['advanced_radius']) && isset($this->http_vars['advanced_mapmode']) && $this->http_vars['advanced_mapmode'] && ( floatval($this->http_vars['advanced_radius'] != 0.0) ) && isset($this->http_vars['lat_val']) && isset($this->http_vars['long_val']) && ( (floatval($this->http_vars['lat_val']) != 0.0) || (floatval($this->http_vars['long_val']) != 0.0) )) {
1378  $this->http_vars['geo_width'] = $this->http_vars['advanced_radius'];
1379  } elseif (!( isset($this->http_vars['geo_width']) && $this->http_vars['geo_width'] ) && isset($this->http_vars['bmlt_search_type']) && ($this->http_vars['bmlt_search_type'] == 'advanced')) {
1380  $this->http_vars['lat_val'] = null;
1381  $this->http_vars['long_val'] = null;
1382  } elseif (!isset($this->http_vars['geo_loc']) || $this->http_vars['geo_loc'] != 'yes') {
1383  if (!isset($this->http_vars['geo_width'])) {
1384  $this->http_vars['geo_width'] = 0;
1385  }
1386  }
1387 
1388  require_once(dirname(dirname(dirname(__FILE__))).'/client_interface/csv/search_results_csv.php');
1389 
1390  $geocode_results = null;
1391  $ignore_me = null;
1392  $meeting_objects = array();
1393  $formats_ar = array ();
1394  $result2 = DisplaySearchResultsCSV($this->http_vars, $ignore_me, $geocode_results, $meeting_objects);
1395 
1396  if (is_array($meeting_objects) && count($meeting_objects) && is_array($formats_ar)) {
1397  foreach ($meeting_objects as $one_meeting) {
1398  $formats = $one_meeting->GetMeetingDataValue('formats');
1399 
1400  foreach ($formats as $format) {
1401  if ($format && ($format instanceof c_comdef_format)) {
1402  $format_shared_id = $format->GetSharedID();
1403  $formats_ar[$format_shared_id] = $format;
1404  }
1405  }
1406  }
1407  }
1408 
1409  if (isset($this->http_vars['data_field_key']) && $this->http_vars['data_field_key']) {
1410  // At this point, we have everything in a CSV. We separate out just the field we want.
1411  $temp_keyed_array = array();
1412  $result = explode("\n", $result);
1413  $keys = array_shift($result);
1414  $keys = explode("\",\"", trim($keys, '"'));
1415  $the_keys = explode(',', $this->http_vars['data_field_key']);
1416 
1417  $result = array();
1418  foreach ($result2 as $row) {
1419  if ($row) {
1420  $index = 0;
1421  $row = explode('","', trim($row, '",'));
1422  $row_columns = array();
1423  foreach ($row as $column) {
1424  if (!$column) {
1425  $column = ' ';
1426  }
1427  if (in_array($keys[$index++], $the_keys)) {
1428  array_push($row_columns, $column);
1429  }
1430  }
1431  $result[$row[0]] = '"'.implode('","', $row_columns).'"';
1432  }
1433  }
1434 
1435  $the_keys = array_intersect($keys, $the_keys);
1436  $result2 = '"'.implode('","', $the_keys)."\"\n".implode("\n", $result);
1437  }
1438 
1439 
1440  $result = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<meetings xmlns=\"http://".c_comdef_htmlspecialchars($_SERVER['SERVER_NAME'])."\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"".$this->getMainURL()."client_interface/xsd/GetSearchResults.php\">";
1441  $result .= $this->TranslateCSVToXML($result2);
1442  if ((isset($http_vars['get_used_formats']) || isset($http_vars['get_formats_only'])) && $formats_ar && is_array($formats_ar) && count($formats_ar)) {
1443  if (isset($http_vars['get_formats_only'])) {
1444  $result = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<formats xmlns=\"http://".c_comdef_htmlspecialchars($_SERVER['SERVER_NAME'])."\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"".$this->getMainURL()."client_interface/xsd/GetFormats.php\">";
1445  } else {
1446  $result .= "<formats>";
1447  }
1448  $result3 = GetFormats($server, $langs, $formats_ar);
1449  $result .= TranslateToXML($result3);
1450 
1451  $result .= "</formats>";
1452  }
1453 
1454  $result .= isset($http_vars['get_formats_only']) ? "" : "</meetings>";
1455 
1456  return $result;
1457  }
1458 
1459  /********************************************************************************************************//**
1460  \brief This fulfills a user request to return format information.
1461 
1462  \returns XML, containing the answer.
1463  ************************************************************************************************************/
1464  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
1465  public function process_format_info()
1466  {
1467  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
1468  $ret = '';
1469 
1470  if ($this->basic_user_validation()) {
1471  $format_ids = array();
1472 
1473  // See if we are receiving a request for just specific formats, or if we are being asked for all of them.
1474  if (isset($this->http_vars['format_id']) && intval(trim($this->http_vars['format_id']))) {
1475  $format_ids[] = intval(trim($this->http_vars['format_id']));
1476  } elseif (isset($this->http_vars['format_id']) && is_array($this->http_vars['format_id']) && count($this->http_vars['format_id'])) {
1477  foreach ($this->http_vars['format_id'] as $format) {
1478  $format_ids[] = intval(trim($format));
1479  }
1480  } else {
1481  $format_ids = null;
1482  }
1483 
1484  $lang = $this->server->GetLocalLang();
1485  if (isset($this->http_vars['lang']) && trim($this->http_vars['lang'])) {
1486  $lang = strtolower(trim($this->http_vars['lang']));
1487  }
1488 
1489  $returned_formats = array(); // We will be returning our formats in this.
1490  $format_objects = $this->server->GetFormatsObj()->GetFormatsByLanguage($lang); // Get all the formats (not just the ones used, but ALL of them).
1491 
1492  // Filter for requested formats in the requested language.
1493  foreach ($format_objects as $format) {
1494  if (!$format_ids || in_array(intval($format->GetSharedID()), $format_ids)) {
1495  $returned_formats[] = $format;
1496  }
1497  }
1498 
1499  // At this point, we have a complete array of just the format[s] that will be returned. Time to make some XML...
1500  $index = 0;
1501 
1502  // We will find out which formats actually appear, somewhere in the DB, and indicate that when we give the info.
1503  $used_formats = $this->server->GetUsedFormatsArray();
1504  $used_ids = array();
1505 
1506  foreach ($used_formats as $format) {
1507  $used_ids[] = intval($format->GetSharedID());
1508  }
1509 
1510  foreach ($returned_formats as $format) {
1511  $ret .= '<row sequence_index="'.strval($index++).'">';
1512  $id = intval($format->GetSharedID());
1513  $ret.= '<key_string>'.c_comdef_htmlspecialchars($format->GetKey()).'</key_string>';
1514  $ret.= '<name_string>'.c_comdef_htmlspecialchars($format->GetLocalName()).'</name_string>';
1515  $ret.= '<description_string>'.c_comdef_htmlspecialchars($format->GetLocalDescription()).'</description_string>';
1516  $ret.= '<lang>'.c_comdef_htmlspecialchars($lang).'</lang>';
1517  $ret.= '<id>'.$id.'</id>';
1518  $world_id = trim($format->GetWorldID());
1519  if (isset($world_id) && $world_id) {
1520  $ret.= '<world_id>'.c_comdef_htmlspecialchars($world_id).'</world_id>';
1521  }
1522 
1523  // If this is used somewehere, we indicate it here.
1524  if (in_array($id, $used_ids)) {
1525  $ret.= '<format_used_in_database>1</format_used_in_database>';
1526  }
1527 
1528  $ret .= '</row>';
1529  }
1530  $ret = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<formats xmlns=\"http://".c_comdef_htmlspecialchars($_SERVER['SERVER_NAME'])."\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"".$this->getMainURL()."client_interface/xsd/GetFormats.php\">$ret</formats>";
1531  } else {
1532  $ret = '<h1>NOT AUTHORIZED</h1>';
1533  }
1534 
1535  return $ret;
1536  }
1537 
1538  /********************************************************************************************************//**
1539  \brief This fulfills a user request to return Service Body information for multiple Service bodies.
1540 
1541  \returns XML, containing the answer.
1542  ************************************************************************************************************/
1543  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
1545  {
1546  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
1547  $ret = '';
1548 
1549  if ($this->basic_user_validation()) {
1550  $service_body_ids = array();
1551 
1552  // Look to see if the caller is asking for particular Service bodies.
1553  if (isset($this->http_vars['sb_id']) && $this->http_vars['sb_id']) {
1554  if (!is_array($this->http_vars['sb_id'])) {
1555  $service_body_ids[] = intval(trim($this->http_vars['sb_id']));
1556  } else {
1557  foreach ($this->http_vars['sb_id'] as $id) {
1558  if (intval(trim($id))) {
1559  $service_body_ids[] = intval(trim($id));
1560  }
1561  }
1562  }
1563  }
1564 
1565  // If we have a request for individual Service bodies, then we just return those ones.
1566  if (isset($service_body_ids) && is_array($service_body_ids) && count($service_body_ids)) {
1567  foreach ($service_body_ids as $id) {
1568  $ret .= $this->process_service_body_info_request($id);
1569  }
1570  } else // If they are not looking for particular bodies, then we return the whole kit & kaboodle.
1571  {
1572  $service_bodies = $this->server->GetServiceBodyArray();
1573 
1574  foreach ($service_bodies as $service_body) {
1575  if (isset($this->http_vars['flat']) || !$service_body->GetOwnerIDObject()) { // We automatically include top-level Service bodies here, and let ones with parents sort themselves out.
1576  $ret .= $this->process_service_body_info_request($service_body->GetID());
1577  }
1578  }
1579  }
1580 
1581  $ret = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<service_bodies xmlns=\"http://".c_comdef_htmlspecialchars($_SERVER['SERVER_NAME'])."\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"".$this->getMainURL()."client_interface/xsd/HierServiceBodies.php\">$ret</service_bodies>";
1582  } else {
1583  $ret = '<h1>NOT AUTHORIZED</h1>';
1584  }
1585 
1586  return $ret;
1587  }
1588 
1589  /********************************************************************************************************//**
1590  \brief This fulfills a user request to return Service Body information.
1591 
1592  \returns XML, containing the answer.
1593  ************************************************************************************************************/
1594  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
1595  public function process_service_body_info_request( $in_service_body_id ///< The ID of the Service body being requested.
1596  )
1597  {
1598  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
1599  $ret = '';
1600  // Belt and suspenders. We need to make sure the user is authorized.
1601  if ($this->basic_user_validation()) {
1602  if (!in_array($in_service_body_id, $this->handled_service_body_ids)) {
1603  $this->handled_service_body_ids[] = $in_service_body_id;
1604  $service_body = $this->server->GetServiceBodyByIDObj($in_service_body_id);
1605 
1606  if (isset($service_body) && ($service_body instanceof c_comdef_service_body)) {
1607  // Everyone gets the type, URI, name, description and parent Service body.
1608  $name = $service_body->GetLocalName();
1609  $description = $service_body->GetLocalDescription();
1610  $uri = $service_body->GetURI();
1611  $helpline = $service_body->GetHelpline();
1612  $type = $service_body->GetSBType();
1613 
1614  $parent_service_body_id = 0;
1615  $parent_service_body_name = "";
1616  $parent_service_body_type = "";
1617 
1618  $parent_service_body = $service_body->GetOwnerIDObject();
1619 
1620  if (isset($parent_service_body) && $parent_service_body) {
1621  $parent_service_body_id = intval($parent_service_body->GetID());
1622  $parent_service_body_name = $parent_service_body->GetLocalName();
1623  $parent_service_body_type = $parent_service_body->GetSBType();
1624  }
1625 
1626  $principal_user = $service_body->GetPrincipalUserObj();
1627  $principal_user_id = intval($principal_user->GetID());
1628 
1629  // Scan for our various editors.
1630  $guest_editors = $this->server->GetUsersByLevelObj(_USER_LEVEL_OBSERVER, true); // Observer or greater.
1631  $service_body_editors = array();
1632  $meeting_list_editors = array();
1633  $observers = array();
1634 
1635  foreach ($guest_editors as $editor) {
1636  if ($service_body->UserCanEdit($editor)) { // We will have at least one of these, as the principal user needs to be listed.
1637  array_push($service_body_editors, $editor);
1638  } elseif ($service_body->UserCanEditMeetings($editor)) {
1639  array_push($meeting_list_editors, $editor);
1640  } elseif ($service_body->UserCanObserve($editor)) {
1641  array_push($observers, $editor);
1642  }
1643  }
1644 
1645  // Scan for direct descendant child Service bodies.
1646  $children = array();
1647  $service_bodies = $this->server->GetServiceBodyArray();
1648 
1649  foreach ($service_bodies as $child) {
1650  if ($child->IsOwnedBy($in_service_body_id, true)) {
1651  $children[] = $child;
1652  }
1653  }
1654 
1655  // We check to see which editors are mentioned in this Service body.
1656  $guest_editors = $service_body->GetEditors();
1657 
1658  // See if we have rights to edit this Service body. Just for the heck of it, we check the user level (not really necessary, but belt and suspenders).
1659  $this_user_can_edit_the_body = ($this->server->GetCurrentUserObj()->GetUserLevel() == _USER_LEVEL_SERVICE_BODY_ADMIN) && $service_body->UserCanEdit();
1660 
1661  $contact_email = null;
1662 
1663  // Service Body Admins (with permission for the body) get more info.
1664  if ($this_user_can_edit_the_body) {
1665  $contact_email = $service_body->GetContactEmail();
1666  }
1667 
1668  // At this point, we have all the information we need to build the response XML.
1669  $ret = '<service_body id="'.c_comdef_htmlspecialchars($in_service_body_id).'" name="'.c_comdef_htmlspecialchars($name).'" type="'.c_comdef_htmlspecialchars($type).'">';
1670  $ret .= '<service_body_type>'.c_comdef_htmlspecialchars($this->my_localized_strings['service_body_types'][$type]).'</service_body_type>';
1671  if (isset($description) && $description) {
1672  $ret .= '<description>'.c_comdef_htmlspecialchars($description).'</description>';
1673  }
1674  if (isset($uri) && $uri) {
1675  $ret .= '<uri>'.c_comdef_htmlspecialchars($uri).'</uri>';
1676  }
1677  if (isset($helpline) && $helpline) {
1678  $ret .= '<helpline>'.c_comdef_htmlspecialchars($helpline).'</helpline>';
1679  }
1680  if (isset($parent_service_body) && $parent_service_body) {
1681  $ret .= '<parent_service_body id="'.intval($parent_service_body_id).'" type="'.c_comdef_htmlspecialchars($parent_service_body_type).'">'.c_comdef_htmlspecialchars($parent_service_body_name).'</parent_service_body>';
1682  }
1683  if ($this_user_can_edit_the_body && isset($contact_email) && $contact_email) {
1684  $ret .= '<contact_email>'.c_comdef_htmlspecialchars($contact_email).'</contact_email>';
1685  }
1686 
1687  $ret .= '<editors>';
1688  if (isset($service_body_editors) && is_array($service_body_editors) && count($service_body_editors)) {
1689  // We will have at least one of these (the principal user).
1690  // These are the users that can directly manipulate the Service body.
1691  $ret .= '<service_body_editors>';
1692  foreach ($service_body_editors as $editor) {
1693  $editor_id = intval($editor->GetID());
1694  $ret .= '<editor id="'.$editor_id.'" admin_type="'.( in_array($editor_id, $guest_editors) ? 'direct' : (( $editor_id == $principal_user_id ) ? 'principal' : 'inherit')).'" admin_name="'.c_comdef_htmlspecialchars($editor->GetLocalName()).'"/>';
1695  }
1696  $ret .= '</service_body_editors>';
1697  }
1698 
1699  // These are users that can't manipulate the Service body, but can edit meetings.
1700  if (isset($meeting_list_editors) && is_array($meeting_list_editors) && count($meeting_list_editors)) {
1701  $ret .= '<meeting_list_editors>';
1702  foreach ($meeting_list_editors as $editor) {
1703  $editor_id = intval($editor->GetID());
1704  $ret .= '<editor id="'.$editor_id.'" admin_type="'.( in_array($editor_id, $guest_editors) ? 'direct' : (( $editor_id == $principal_user_id ) ? 'principal' : 'inherit' )).'" admin_name="'.c_comdef_htmlspecialchars($editor->GetLocalName()).'"/>';
1705  }
1706  $ret .= '</meeting_list_editors>';
1707  }
1708 
1709  // These are users that can only see hidden fields in meetings.
1710  if (isset($observers) && is_array($observers) && count($observers)) {
1711  $ret .= '<observers>';
1712  foreach ($observers as $editor) {
1713  $editor_id = intval($editor->GetID());
1714  $ret .= '<editor id="'.$editor_id.'" admin_type="'.( in_array($editor_id, $guest_editors) ? 'direct' : (( $editor_id == $principal_user_id ) ? 'principal' : 'inherit' )).'" admin_name="'.c_comdef_htmlspecialchars($editor->GetLocalName()).'"/>';
1715  }
1716  $ret .= '</observers>';
1717  }
1718  $ret .= '</editors>';
1719 
1720  // If this is a hierarchical response, we embed the children as XML service_body elements. Otherwise, we list them as simple catalog elements.
1721  if (!isset($this->http_vars['flat']) && isset($children) && is_array($children) && count($children)) {
1722  $ret .= "<service_bodies>";
1723  foreach ($children as $child) {
1724  $ret .= $this->process_service_body_info_request($child->GetID());
1725  }
1726  $ret .= "</service_bodies>";
1727  } elseif (isset($children) && is_array($children) && count($children)) {
1728  $ret .= '<children>';
1729  foreach ($children as $child) {
1730  $ret .= '<child_service_body id="'.intval($child->GetID()).'" type="'.c_comdef_htmlspecialchars($child->GetSBType()).'">'.c_comdef_htmlspecialchars($child->GetLocalName()).'</child_service_body>';
1731  }
1732  $ret .= '</children>';
1733  }
1734 
1735  $ret .= '</service_body>';
1736  }
1737  }
1738  } else {
1739  $ret = '<h1>NOT AUTHORIZED</h1>';
1740  }
1741 
1742  return $ret;
1743  }
1744 
1745  /********************************************************************************************************//**
1746  \brief This fulfills a user request to report the rights for the logged-in user.
1747 
1748  \returns XML, containing the answer.
1749  ************************************************************************************************************/
1750  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
1752  {
1753  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
1754  $ret = '';
1755  $service_bodies = $this->server->GetServiceBodyArray();
1756 
1757  // We will fill these three arrays, depending on the users' rights for a given Service body.
1758  $my_meeting_observer_service_bodies = array();
1759  $my_meeting_editor_service_bodies = array();
1760  $my_editable_service_bodies = array();
1761 
1762  $user_obj = $this->server->GetCurrentUserObj();
1763  if ($this->basic_user_validation()) {
1764  // We cycle through all the Service bodies, and look for ones in which we have permissions.
1765  // We use the Service body IDs to key them in associative arrays.
1766  foreach ($service_bodies as $service_body) {
1767  if (($user_obj->GetUserLevel() == _USER_LEVEL_SERVICE_BODY_ADMIN) && $service_body->UserCanEdit()) { // We are a full Service body editor, with rights to edit the Service body itself (as well as all its meetings).
1768  $my_editable_service_bodies['sb_'.$service_body->GetID()] = $service_body;
1769  } elseif ((($user_obj->GetUserLevel() == _USER_LEVEL_SERVICE_BODY_ADMIN) || ($user_obj->GetUserLevel() == _USER_LEVEL_OBSERVER)) && $service_body->UserCanObserve()) { // We are a "guest" editor, or an observer (depends on our user level).
1770  // Again, we keep checking credentials, over and over again.
1771  if ($user_obj->GetUserLevel() == _USER_LEVEL_OBSERVER) {
1772  $my_meeting_observer_service_bodies['sb_'.$service_body->GetID()] = $service_body;
1773  } elseif ($service_body->UserCanEditMeetings()) {
1774  $my_meeting_editor_service_bodies['sb_'.$service_body->GetID()] = $service_body;
1775  }
1776  }
1777  }
1778  // Now, we grant rights to Service bodies that are implicit from other rights (for example, a Service Body Admin can also observe and edit meetings).
1779 
1780  // A full Service Body Admin can edit meetings in that Service body.
1781  foreach ($my_editable_service_bodies as $service_body) {
1782  $my_meeting_editor_service_bodies['sb_'.$service_body->GetID()] = $service_body;
1783  }
1784 
1785  // An editor (whether an admin or a "guest") also has observe rights.
1786  foreach ($my_meeting_editor_service_bodies as $service_body) {
1787  $my_meeting_observer_service_bodies['sb_'.$service_body->GetID()] = $service_body;
1788  }
1789 
1790  // At this point, we have 3 arrays (or fewer), filled with Service bodies that we have rights on. It is entirely possible that only one of them could be filled, and it may only have one member.
1791 
1792  // We start to construct the XML filler.
1793  foreach ($service_bodies as $service_body) {
1794  // If we can observe, then we have at least one permission for this Service body.
1795  if (isset($my_meeting_observer_service_bodies['sb_'.$service_body->GetID()]) && $my_meeting_observer_service_bodies['sb_'.$service_body->GetID()]) {
1796  $ret .= '<service_body id="'.$service_body->GetID().'" name="'.c_comdef_htmlspecialchars($service_body->GetLocalName()).'" permissions="';
1797  if (isset($my_editable_service_bodies['sb_'.$service_body->GetID()]) && $my_editable_service_bodies['sb_'.$service_body->GetID()]) {
1798  $ret .= '3';
1799  } elseif (isset($my_meeting_editor_service_bodies['sb_'.$service_body->GetID()]) && $my_meeting_editor_service_bodies['sb_'.$service_body->GetID()]) {
1800  $ret .= '2';
1801  } elseif (isset($my_meeting_observer_service_bodies['sb_'.$service_body->GetID()]) && $my_meeting_observer_service_bodies['sb_'.$service_body->GetID()]) {
1802  $ret .= '1';
1803  } else {
1804  $ret .= '0';
1805  }
1806  $ret .= '"/>';
1807  }
1808  }
1809  // Create a proper XML wrapper for the response data.
1810  $ret = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<permissions xmlns=\"http://".c_comdef_htmlspecialchars($_SERVER['SERVER_NAME'])."\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"".$this->getMainURL()."client_interface/xsd/AdminPermissions.php\">$ret</permissions>";
1811  // We now have XML that states the current user's permission levels in all Service bodies.
1812  } else {
1813  $ret = '<h1>NOT AUTHORIZED</h1>';
1814  }
1815 
1816  return $ret;
1817  }
1818 
1819  /********************************************************************************************************//**
1820  \brief This fulfills a user request to return the current users info.
1821 
1822  \returns XML, containing the answer.
1823  ************************************************************************************************************/
1824  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
1825  public function process_user_info()
1826  {
1827  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
1828  $ret = '';
1829  $user_obj = $this->server->GetCurrentUserObj();
1830 
1831  if ($this->basic_user_validation()) {
1832  $ret = '<current_user id="'.$user_obj->GetID().'" name="'.c_comdef_htmlspecialchars($user_obj->GetLocalName()).'" type="' . $user_obj->GetUserLevel() . '"/>';
1833  // Create a proper XML wrapper for the response data.
1834  $ret = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<user_info xmlns=\"http://".c_comdef_htmlspecialchars($_SERVER['SERVER_NAME'])."\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"".$this->getMainURL()."client_interface/xsd/UserInfo.php\">$ret</user_info>";
1835  // We now have XML that states the current user's permission levels in all Service bodies.
1836  } else {
1837  $ret = '<h1>NOT AUTHORIZED</h1>';
1838  }
1839 
1840  return $ret;
1841  }
1842 
1843  /*******************************************************************/
1844  /**
1845  \brief Translates CSV to XML.
1846 
1847  \returns an XML string, with all the data in the CSV.
1848  */
1849  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
1850  public function TranslateCSVToXML( $in_csv_data ///< An array of CSV data, with the first element being the field names.
1851  )
1852  {
1853  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
1854  require_once(dirname(dirname(dirname(__FILE__))).'/server/shared/Array2XML.php');
1855  $temp_keyed_array = array();
1856  $in_csv_data = explode("\n", $in_csv_data);
1857  $keys = array_shift($in_csv_data);
1858  $keys = rtrim(ltrim($keys, '"'), '",');
1859  $keys = preg_split('/","/', $keys);
1860 
1861  foreach ($in_csv_data as $row) {
1862  if ($row) {
1863  $line = null;
1864  $index = 0;
1865  $row_t = rtrim(ltrim($row, '"'), '",');
1866  $row_t = preg_split('/","/', $row_t);
1867  foreach ($row_t as $column) {
1868  if (isset($column)) {
1869  $line[$keys[$index++]] = trim($column);
1870  }
1871  }
1872  array_push($temp_keyed_array, $line);
1873  }
1874  }
1875 
1876  $out_xml_data = array2xml($temp_keyed_array, 'not_used', false);
1877 
1878  return $out_xml_data;
1879  }
1880 }
static GetLocalStrings($in_lang_enum=null)
This gets the appropriate language files, and puts all the the strings into an associative array...
$uri
Definition: index.php:25
A Class for Service Body Objects.
__construct($in_http_vars, $in_server)
The class constructor.
process_user_info()
This fulfills a user request to return the current users info.
A class to hold a single meeting object.
$handled_service_body_ids
This is used to ensure that we respect the hierarchy when doing a hierarchical Service body request...
process_capabilities_request()
This fulfills a user request to report the rights for the logged-in user.
function htmlspecialchars_decode(string, quote_style)
process_rollback_meeting()
This fulfills a user request to restore a single deleted meeting.
static AddNewMeeting($in_service_body_bigint, $in_weekday_tinyint, $in_start_time_int, $in_lang_enum)
Creates a new, relatively empty meeting in the database, with no data fields and minimal information...
static GetAllMeetingKeys()
Returns an array of strings, containing the keys (table columns) used for all meetings (specified in ...
process_commands()
This is called to process the input and generate the output. It is the "heart" of the class...
This class handles BMLT users. One instance is created for each user on the server.
$http_vars
This will hold the combined GET and POST parameters for this call.
TranslateToXML($in_csv_data)
Translates CSV to XML.
Definition: csv.php:1535
static GetLongDataTableTemplate($in_lang_enum=null)
Returns an array that provides a template for the long data table values (the optional/additional val...
$ret
Definition: contact.php:226
getMainURL()
This returns the URL to the main server. It needs extra stripping, because we&#39;re depper than usual...
process_deleted_meetings()
This fulfills a user request to delete a meeting.
const _USER_LEVEL_SERVICE_BODY_ADMIN
const _USER_LEVEL_OBSERVER
array2xml($array, $name= 'array', $beginning=true)
array2xml() will convert any given array into a XML structure.
Definition: Array2XML.php:38
process_get_field_templates()
This fulfills a user request to get all the available fields for adding/modifying meeting data...
$meeting_id
Definition: contact.php:227
const _USER_LEVEL_DISABLED
GetFormats(&$server, $in_lang=null, $in_formats=null)
This returns the complete formats table.
Definition: csv.php:896
const _USER_LEVEL_SERVER_ADMIN
A Class for Format Codes.
process_meeting_search()
This fulfills a user request to return meeting information from a search.
global $http_vars
Definition: index.php:21
static GetUserByIDObj($in_user_id_bigint)
Get the object for a single user, given an ID.
c_comdef_htmlspecialchars($in_string)
This function creates a displayable string.
static GetMeetingsByID($in_id_bigint_array)
Get a series of meetings, each identified by an ID. This does not filter by any of the other major cr...
get_meeting_data($meeting_id)
This extracts a meeting&#39;s essential data as XML.
process_service_body_info_request($in_service_body_id)
This fulfills a user request to return Service Body information.
get_changes_as_csv($in_start_date=null, $in_end_date=null, $in_meeting_id=null, $in_user_id=null, $in_sb_id=null, $in_change_type= 'c_comdef_meeting')
This returns change records in CSV form (which we turn into XML).
$server
Definition: GetLangs.php:25
$my_localized_strings
An array of localized strings.
A Class for Change Record Objects.
process_format_info()
This fulfills a user request to return format information.
A class to hold a collection of c_comdef_change objects.
GetURLToMainServerDirectory($inAllowHTTPS=true)
Returns a URL (HTTP) to the main_server directory (or renamed).
static GetMainDataTemplate()
Returns an array that provides a template for the main table values (the standard values)...
static GetServiceBodyByIDObj($in_service_body_id_bigint)
Get the object for a single service body, given an ID.
process_meeting_modify()
This fulfills a user request to modify fields in a meeting (or create a new meeting). This requires that the following HTTP parameters be set:
DisplaySearchResultsCSV($in_http_vars, &$return_array=null, &$return_geocode=null, &$return_results=null, $in_supress_hidden_concat=false, $in_editor_only=false)
This function does a search, then builds a CSV result, with each row being a meeting. The first row is a row of keys.
process_service_bodies_info_request()
This fulfills a user request to return Service Body information for multiple Service bodies...
process_meeting_delete()
This fulfills a user request to delete an existing meeting. $this->http_vars[&#39;meeting_id&#39;] must be se...
static GetDataTableTemplate()
Returns an array that provides a template for the data table values (the optional/additional values)...
defined('BMLT_EXEC') or define('BMLT_EXEC'
Definition: index.php:3
process_changes()
This fulfills a user request to get change records.
static GetChangesFromIDAndType($in_type, $in_id=null, $in_start_date=null, $in_end_date=null)
Gets a list of all change objects of a certain type, or only one, if the change affects a certain cla...
process_restore_deleted_meeting()
This fulfills a user request to restore a single deleted meeting.
$user_obj
Definition: index.php:7
$server
The BMLT server model instance.
static GetOneMeeting($in_id_bigint, $test_only=false)
Given an ID for a meeting, it returns one instance.
basic_user_validation()
This is a basic funtion that tests the current user, to see if they are basically valid...
TranslateCSVToXML($in_csv_data)
Translates CSV to XML.
Controls handling of the admin semantic interface.
get_deleted_meetings_as_csv($in_start_date=null, $in_end_date=null, $in_meeting_id=null, $in_user_id=null, $in_sb_id=null)
This returns deleted meeting records in CSV form (which we turn into XML).