diff --git a/app/Audit/AuditLogFormatterFactory.php b/app/Audit/AuditLogFormatterFactory.php index 4536bbfd0..150d8e237 100644 --- a/app/Audit/AuditLogFormatterFactory.php +++ b/app/Audit/AuditLogFormatterFactory.php @@ -29,13 +29,6 @@ public function __construct() $this->config = config('audit_log', []); } - public function getStrategyClass(object $subject, string $event_type): ?IAuditLogFormatter - { - $class = get_class($subject); - $cls = $this->config['entities'][$class]['strategy'] ?? null; - return !is_null($cls) ? new $cls($event_type):null; - } - public function make(AuditContext $ctx, $subject, $eventType): ?IAuditLogFormatter { $formatter = null; @@ -53,18 +46,12 @@ public function make(AuditContext $ctx, $subject, $eventType): ?IAuditLogFormatt break; case IAuditStrategy::EVENT_ENTITY_CREATION: $formatter = $this->getFormatterByContext($subject, $eventType, $ctx); - if (is_null($formatter)) { - $formatter = $this->getStrategyClass($subject, $eventType); - } if(is_null($formatter)) { $formatter = new EntityCreationAuditLogFormatter(); } break; case IAuditStrategy::EVENT_ENTITY_DELETION: $formatter = $this->getFormatterByContext($subject, $eventType, $ctx); - if (is_null($formatter)) { - $formatter = $this->getStrategyClass($subject, $eventType); - } if(is_null($formatter)) { $child_entity_formatter = ChildEntityFormatterFactory::build($subject); $formatter = new EntityDeletionAuditLogFormatter($child_entity_formatter); @@ -72,9 +59,6 @@ public function make(AuditContext $ctx, $subject, $eventType): ?IAuditLogFormatt break; case IAuditStrategy::EVENT_ENTITY_UPDATE: $formatter = $this->getFormatterByContext($subject, $eventType, $ctx); - if (is_null($formatter)) { - $formatter = $this->getStrategyClass($subject, $eventType); - } if(is_null($formatter)) { $child_entity_formatter = ChildEntityFormatterFactory::build($subject); $formatter = new EntityUpdateAuditLogFormatter($child_entity_formatter); @@ -90,17 +74,24 @@ private function getFormatterByContext(object $subject, string $event_type, Audi $class = get_class($subject); $entity_config = $this->config['entities'][$class] ?? null; - if (!$entity_config || !isset($entity_config['strategies'])) { + if (!$entity_config) { return null; } - foreach ($entity_config['strategies'] as $strategy) { - if (!$this->matchesStrategy($strategy, $ctx)) { - continue; + if (isset($entity_config['strategies'])) { + foreach ($entity_config['strategies'] as $strategy) { + if (!$this->matchesStrategy($strategy, $ctx)) { + continue; + } + + $formatter_class = $strategy['formatter'] ?? null; + return $formatter_class ? new $formatter_class($event_type) : null; } + } - $formatter_class = $strategy['formatter'] ?? null; - return $formatter_class ? new $formatter_class($event_type) : null; + if (isset($entity_config['strategy'])) { + $strategy_class = $entity_config['strategy']; + return new $strategy_class($event_type); } return null; diff --git a/app/Audit/ConcreteFormatters/ChildEntityFormatters/PresentationTrackChairScoreAuditLogFormatter.php b/app/Audit/ConcreteFormatters/ChildEntityFormatters/PresentationTrackChairScoreAuditLogFormatter.php new file mode 100644 index 000000000..bbd728c2d --- /dev/null +++ b/app/Audit/ConcreteFormatters/ChildEntityFormatters/PresentationTrackChairScoreAuditLogFormatter.php @@ -0,0 +1,54 @@ +getScoreType(); + $score_label = $score_type ? $score_type->getLabel() : 'Unknown Score'; + + $presentation = $subject->getPresentation(); + $presentation_title = $presentation ? $presentation->getTitle() : 'Unknown Presentation'; + + $created_by = $subject->getCreatedBy(); + $chair_name = $created_by + ? sprintf("%s %s", $created_by->getFirstName(), $created_by->getLastName()) + : 'Unknown Chair'; + + switch ($child_entity_action_type) { + case self::CHILD_ENTITY_CREATION: + return sprintf( + "Track Chair '%s' scored '%s' on presentation '%s'", + $chair_name, + $score_label, + $presentation_title + ); + case self::CHILD_ENTITY_DELETION: + return sprintf( + "Score removed for Track Chair '%s' from presentation '%s'", + $chair_name, + $presentation_title + ); + case self::CHILD_ENTITY_UPDATE: + return sprintf( + "Track Chair '%s' score updated to '%s' on presentation '%s'", + $chair_name, + $score_label, + $presentation_title + ); + } + } catch (\Exception $ex) { + Log::warning("PresentationTrackChairScoreAuditLogFormatter error: " . $ex->getMessage()); + } + + return null; + } +} diff --git a/app/Audit/ConcreteFormatters/PresentationTrackChairRatingTypeAuditLogFormatter.php b/app/Audit/ConcreteFormatters/PresentationTrackChairRatingTypeAuditLogFormatter.php new file mode 100644 index 000000000..4fb260e97 --- /dev/null +++ b/app/Audit/ConcreteFormatters/PresentationTrackChairRatingTypeAuditLogFormatter.php @@ -0,0 +1,80 @@ +event_type = $event_type; + } + + public function format($subject, array $change_set): ?string + { + if (!$subject instanceof PresentationTrackChairRatingType) { + return null; + } + + try { + $name = $subject->getName() ?? 'Unknown'; + $selection_plan = $subject->getSelectionPlan(); + $plan_name = $selection_plan ? $selection_plan->getName() : 'Unknown'; + + switch ($this->event_type) { + case IAuditStrategy::EVENT_ENTITY_CREATION: + return sprintf( + "Track Chair Rating Type '%s' created for Selection Plan '%s' by user %s", + $name, + $plan_name, + $this->getUserInfo() + ); + + case IAuditStrategy::EVENT_ENTITY_UPDATE: + $changed_fields = []; + if (isset($change_set['name'])) { + $changed_fields[] = "name"; + } + + $fields_str = !empty($changed_fields) ? implode(', ', $changed_fields) : 'properties'; + return sprintf( + "Track Chair Rating Type '%s' updated (%s changed) by user %s", + $name, + $fields_str, + $this->getUserInfo() + ); + + case IAuditStrategy::EVENT_ENTITY_DELETION: + return sprintf( + "Track Chair Rating Type '%s' deleted from Selection Plan '%s' by user %s", + $name, + $plan_name, + $this->getUserInfo() + ); + } + } catch (\Exception $ex) { + Log::warning("PresentationTrackChairRatingTypeAuditLogFormatter error: " . $ex->getMessage()); + } + + return null; + } +} diff --git a/app/Audit/ConcreteFormatters/PresentationTrackChairScoreTypeAuditLogFormatter.php b/app/Audit/ConcreteFormatters/PresentationTrackChairScoreTypeAuditLogFormatter.php new file mode 100644 index 000000000..abc722245 --- /dev/null +++ b/app/Audit/ConcreteFormatters/PresentationTrackChairScoreTypeAuditLogFormatter.php @@ -0,0 +1,85 @@ +event_type = $event_type; + } + + public function format($subject, array $change_set): ?string + { + if (!$subject instanceof PresentationTrackChairScoreType) { + return null; + } + + try { + $label = $subject->getLabel() ?? 'Unknown'; + $score = $subject->getScore() ?? 'unknown'; + $rating_type = $subject->getRatingType(); + $rating_type_name = $rating_type ? $rating_type->getName() : 'Unknown'; + + switch ($this->event_type) { + case IAuditStrategy::EVENT_ENTITY_CREATION: + return sprintf( + "Score Type '%s' (value: %s) added to Rating Type '%s' by user %s", + $label, + $score, + $rating_type_name, + $this->getUserInfo() + ); + + case IAuditStrategy::EVENT_ENTITY_UPDATE: + $changed_fields = []; + if (isset($change_set['label'])) { + $changed_fields[] = "label"; + } + if (isset($change_set['score'])) { + $changed_fields[] = "score"; + } + + $fields_str = !empty($changed_fields) ? implode(', ', $changed_fields) : 'properties'; + return sprintf( + "Score Type '%s' updated (%s changed) by user %s", + $label, + $fields_str, + $this->getUserInfo() + ); + + case IAuditStrategy::EVENT_ENTITY_DELETION: + return sprintf( + "Score Type '%s' removed from Rating Type '%s' by user %s", + $label, + $rating_type_name, + $this->getUserInfo() + ); + } + } catch (\Exception $ex) { + Log::warning("PresentationTrackChairScoreTypeAuditLogFormatter error: " . $ex->getMessage()); + } + + return null; + } +} diff --git a/app/Audit/ConcreteFormatters/SummitTrackChairAuditLogFormatter.php b/app/Audit/ConcreteFormatters/SummitTrackChairAuditLogFormatter.php new file mode 100644 index 000000000..2fbe1ad4f --- /dev/null +++ b/app/Audit/ConcreteFormatters/SummitTrackChairAuditLogFormatter.php @@ -0,0 +1,97 @@ +event_type = $event_type; + } + + public function format($subject, array $change_set): ?string + { + if (!$subject instanceof SummitTrackChair) { + return null; + } + + try { + $member = $subject->getMember(); + $member_name = $member ? sprintf("%s %s", $member->getFirstName(), $member->getLastName()) : 'Unknown'; + $member_id = $member ? $member->getId() : 'unknown'; + + switch ($this->event_type) { + case IAuditStrategy::EVENT_ENTITY_CREATION: + $categories = []; + foreach ($subject->getCategories() as $category) { + $categories[] = $category->getTitle(); + } + $tracks_list = !empty($categories) ? implode(', ', $categories) : 'No tracks assigned'; + return sprintf( + "Track Chair '%s' (%d) assigned with tracks: %s by user %s", + $member_name, + $member_id, + $tracks_list, + $this->getUserInfo() + ); + + case IAuditStrategy::EVENT_ENTITY_UPDATE: + if (isset($change_set['categories'])) { + $old_cats = $change_set['categories'][0] ?? []; + $new_cats = $change_set['categories'][1] ?? []; + + $old_names = is_array($old_cats) + ? array_map(fn($c) => $c->getTitle() ?? 'Unknown', $old_cats) + : []; + $new_names = is_array($new_cats) + ? array_map(fn($c) => $c->getTitle() ?? 'Unknown', $new_cats) + : []; + + $old_str = !empty($old_names) ? implode(', ', $old_names) : 'None'; + $new_str = !empty($new_names) ? implode(', ', $new_names) : 'None'; + + return sprintf( + "Track Chair '%s' tracks changed: [%s] → [%s] by user %s", + $member_name, + $old_str, + $new_str, + $this->getUserInfo() + ); + } + return sprintf("Track Chair '%s' updated by user %s", $member_name, $this->getUserInfo()); + + case IAuditStrategy::EVENT_ENTITY_DELETION: + return sprintf( + "Track Chair '%s' (%d) removed from summit by user %s", + $member_name, + $member_id, + $this->getUserInfo() + ); + } + } catch (\Exception $ex) { + Log::warning("SummitTrackChairAuditLogFormatter error: " . $ex->getMessage()); + } + + return null; + } +} diff --git a/config/audit_log.php b/config/audit_log.php index 9b576c608..23e9de21b 100644 --- a/config/audit_log.php +++ b/config/audit_log.php @@ -50,6 +50,18 @@ \models\summit\PresentationSpeakerSummitAssistanceConfirmationRequest::class => [ 'enabled' => true, 'strategy' => \App\Audit\ConcreteFormatters\SpeakerAssistanceAuditLogFormatter::class, - ] + ], + \models\summit\SummitTrackChair::class => [ + 'enabled' => true, + 'strategy' => \App\Audit\ConcreteFormatters\SummitTrackChairAuditLogFormatter::class, + ], + \App\Models\Foundation\Summit\Events\Presentations\TrackChairs\PresentationTrackChairRatingType::class => [ + 'enabled' => true, + 'strategy' => \App\Audit\ConcreteFormatters\PresentationTrackChairRatingTypeAuditLogFormatter::class, + ], + \App\Models\Foundation\Summit\Events\Presentations\TrackChairs\PresentationTrackChairScoreType::class => [ + 'enabled' => true, + 'strategy' => \App\Audit\ConcreteFormatters\PresentationTrackChairScoreTypeAuditLogFormatter::class, + ], ] ];