Skip to content

S28-3289 Refactor edit email notifications to use common notifier#1470

Open
lydiaralphgov wants to merge 39 commits into
masterfrom
S28-3289/edit-request-emails
Open

S28-3289 Refactor edit email notifications to use common notifier#1470
lydiaralphgov wants to merge 39 commits into
masterfrom
S28-3289/edit-request-emails

Conversation

@lydiaralphgov

@lydiaralphgov lydiaralphgov commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

JIRA ticket(s)

Change description

  • Consolidate edit request emails into a single service
  • Move edit email parameters validation and calculation into separate class
  • Shift responsibility: EditNotificationService calculates whether to send notifications
  • Write functional tests for first half of edit request process (DRAFT to PENDING)
  • FTs for edit email notifications already exist

Important

This PR requires manual testing by QA. Please notify the QA team @hmcts/pre-rec-evidence-qa.

QA instructions

Notes:

  • https://pre-api-pr-1470.dev.platform.hmcts.net/swagger-ui/index.html?urls.primaryName=pre-api
  • Do not use the CSV endpoint for testing this, as the edits will go straight into PENDING status. Create edit requests via the PUT endpoint instead.
  • Edit request instructions can only be changed while the status is DRAFT
  • A notification should be sent to the court group email address, and any shared-with users
  • Each edit request should generate a separate email when it goes to SUBMITTED or REJECTED status

Steps:

Test 1: Submitted email

  1. Share a booking with yourself
  2. Make sure the court email address has been set for that court
  3. Create an edit request for a recording on that booking
  4. Update the edit request status to SUBMITTED
  5. Check that you receive an email from gov notify
  6. The email should contain: Start time, end time, time removed and reason for edit, for each edit instruction on the edit request

Test 2: Rejected email

  1. Share a booking with yourself
  2. Make sure the court email address has been set for that court
  3. Create an edit request for a recording on that booking
  4. Update the edit request status to REJECTED
  5. Check that you receive an email from gov notify
  6. The email should contain: rejection reason


@Slf4j
@Service
@SuppressWarnings("PMD.CouplingBetweenObjects")

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

whoop whoop another one bites the dust!

@lydiaralphgov
lydiaralphgov marked this pull request as ready for review June 11, 2026 18:03
@lydiaralphgov
lydiaralphgov requested a review from a team as a code owner June 11, 2026 18:03
Comment thread src/test/java/uk/gov/hmcts/reform/preapi/services/EditRequestServiceTest.java Outdated
@lydiaralphgov lydiaralphgov changed the title S28-3289 Refactor email notifications to use common notifier S28-3289 Refactor edit email notifications to use common notifier Jun 25, 2026
recording,
"{\"ffmpegInstructions\":[{\"start\":0,\"end\":60},{\"start\":120,\"end\":180}]}",
EditRequestStatus.PENDING,
EditRequestStatus.DRAFT,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Due to new restriction where edit request cannot be altered after submission

@hmcts-jenkins-cnp

hmcts-jenkins-cnp Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Plan Result (stg)

Plan: 0 to add, 3 to change, 0 to destroy.
  • Update
    • module.pre-api-exception-alert[0].azurerm_resource_group_template_deployment.custom_alert[0]
    • module.pre_api[0].azurerm_api_management_api.api
    • module.pre_b2c_product.azurerm_api_management_product.product
