From 1b07b5712d89f35af0dd17724981b8c78b78013d Mon Sep 17 00:00:00 2001 From: Marks Polakovs Date: Sat, 20 Nov 2021 19:18:10 +0000 Subject: [PATCH 1/6] Implement audit log --- src/Classes/MyRadio/AuditLogTypes.php | 17 +++++ src/Classes/ServiceAPI/MyRadio_AuditLog.php | 68 +++++++++++++++++++ src/Classes/ServiceAPI/MyRadio_Creditable.php | 2 +- src/Classes/ServiceAPI/MyRadio_Season.php | 54 +++++++++++++++ src/Classes/ServiceAPI/MyRadio_Show.php | 46 +++++++++++++ src/Classes/ServiceAPI/MyRadio_Timeslot.php | 27 ++++++++ 6 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 src/Classes/MyRadio/AuditLogTypes.php create mode 100644 src/Classes/ServiceAPI/MyRadio_AuditLog.php diff --git a/src/Classes/MyRadio/AuditLogTypes.php b/src/Classes/MyRadio/AuditLogTypes.php new file mode 100644 index 000000000..1e0262424 --- /dev/null +++ b/src/Classes/MyRadio/AuditLogTypes.php @@ -0,0 +1,17 @@ +entry_id = (int) $data['entry_id']; + $this->entry_type = $data['entry_type']; + $this->target_class = $data['target_class']; + $this->target_id = (int) $data['target_id']; + $this->actor_id = (int) $data['actor_id']; + $this->payload = $data['payload']; + $this->entry_time = (int) $data['entry_time']; + } + + /** + * Logs an event to the audit log, attributing it to the currently signed in user. + * + * If no $target_class is given, uses the calling class name. + */ + public static function log(string $type, int $target_id, array $payload, string $target_class='') + { + if ($target_class === '') + { + $caller = debug_backtrace(0, 1); + $target_class = $caller['class']; + } + $actor_id = MyRadio_User::getCurrentOrSystemUser()->getID(); + $sql = "INSERT INTO myradio.audit_log (entry_type, target_class, target_id, actor_id, payload, entry_time) VALUES ($1, $2, $3, $4, $5::JSONB, NOW())"; + self::$db->query( + $sql, + [$type, $target_class, $target_id, $actor_id, json_encode($payload)] + ); + } + + protected static function factory($itemid) + { + $sql = self::BASE_SQL . " WHERE eventid = $1"; + + $result = self::$db->fetchOne($sql, [$itemid]); + if (empty($result)) { + throw new MyRadioException("Event $itemid does not exist", 404); + } + + return new self($result); + } +} diff --git a/src/Classes/ServiceAPI/MyRadio_Creditable.php b/src/Classes/ServiceAPI/MyRadio_Creditable.php index 79352150d..ff482ef5e 100644 --- a/src/Classes/ServiceAPI/MyRadio_Creditable.php +++ b/src/Classes/ServiceAPI/MyRadio_Creditable.php @@ -27,7 +27,7 @@ trait MyRadio_Creditable * @param MyRadio_Metadata_Common $parent Used when there is inheritance enabled * for this object. In this case credits are merged. * - * @return type + * @return array */ public function getCredits(\MyRadio\ServiceAPI\MyRadio_Metadata_Common $parent = null) { diff --git a/src/Classes/ServiceAPI/MyRadio_Season.php b/src/Classes/ServiceAPI/MyRadio_Season.php index bfa7713a9..2443615b8 100644 --- a/src/Classes/ServiceAPI/MyRadio_Season.php +++ b/src/Classes/ServiceAPI/MyRadio_Season.php @@ -7,11 +7,13 @@ use MyRadio\Config; use MyRadio\MyRadioException; +use MyRadio\MyRadio\AuditLogTypes; use MyRadio\MyRadio\CoreUtils; use MyRadio\MyRadio\URLUtils; use MyRadio\MyRadio\MyRadioForm; use MyRadio\MyRadio\MyRadioFormField; use MyRadio\MyRadioEmail; +use MyRadio\ServiceAPI\MyRadio_AuditLog; /** * The Season class is used to create, view and manipulate Seasons within the new MyRadio Scheduler Format. @@ -314,6 +316,12 @@ public static function create($params = []) ); } + MyRadio_AuditLog::log( + AuditLogTypes::Created, + $newSeason->season_id, + $newSeason->toDataSource() + ); + return $newSeason; } @@ -618,6 +626,12 @@ public function setCredits($users, $credittypes, $table = null, $pkey = null) $r = parent::setCredits($users, $credittypes, 'schedule.show_credit', 'show_id'); $this->updateCacheObject(); + MyRadio_AuditLog::log( + AuditLogTypes::Edited, + $this->season_id, + ['credits' => ['users' => $users, 'credit_types' => $credittypes]] + ); + return $r; } @@ -703,6 +717,12 @@ public function reject($reason, $notify_user = true) ); } + MyRadio_AuditLog::log( + AuditLogTypes::Rejected, + $this->season_id, + ['reason' => $reason] + ); + self::$db->query('COMMIT'); } @@ -755,6 +775,12 @@ public function setMeta($string_key, $value, $effective_from = null, $effective_ $this->metadata[$string_key] = $value; $this->updateCacheObject(); + MyRadio_AuditLog::log( + AuditLogTypes::MetaUpdated, + $this->season_id, + ['key' => $string_key, 'value' => $value] + ); + return $r; } @@ -809,6 +835,11 @@ public function setSubtype($subtypeId) self::$db->query('UPDATE schedule.show_season_subtype SET show_subtype_id = $1 WHERE season_id = $1', [ $subtypeId, $this->season_id ]); + MyRadio_AuditLog::log( + AuditLogTypes::Edited, + $this->season_id, + ['subtype' => $this->getSubtype()->toDataSource()] + ); } /** @@ -824,6 +855,11 @@ public function setSubtypeByName($subtypeName) WHERE season_id = $1', [$this->season_id, $subtypeName] ); + MyRadio_AuditLog::log( + AuditLogTypes::Edited, + $this->season_id, + ['subtype' => $this->getSubtype()->toDataSource()] + ); } /** @@ -832,6 +868,11 @@ public function setSubtypeByName($subtypeName) public function clearSubtype() { self::$db->query('DELETE FROM schedule.show_season_subtype WHERE season_id = $1', [$this->season_id]); + MyRadio_AuditLog::log( + AuditLogTypes::Edited, + $this->season_id, + ['subtype' => null] + ); } public function getRequestedTimes() @@ -1107,6 +1148,13 @@ public function schedule($params) self::$cache->delete('MyRadioScheduleFor'.$weekAndYear[0].'W'.$weekAndYear[1]); } } + + MyRadio_AuditLog::log( + AuditLogTypes::Scheduled, + $this->season_id, + ['times' => explode('\n', $times)] + ); + //COMMIT self::$db->query('COMMIT'); $this->updateCacheObject(); @@ -1169,6 +1217,12 @@ public function cancelRestOfSeason() MyRadioEmail::sendEmailToUser($u, 'Show Cancelled', $email); } + MyRadio_AuditLog::log( + AuditLogTypes::SeasonCancelled, + $this->season_id, + ['timeslots' => explode('\r\n', $timeslot_str)] + ); + $r = (bool) self::$db->query( 'DELETE FROM schedule.show_season_timeslot WHERE show_season_id=$1 AND start_time >= NOW()', [$this->getID()] diff --git a/src/Classes/ServiceAPI/MyRadio_Show.php b/src/Classes/ServiceAPI/MyRadio_Show.php index 8c68359f8..354deb78d 100755 --- a/src/Classes/ServiceAPI/MyRadio_Show.php +++ b/src/Classes/ServiceAPI/MyRadio_Show.php @@ -7,10 +7,12 @@ use MyRadio\Config; use MyRadio\Database; use MyRadio\MyRadioException; +use MyRadio\MyRadio\AuditLogTypes; use MyRadio\MyRadio\CoreUtils; use MyRadio\MyRadio\URLUtils; use MyRadio\MyRadio\MyRadioForm; use MyRadio\MyRadio\MyRadioFormField; +use MyRadio\ServiceAPI\MyRadio_AuditLog; use MyRadio\ServiceAPI\MyRadio_User; use MyRadio\ServiceAPI\MyRadio_Season; use MyRadio\ServiceAPI\MyRadio_Scheduler; @@ -383,6 +385,12 @@ public static function create($params = []) $show = self::factory($show_id); + MyRadio_AuditLog::log( + AuditLogTypes::Created, + $show_id, + $show->toDataSource() + ); + /* * Enable mixcloud upload if requested */ @@ -714,6 +722,11 @@ public function setSubtype($subtypeId) self::$db->query('UPDATE schedule.show_season_subtype SET show_subtype_id = $1 WHERE show_id = $1', [ $subtypeId, $this->show_id ]); + MyRadio_AuditLog::log( + AuditLogTypes::Edited, + $this->show_id, + ['subtype' => $this->getSubtype()->toDataSource()] + ); } /** @@ -729,6 +742,11 @@ public function setSubtypeByName($subtypeName) WHERE show_id = $1', [$this->show_id, $subtypeName] ); + MyRadio_AuditLog::log( + AuditLogTypes::Edited, + $this->show_id, + ['subtype' => $this->getSubtype()->toDataSource()] + ); } /** @@ -770,6 +788,12 @@ public function setShowPhoto($tmp_path) $this->photo_url = Config::$public_media_uri.'/'.$suffix; $this->updateCacheObject(); + + MyRadio_AuditLog::log( + AuditLogTypes::Edited, + $this->show_id, + ['photo' => ['url' => $this->photo_url]] + ); } /** @@ -799,6 +823,12 @@ public function setMeta($string_key, $value, $effective_from = null, $effective_ ); $this->updateCacheObject(); + MyRadio_AuditLog::log( + AuditLogTypes::MetaUpdated, + $this->show_id, + ['key' => $string_key, 'value' => $value] + ); + return $r; } @@ -824,6 +854,11 @@ public function setGenre($genreid) ); $this->genres = [$genreid]; $this->updateCacheObject(); + MyRadio_AuditLog::log( + AuditLogTypes::Edited, + $this->show_id, + ['genre' => $genreid] + ); } } @@ -838,6 +873,11 @@ public function setPodcastExplicit($value) [$this->getID(), $value ? 1 : 0] ); $this->updateCacheObject(); + MyRadio_AuditLog::log( + AuditLogTypes::Edited, + $this->show_id, + ['podcast_explicit' => $value] + ); } /** @@ -854,6 +894,12 @@ public function setCredits($users, $credittypes, $table = null, $pkey = null) $r = parent::setCredits($users, $credittypes, 'schedule.show_credit', 'show_id'); $this->updateCacheObject(); + MyRadio_AuditLog::log( + AuditLogTypes::Edited, + $this->show_id, + ['credits' => ['users' => $users, 'credit_types' => $credittypes]] + ); + return $r; } diff --git a/src/Classes/ServiceAPI/MyRadio_Timeslot.php b/src/Classes/ServiceAPI/MyRadio_Timeslot.php index 52900e778..4d25842c6 100644 --- a/src/Classes/ServiceAPI/MyRadio_Timeslot.php +++ b/src/Classes/ServiceAPI/MyRadio_Timeslot.php @@ -8,6 +8,7 @@ use DateTime; use MyRadio\Config; +use MyRadio\MyRadio\AuditLogTypes; use MyRadio\MyRadio\AuthUtils; use MyRadio\MyRadioException; use MyRadio\MyRadio\CoreUtils; @@ -17,6 +18,7 @@ use MyRadio\MyRadio\MyRadioFormField; use MyRadio\NIPSWeb\NIPSWeb_TimeslotItem; use MyRadio\NIPSWeb\NIPSWeb_BAPSUtils; +use MyRadio\ServiceAPI\MyRadio_AuditLog; use MyRadio\SIS\SIS_Utils; use Spatie\IcalendarGenerator\Components\Event; @@ -323,6 +325,11 @@ public function setMeta($string_key, $value, $effective_from = null, $effective_ 'show_season_timeslot_id' ); $this->updateCacheObject(); + MyRadio_AuditLog::log( + AuditLogTypes::MetaUpdated, + $this->season_id, + ['key' => $string_key, 'value' => $value] + ); return $r; } @@ -969,6 +976,11 @@ private function cancelTimeslotAdmin($reason) 'Episode of ' . $this->getMeta('title') . ' Cancelled', $email ); + MyRadio_AuditLog::log( + AuditLogTypes::Cancelled, + $this->timeslot_id, + ['type' => 'admin', 'reason' => $reason] + ); return true; } @@ -1000,6 +1012,11 @@ private function cancelTimeslotSelfService($reason) 'Episode of ' . $this->getMeta('title') . ' Cancelled', $email2 ); + MyRadio_AuditLog::log( + AuditLogTypes::Cancelled, + $this->timeslot_id, + ['type' => 'self_service', 'reason' => $reason] + ); return true; } @@ -1056,6 +1073,11 @@ public function moveTimeslot($newStart, $newEnd) ); self::$cache->purge(); + MyRadio_AuditLog::log( + AuditLogTypes::Moved, + $this->timeslot_id, + ['new_start' => CoreUtils::getRfc2822Timestamp($newStart), 'new_end' => CoreUtils::getRfc2822Timestamp($newEnd)] + ); return $r; } @@ -1201,6 +1223,11 @@ public function setPlayout($playout) ); $this->playout = $playout; $this->updateCacheObject(); + MyRadio_AuditLog::log( + AuditLogTypes::Edited, + $this->timeslot_id, + ['playout' => $playout] + ); } public function getAutoVizConfig() From 66bbf2559dd4d4fa46523ae6db05fbe765d173dc Mon Sep 17 00:00:00 2001 From: Marks Polakovs Date: Sat, 20 Nov 2021 20:07:59 +0000 Subject: [PATCH 2/6] Add GUI for audit log --- src/Classes/ServiceAPI/MyRadio_AuditLog.php | 83 ++++++++++++++++++- src/Controllers/Audit/default.php | 88 +++++++++++++++++++++ src/Public/js/myradio.audit.view.js | 31 ++++++++ src/Templates/Audit/view.twig | 58 ++++++++++++++ 4 files changed, 256 insertions(+), 4 deletions(-) create mode 100644 src/Controllers/Audit/default.php create mode 100644 src/Public/js/myradio.audit.view.js create mode 100644 src/Templates/Audit/view.twig diff --git a/src/Classes/ServiceAPI/MyRadio_AuditLog.php b/src/Classes/ServiceAPI/MyRadio_AuditLog.php index d9bdff992..7c3b5ecfb 100644 --- a/src/Classes/ServiceAPI/MyRadio_AuditLog.php +++ b/src/Classes/ServiceAPI/MyRadio_AuditLog.php @@ -2,12 +2,13 @@ namespace MyRadio\ServiceAPI; +use MyRadio\MyRadio\CoreUtils; use MyRadio\ServiceAPI\MyRadio_User; use MyRadio\MyRadioException; class MyRadio_AuditLog extends ServiceAPI { - private const BASE_SQL = "SELECT entry_id, entry_type, target_class, target_id, actor_id, payload, entry_time FROM myradio.audit_log"; + private const BASE_SQL = "SELECT log_entry_id, entry_type, target_class, target_id, actor_id, payload, entry_time FROM myradio.audit_log"; private int $entry_id; @@ -25,13 +26,51 @@ class MyRadio_AuditLog extends ServiceAPI protected function __construct(array $data) { - $this->entry_id = (int) $data['entry_id']; + $this->entry_id = (int) $data['log_entry_id']; $this->entry_type = $data['entry_type']; $this->target_class = $data['target_class']; $this->target_id = (int) $data['target_id']; $this->actor_id = (int) $data['actor_id']; - $this->payload = $data['payload']; - $this->entry_time = (int) $data['entry_time']; + $this->payload = json_decode($data['payload'], true); + $this->entry_time = strtotime($data['entry_time']); + } + + public function getID() + { + return $this->entry_id; + } + + public function getEventType() + { + return $this->entry_type; + } + + public function getTargetClass() + { + return $this->target_class; + } + + public function getTargetID() + { + return $this->target_id; + } + + /** + * @return MyRadio\ServiceAPI\MyRadio_User + */ + public function getActor() + { + return MyRadio_User::getInstance($this->actor_id); + } + + public function getPayload() + { + return $this->payload; + } + + public function getEntryTime() + { + return $this->entry_time; } /** @@ -54,6 +93,42 @@ public static function log(string $type, int $target_id, array $payload, string ); } + /** + * @return self[] + */ + public static function getEvents(int $since, int $until, array $query = []) + { + $sql = self::BASE_SQL . ' WHERE entry_time >= $1 AND entry_time <= $2'; + $paramId = 0; + $params = [CoreUtils::getTimestamp($since), CoreUtils::getTimestamp($until)]; + if (in_array('event_type', $query)) + { + $sql .= " AND event_type = $$paramId"; + $params[] = $query['event_type']; + $paramId++; + } + if (in_array('target_type', $query)) + { + $sql .= " AND target_type = $$paramId"; + $params[] = $query['target_type']; + $paramId++; + } + if (in_array('actor_id', $query)) + { + $sql .= " AND actor_id = $$paramId"; + $params[] = $query['actor_id']; + $paramId++; + } + + $rows = self::$db->fetchAll($sql, $params); + $result = []; + foreach ($rows as $row) + { + $result[] = new self($row); + } + return $result; + } + protected static function factory($itemid) { $sql = self::BASE_SQL . " WHERE eventid = $1"; diff --git a/src/Controllers/Audit/default.php b/src/Controllers/Audit/default.php new file mode 100644 index 000000000..916f1f9bf --- /dev/null +++ b/src/Controllers/Audit/default.php @@ -0,0 +1,88 @@ + null, 'text' => 'All']]; +foreach (array_values($typesClass->getConstants()) as $constant) +{ + $eventTypes[] = ['value' => $constant, 'text' => $constant]; +} + +$targetTypes = [['value' => null, 'text' => 'All']]; +$classRoot = dirname(__FILE__, 3) . '/Classes/ServiceAPI'; +foreach (scandir($classRoot) as $fileName) +{ + if ($fileName[0] === '.') + { + continue; + } + require_once('Classes/ServiceAPI/' . $fileName); + $class = 'MyRadio\\ServiceAPI\\' . basename($fileName, '.php'); + if (is_subclass_of($class, ServiceAPI::class)) + { + $targetTypes[] = ['value' => $class, 'text' => (new ReflectionClass($class))->getShortName()]; + } +} + +$data = []; +foreach ($events as $event) +{ + $data[] = [ + 'time' => CoreUtils::happyTime($event->getEntryTime()), + 'actor' => $event->getActor()->getName(), + 'event_type' => $event->getEventType(), + 'target_type' => (new ReflectionClass($event->getTargetClass()))->getShortName(), + 'target_id' => $event->getTargetID(), + 'payload' => json_encode($event->getPayload(), JSON_PRETTY_PRINT) + ]; +} + +$twig = CoreUtils::getTemplateObject()->setTemplate('Audit/view.twig') + ->addVariable('title', 'View Audit Log') + ->addVariable('tablescript', 'myradio.audit.view') + ->addVariable('tabledata', $data) + ->addVariable('starttime', $start) + ->addVariable('endtime', $end) + ->addVariable('actor', $actorId) + ->addVariable('eventType', $eventType) + ->addVariable('targetType', $targetType) + ->addVariable('eventTypes', $eventTypes) + ->addVariable('targetTypes', $targetTypes); + +if ($actor !== null) +{ + $twig = $twig->addVariable('actorOptions', [ 'membername' => MyRadio_User::getInstance($actor)->getName() ]); +} + +$twig->render(); diff --git a/src/Public/js/myradio.audit.view.js b/src/Public/js/myradio.audit.view.js new file mode 100644 index 000000000..aee205665 --- /dev/null +++ b/src/Public/js/myradio.audit.view.js @@ -0,0 +1,31 @@ +$(".twig-datatable").dataTable({ + bSort: true, + "aoColumns": [ + //time + { + "sTitle": "Time" + }, + //actor + { + "sTitle": "Actor" + }, + //event_type + { + "sTitle": "Event Type" + }, + //target_type + { + "sTitle": "Target Type" + }, + //target_id + { + "sTitle": "Target ID" + }, + //payload + { + "sTitle": "Payload" + }, + ], + "bPaginate": false, + aaSorting: [] +}); diff --git a/src/Templates/Audit/view.twig b/src/Templates/Audit/view.twig new file mode 100644 index 000000000..ec5bb8672 --- /dev/null +++ b/src/Templates/Audit/view.twig @@ -0,0 +1,58 @@ +{% extends 'table.twig' %} + +{% block stripecontent %} +
+
+ Last Day | + Last Week | + Last Fortnight | + Last Month +
+
+ {% set frm_name = 'auditsel' %} + {#
+ {% set field = {'name': 'starttime', 'label': 'From Time', 'value' : null, 'enabled': true, 'explanation': '', + 'required': false, 'value': starttime} %} + {% set sfieldname = field.name %} + {% include ('FormFields/FieldType_4.twig') %} + {% set field = {'name': 'endtime', 'label': 'To Time', 'value' : null, 'enabled': true, 'explanation': '', + 'required': false, 'value': endtime} %} + {% set sfieldname = field.name %} + {% include ('FormFields/FieldType_4.twig') %} +
#} +
+ {% set field = {'name': 'eventtype', 'label': 'Event Type', 'value' : null, 'enabled': true, 'explanation': '', + 'required': false, 'value': eventType, 'options': eventTypes} %} + {% set sfieldname = field.name %} + {% include ('FormFields/FieldType_9.twig') %} +
+
+ {% set field = {'name': 'targettype', 'label': 'Target Type', 'value' : null, 'enabled': true, 'explanation': '', + 'required': false, 'value': targetType, 'options': targetTypes} %} + {% set sfieldname = field.name %} + {% include ('FormFields/FieldType_9.twig') %} +
+
+ {% set field = {'name': 'actor', 'label': 'Actor', 'value' : null, 'enabled': true, 'explanation': '', + 'required': false, 'value': actor} %} + {% set sfieldname = field.name %} + {% include ('FormFields/FieldType_5.twig') %} +
+ +
+
+ +{{ parent() }} +{% endblock %} + +{% block foot %} +{{ parent() }} + + + + + +{% endblock %} + From d81fd295a2a1d113c014fd3127cbbb0c5e0f4eae Mon Sep 17 00:00:00 2001 From: Marks Polakovs Date: Sun, 29 Jan 2023 13:23:19 +0000 Subject: [PATCH 3/6] Rebase schema patch --- schema/patches/16.sql | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 schema/patches/16.sql diff --git a/schema/patches/16.sql b/schema/patches/16.sql new file mode 100644 index 000000000..e6195b5da --- /dev/null +++ b/schema/patches/16.sql @@ -0,0 +1,21 @@ +BEGIN; + +CREATE TABLE myradio.audit_log ( + log_entry_id BIGSERIAL PRIMARY KEY, + entry_type TEXT, + target_class TEXT, + target_id BIGINT, + actor_id INTEGER REFERENCES public.member (memberid), + payload JSONB, + entry_time TIMESTAMPTZ DEFAULT NOW() +); + +CREATE INDEX idx_audit_types ON myradio.audit_log (entry_type); +CREATE INDEX idx_audit_class_id ON myradio.audit_log (target_class, target_id); +CREATE INDEX idx_audit_actor ON myradio.audit_log (actor_id); + +UPDATE myradio.schema + SET value = 16 + WHERE attr='version'; + +COMMIT; From 4c5aeaa41666d11640d4d57b6644ee82a0f9bf47 Mon Sep 17 00:00:00 2001 From: Marks Polakovs Date: Sun, 29 Jan 2023 13:46:28 +0000 Subject: [PATCH 4/6] Tweaks, add to menu --- src/Classes/ServiceAPI/MyRadio_AuditLog.php | 5 +++-- src/Menus/menu.json | 5 +++++ src/Templates/Audit/view.twig | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Classes/ServiceAPI/MyRadio_AuditLog.php b/src/Classes/ServiceAPI/MyRadio_AuditLog.php index 7c3b5ecfb..716bf8130 100644 --- a/src/Classes/ServiceAPI/MyRadio_AuditLog.php +++ b/src/Classes/ServiceAPI/MyRadio_AuditLog.php @@ -14,7 +14,8 @@ class MyRadio_AuditLog extends ServiceAPI private string $entry_type; - private string $target_class; + /** @var string|null */ + private $target_class; private int $target_id; @@ -82,7 +83,7 @@ public static function log(string $type, int $target_id, array $payload, string { if ($target_class === '') { - $caller = debug_backtrace(0, 1); + $caller = debug_backtrace(!DEBUG_BACKTRACE_PROVIDE_OBJECT|DEBUG_BACKTRACE_IGNORE_ARGS,2)[1]; $target_class = $caller['class']; } $actor_id = MyRadio_User::getCurrentOrSystemUser()->getID(); diff --git a/src/Menus/menu.json b/src/Menus/menu.json index f2deef3a6..9f9d342ff 100644 --- a/src/Menus/menu.json +++ b/src/Menus/menu.json @@ -163,6 +163,11 @@ "title": "Website Tools", "url": "module=Website", "description": "Edit website banners, navigation and probably other stuff too." + }, + { + "title": "MyRadio Audit Log", + "url": "module=Audit", + "description": "View the MyRadio audit log." } ] }, diff --git a/src/Templates/Audit/view.twig b/src/Templates/Audit/view.twig index ec5bb8672..9f8f92bcc 100644 --- a/src/Templates/Audit/view.twig +++ b/src/Templates/Audit/view.twig @@ -42,7 +42,7 @@ {{ parent() }} {% endblock %} From 2b5acba7079b193a484b7e94878589fa96e5c4e7 Mon Sep 17 00:00:00 2001 From: Marks Polakovs Date: Sun, 29 Jan 2023 13:50:18 +0000 Subject: [PATCH 5/6] Reduce infospam --- src/Classes/ServiceAPI/MyRadio_Season.php | 2 +- src/Classes/ServiceAPI/MyRadio_Show.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Classes/ServiceAPI/MyRadio_Season.php b/src/Classes/ServiceAPI/MyRadio_Season.php index 2443615b8..b1d3594e4 100644 --- a/src/Classes/ServiceAPI/MyRadio_Season.php +++ b/src/Classes/ServiceAPI/MyRadio_Season.php @@ -319,7 +319,7 @@ public static function create($params = []) MyRadio_AuditLog::log( AuditLogTypes::Created, $newSeason->season_id, - $newSeason->toDataSource() + ['show_id' => $newSeason->show_id, 'term_id' => $newSeason->term_id, 'requested_weeks' => $newSeason->requested_weeks, 'requested_times' => $newSeason->requested_times], ); return $newSeason; diff --git a/src/Classes/ServiceAPI/MyRadio_Show.php b/src/Classes/ServiceAPI/MyRadio_Show.php index 354deb78d..c3eebb959 100755 --- a/src/Classes/ServiceAPI/MyRadio_Show.php +++ b/src/Classes/ServiceAPI/MyRadio_Show.php @@ -388,7 +388,7 @@ public static function create($params = []) MyRadio_AuditLog::log( AuditLogTypes::Created, $show_id, - $show->toDataSource() + array_intersect_key($show->toDataSource(), array_flip(['title', 'description'])), ); /* From 71b677e4c2013ad819c7d784724c9fe0ea71547d Mon Sep 17 00:00:00 2001 From: Marks Polakovs Date: Sun, 29 Jan 2023 13:53:43 +0000 Subject: [PATCH 6/6] More log data improvements --- src/Classes/ServiceAPI/MyRadio_Season.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Classes/ServiceAPI/MyRadio_Season.php b/src/Classes/ServiceAPI/MyRadio_Season.php index b1d3594e4..bd0738aa3 100644 --- a/src/Classes/ServiceAPI/MyRadio_Season.php +++ b/src/Classes/ServiceAPI/MyRadio_Season.php @@ -1152,7 +1152,7 @@ public function schedule($params) MyRadio_AuditLog::log( AuditLogTypes::Scheduled, $this->season_id, - ['times' => explode('\n', $times)] + ['times' => explode("\n", $times)] ); //COMMIT