From 5b51337010b573308ab6453685a6f86c62347c1b Mon Sep 17 00:00:00 2001 From: Yasen Pramatarov Date: Sun, 7 Jul 2024 12:10:41 +0300 Subject: [PATCH] Adds participant search page and filters --- CHANGELOG.md | 1 + public_html/classes/participant.php | 124 +++++++ public_html/classes/queries.php | 151 ++++++++ public_html/index.php | 1 + public_html/pages/conferences.php | 18 + public_html/pages/participants.php | 420 +++++++++++++++++++++++ public_html/static/all.css | 11 +- public_html/templates/menu.php | 1 + public_html/templates/results-filter.php | 4 + 9 files changed, 726 insertions(+), 5 deletions(-) create mode 100644 public_html/classes/participant.php create mode 100644 public_html/pages/participants.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 495a5af..9b8bf22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ All notable changes to this project will be documented in this file. - Added search filter for conferences with time, ID and name - Added front page widgets - Added demo installation on https://work.lindeas.com/jilo-web-demo/ +- Added participant search page ### Changed diff --git a/public_html/classes/participant.php b/public_html/classes/participant.php new file mode 100644 index 0000000..38476d3 --- /dev/null +++ b/public_html/classes/participant.php @@ -0,0 +1,124 @@ +db = $database->getConnection(); + $this->queries = include('queries.php'); + } + + + // search/list specific participant ID + public function conferenceByParticipantId($participant_id, $from_time, $until_time) { + + // time period drill-down + // FIXME make it similar to the bash version + if (empty($from_time)) { + $from_time = '0000-01-01'; + } + if (empty($until_time)) { + $until_time = '9999-12-31'; + } + + // this is needed for compatibility with the bash version, so we use '%s' placeholders + $from_time = htmlspecialchars(strip_tags($from_time)); + $until_time = htmlspecialchars(strip_tags($until_time)); + $sql = $this->queries['conference_by_participant_id']; + $sql = sprintf($sql, $participant_id, $from_time, $until_time, $participant_id, $from_time, $until_time); + + $query = $this->db->prepare($sql); + $query->execute(); + + return $query->fetchAll(PDO::FETCH_ASSOC); + } + + + // search/list specific participant name (stats_id) + public function conferenceByParticipantName($participant_name, $from_time, $until_time) { + + // time period drill-down + // FIXME make it similar to the bash version + if (empty($from_time)) { + $from_time = '0000-01-01'; + } + if (empty($until_time)) { + $until_time = '9999-12-31'; + } + + // this is needed for compatibility with the bash version, so we use '%s' placeholders + $from_time = htmlspecialchars(strip_tags($from_time)); + $until_time = htmlspecialchars(strip_tags($until_time)); + $sql = $this->queries['participant_by_stats_id']; + $sql = sprintf($sql, $participant_name, $from_time, $until_time, $participant_name, $from_time, $until_time); + + $query = $this->db->prepare($sql); + $query->execute(); + + return $query->fetchAll(PDO::FETCH_ASSOC); + } + + + // search/list specific participant IP + public function conferenceByParticipantIP($participant_ip, $from_time, $until_time) { + + // time period drill-down + // FIXME make it similar to the bash version + if (empty($from_time)) { + $from_time = '0000-01-01'; + } + if (empty($until_time)) { + $until_time = '9999-12-31'; + } + + // this is needed for compatibility with the bash version, so we use '%s' placeholders + $from_time = htmlspecialchars(strip_tags($from_time)); + $until_time = htmlspecialchars(strip_tags($until_time)); + $sql = $this->queries['participant_by_ip']; + $sql = sprintf($sql, $participant_ip, $from_time, $until_time, $participant_ip, $from_time, $until_time); + + $query = $this->db->prepare($sql); + $query->execute(); + + return $query->fetchAll(PDO::FETCH_ASSOC); + } + + + // list of all conferences + public function participantsAll($from_time, $until_time) { + + // time period drill-down + // FIXME make it similar to the bash version + if (empty($from_time)) { + $from_time = '0000-01-01'; + } + if (empty($until_time)) { + $until_time = '9999-12-31'; + } + + // this is needed for compatibility with the bash version, so we use '%s' placeholders + $from_time = htmlspecialchars(strip_tags($from_time)); + $until_time = htmlspecialchars(strip_tags($until_time)); + $sql = $this->queries['participants_all']; + $sql = sprintf($sql, $from_time, $until_time); + + $query = $this->db->prepare($sql); + $query->execute(); + + return $query->fetchAll(PDO::FETCH_ASSOC); + } + + +} + +?> diff --git a/public_html/classes/queries.php b/public_html/classes/queries.php index be825fc..9c25ef9 100644 --- a/public_html/classes/queries.php +++ b/public_html/classes/queries.php @@ -139,6 +139,157 @@ WHERE c.conference_name = '%s' AND (event_time >= '%s 00:00:00' AND event_time <= '%s 23:59:59') +ORDER BY + pe.time;", + + + // list all participants + 'participants_all' => " +SELECT DISTINCT + p.jitsi_component, p.endpoint_id, p.conference_id +FROM + participants p +JOIN + participant_events pe ON p.endpoint_id = pe.participant_id +WHERE + pe.time >= '%s 00:00:00' AND pe.time <= '%s 23:59:59' +ORDER BY p.id;", + + + // list conferences where participant ID (endpoint_id) is found + 'conference_by_participant_id' => " +SELECT + pe.time, + c.conference_id, + c.conference_name, + c.conference_host, + pe.loglevel, + pe.event_type, + p.endpoint_id AS participant_id, + pe.event_param +FROM + conferences c +LEFT JOIN + conference_events ce ON c.conference_id = ce.conference_id +LEFT JOIN + participants p ON c.conference_id = p.conference_id +LEFT JOIN + participant_events pe ON p.endpoint_id = pe.participant_id +WHERE + p.endpoint_id = '%s' +AND (pe.time >= '%s 00:00:00' AND pe.time <= '%s 23:59:59') + +UNION + +SELECT + ce.time AS event_time, + c.conference_id, + c.conference_name, + c.conference_host, + ce.loglevel, + ce.conference_event AS event_type, + NULL AS participant_id, + ce.conference_param AS event_param +FROM + conferences c +LEFT JOIN + conference_events ce ON c.conference_id = ce.conference_id +WHERE + participant_id = '%s' +AND (event_time >= '%s 00:00:00' AND event_time <= '%s 23:59:59') + +ORDER BY + pe.time;", + + + // list conferences where participant name (stats_id) is found + 'participant_by_stats_id' => " +SELECT + pe.time, + c.conference_id, + c.conference_name, + c.conference_host, + pe.loglevel, + pe.event_type, + p.endpoint_id AS participant_id, + pe.event_param +FROM + conferences c +LEFT JOIN + conference_events ce ON c.conference_id = ce.conference_id +LEFT JOIN + participants p ON c.conference_id = p.conference_id +LEFT JOIN + participant_events pe ON p.endpoint_id = pe.participant_id +WHERE + pe.event_type = 'stats_id' AND pe.event_param LIKE '%%%s%%' +AND (pe.time >= '%s 00:00:00' AND pe.time <= '%s 23:59:59') + +UNION + +SELECT + ce.time AS event_time, + c.conference_id, + c.conference_name, + c.conference_host, + ce.loglevel, + ce.conference_event AS event_type, + NULL AS participant_id, + ce.conference_param AS event_param +FROM + conferences c +LEFT JOIN + conference_events ce ON c.conference_id = ce.conference_id +WHERE + event_type = 'stats_id' AND event_param LIKE '%%%s%%' +AND (event_time >= '%s 00:00:00' AND event_time <= '%s 23:59:59') + +ORDER BY + pe.time;", + + + // list conferences where participant IP is found + 'participant_by_ip' => " +SELECT + pe.time, + c.conference_id, + c.conference_name, + c.conference_host, + pe.loglevel, + pe.event_type, + p.endpoint_id AS participant_id, + pe.event_param +FROM + conferences c +LEFT JOIN + conference_events ce ON c.conference_id = ce.conference_id +LEFT JOIN + participants p ON c.conference_id = p.conference_id +LEFT JOIN + participant_events pe ON p.endpoint_id = pe.participant_id +WHERE + pe.event_type = 'pair selected' AND pe.event_param = '%s' +AND (pe.time >= '%s 00:00:00' AND pe.time <= '%s 23:59:59') + +UNION + +SELECT + ce.time AS event_time, + c.conference_id, + c.conference_name, + c.conference_host, + ce.loglevel, + ce.conference_event AS event_type, + NULL AS participant_id, + ce.conference_param AS event_param +FROM + conferences c +LEFT JOIN + conference_events ce ON c.conference_id = ce.conference_id +WHERE + event_type = 'pair selected' AND event_param = '%s' +AND (event_time >= '%s 00:00:00' AND event_time <= '%s 23:59:59') + ORDER BY pe.time;", diff --git a/public_html/index.php b/public_html/index.php index 80f8807..1582908 100644 --- a/public_html/index.php +++ b/public_html/index.php @@ -26,6 +26,7 @@ $allowed_urls = [ 'profile', 'config', 'conferences', + 'participants', ]; // cnfig file diff --git a/public_html/pages/conferences.php b/public_html/pages/conferences.php index 1d650dc..ea4683d 100644 --- a/public_html/pages/conferences.php +++ b/public_html/pages/conferences.php @@ -115,12 +115,20 @@ if (isset($conference_id)) { //table rows foreach ($conferences['records'] as $row) { echo "\t\t\n"; + $stats_id = false; + $participant_ip = false; + if ($row['event'] === 'stats_id') $stats_id = true; + if ($row['event'] === 'pair selected') $participant_ip = true; // sometimes $column is empty, we make it '' then foreach ($row as $key => $column) { if ($key === 'conference ID' && $column === $conference_id) { echo "\t\t\t" . htmlspecialchars($column ?? '') . "\n"; } elseif ($key === 'conference name') { echo "\t\t\t" . htmlspecialchars($column ?? '') . "\n"; + } elseif ($stats_id && $key === 'parameter') { + echo "\t\t\t" . htmlspecialchars($column ?? '') . "\n"; + } elseif ($participant_ip && $key === 'parameter') { + echo "\t\t\t" . htmlspecialchars($column ?? '') . "\n"; } else { echo "\t\t\t" . htmlspecialchars($column ?? '') . "\n"; } @@ -203,12 +211,22 @@ if (isset($conference_id)) { //table rows foreach ($conferences['records'] as $row) { echo "\t\t\n"; + $stats_id = false; + $participant_ip = false; + if ($row['event'] === 'stats_id') $stats_id = true; + if ($row['event'] === 'pair selected') $participant_ip = true; // sometimes $column is empty, we make it '' then foreach ($row as $key => $column) { if ($key === 'conference name' && $column === $conference_name) { echo "\t\t\t" . htmlspecialchars($column ?? '') . "\n"; } elseif ($key === 'conference ID') { echo "\t\t\t" . htmlspecialchars($column ?? '') . "\n"; + } elseif ($key === 'participant ID') { + echo "\t\t\t" . htmlspecialchars($column ?? '') . "\n"; + } elseif ($stats_id && $key === 'parameter') { + echo "\t\t\t" . htmlspecialchars($column ?? '') . "\n"; + } elseif ($participant_ip && $key === 'parameter') { + echo "\t\t\t" . htmlspecialchars($column ?? '') . "\n"; } else { echo "\t\t\t" . htmlspecialchars($column ?? '') . "\n"; } diff --git a/public_html/pages/participants.php b/public_html/pages/participants.php new file mode 100644 index 0000000..a24fd7f --- /dev/null +++ b/public_html/pages/participants.php @@ -0,0 +1,420 @@ +getMessage(); + include 'templates/message.php'; + exit(); +} + + +// +// Participant listings +// + + +// search and list specific participant ID +if (isset($participant_id)) { + + try { + $participant = new Participant($db); + + // prepare the result + $search = $participant->conferenceByParticipantId($participant_id, $from_time, $until_time, $participant_id, $from_time, $until_time); + + if (!empty($search)) { + $conferences = array(); + $conferences['records'] = array(); + + foreach ($search as $item) { + extract($item); + $conference_record = array( + // assign title to the field in the array record + 'time' => $time, + 'conference ID' => $conference_id, + 'conference name' => $conference_name, + 'conference host' => $conference_host, + 'loglevel' => $loglevel, + 'participant ID' => $participant_id, + 'event' => $event_type, + 'parameter' => $event_param + ); + // populate the result array + array_push($conferences['records'], $conference_record); + } + } + + } catch (Exception $e) { + $error = 'Error: ' . $e->getMessage(); + include 'templates/message.php'; + exit(); + } + + // display the result + echo "
\n"; + echo "
Conferences with participant ID matching \"$participant_id\""; + if ($time_range_specified) { + echo "
for the time period $from_time - $until_time"; + } + echo "
\n\n"; + + // filters - time selection and sorting dropdowns + include 'templates/results-filter.php'; + + echo "
\n\n"; + + // results table + echo "
\n"; + + if (!empty($conferences['records'])) { + + echo "\t\n"; + echo "\t\t\n"; + + // table headers + foreach (array_keys($conferences['records'][0]) as $header) { + echo "\t\t\t\n"; + } + echo "\t\t\n"; + + //table rows + foreach ($conferences['records'] as $row) { + echo "\t\t\n"; + $stats_id = false; + $participant_ip = false; + if ($row['event'] === 'stats_id') $stats_id = true; + if ($row['event'] === 'pair selected') $participant_ip = true; + // sometimes $column is empty, we make it '' then + foreach ($row as $key => $column) { + if ($key === 'participant ID' && $column === $participant_id) { + echo "\t\t\t\n"; + } elseif ($key === 'conference ID') { + echo "\t\t\t\n"; + } elseif ($key === 'conference name') { + echo "\t\t\t\n"; + } elseif ($stats_id && $key === 'parameter') { + echo "\t\t\t\n"; + } elseif ($participant_ip && $key === 'parameter') { + echo "\t\t\t\n"; + } else { + echo "\t\t\t\n"; + } + } + echo "\t\t\n"; + } + + echo "\t
" . htmlspecialchars($header) . "
" . htmlspecialchars($column ?? '') . "" . htmlspecialchars($column ?? '') . "" . htmlspecialchars($column ?? '') . "" . htmlspecialchars($column ?? '') . "" . htmlspecialchars($column ?? '') . "" . htmlspecialchars($column ?? '') . "
\n"; + + } else { + echo '

No matching conferences found.

'; + } + echo "\n
\n"; + + +// search and list specific participant name (stats_id) +} elseif (isset($participant_name)) { + + try { + $participant = new Participant($db); + + // prepare the result + $search = $participant->conferenceByParticipantName($participant_name, $from_time, $until_time); + + if (!empty($search)) { + $conferences = array(); + $conferences['records'] = array(); + + foreach ($search as $item) { + extract($item); + $conference_record = array( + // assign title to the field in the array record + 'time' => $time, + 'conference ID' => $conference_id, + 'conference name' => $conference_name, + 'conference host' => $conference_host, + 'loglevel' => $loglevel, + 'participant ID' => $participant_id, + 'event' => $event_type, + 'parameter' => $event_param + ); + // populate the result array + array_push($conferences['records'], $conference_record); + } + } + + } catch (Exception $e) { + $error = 'Error: ' . $e->getMessage(); + include 'templates/message.php'; + exit(); + } + + // display the result + echo "
\n"; + echo "
Conferences with participant name (stats_id) matching \"$participant_name\""; + if ($time_range_specified) { + echo "
for the time period $from_time - $until_time"; + } + echo "
\n\n"; + + // filters - time selection and sorting dropdowns + include 'templates/results-filter.php'; + + echo "
\n\n"; + + // results table + echo "
\n"; + + if (!empty($conferences['records'])) { + + echo "\t\n"; + echo "\t\t\n"; + + // table headers + foreach (array_keys($conferences['records'][0]) as $header) { + echo "\t\t\t\n"; + } + echo "\t\t\n"; + + //table rows + foreach ($conferences['records'] as $row) { + echo "\t\t\n"; + // sometimes $column is empty, we make it '' then + foreach ($row as $key => $column) { + if ($key === 'parameter' && $column === $participant_name) { + echo "\t\t\t\n"; + } elseif ($key === 'conference ID') { + echo "\t\t\t\n"; + } elseif ($key === 'conference name') { + echo "\t\t\t\n"; + } elseif ($key === 'participant ID') { + echo "\t\t\t\n"; + } else { + echo "\t\t\t\n"; + } + } + echo "\t\t\n"; + } + + echo "\t
" . htmlspecialchars($header) . "
" . htmlspecialchars($column ?? '') . "" . htmlspecialchars($column ?? '') . "" . htmlspecialchars($column ?? '') . "" . htmlspecialchars($column ?? '') . "" . htmlspecialchars($column ?? '') . "
\n"; + + } else { + echo '

No matching conferences found.

'; + } + echo "\n
\n"; + + +// search and list specific participant IP +} elseif (isset($participant_ip)) { + + try { + $participant = new Participant($db); + + // prepare the result + $search = $participant->conferenceByParticipantIP($participant_ip, $from_time, $until_time); + + if (!empty($search)) { + $conferences = array(); + $conferences['records'] = array(); + + foreach ($search as $item) { + extract($item); + $conference_record = array( + // assign title to the field in the array record + 'time' => $time, + 'conference ID' => $conference_id, + 'conference name' => $conference_name, + 'conference host' => $conference_host, + 'loglevel' => $loglevel, + 'participant ID' => $participant_id, + 'event' => $event_type, + 'parameter' => $event_param + ); + // populate the result array + array_push($conferences['records'], $conference_record); + } + } + + } catch (Exception $e) { + $error = 'Error: ' . $e->getMessage(); + include 'templates/message.php'; + exit(); + } + + // display the result + echo "
\n"; + echo "
Conferences with participant IP matching \"$participant_ip\""; + if ($time_range_specified) { + echo "
for the time period $from_time - $until_time"; + } + echo "
\n\n"; + + // filters - time selection and sorting dropdowns + include 'templates/results-filter.php'; + + echo "
\n\n"; + + // results table + echo "
\n"; + + if (!empty($conferences['records'])) { + + echo "\t\n"; + echo "\t\t\n"; + + // table headers + foreach (array_keys($conferences['records'][0]) as $header) { + echo "\t\t\t\n"; + } + echo "\t\t\n"; + + //table rows + foreach ($conferences['records'] as $row) { + echo "\t\t\n"; + // sometimes $column is empty, we make it '' then + foreach ($row as $key => $column) { + if ($key === 'parameter' && $column === $participant_ip) { + echo "\t\t\t\n"; + } elseif ($key === 'conference ID') { + echo "\t\t\t\n"; + } elseif ($key === 'conference name') { + echo "\t\t\t\n"; + } elseif ($key === 'participant ID') { + echo "\t\t\t\n"; + } else { + echo "\t\t\t\n"; + } + } + echo "\t\t\n"; + } + + echo "\t
" . htmlspecialchars($header) . "
" . htmlspecialchars($column ?? '') . "" . htmlspecialchars($column ?? '') . "" . htmlspecialchars($column ?? '') . "" . htmlspecialchars($column ?? '') . "" . htmlspecialchars($column ?? '') . "
\n"; + + } else { + echo '

No matching conferences found.

'; + } + echo "\n
\n"; + + +// list of all participants (default) +} else { + try { + $participant = new Participant($db); + + // prepare the result + $search = $participant->participantsAll($from_time, $until_time); + + if (!empty($search)) { + $participants = array(); + $participants['records'] = array(); + + foreach ($search as $item) { + extract($item); + $participant_record = array( + // assign title to the field in the array record + 'component' => $jitsi_component, + 'participant ID' => $endpoint_id, + 'conference ID' => $conference_id, + ); + // populate the result array + array_push($participants['records'], $participant_record); + } + } + + } catch (Exception $e) { + $error = 'Error: ' . $e->getMessage(); + include 'templates/message.php'; + exit(); + } + + // display the result + echo "
\n"; + echo "
All participants"; + if ($time_range_specified) { + echo "
for the time period $from_time - $until_time"; + } + echo "
\n\n"; + + // filters - time selection and sorting dropdowns + include 'templates/results-filter.php'; + + echo "
\n\n"; + + // results table + echo "
\n"; + + if (!empty($participants['records'])) { + + echo "\t\n"; + echo "\t\t\n"; + + // table headers + foreach (array_keys($participants['records'][0]) as $header) { + echo "\t\t\t\n"; + } + echo "\t\t\n"; + + //table rows + foreach ($participants['records'] as $row) { + echo "\t\t\n"; + // sometimes $column is empty, we make it '' then + foreach ($row as $key => $column) { + if ($key === 'participant ID') { + echo "\t\t\t\n"; + } elseif ($key === 'conference ID') { + echo "\t\t\t\n"; + } else { + echo "\t\t\t\n"; + } + } + echo "\t\t\n"; + } + + echo "\t
" . htmlspecialchars($header) . "
" . htmlspecialchars($column ?? '') . "" . htmlspecialchars($column ?? '') . "" . htmlspecialchars($column ?? '') . "
\n"; + + } else { + echo '

No matching participants found.

'; + } + echo "\n
\n"; + +} + +?> diff --git a/public_html/static/all.css b/public_html/static/all.css index 2cd776a..eeaa4b0 100644 --- a/public_html/static/all.css +++ b/public_html/static/all.css @@ -104,16 +104,17 @@ .results-header { display: flex; + justify-content: space-between; +} + +.results-message { + width: 25%; } .results-message, .results-filter { - width: 50%; - padding: 20px; + padding: 10px 10px 10px 10px; } -.results-filter { - text-align: right; -} .widget { border: 1px solid gray; diff --git a/public_html/templates/menu.php b/public_html/templates/menu.php index f1cad74..14d9eab 100644 --- a/public_html/templates/menu.php +++ b/public_html/templates/menu.php @@ -5,6 +5,7 @@
  • config
  • conferences
  • +
  • participants
  • diff --git a/public_html/templates/results-filter.php b/public_html/templates/results-filter.php index 10e03ed..fa9470c 100644 --- a/public_html/templates/results-filter.php +++ b/public_html/templates/results-filter.php @@ -13,6 +13,10 @@ /> + + maxlength="15" size="15" /> + +