Skip to content

Commit

Permalink
add handler for notification by id (#4280)
Browse files Browse the repository at this point in the history
Co-authored-by: Feroze Mohideen <[email protected]>
  • Loading branch information
d-g-town and Feroze Mohideen authored Feb 15, 2024
1 parent 68cd439 commit 8e3a14b
Show file tree
Hide file tree
Showing 16 changed files with 526 additions and 117 deletions.
6 changes: 3 additions & 3 deletions api/server/handlers/notifications/get_notification_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
"github.com/porter-dev/porter/api/server/shared/config"
)

// GetNotificationConfigHandler is the handler for the POST /notifications/{notification_config_id} endpoint
// GetNotificationConfigHandler is the handler for the POST /notifications/config/{notification_config_id} endpoint
type GetNotificationConfigHandler struct {
handlers.PorterHandlerReadWriter
}
Expand All @@ -34,10 +34,10 @@ func NewNotificationConfigHandler(
}
}

// GetNotificationConfigRequest is the request object for the /notifications/{notification_config_id} endpoint
// GetNotificationConfigRequest is the request object for the /notifications/config/{notification_config_id} endpoint
type GetNotificationConfigRequest struct{}

// GetNotificationConfigResponse is the response object for the /notifications/{notification_config_id} endpoint
// GetNotificationConfigResponse is the response object for the /notifications/config/{notification_config_id} endpoint
type GetNotificationConfigResponse struct {
Config Config `json:"config"`
}
Expand Down
100 changes: 100 additions & 0 deletions api/server/handlers/notifications/notification.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package notifications

import (
"net/http"

"github.com/google/uuid"

"github.com/porter-dev/porter/internal/models"

"github.com/porter-dev/porter/internal/porter_app/notifications"

"github.com/porter-dev/porter/api/server/shared/requestutils"

"github.com/porter-dev/porter/api/server/shared/apierrors"
"github.com/porter-dev/porter/api/types"
"github.com/porter-dev/porter/internal/telemetry"

"github.com/porter-dev/porter/api/server/handlers"
"github.com/porter-dev/porter/api/server/shared"
"github.com/porter-dev/porter/api/server/shared/config"
)

// GetNotificationHandler is the handler for the POST /notifications/{notification_config_id} endpoint
type GetNotificationHandler struct {
handlers.PorterHandlerReadWriter
}

// NewNotificationHandler returns a new GetNotificationHandler
func NewNotificationHandler(
config *config.Config,
decoderValidator shared.RequestDecoderValidator,
writer shared.ResultWriter,
) *GetNotificationHandler {
return &GetNotificationHandler{
PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
}
}

// GetNotificationRequest is the request object for the /notifications/{notification_id} endpoint
type GetNotificationRequest struct{}

// NotificationResponse is the response object for the notifications endpoint
type NotificationResponse struct {
// Notifications are the notifications associated with the app revision
Notification notifications.Notification `json:"notification"`
}

// ServeHTTP returns a notification by id
func (n *GetNotificationHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ctx, span := telemetry.NewSpan(r.Context(), "serve-notification")
defer span.End()

project, _ := ctx.Value(types.ProjectScope).(*models.Project)

notificationID, reqErr := requestutils.GetURLParamString(r, types.URLParamNotificationID)
if reqErr != nil {
e := telemetry.Error(ctx, span, nil, "error parsing notification id from url")
n.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(e, http.StatusBadRequest))
return
}

telemetry.WithAttributes(span,
telemetry.AttributeKV{Key: "notification-id", Value: notificationID},
)

request := &GetNotificationRequest{}
if ok := n.DecodeAndValidate(w, r, request); !ok {
err := telemetry.Error(ctx, span, nil, "error decoding request")
n.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest))
return
}

event, err := n.Repo().PorterAppEvent().NotificationByID(ctx, notificationID)
if err != nil {
e := telemetry.Error(ctx, span, nil, "error getting notification by id")
n.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(e, http.StatusBadRequest))
return
}

// check project scope indirectly with deployment target
deploymentTarget, err := n.Repo().DeploymentTarget().DeploymentTarget(project.ID, event.DeploymentTargetID.String())
if err != nil || deploymentTarget == nil || deploymentTarget.ID == uuid.Nil {
e := telemetry.Error(ctx, span, err, "notification is not in project scope")
n.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(e, http.StatusBadRequest))
return
}

notification, err := notifications.NotificationFromPorterAppEvent(event)
if err != nil {
e := telemetry.Error(ctx, span, nil, "error converting app event to notification")
n.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(e, http.StatusInternalServerError))
return
}

resp := &NotificationResponse{
Notification: *notification,
}

n.WriteResult(w, r, resp)
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
"github.com/porter-dev/porter/api/server/shared/config"
)

// UpdateNotificationConfigHandler is the handler for the POST /notifications/{notification_config_id} endpoint
// UpdateNotificationConfigHandler is the handler for the POST /notifications/config/{notification_config_id} endpoint
type UpdateNotificationConfigHandler struct {
handlers.PorterHandlerReadWriter
}
Expand All @@ -34,7 +34,7 @@ func NewUpdateNotificationConfigHandler(
}
}

// UpdateNotificationConfigRequest is the request object for the /notifications/{notification_config_id} endpoint
// UpdateNotificationConfigRequest is the request object for the /notifications/config/{notification_config_id} endpoint
type UpdateNotificationConfigRequest struct {
Config Config `json:"config"`
SlackIntegrationID uint `json:"slack_integration_id"`
Expand All @@ -57,7 +57,7 @@ type Type struct {
Type string `json:"type"`
}

// UpdateNotificationConfigResponse is the response object for the /notifications/{notification_config_id} endpoint
// UpdateNotificationConfigResponse is the response object for the /notifications/config/{notification_config_id} endpoint
type UpdateNotificationConfigResponse struct {
ID uint `json:"id"`
}
Expand Down
36 changes: 32 additions & 4 deletions api/server/router/notification.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,14 @@ func getNotificationRoutes(

routes := make([]*router.Route, 0)

// POST /api/projects/{project_id}/notifications/{notification_config_id} -> notifications.NewUpdateNotificationConfigHandler
// POST /api/projects/{project_id}/notifications/config/{notification_config_id} -> notifications.NewUpdateNotificationConfigHandler
updateNotificationConfigEndpoint := factory.NewAPIEndpoint(
&types.APIRequestMetadata{
Verb: types.APIVerbUpdate,
Method: types.HTTPVerbPost,
Path: &types.Path{
Parent: basePath,
RelativePath: fmt.Sprintf("%s/{%s}", relPath, types.URLParamNotificationConfigID),
RelativePath: fmt.Sprintf("%s/config/{%s}", relPath, types.URLParamNotificationConfigID),
},
Scopes: []types.PermissionScope{
types.UserScope,
Expand All @@ -86,14 +86,14 @@ func getNotificationRoutes(
Router: r,
})

// GET /api/projects/{project_id}/notifications/{notification_config_id} -> notifications.NewNotificationConfigHandler
// GET /api/projects/{project_id}/notifications/config/{notification_config_id} -> notifications.NewNotificationConfigHandler
getNotificationConfigEndpoint := factory.NewAPIEndpoint(
&types.APIRequestMetadata{
Verb: types.APIVerbGet,
Method: types.HTTPVerbGet,
Path: &types.Path{
Parent: basePath,
RelativePath: fmt.Sprintf("%s/{%s}", relPath, types.URLParamNotificationConfigID),
RelativePath: fmt.Sprintf("%s/config/{%s}", relPath, types.URLParamNotificationConfigID),
},
Scopes: []types.PermissionScope{
types.UserScope,
Expand All @@ -114,5 +114,33 @@ func getNotificationRoutes(
Router: r,
})

// GET /api/projects/{project_id}/notifications/{notification_id} -> notifications.NewNotificationConfigHandler
notificationEndpoint := factory.NewAPIEndpoint(
&types.APIRequestMetadata{
Verb: types.APIVerbGet,
Method: types.HTTPVerbGet,
Path: &types.Path{
Parent: basePath,
RelativePath: fmt.Sprintf("%s/{%s}", relPath, types.URLParamNotificationID),
},
Scopes: []types.PermissionScope{
types.UserScope,
types.ProjectScope,
},
},
)

notificationHandler := notifications.NewNotificationHandler(
config,
factory.GetDecoderValidator(),
factory.GetResultWriter(),
)

routes = append(routes, &router.Route{
Endpoint: notificationEndpoint,
Handler: notificationHandler,
Router: r,
})

return routes, newPath
}
1 change: 1 addition & 0 deletions api/types/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ const (
URLParamDatastoreType URLParam = "datastore_type"
URLParamDatastoreName URLParam = "datastore_name"
URLParamNotificationConfigID URLParam = "notification_config_id"
URLParamNotificationID URLParam = "notification_id"
URLParamCloudProviderType URLParam = "cloud_provider_type"
URLParamCloudProviderID URLParam = "cloud_provider_id"
URLParamDeploymentTargetID URLParam = "deployment_target_id"
Expand Down
Loading

0 comments on commit 8e3a14b

Please sign in to comment.