Change Result (Click me)
  # module.pre-api-exception-alert[0].azurerm_resource_group_template_deployment.custom_alert[0] will be updated in-place
  ~ resource "azurerm_resource_group_template_deployment" "custom_alert" {
        id                       = "/subscriptions/74dacd4f-a248-45bb-a2f0-af700dc4cf68/resourceGroups/pre-stg/providers/Microsoft.Resources/deployments/PRE_API_exception"
        name                     = "PRE_API_exception"
        tags                     = {}
      ~ template_content         = jsonencode(
          ~ {
              ~ parameters     = {
                  ~ actionGroupName          = {
                      ~ type = "String" -> "string"
                    }
                  ~ actionGroupRg            = {
                      ~ type = "String" -> "string"
                    }
                  ~ alertDesc                = {
                      ~ type = "String" -> "string"
                    }
                  ~ alertName                = {
                      ~ type = "String" -> "string"
                    }
                  ~ appInsightsName          = {
                      ~ type = "String" -> "string"
                    }
                  ~ appInsightsQuery         = {
                      ~ type = "String" -> "string"
                    }
                  ~ commonTags               = {
                      ~ type = "String" -> "string"
                    }
                  ~ customEmailSubject       = {
                      ~ type = "String" -> "string"
                    }
                  ~ frequencyInMinutes       = {
                      ~ type         = "String" -> "string"
                        # (1 unchanged attribute hidden)
                    }
                  ~ location                 = {
                      ~ type = "String" -> "string"
                    }
                  ~ severityLevel            = {
                      ~ type         = "String" -> "string"
                        # (1 unchanged attribute hidden)
                    }
                  ~ timeWindowInMinutes      = {
                      ~ type         = "String" -> "string"
                        # (1 unchanged attribute hidden)
                    }
                  ~ triggerThreshold         = {
                      ~ type = "String" -> "string"
                    }
                  ~ triggerThresholdOperator = {
                      ~ type          = "String" -> "string"
                        # (2 unchanged attributes hidden)
                    }
                }
                # (4 unchanged attributes hidden)
            }
        )
        # (6 unchanged attributes hidden)
    }

  # module.pre_api[0].azurerm_api_management_api.api will be updated in-place
  ~ resource "azurerm_api_management_api" "api" {
        id                    = "/subscriptions/74dacd4f-a248-45bb-a2f0-af700dc4cf68/resourceGroups/ss-stg-network-rg/providers/Microsoft.ApiManagement/service/sds-api-mgmt-stg/apis/pre-api;rev=999"
        name                  = "pre-api"
        # (17 unchanged attributes hidden)

      ~ import {
          ~ content_value  = jsonencode(
              ~ {
                  ~ components   = {
                      ~ schemas         = {
                          ~ CaptureSessionDTO                         = {
                              ~ properties  = {
                                  - displayed_rtmps_link = {
                                      - description = "CreateCaptureSessionDisplayedRtmpsLink"
                                      - type        = "string"
                                    }
                                    id                   = {
                                        description = "CreateCaptureSessionId"
                                        format      = "uuid"
                                        type        = "string"
                                    }
                                    # (13 unchanged attributes hidden)
                                }
                                # (3 unchanged attributes hidden)
                            }
                          ~ EntityModelCaptureSessionDTO              = {
                              ~ properties = {
                                  - displayed_rtmps_link = {
                                      - description = "CreateCaptureSessionDisplayedRtmpsLink"
                                      - type        = "string"
                                    }
                                    id                   = {
                                        description = "CreateCaptureSessionId"
                                        format      = "uuid"
                                        type        = "string"
                                    }
                                    # (14 unchanged attributes hidden)
                                }
                                # (2 unchanged attributes hidden)
                            }
                          ~ LiveEventDTO                              = {
                              ~ properties  = {
                                  - displayed_rtmps_link = {
                                      - description = "DisplayedRtmpsLink"
                                      - type        = "string"
                                    }
                                    id                   = {
                                        description = "LiveEventId"
                                        type        = "string"
                                    }
                                    name                 = {
                                        description = "LiveEventName"
                                        type        = "string"
                                    }
                                    # (3 unchanged attributes hidden)
                                }
                                # (2 unchanged attributes hidden)
                            }
                            # (83 unchanged attributes hidden)
                        }
                        # (1 unchanged attribute hidden)
                    }
                    tags         = [
                        {
                            description  = "Monitor and interact"
                            externalDocs = {
                                description = "Spring Boot Actuator Web API Documentation"
                                url         = "https://docs.spring.io/spring-boot/docs/current/actuator-api/html/"
                            }
                            name         = "Actuator"
                        },
                    ]
                    # (6 unchanged attributes hidden)
                }
            )
            # (1 unchanged attribute hidden)
        }

        # (1 unchanged block hidden)
    }

  # module.pre_b2c_product.azurerm_api_management_product.product will be updated in-place
  ~ resource "azurerm_api_management_product" "product" {
        id                    = "/subscriptions/74dacd4f-a248-45bb-a2f0-af700dc4cf68/resourceGroups/ss-stg-network-rg/providers/Microsoft.ApiManagement/service/sds-api-mgmt-stg/products/pre-api-b2c"
      ~ subscriptions_limit   = 0 -> 20
        # (9 unchanged attributes hidden)
    }

Plan: 0 to add, 3 to change, 0 to destroy.

@hmcts-jenkins-cnp

Copy link
Copy Markdown
Contributor

Plan Result (prod)

Plan: 0 to add, 4 to change, 0 to destroy.
  • Update
    • module.pre-api-exception-alert[0].azurerm_resource_group_template_deployment.custom_alert[0]
    • module.pre-api-liveness-alert[0].azurerm_resource_group_template_deployment.custom_alert[0]
    • module.pre_api[0].azurerm_api_management_api.api
    • module.pre_b2c_product.azurerm_api_management_product.product
Change Result (Click me)
  # module.pre-api-exception-alert[0].azurerm_resource_group_template_deployment.custom_alert[0] will be updated in-place
  ~ resource "azurerm_resource_group_template_deployment" "custom_alert" {
        id                       = "/subscriptions/5ca62022-6aa2-4cee-aaa7-e7536c8d566c/resourceGroups/pre-prod/providers/Microsoft.Resources/deployments/PRE_API_exception"
        name                     = "PRE_API_exception"
        tags                     = {}
      ~ template_content         = jsonencode(
          ~ {
              ~ parameters     = {
                  ~ actionGroupName          = {
                      ~ type = "String" -> "string"
                    }
                  ~ actionGroupRg            = {
                      ~ type = "String" -> "string"
                    }
                  ~ alertDesc                = {
                      ~ type = "String" -> "string"
                    }
                  ~ alertName                = {
                      ~ type = "String" -> "string"
                    }
                  ~ appInsightsName          = {
                      ~ type = "String" -> "string"
                    }
                  ~ appInsightsQuery         = {
                      ~ type = "String" -> "string"
                    }
                  ~ commonTags               = {
                      ~ type = "String" -> "string"
                    }
                  ~ customEmailSubject       = {
                      ~ type = "String" -> "string"
                    }
                  ~ frequencyInMinutes       = {
                      ~ type         = "String" -> "string"
                        # (1 unchanged attribute hidden)
                    }
                  ~ location                 = {
                      ~ type = "String" -> "string"
                    }
                  ~ severityLevel            = {
                      ~ type         = "String" -> "string"
                        # (1 unchanged attribute hidden)
                    }
                  ~ timeWindowInMinutes      = {
                      ~ type         = "String" -> "string"
                        # (1 unchanged attribute hidden)
                    }
                  ~ triggerThreshold         = {
                      ~ type = "String" -> "string"
                    }
                  ~ triggerThresholdOperator = {
                      ~ type          = "String" -> "string"
                        # (2 unchanged attributes hidden)
                    }
                }
                # (4 unchanged attributes hidden)
            }
        )
        # (6 unchanged attributes hidden)
    }

  # module.pre-api-liveness-alert[0].azurerm_resource_group_template_deployment.custom_alert[0] will be updated in-place
  ~ resource "azurerm_resource_group_template_deployment" "custom_alert" {
        id                       = "/subscriptions/5ca62022-6aa2-4cee-aaa7-e7536c8d566c/resourceGroups/pre-prod/providers/Microsoft.Resources/deployments/PRE_API_liveness"
        name                     = "PRE_API_liveness"
        tags                     = {}
      ~ template_content         = jsonencode(
          ~ {
              ~ parameters     = {
                  ~ actionGroupName          = {
                      ~ type = "String" -> "string"
                    }
                  ~ actionGroupRg            = {
                      ~ type = "String" -> "string"
                    }
                  ~ alertDesc                = {
                      ~ type = "String" -> "string"
                    }
                  ~ alertName                = {
                      ~ type = "String" -> "string"
                    }
                  ~ appInsightsName          = {
                      ~ type = "String" -> "string"
                    }
                  ~ appInsightsQuery         = {
                      ~ type = "String" -> "string"
                    }
                  ~ commonTags               = {
                      ~ type = "String" -> "string"
                    }
                  ~ customEmailSubject       = {
                      ~ type = "String" -> "string"
                    }
                  ~ frequencyInMinutes       = {
                      ~ type         = "String" -> "string"
                        # (1 unchanged attribute hidden)
                    }
                  ~ location                 = {
                      ~ type = "String" -> "string"
                    }
                  ~ severityLevel            = {
                      ~ type         = "String" -> "string"
                        # (1 unchanged attribute hidden)
                    }
                  ~ timeWindowInMinutes      = {
                      ~ type         = "String" -> "string"
                        # (1 unchanged attribute hidden)
                    }
                  ~ triggerThreshold         = {
                      ~ type = "String" -> "string"
                    }
                  ~ triggerThresholdOperator = {
                      ~ type          = "String" -> "string"
                        # (2 unchanged attributes hidden)
                    }
                }
                # (4 unchanged attributes hidden)
            }
        )
        # (6 unchanged attributes hidden)
    }

  # module.pre_api[0].azurerm_api_management_api.api will be updated in-place
  ~ resource "azurerm_api_management_api" "api" {
        id                    = "/subscriptions/5ca62022-6aa2-4cee-aaa7-e7536c8d566c/resourceGroups/ss-prod-network-rg/providers/Microsoft.ApiManagement/service/sds-api-mgmt-prod/apis/pre-api;rev=999"
        name                  = "pre-api"
        # (17 unchanged attributes hidden)

      ~ import {
          ~ content_value  = jsonencode(
              ~ {
                  ~ components   = {
                      ~ schemas         = {
                          ~ CaptureSessionDTO                         = {
                              ~ properties  = {
                                  - displayed_rtmps_link = {
                                      - description = "CreateCaptureSessionDisplayedRtmpsLink"
                                      - type        = "string"
                                    }
                                    id                   = {
                                        description = "CreateCaptureSessionId"
                                        format      = "uuid"
                                        type        = "string"
                                    }
                                    # (13 unchanged attributes hidden)
                                }
                                # (3 unchanged attributes hidden)
                            }
                          ~ EntityModelCaptureSessionDTO              = {
                              ~ properties = {
                                  - displayed_rtmps_link = {
                                      - description = "CreateCaptureSessionDisplayedRtmpsLink"
                                      - type        = "string"
                                    }
                                    id                   = {
                                        description = "CreateCaptureSessionId"
                                        format      = "uuid"
                                        type        = "string"
                                    }
                                    # (14 unchanged attributes hidden)
                                }
                                # (2 unchanged attributes hidden)
                            }
                          ~ LiveEventDTO                              = {
                              ~ properties  = {
                                  - displayed_rtmps_link = {
                                      - description = "DisplayedRtmpsLink"
                                      - type        = "string"
                                    }
                                    id                   = {
                                        description = "LiveEventId"
                                        type        = "string"
                                    }
                                    name                 = {
                                        description = "LiveEventName"
                                        type        = "string"
                                    }
                                    # (3 unchanged attributes hidden)
                                }
                                # (2 unchanged attributes hidden)
                            }
                            # (83 unchanged attributes hidden)
                        }
                        # (1 unchanged attribute hidden)
                    }
                    tags         = [
                        {
                            description  = "Monitor and interact"
                            externalDocs = {
                                description = "Spring Boot Actuator Web API Documentation"
                                url         = "https://docs.spring.io/spring-boot/docs/current/actuator-api/html/"
                            }
                            name         = "Actuator"
                        },
                    ]
                    # (6 unchanged attributes hidden)
                }
            )
            # (1 unchanged attribute hidden)
        }

        # (1 unchanged block hidden)
    }

  # module.pre_b2c_product.azurerm_api_management_product.product will be updated in-place
  ~ resource "azurerm_api_management_product" "product" {
        id                    = "/subscriptions/5ca62022-6aa2-4cee-aaa7-e7536c8d566c/resourceGroups/ss-prod-network-rg/providers/Microsoft.ApiManagement/service/sds-api-mgmt-prod/products/pre-api-b2c"
      ~ subscriptions_limit   = 0 -> 20
        # (9 unchanged attributes hidden)
    }

Plan: 0 to add, 4 to change, 0 to destroy.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant