diff --git a/app/Audit/ConcreteFormatters/PrePaidSummitRegistrationDiscountCodeAuditLogFormatter.php b/app/Audit/ConcreteFormatters/PrePaidSummitRegistrationDiscountCodeAuditLogFormatter.php index 58091d486..73a32ed2e 100644 --- a/app/Audit/ConcreteFormatters/PrePaidSummitRegistrationDiscountCodeAuditLogFormatter.php +++ b/app/Audit/ConcreteFormatters/PrePaidSummitRegistrationDiscountCodeAuditLogFormatter.php @@ -23,6 +23,7 @@ class PrePaidSummitRegistrationDiscountCodeAuditLogFormatter extends AbstractAuditLogFormatter { + private function buildDiscountDetails(PrePaidSummitRegistrationDiscountCode $subject): string { $details = []; @@ -90,6 +91,10 @@ public function format($subject, array $change_set): ?string $discount_details, $this->getUserInfo() ); + + case IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE: + case IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_DELETE: + return $this->formatManyToManyCollectionChange($change_set, sprintf("Pre-Paid Discount Code '%s' (%s) for Summit '%s'", $code, $id, $summit_name)); } } catch (\Exception $ex) { Log::warning("PrePaidSummitRegistrationDiscountCodeAuditLogFormatter error: " . $ex->getMessage()); diff --git a/app/Audit/ConcreteFormatters/SponsorSummitRegistrationDiscountCodeAuditLogFormatter.php b/app/Audit/ConcreteFormatters/SponsorSummitRegistrationDiscountCodeAuditLogFormatter.php index 63d88107c..59f27a4c5 100644 --- a/app/Audit/ConcreteFormatters/SponsorSummitRegistrationDiscountCodeAuditLogFormatter.php +++ b/app/Audit/ConcreteFormatters/SponsorSummitRegistrationDiscountCodeAuditLogFormatter.php @@ -22,6 +22,7 @@ class SponsorSummitRegistrationDiscountCodeAuditLogFormatter extends AbstractAuditLogFormatter { + private function buildDiscountDetails($subject): string { $details = []; @@ -86,6 +87,10 @@ public function format($subject, array $change_set): ?string $discount_details, $this->getUserInfo() ); + + case IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE: + case IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_DELETE: + return $this->formatManyToManyCollectionChange($change_set, sprintf("Sponsor Registration Discount Code '%s' (ID: %s) in Summit '%s'", $code, $id, $summit_name)); } } catch (\Exception $ex) { Log::warning("SponsorSummitRegistrationDiscountCodeAuditLogFormatter error: " . $ex->getMessage()); diff --git a/app/Audit/ConcreteFormatters/SponsorSummitRegistrationPromoCodeAuditLogFormatter.php b/app/Audit/ConcreteFormatters/SponsorSummitRegistrationPromoCodeAuditLogFormatter.php index dedf9cf6a..70b11efbf 100644 --- a/app/Audit/ConcreteFormatters/SponsorSummitRegistrationPromoCodeAuditLogFormatter.php +++ b/app/Audit/ConcreteFormatters/SponsorSummitRegistrationPromoCodeAuditLogFormatter.php @@ -22,6 +22,7 @@ class SponsorSummitRegistrationPromoCodeAuditLogFormatter extends AbstractAuditLogFormatter { + public function format($subject, array $change_set): ?string { if (!$subject instanceof SponsorSummitRegistrationPromoCode) { @@ -64,6 +65,10 @@ public function format($subject, array $change_set): ?string $summit_name, $this->getUserInfo() ); + + case IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE: + case IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_DELETE: + return $this->formatManyToManyCollectionChange($change_set, sprintf("Sponsor Registration Promo Code '%s' (ID: %s) in Summit '%s'", $code, $id, $summit_name)); } } catch (\Exception $ex) { Log::warning("SponsorSummitRegistrationPromoCodeAuditLogFormatter error: " . $ex->getMessage()); diff --git a/tests/OpenTelemetry/Formatters/PrePaidSummitRegistrationDiscountCodeManyToManyAuditLogFormatterTest.php b/tests/OpenTelemetry/Formatters/PrePaidSummitRegistrationDiscountCodeManyToManyAuditLogFormatterTest.php new file mode 100644 index 000000000..918f9a9d4 --- /dev/null +++ b/tests/OpenTelemetry/Formatters/PrePaidSummitRegistrationDiscountCodeManyToManyAuditLogFormatterTest.php @@ -0,0 +1,158 @@ +makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('badge_features', SummitBadgeFeatureType::class, [10, 11], [11, 12]), + ]); + + $this->assertStringStartsWith( + self::MESSAGE_PREFIX . " badge_features (SummitBadgeFeatureType) updated: Added IDs: [12], Removed IDs: [10] by user ", + $result + ); + } + + public function testUpdateEventReportsAddedIds(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('allowed_ticket_types', SummitTicketType::class, [], [5, 6]), + ]); + + $this->assertStringStartsWith( + self::MESSAGE_PREFIX . " allowed_ticket_types (SummitTicketType) updated: Added IDs: [5,6] by user ", + $result + ); + } + + public function testDeleteEventReportsRemovedIdsFromPayload(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_DELETE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('badge_features', SummitBadgeFeatureType::class, [], []), + 'deleted_ids' => [3, 4], + ]); + + $this->assertStringStartsWith( + self::MESSAGE_PREFIX . " badge_features (SummitBadgeFeatureType) deleted: Removed IDs: [3,4] by user ", + $result + ); + } + + public function testUpdateEventWithoutDiffIsSuppressed(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('allowed_ticket_types', SummitTicketType::class, [3], [3]), + ]); + + $this->assertNull($result); + } + + public function testDeleteEventWithNothingToRemoveIsSuppressed(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_DELETE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('allowed_ticket_types', SummitTicketType::class, [], []), + 'deleted_ids' => [], + ]); + + $this->assertNull($result); + } + + public function testManyToManyEventWithoutCollectionReturnsNull(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $this->assertNull($formatter->format($this->makeSubject(), [])); + } + + public function testManyToManyEventWithInvalidSubjectReturnsNull(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $this->assertNull($formatter->format(new \stdClass(), [ + 'collection' => $this->makeCollection('badge_features', SummitBadgeFeatureType::class, [], [7]), + ])); + } + + private function makeFormatter(string $eventType): PrePaidSummitRegistrationDiscountCodeAuditLogFormatter + { + $formatter = new PrePaidSummitRegistrationDiscountCodeAuditLogFormatter($eventType); + $formatter->setContext(AuditContextBuilder::default()->build()); + return $formatter; + } + + private function makeCollection(string $field, string $targetEntity, array $snapshotIds, array $currentIds) + { + return PersistentCollectionTestHelper::buildManyToManyCollection( + PrePaidSummitRegistrationDiscountCode::class, + $field, + $targetEntity, + $snapshotIds, + $currentIds + ); + } + + private function makeSubject(): PrePaidSummitRegistrationDiscountCode + { + $summit = Mockery::mock(Summit::class); + $summit->shouldReceive('getName')->andReturn('Test Summit'); + + $code = Mockery::mock(PrePaidSummitRegistrationDiscountCode::class); + $code->shouldReceive('getId')->andReturn(40); + $code->shouldReceive('getCode')->andReturn('PREPAID10'); + $code->shouldReceive('getRate')->andReturn(10.0); + $code->shouldReceive('getAmount')->andReturn(0.0); + $code->shouldReceive('getQuantityAvailable')->andReturn(5); + $code->shouldReceive('getSummit')->andReturn($summit); + + return $code; + } +} diff --git a/tests/OpenTelemetry/Formatters/SponsorSummitRegistrationDiscountCodeManyToManyAuditLogFormatterTest.php b/tests/OpenTelemetry/Formatters/SponsorSummitRegistrationDiscountCodeManyToManyAuditLogFormatterTest.php new file mode 100644 index 000000000..bbb5e97c1 --- /dev/null +++ b/tests/OpenTelemetry/Formatters/SponsorSummitRegistrationDiscountCodeManyToManyAuditLogFormatterTest.php @@ -0,0 +1,158 @@ +makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('badge_features', SummitBadgeFeatureType::class, [10, 11], [11, 12]), + ]); + + $this->assertStringStartsWith( + self::MESSAGE_PREFIX . " badge_features (SummitBadgeFeatureType) updated: Added IDs: [12], Removed IDs: [10] by user ", + $result + ); + } + + public function testUpdateEventReportsAddedIds(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('allowed_ticket_types', SummitTicketType::class, [], [5, 6]), + ]); + + $this->assertStringStartsWith( + self::MESSAGE_PREFIX . " allowed_ticket_types (SummitTicketType) updated: Added IDs: [5,6] by user ", + $result + ); + } + + public function testDeleteEventReportsRemovedIdsFromPayload(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_DELETE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('badge_features', SummitBadgeFeatureType::class, [], []), + 'deleted_ids' => [3, 4], + ]); + + $this->assertStringStartsWith( + self::MESSAGE_PREFIX . " badge_features (SummitBadgeFeatureType) deleted: Removed IDs: [3,4] by user ", + $result + ); + } + + public function testUpdateEventWithoutDiffIsSuppressed(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('allowed_ticket_types', SummitTicketType::class, [3], [3]), + ]); + + $this->assertNull($result); + } + + public function testDeleteEventWithNothingToRemoveIsSuppressed(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_DELETE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('allowed_ticket_types', SummitTicketType::class, [], []), + 'deleted_ids' => [], + ]); + + $this->assertNull($result); + } + + public function testManyToManyEventWithoutCollectionReturnsNull(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $this->assertNull($formatter->format($this->makeSubject(), [])); + } + + public function testManyToManyEventWithInvalidSubjectReturnsNull(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $this->assertNull($formatter->format(new \stdClass(), [ + 'collection' => $this->makeCollection('badge_features', SummitBadgeFeatureType::class, [], [7]), + ])); + } + + private function makeFormatter(string $eventType): SponsorSummitRegistrationDiscountCodeAuditLogFormatter + { + $formatter = new SponsorSummitRegistrationDiscountCodeAuditLogFormatter($eventType); + $formatter->setContext(AuditContextBuilder::default()->build()); + return $formatter; + } + + private function makeCollection(string $field, string $targetEntity, array $snapshotIds, array $currentIds) + { + return PersistentCollectionTestHelper::buildManyToManyCollection( + SponsorSummitRegistrationDiscountCode::class, + $field, + $targetEntity, + $snapshotIds, + $currentIds + ); + } + + private function makeSubject(): SponsorSummitRegistrationDiscountCode + { + $summit = Mockery::mock(Summit::class); + $summit->shouldReceive('getName')->andReturn('Test Summit'); + + $code = Mockery::mock(SponsorSummitRegistrationDiscountCode::class); + $code->shouldReceive('getId')->andReturn(41); + $code->shouldReceive('getCode')->andReturn('SPONSOR20'); + $code->shouldReceive('getSponsorId')->andReturn(7); + $code->shouldReceive('getRate')->andReturn(20.0); + $code->shouldReceive('getAmount')->andReturn(0.0); + $code->shouldReceive('getSummit')->andReturn($summit); + + return $code; + } +} diff --git a/tests/OpenTelemetry/Formatters/SponsorSummitRegistrationPromoCodeManyToManyAuditLogFormatterTest.php b/tests/OpenTelemetry/Formatters/SponsorSummitRegistrationPromoCodeManyToManyAuditLogFormatterTest.php new file mode 100644 index 000000000..6060ec499 --- /dev/null +++ b/tests/OpenTelemetry/Formatters/SponsorSummitRegistrationPromoCodeManyToManyAuditLogFormatterTest.php @@ -0,0 +1,156 @@ +makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('badge_features', SummitBadgeFeatureType::class, [10, 11], [11, 12]), + ]); + + $this->assertStringStartsWith( + self::MESSAGE_PREFIX . " badge_features (SummitBadgeFeatureType) updated: Added IDs: [12], Removed IDs: [10] by user ", + $result + ); + } + + public function testUpdateEventReportsAddedIds(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('allowed_ticket_types', SummitTicketType::class, [], [5, 6]), + ]); + + $this->assertStringStartsWith( + self::MESSAGE_PREFIX . " allowed_ticket_types (SummitTicketType) updated: Added IDs: [5,6] by user ", + $result + ); + } + + public function testDeleteEventReportsRemovedIdsFromPayload(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_DELETE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('badge_features', SummitBadgeFeatureType::class, [], []), + 'deleted_ids' => [3, 4], + ]); + + $this->assertStringStartsWith( + self::MESSAGE_PREFIX . " badge_features (SummitBadgeFeatureType) deleted: Removed IDs: [3,4] by user ", + $result + ); + } + + public function testUpdateEventWithoutDiffIsSuppressed(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('allowed_ticket_types', SummitTicketType::class, [3], [3]), + ]); + + $this->assertNull($result); + } + + public function testDeleteEventWithNothingToRemoveIsSuppressed(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_DELETE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('allowed_ticket_types', SummitTicketType::class, [], []), + 'deleted_ids' => [], + ]); + + $this->assertNull($result); + } + + public function testManyToManyEventWithoutCollectionReturnsNull(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $this->assertNull($formatter->format($this->makeSubject(), [])); + } + + public function testManyToManyEventWithInvalidSubjectReturnsNull(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $this->assertNull($formatter->format(new \stdClass(), [ + 'collection' => $this->makeCollection('badge_features', SummitBadgeFeatureType::class, [], [7]), + ])); + } + + private function makeFormatter(string $eventType): SponsorSummitRegistrationPromoCodeAuditLogFormatter + { + $formatter = new SponsorSummitRegistrationPromoCodeAuditLogFormatter($eventType); + $formatter->setContext(AuditContextBuilder::default()->build()); + return $formatter; + } + + private function makeCollection(string $field, string $targetEntity, array $snapshotIds, array $currentIds) + { + return PersistentCollectionTestHelper::buildManyToManyCollection( + SponsorSummitRegistrationPromoCode::class, + $field, + $targetEntity, + $snapshotIds, + $currentIds + ); + } + + private function makeSubject(): SponsorSummitRegistrationPromoCode + { + $summit = Mockery::mock(Summit::class); + $summit->shouldReceive('getName')->andReturn('Test Summit'); + + $code = Mockery::mock(SponsorSummitRegistrationPromoCode::class); + $code->shouldReceive('getId')->andReturn(42); + $code->shouldReceive('getCode')->andReturn('SPONSORPROMO'); + $code->shouldReceive('getSponsorId')->andReturn(7); + $code->shouldReceive('getSummit')->andReturn($summit); + + return $code; + } +}