Skip to content

Conversation

Fabinatix97
Copy link
Member

@Fabinatix97 Fabinatix97 commented Oct 9, 2025

Pull Request Checklist (Feature Branch to next):

  • Ich habe die neuesten Änderungen aus dem next Branch in meinen Feature-Branch gemergt.
  • Das Code-Review wurde abgeschlossen.
  • Fachliche Tests wurden durchgeführt und sind abgeschlossen.

Context

This PR is based on the commits from PR #1545, which has already been merged into next. However, an issue was subsequently noticed on zms-test, which is why #1545 was initially reverted from next (see PR #1565). This PR serves to implement the outstanding issues and then merge them back into next together with all the features that have already been implemented by @ThomasAFink.

Summary by CodeRabbit

  • New Features

    • Appointment responses now include ICS calendar content; users can download ICS files when not signed in. Signed-in users get a "View Appointment" button that navigates to a configurable detail page.
  • Configuration

    • New secure token setting required for fetching mail templates used in ICS generation.
  • Localization

    • Added "View Appointment" label in English and German.
  • Tests

    • Expanded tests for ICS generation, mail-template fetching, downloads, and UI states.

Copy link
Contributor

coderabbitai bot commented Oct 13, 2025

Walkthrough

Generates and surfaces ICS calendar content: backend maps processes to include optional icsContent, fetches mail templates using a secure token, exposes icsContent in API responses; frontend DTOs/components/types support download/view of ICS; tests, fixtures and schema updated; Application enforces/initializes a secure token from env.

Changes

Cohort / File(s) Summary
Secure token config & init
zmscitizenapi/config.example.php, zmscitizenapi/src/Zmscitizenapi/Application.php
Adds global ZMS_CONFIG_SECURE_TOKEN in config example; Application gains public static string $SECURE_TOKEN, initializes it from env in initializeSecureToken() and throws if missing/empty.
ThinnedProcess model & schema
zmscitizenapi/src/Zmscitizenapi/Models/ThinnedProcess.php, zmsentities/schema/citizenapi/thinnedProcess.json
Adds optional icsContent property, constructor param and accessors; includes icsContent in toArray; JSON schema adds icsContent (string
Mapper service
zmscitizenapi/src/Zmscitizenapi/Services/Core/MapperService.php
Adds ICS generation path: new generateIcsContent(Process, $templateProvider) called during mapping, attaches generated icsContent to ThinnedProcess, logs errors.
Mail template helper
zmscitizenapi/src/Zmscitizenapi/Utils/MailTemplateHelper.php
New MailTemplateHelper class: resolves providerId from a Process, fetches /merged-mailtemplates/{providerId}/ via App::$http with App::$SECURE_TOKEN, caches templates, exposes getTemplate(s), logs failures.
Messaging exception change
zmsentities/src/Zmsentities/Helper/Messaging.php
When an ICS template is missing, now throws BO\Zmsentities\Exception\TemplateNotFound and sets data->status instead of a generic \Exception.
Backend tests, bootstrap & fixtures
zmscitizenapi/tests/...ControllerTest.php, zmscitizenapi/tests/.../MapperServiceTest.php, zmscitizenapi/tests/Zmscitizenapi/bootstrap.php, zmscitizenapi/tests/Zmscitizenapi/fixtures/GET_merged_mailtemplates.json, zmscitizenapi/tests/.../AppointmentUpdateServiceTest.php
Tests add mocked /merged-mailtemplates/{id}/ reads, assert icsContent presence and VCALENDAR content (then strip for canonical comparison), adapt appointment stub to include hasTime(), add fixture file, set ZMS_CONFIG_SECURE_TOKEN in test bootstrap, update expected call counts.
Frontend DTOs, types & schema
zmscitizenview/src/api/models/AppointmentDTO.ts, zmscitizenview/src/types/AppointmentImpl.ts, zmscitizenview/src/types/ProvideInjectTypes.ts
Adds optional icsContent?: string to DTO and Impl; AppointmentImpl constructor accepts icsContent; provider types switched to AppointmentDTO.
Frontend components & wiring
zmscitizenview/src/components/Appointment/AppointmentView.vue, zmscitizenview/src/zms-appointment.ce.vue, zmscitizenview/src/components/Appointment/CustomerInfo.vue, zmscitizenview/resources/loader-test/index.html
AppointmentView conditionally shows download/view buttons, adds download and navigation helpers, adds appointmentDetailUrl prop; zms-appointment.ce.vue exposes appointmentDetailUrl; CustomerInfo.vue import cleanup; loader demo binds detail URL.
Frontend i18n & tests
zmscitizenview/src/utils/en-US.json, zmscitizenview/src/utils/de-DE.json, zmscitizenview/tests/unit/Appointment/AppointmentView.spec.ts
Adds viewAppointment translations; unit tests added/updated to cover ICS download/view behavior and auth-conditional UI.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Client
  participant Controller
  participant Mapper as MapperService
  participant MHelper as MailTemplateHelper
  participant HTTP as App::$http
  participant Logger as LoggerService

  Client->>Controller: Request appointment/process
  Controller->>Mapper: map(Process) → ThinnedProcess
  Mapper->>Mapper: generateIcsContent(process)
  alt providerId available
    Mapper->>MHelper: load templates for provider
    MHelper->>HTTP: GET /merged-mailtemplates/{providerId}/ (xtoken=App::$SECURE_TOKEN)
    HTTP-->>MHelper: templates payload
    MHelper-->>Mapper: templates
    Mapper->>Mapper: build ICS (BEGIN:VCALENDAR...)
    Mapper-->>Controller: ThinnedProcess{..., icsContent}
  else missing provider/templates or error
    Mapper->>Logger: log error with context
    Mapper-->>Controller: ThinnedProcess{..., icsContent: null}
  end
  Controller-->>Client: JSON response includes `icsContent`
Loading
sequenceDiagram
  autonumber
  participant Bootstrap
  participant App as Application
  participant Env as Environment

  Bootstrap->>App: initialize()
  App->>App: initializeSecureToken()
  App->>Env: getenv('ZMS_CONFIG_SECURE_TOKEN')
  alt token present & non-empty
    App-->>Bootstrap: set App::$SECURE_TOKEN
  else missing/empty
    App-->>Bootstrap: throw RuntimeException("ZMS_CONFIG_SECURE_TOKEN missing")
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

I twitch my whiskers at the ticking clock,
Spinning tiny calendars in a floppy sock,
Tokens snug, templates fetched with care,
Click to download, or hop to view — beware!
A rabbit’s hop: an appointment stitched with flair. 🥕📅

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The pull request title "feat(ZMSKVR-97): Add ICS download functionality for appointment confirmation" clearly and accurately summarizes the primary user-facing feature being introduced across the changeset. The title is specific, using the ticket reference and identifying the concrete capability being added. While the PR includes supporting infrastructure changes (security token management, mail template fetching, and backend ICS generation), these are implementation details that enable the main feature. The title successfully captures the primary objective at an appropriate level of abstraction for a developer scanning the commit history, and it is formatted correctly with conventional commit syntax.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch revert-1565-revert-1545-feature-zmskvr-97-add-appointment-ics-as-download-in-zmscitizenview

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (8)
zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentConfirmControllerTest.php (1)

117-125: Consider extracting ICS validation to a helper method.

The ICS content validation pattern (assert key exists, assert contains VCALENDAR, unset for comparison) is repeated across multiple test files (AppointmentCancelControllerTest, AppointmentReserveControllerTest, AppointmentByIdControllerTest, AppointmentPreconfirmControllerTest, AppointmentConfirmControllerTest, AppointmentUpdateControllerTest). This duplication could be reduced by extracting to a shared helper method in the base ControllerTestCase class.

Example helper method:

// In ControllerTestCase.php
protected function assertAndStripIcsContent(array &$responseBody, array &$expectedResponse): void
{
    $this->assertArrayHasKey('icsContent', $responseBody);
    $this->assertStringContainsString('BEGIN:VCALENDAR', $responseBody['icsContent']);
    unset($responseBody['icsContent']);
    unset($expectedResponse['icsContent']);
}

Then in each test:

$this->assertAndStripIcsContent($responseBody, $expectedResponse);
$this->assertEquals($expectedResponse, $responseBody);
zmscitizenapi/src/Zmscitizenapi/Application.php (1)

63-66: Improve documentation for SECURE_TOKEN.

The docblock "Security Token for API Access" is vague. Consider documenting:

  • What specific API this token provides access to (based on the PR context, this appears to be for mail template API access used in ICS generation)
  • What security guarantees this token provides
  • How it should be configured (relationship to other ZMS module tokens)
  • Any format requirements beyond non-empty string

Example improved documentation:

/**
 * Security token for accessing ZMS mail template API endpoints.
 * Used by MailTemplateHelper to fetch ICS calendar templates.
 * Must match the SECURE_TOKEN configured in zmsapi module.
 * 
 * @var string
 */
public static string $SECURE_TOKEN;

Also applies to: 83-90

zmscitizenview/src/types/AppointmentImpl.ts (1)

53-55: Tighten constructor param typing for subRequestCounts

Ctor uses any[] but class property is SubRequestCount[]. Align for type safety.

Consider updating the constructor signature:

constructor(
  // ...
  subRequestCounts: SubRequestCount[],
  // ...
  icsContent?: string
) { /* ... */ }
zmscitizenapi/tests/Zmscitizenapi/Services/Core/MapperServiceTest.php (1)

170-175: Stabilize appointment stub

Add a return type to hasTime() and consider returning false to skip ICS generation during this unit test (reduces noise/logging).

$appointment = new class {
    public $date = '1724907600';
    public function hasTime(): bool { return false; } // or true if explicitly needed
};
zmscitizenview/tests/unit/Appointment/AppointmentView.spec.ts (1)

16-19: Place vi.mock before importing the mocked module

To avoid subtle ESM mocking issues, move the vi.mock('@/utils/auth', ...) above all imports that reference it (even though Vitest hoists, ordering it first is clearer).

zmscitizenapi/src/Zmscitizenapi/Services/Core/MapperService.php (1)

598-611: Avoid unnecessary ICS generation and respect no-attachment domains

Generating ICS on every mapping can be heavy (HTTP + Twig). Optionally skip when not required.

Add after creating Config:

-            $config = new Config();
+            $config = new Config();
+            // Skip if configuration says ICS is not required (e.g., no-attachment email domains)
+            if (!Messaging::isIcsRequired($config, $process, 'appointment')) {
+                return null;
+            }
zmscitizenview/src/components/Appointment/AppointmentView.vue (1)

903-917: Consider using regular quotes for the static filename string.

The implementation correctly handles ICS download with proper blob creation and cleanup. Minor style point: Line 911 uses template literal backticks for a static string without interpolation.

Apply this diff for consistency:

-    link.download = `Termin.ics`;
+    link.download = "Termin.ics";
zmscitizenapi/src/Zmscitizenapi/Utils/MailTemplateHelper.php (1)

15-15: Consider using null as the sentinel value for clarity.

The current implementation uses false to indicate "not loaded yet", which works but creates confusion:

  1. Line 47's ?? [] operator only handles null, not false. However, this works because loadTemplates() always sets $templates = [] first (line 55).
  2. The pattern mixes boolean logic with array operations, reducing readability.

Consider this clearer approach:

-    protected $templates = false;
+    protected ?array $templates = null;

     public function getTemplate(string $templateName): ?string
     {
-        if (!$this->templates) {
+        if ($this->templates === null) {
             $this->loadTemplates();
         }
         return $this->templates[$templateName] ?? null;
     }

     public function getTemplates(): array
     {
-        if (!$this->templates) {
+        if ($this->templates === null) {
             $this->loadTemplates();
         }
         return $this->templates ?? [];
     }

This makes the "not loaded yet" state explicit and type-safe. As per coding guidelines, prefer meaningful types over boolean flags for state tracking.

Also applies to: 29-48

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e53245f and 4b260ae.

📒 Files selected for processing (24)
  • zmscitizenapi/config.example.php (1 hunks)
  • zmscitizenapi/src/Zmscitizenapi/Application.php (2 hunks)
  • zmscitizenapi/src/Zmscitizenapi/Models/ThinnedProcess.php (4 hunks)
  • zmscitizenapi/src/Zmscitizenapi/Services/Core/MapperService.php (5 hunks)
  • zmscitizenapi/src/Zmscitizenapi/Utils/MailTemplateHelper.php (1 hunks)
  • zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentByIdControllerTest.php (1 hunks)
  • zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentCancelControllerTest.php (1 hunks)
  • zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentConfirmControllerTest.php (1 hunks)
  • zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentPreconfirmControllerTest.php (1 hunks)
  • zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentReserveControllerTest.php (1 hunks)
  • zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentUpdateControllerTest.php (1 hunks)
  • zmscitizenapi/tests/Zmscitizenapi/Services/Core/MapperServiceTest.php (1 hunks)
  • zmscitizenview/resources/loader-test/index.html (1 hunks)
  • zmscitizenview/src/api/models/AppointmentDTO.ts (1 hunks)
  • zmscitizenview/src/components/Appointment/AppointmentView.vue (6 hunks)
  • zmscitizenview/src/components/Appointment/CustomerInfo.vue (1 hunks)
  • zmscitizenview/src/types/AppointmentImpl.ts (3 hunks)
  • zmscitizenview/src/types/ProvideInjectTypes.ts (2 hunks)
  • zmscitizenview/src/utils/de-DE.json (1 hunks)
  • zmscitizenview/src/utils/en-US.json (1 hunks)
  • zmscitizenview/src/zms-appointment.ce.vue (2 hunks)
  • zmscitizenview/tests/unit/Appointment/AppointmentView.spec.ts (2 hunks)
  • zmsentities/schema/citizenapi/thinnedProcess.json (1 hunks)
  • zmsentities/src/Zmsentities/Helper/Messaging.php (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*

⚙️ CodeRabbit configuration file

**/*: Apply the following Clean Code guidelines to all files, as summarized by wojteklu's Clean Code gist:

Code is clean if it can be understood easily – by everyone on the team. Clean code can be read and enhanced by a developer other than its original author. With understandability comes readability, changeability, extensibility and maintainability.

General rules

  1. Follow standard conventions.
  2. Keep it simple stupid. Simpler is always better. Reduce complexity as much as possible.
  3. Boy scout rule. Leave the campground cleaner than you found it.
  4. Always find root cause. Always look for the root cause of a problem.

Design rules

  1. Keep configurable data at high levels.
  2. Prefer polymorphism to if/else or switch/case.
  3. Separate multi-threading code.
  4. Prevent over-configurability.
  5. Use dependency injection.
  6. Follow Law of Demeter. A class should know only its direct dependencies.

Understandability tips

  1. Be consistent. If you do something a certain way, do all similar things in the same way.
  2. Use explanatory variables.
  3. Encapsulate boundary conditions. Boundary conditions are hard to keep track of. Put the processing for them in one place.
  4. Prefer dedicated value objects to primitive type.
  5. Avoid logical dependency. Don't write methods which works correctly depending on something else in the same class.
  6. Avoid negative conditionals.

Names rules

  1. Choose descriptive and unambiguous names.
  2. Make meaningful distinction.
  3. Use pronounceable names.
  4. Use searchable names.
  5. Replace magic numbers with named constants.
  6. Avoid encodings. Don't append prefixes or type information.

Functions rules

  1. Small.
  2. Do one thing.
  3. Use descriptive names.
  4. Prefer fewer arguments.
  5. Have no side effects.
  6. Don't use flag arguments. Split method into several independent methods that can b...

Files:

  • zmscitizenview/src/components/Appointment/CustomerInfo.vue
  • zmscitizenapi/tests/Zmscitizenapi/Services/Core/MapperServiceTest.php
  • zmscitizenview/src/utils/en-US.json
  • zmscitizenview/src/types/AppointmentImpl.ts
  • zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentReserveControllerTest.php
  • zmsentities/src/Zmsentities/Helper/Messaging.php
  • zmscitizenview/src/zms-appointment.ce.vue
  • zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentByIdControllerTest.php
  • zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentPreconfirmControllerTest.php
  • zmscitizenapi/src/Zmscitizenapi/Models/ThinnedProcess.php
  • zmscitizenapi/src/Zmscitizenapi/Application.php
  • zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentConfirmControllerTest.php
  • zmscitizenview/src/api/models/AppointmentDTO.ts
  • zmscitizenapi/src/Zmscitizenapi/Utils/MailTemplateHelper.php
  • zmscitizenview/src/utils/de-DE.json
  • zmscitizenview/src/components/Appointment/AppointmentView.vue
  • zmscitizenapi/config.example.php
  • zmsentities/schema/citizenapi/thinnedProcess.json
  • zmscitizenapi/src/Zmscitizenapi/Services/Core/MapperService.php
  • zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentCancelControllerTest.php
  • zmscitizenview/resources/loader-test/index.html
  • zmscitizenview/src/types/ProvideInjectTypes.ts
  • zmscitizenview/tests/unit/Appointment/AppointmentView.spec.ts
  • zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentUpdateControllerTest.php
**/*.php

⚙️ CodeRabbit configuration file

**/*.php: Flag any usage of error_log() as it should be replaced with proper Monolog logging mechanisms provided by zmsslim which should be setup in the App/Application of each module:

  1. For error handling: Use the proper Monolog logging framework with error levels
  2. For application info logs: Use the proper Monolog logging framework with info levels
  3. For debugging: Use a dedicated debug logger or remove debug statements
  4. For CLI output: Use a CLI output handler or symfony/console
  5. The application log levels are as follows DEBUG, INFO, NOTICE, WARNING, ERROR, CRITICAL, ALERT, and EMERGENCY

Example replacement:

// Instead of:
error_log("Import failed - " . $e->getMessage());

// Use:
$log->error("Import failed", ['error' => $e->getMessage()]);

Flag specific logging violations:

  1. error_log(), var_dump(), print_r(), die(), exit() usage (except proper error logging in catch blocks)
  2. Any debug output that should use proper Monolog logging
  3. Debug constants like DEBUG = true
  4. Debug logging that should be removed in production
  5. Commented debug code that should be cleaned up

Example replacements:

// Instead of:
error_log("Error occurred");
var_dump($data);
die('debug point');

// Use:
$log->error("Error occurred", ['context' => 'processing']);
$log->debug('Data dump', ['data' => $data]);
// Remove die() statements entirely

Exception handling should use proper logging:

// Instead of:
try {
    $result = $this->process();
} catch (Exception $e) {
    error_log("Processing failed: " . $e->getMessage());
}

// Use:
try {
    $result = $this->process();
} catch (Exception $e) {
    $log->error("Processing failed", ['error' => $e->getMessage(), 'trace' => $e->getTraceAsString()]);
}
```...

Files:

  • zmscitizenapi/tests/Zmscitizenapi/Services/Core/MapperServiceTest.php
  • zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentReserveControllerTest.php
  • zmsentities/src/Zmsentities/Helper/Messaging.php
  • zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentByIdControllerTest.php
  • zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentPreconfirmControllerTest.php
  • zmscitizenapi/src/Zmscitizenapi/Models/ThinnedProcess.php
  • zmscitizenapi/src/Zmscitizenapi/Application.php
  • zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentConfirmControllerTest.php
  • zmscitizenapi/src/Zmscitizenapi/Utils/MailTemplateHelper.php
  • zmscitizenapi/config.example.php
  • zmscitizenapi/src/Zmscitizenapi/Services/Core/MapperService.php
  • zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentCancelControllerTest.php
  • zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentUpdateControllerTest.php
**/*.{js,jsx,ts,tsx}

⚙️ CodeRabbit configuration file

**/*.{js,jsx,ts,tsx}: Flag any usage of console.log() as it should be replaced with proper logging or removed:

  1. For development: console.debug()
  2. For production: Remove console.log() statements or use structured logging
  3. For errors: Use error console.error()

Example replacement:

// Instead of:
console.log('User data:', userData);

// Use:
console.debug('Processing user data', { userData });
// or for development only:
Remove the console.log entirely

Flag specific logging violations:

  1. console.log(), console.debug(), console.warn() usage (except console.error in catch blocks)
  2. Any debug output that should use proper logging frameworks

Example replacements:

// Instead of:
console.log('User data:', userData);
console.debug('Processing...');

// Use:
// Remove console.log entirely or use proper logging
// Only console.error in catch blocks is acceptable
try {
  processData(userData);
} catch (error) {
  console.error('Processing failed:', error);
}

Flag JavaScript security and UX issues:

  1. alert(), confirm(), prompt() usage (poor UX)
  2. eval() usage (security risk)
  3. innerHTML with user input (XSS risk)
  4. Unfiltered user input in DOM manipulation

Example replacements:

// Instead of:
alert('Error occurred');
eval(userInput);

// Use:
// Use proper error handling and UI components
this.showErrorNotification('Error occurred');
// Avoid eval() entirely

Flag TODO/FIXME comments that indicate technical debt:

  1. TODO comments without clear action items
  2. FIXME comments indicating broken functionality
  3. HACK comments indicating temporary workarounds
  4. XXX comments indicating problematic code

These should be converted to proper issues or addressed:

// Instead of:
// TODO: fix this later
// FIXME: this is broken

// Use:
// Create proper issue and reference it
// @see Issue #123: Refactor validation logic

Flag code complexity issues:

  1. Functions longer than 50 lines
  2. Deep nesting (...

Files:

  • zmscitizenview/src/types/AppointmentImpl.ts
  • zmscitizenview/src/api/models/AppointmentDTO.ts
  • zmscitizenview/src/types/ProvideInjectTypes.ts
  • zmscitizenview/tests/unit/Appointment/AppointmentView.spec.ts
🧬 Code graph analysis (5)
zmscitizenapi/src/Zmscitizenapi/Models/ThinnedProcess.php (1)
zmscitizenapi/src/Zmscitizenapi/Models/ThinnedScope.php (1)
  • ThinnedScope (12-209)
zmscitizenapi/src/Zmscitizenapi/Utils/MailTemplateHelper.php (1)
zmscitizenapi/src/Zmscitizenapi/Services/Core/LoggerService.php (1)
  • LoggerService (14-220)
zmscitizenapi/src/Zmscitizenapi/Services/Core/MapperService.php (6)
zmscitizenapi/src/Zmscitizenapi/Services/Core/LoggerService.php (2)
  • LoggerService (14-220)
  • logError (96-127)
zmscitizenapi/src/Zmscitizenapi/Utils/ClientIpHelper.php (1)
  • ClientIpHelper (7-34)
zmscitizenapi/src/Zmscitizenapi/Utils/MailTemplateHelper.php (2)
  • MailTemplateHelper (13-102)
  • getTemplates (42-48)
zmsentities/src/Zmsentities/Helper/Messaging.php (3)
  • Messaging (25-403)
  • generateIcsContent (302-356)
  • getMailIcs (287-300)
zmsentities/src/Zmsentities/Config.php (1)
  • Config (5-78)
zmscitizenapi/tests/Zmscitizenapi/Services/Core/MapperServiceTest.php (1)
  • hasTime (172-172)
zmscitizenview/src/types/ProvideInjectTypes.ts (1)
zmscitizenview/src/api/models/AppointmentDTO.ts (1)
  • AppointmentDTO (9-100)
zmscitizenview/tests/unit/Appointment/AppointmentView.spec.ts (1)
zmscitizenview/src/utils/auth.ts (1)
  • isAuthenticated (6-8)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: call-php-unit-tests / zmsdb-test
🔇 Additional comments (17)
zmscitizenview/src/api/models/AppointmentDTO.ts (1)

94-99: LGTM!

The addition of the optional icsContent property is well-structured and properly documented. The type definition is clear and follows the existing interface pattern.

zmsentities/schema/citizenapi/thinnedProcess.json (1)

155-162: LGTM!

The icsContent property addition follows the established schema pattern, with proper type definition and clear description. The nullable string type is appropriate for optional calendar content.

zmscitizenview/src/utils/de-DE.json (1)

179-179: LGTM!

The German translation entry is properly placed and follows the existing localization pattern. The translation "Termin ansehen" is clear and consistent with German UI conventions.

zmscitizenview/resources/loader-test/index.html (1)

17-19: LGTM!

The addition of the appointment-detail-url attribute configures the component appropriately for the test environment and aligns with the new appointment detail view functionality.

zmscitizenview/src/utils/en-US.json (1)

167-167: LGTM!

The English translation entry is properly placed and maintains consistency with the German locale. The translation is clear and appropriate for the UI action.

zmscitizenview/src/components/Appointment/CustomerInfo.vue (1)

109-109: LGTM!

Removing the unused SelectedAppointmentProvider import improves code cleanliness and reduces unnecessary dependencies. This is good housekeeping practice.

zmsentities/src/Zmsentities/Helper/Messaging.php (1)

321-323: LGTM!

The enhanced exception handling improves error diagnostics by storing the status value in exception->data. This change is consistent with the error handling pattern used elsewhere in the file (e.g., lines 156-158) and provides better context for debugging template-related issues.

zmscitizenview/src/types/AppointmentImpl.ts (1)

36-36: ICS field addition looks good

Property and assignment are consistent with AppointmentDTO.

Also applies to: 71-71

zmscitizenview/src/types/ProvideInjectTypes.ts (1)

3-3: Good move to DTO

Using AppointmentDTO in the provider is cleaner and aligns with API contracts.

Also applies to: 23-24

zmscitizenview/tests/unit/Appointment/AppointmentView.spec.ts (1)

1281-1393: ICS tests are coherent

Covers button visibility, method existence, and API call args. Looks good.

zmscitizenapi/src/Zmscitizenapi/Services/Core/MapperService.php (1)

386-406: Ensure timestamp mapping matches frontend DTO
The backend casts timestamp to string via strval(...), but AppointmentDTO uses a numeric type. Verify the DTO’s timestamp type and either cast to an integer in MapperService or update the frontend to accept a string.

zmscitizenview/src/components/Appointment/AppointmentView.vue (2)

233-246: LGTM! Clear separation of authenticated vs. unauthenticated flows.

The button rendering logic appropriately separates concerns: unauthenticated users receive a download option when ICS content is available, while authenticated users are directed to the detail page where they likely have additional options.


919-930: LGTM! Proper URL construction and navigation.

The function correctly builds the detail page URL with appropriate fallback and properly passes the appointment ID as a query parameter using the defined constant.

zmscitizenapi/src/Zmscitizenapi/Models/ThinnedProcess.php (2)

51-74: LGTM! Consistent with existing property patterns.

The icsContent property is properly declared, initialized, and serialized following the same patterns as other properties in the class. Type hints and null safety are correctly applied.

Also applies to: 103-104


118-126: LGTM! Accessor methods follow established patterns.

The getter and setter methods are consistent with the existing captchaToken accessors and provide appropriate type safety.

zmscitizenapi/src/Zmscitizenapi/Utils/MailTemplateHelper.php (2)

53-84: LGTM! Robust template loading with proper error handling.

The method correctly:

  • Initializes the templates array early to ensure consistency
  • Guards against missing provider ID
  • Uses secure authentication token for API calls
  • Validates template structure before populating
  • Logs errors with detailed context without interrupting execution

91-101: LGTM! Defensive and flexible provider ID extraction.

The method correctly handles both object and array provider formats with appropriate null safety checks and type casting.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentByIdControllerTest.php (1)

42-48: Test additions follow consistent pattern.

The mail template mock setup and ICS content validation are correctly implemented, consistent with other controller tests. Refer to the earlier comment on AppointmentCancelControllerTest regarding refactoring opportunities for this duplicated pattern.

Also applies to: 125-129

zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentPreconfirmControllerTest.php (1)

43-48: Duplication of mail template setup across multiple test methods.

This file exhibits the same duplication pattern discussed in AppointmentCancelControllerTest and AppointmentUpdateControllerTest. The mail template mock appears in 7+ test methods. Please refer to the earlier comments recommending extraction into a helper method or setUp() configuration.

Also applies to: 125-129, 217-222, 275-280, 383-388, 432-437, 481-486, 530-535

🧹 Nitpick comments (1)
zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentCancelControllerTest.php (1)

47-52: Consider extracting duplicate test setup into a helper method.

This mail template mock setup pattern is duplicated across AppointmentCancelControllerTest, AppointmentByIdControllerTest, AppointmentUpdateControllerTest, and AppointmentPreconfirmControllerTest. The ICS content validation is also repeated.

Consider creating a base test helper method in ControllerTestCase:

protected function addMailTemplateMock(int $providerId = 102522): array
{
    return [
        'function' => 'readGetResult',
        'url' => "/merged-mailtemplates/{$providerId}/",
        'xtoken' => 'hash',
        'response' => $this->readFixture("GET_merged_mailtemplates.json")
    ];
}

protected function assertIcsContent(array $responseBody): void
{
    $this->assertArrayHasKey('icsContent', $responseBody);
    $this->assertStringContainsString('BEGIN:VCALENDAR', $responseBody['icsContent']);
}

Then use:

$this->setApiCalls([
    // ... other mocks ...
    $this->addMailTemplateMock()
]);

$this->assertIcsContent($responseBody);
unset($responseBody['icsContent']);
unset($expectedResponse['icsContent']);

Also applies to: 130-134

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4b260ae and 972d9b5.

📒 Files selected for processing (8)
  • zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentByIdControllerTest.php (2 hunks)
  • zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentCancelControllerTest.php (3 hunks)
  • zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentConfirmControllerTest.php (8 hunks)
  • zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentPreconfirmControllerTest.php (8 hunks)
  • zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentUpdateControllerTest.php (21 hunks)
  • zmscitizenapi/tests/Zmscitizenapi/Services/Appointment/AppointmentUpdateServiceTest.php (2 hunks)
  • zmscitizenapi/tests/Zmscitizenapi/bootstrap.php (1 hunks)
  • zmscitizenapi/tests/Zmscitizenapi/fixtures/GET_merged_mailtemplates.json (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • zmscitizenapi/tests/Zmscitizenapi/fixtures/GET_merged_mailtemplates.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentConfirmControllerTest.php
🧰 Additional context used
📓 Path-based instructions (2)
**/*

⚙️ CodeRabbit configuration file

**/*: Apply the following Clean Code guidelines to all files, as summarized by wojteklu's Clean Code gist:

Code is clean if it can be understood easily – by everyone on the team. Clean code can be read and enhanced by a developer other than its original author. With understandability comes readability, changeability, extensibility and maintainability.

General rules

  1. Follow standard conventions.
  2. Keep it simple stupid. Simpler is always better. Reduce complexity as much as possible.
  3. Boy scout rule. Leave the campground cleaner than you found it.
  4. Always find root cause. Always look for the root cause of a problem.

Design rules

  1. Keep configurable data at high levels.
  2. Prefer polymorphism to if/else or switch/case.
  3. Separate multi-threading code.
  4. Prevent over-configurability.
  5. Use dependency injection.
  6. Follow Law of Demeter. A class should know only its direct dependencies.

Understandability tips

  1. Be consistent. If you do something a certain way, do all similar things in the same way.
  2. Use explanatory variables.
  3. Encapsulate boundary conditions. Boundary conditions are hard to keep track of. Put the processing for them in one place.
  4. Prefer dedicated value objects to primitive type.
  5. Avoid logical dependency. Don't write methods which works correctly depending on something else in the same class.
  6. Avoid negative conditionals.

Names rules

  1. Choose descriptive and unambiguous names.
  2. Make meaningful distinction.
  3. Use pronounceable names.
  4. Use searchable names.
  5. Replace magic numbers with named constants.
  6. Avoid encodings. Don't append prefixes or type information.

Functions rules

  1. Small.
  2. Do one thing.
  3. Use descriptive names.
  4. Prefer fewer arguments.
  5. Have no side effects.
  6. Don't use flag arguments. Split method into several independent methods that can b...

Files:

  • zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentPreconfirmControllerTest.php
  • zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentUpdateControllerTest.php
  • zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentByIdControllerTest.php
  • zmscitizenapi/tests/Zmscitizenapi/bootstrap.php
  • zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentCancelControllerTest.php
  • zmscitizenapi/tests/Zmscitizenapi/Services/Appointment/AppointmentUpdateServiceTest.php
**/*.php

⚙️ CodeRabbit configuration file

**/*.php: Flag any usage of error_log() as it should be replaced with proper Monolog logging mechanisms provided by zmsslim which should be setup in the App/Application of each module:

  1. For error handling: Use the proper Monolog logging framework with error levels
  2. For application info logs: Use the proper Monolog logging framework with info levels
  3. For debugging: Use a dedicated debug logger or remove debug statements
  4. For CLI output: Use a CLI output handler or symfony/console
  5. The application log levels are as follows DEBUG, INFO, NOTICE, WARNING, ERROR, CRITICAL, ALERT, and EMERGENCY

Example replacement:

// Instead of:
error_log("Import failed - " . $e->getMessage());

// Use:
$log->error("Import failed", ['error' => $e->getMessage()]);

Flag specific logging violations:

  1. error_log(), var_dump(), print_r(), die(), exit() usage (except proper error logging in catch blocks)
  2. Any debug output that should use proper Monolog logging
  3. Debug constants like DEBUG = true
  4. Debug logging that should be removed in production
  5. Commented debug code that should be cleaned up

Example replacements:

// Instead of:
error_log("Error occurred");
var_dump($data);
die('debug point');

// Use:
$log->error("Error occurred", ['context' => 'processing']);
$log->debug('Data dump', ['data' => $data]);
// Remove die() statements entirely

Exception handling should use proper logging:

// Instead of:
try {
    $result = $this->process();
} catch (Exception $e) {
    error_log("Processing failed: " . $e->getMessage());
}

// Use:
try {
    $result = $this->process();
} catch (Exception $e) {
    $log->error("Processing failed", ['error' => $e->getMessage(), 'trace' => $e->getTraceAsString()]);
}
```...

Files:

  • zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentPreconfirmControllerTest.php
  • zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentUpdateControllerTest.php
  • zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentByIdControllerTest.php
  • zmscitizenapi/tests/Zmscitizenapi/bootstrap.php
  • zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentCancelControllerTest.php
  • zmscitizenapi/tests/Zmscitizenapi/Services/Appointment/AppointmentUpdateServiceTest.php
🧬 Code graph analysis (1)
zmscitizenapi/tests/Zmscitizenapi/Services/Appointment/AppointmentUpdateServiceTest.php (2)
zmsclient/src/Zmsclient/Http.php (1)
  • Http (16-260)
zmsclient/src/Zmsclient/Result.php (1)
  • Result (17-248)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (python)
  • GitHub Check: call-php-code-quality / module-code-quality (zmsapi, 8.3)
  • GitHub Check: call-php-code-quality / module-code-quality (zmscalldisplay, 8.3)
  • GitHub Check: call-php-unit-tests / zmsdb-test
🔇 Additional comments (3)
zmscitizenapi/tests/Zmscitizenapi/bootstrap.php (1)

13-14: LGTM! Test environment setup is appropriate.

The secure token environment variable is correctly set before loading the bootstrap, enabling tests to access merged mail templates via authenticated API calls.

zmscitizenapi/tests/Zmscitizenapi/Controllers/Appointment/AppointmentCancelControllerTest.php (1)

159-165: Request verification: Error handling for mail template fetch failures.

While the mail template mock is added, there are no test cases covering scenarios where the merged mail templates fetch fails. Consider adding tests to verify graceful degradation.

Do the controllers handle mail template fetch failures gracefully? If the /merged-mailtemplates/ endpoint returns an error, does the appointment operation still succeed without the ICS content, or does it fail the entire request?

Consider adding test cases like:

public function testRenderingWithMailTemplateFetchFailure()
{
    $exception = new \BO\Zmsclient\Exception();
    $exception->template = 'BO\\Zmsapi\\Exception\\MailTemplate\\MailTemplateNotFound';
    
    $this->setApiCalls([
        // ... process and source mocks ...
        [
            'function' => 'readGetResult',
            'url' => '/merged-mailtemplates/102522/',
            'xtoken' => 'hash',
            'exception' => $exception
        ]
    ]);
    // Verify appointment still works but no icsContent
}
zmscitizenapi/tests/Zmscitizenapi/Services/Appointment/AppointmentUpdateServiceTest.php (1)

230-273: Service test correctly handles new mail template dependency.

The test properly:

  • Adds the mail templates JSON structure and mock response
  • Increments the expected call count from 2 to 3
  • Routes the /merged-mailtemplates/ URL in the callback

The empty data array in mailTemplatesJson (line 238) is acceptable for this test since it focuses on client data validation rather than template content processing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant