Ver código fonte

add notifications handlers

Alexander Belanger 4 anos atrás
pai
commit
fb2c1564a5

+ 64 - 0
api/server/handlers/release/get_notifications.go

@@ -0,0 +1,64 @@
+package release
+
+import (
+	"net/http"
+
+	"github.com/porter-dev/porter/api/server/handlers"
+	"github.com/porter-dev/porter/api/server/shared"
+	"github.com/porter-dev/porter/api/server/shared/apierrors"
+	"github.com/porter-dev/porter/api/server/shared/config"
+	"github.com/porter-dev/porter/api/server/shared/requestutils"
+	"github.com/porter-dev/porter/api/types"
+	"github.com/porter-dev/porter/internal/models"
+	"gorm.io/gorm"
+)
+
+type GetNotificationHandler struct {
+	handlers.PorterHandlerReadWriter
+}
+
+func NewGetNotificationHandler(
+	config *config.Config,
+	writer shared.ResultWriter,
+) *GetNotificationHandler {
+	return &GetNotificationHandler{
+		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, nil, writer),
+	}
+}
+
+func (c *GetNotificationHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
+	name, _ := requestutils.GetURLParamString(r, types.URLParamReleaseName)
+	namespace := r.Context().Value(types.NamespaceScope).(string)
+
+	release, err := c.Repo().Release().ReadRelease(cluster.ID, name, namespace)
+
+	if err != nil {
+		if err == gorm.ErrRecordNotFound {
+			w.WriteHeader(http.StatusNotFound)
+			return
+		}
+
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	config := &models.NotificationConfigExternal{
+		Enabled: true,
+		Success: true,
+		Failure: true,
+	}
+
+	if release.NotificationConfig != 0 {
+		notifConfig, err := c.Repo().NotificationConfig().ReadNotificationConfig(release.NotificationConfig)
+
+		if err != nil {
+			c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+			return
+		}
+
+		config = notifConfig.Externalize()
+	}
+
+	c.WriteResult(w, r, config)
+}

+ 79 - 0
api/server/handlers/release/update_notifications.go

@@ -0,0 +1,79 @@
+package release
+
+import (
+	"net/http"
+
+	"github.com/porter-dev/porter/api/server/handlers"
+	"github.com/porter-dev/porter/api/server/shared"
+	"github.com/porter-dev/porter/api/server/shared/apierrors"
+	"github.com/porter-dev/porter/api/server/shared/config"
+	"github.com/porter-dev/porter/api/server/shared/requestutils"
+	"github.com/porter-dev/porter/api/types"
+	"github.com/porter-dev/porter/internal/models"
+	"gorm.io/gorm"
+)
+
+type UpdateNotificationHandler struct {
+	handlers.PorterHandlerReadWriter
+}
+
+func NewUpdateNotificationHandler(
+	config *config.Config,
+	decoderValidator shared.RequestDecoderValidator,
+	writer shared.ResultWriter,
+) *UpdateNotificationHandler {
+	return &UpdateNotificationHandler{
+		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
+	}
+}
+
+func (c *UpdateNotificationHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
+	name, _ := requestutils.GetURLParamString(r, types.URLParamReleaseName)
+	namespace := r.Context().Value(types.NamespaceScope).(string)
+
+	request := &types.UpdateNotificationConfigRequest{}
+
+	if ok := c.DecodeAndValidate(w, r, request); !ok {
+		return
+	}
+
+	release, err := c.Repo().Release().ReadRelease(cluster.ID, name, namespace)
+
+	if err != nil {
+		if err == gorm.ErrRecordNotFound {
+			w.WriteHeader(http.StatusNotFound)
+			return
+		}
+
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+	}
+
+	// either create a new notification config or update the current one
+	newConfig := &models.NotificationConfig{
+		Enabled: request.Payload.Enabled,
+		Success: request.Payload.Success,
+		Failure: request.Payload.Failure,
+	}
+
+	if release.NotificationConfig == 0 {
+		newConfig, err = c.Repo().NotificationConfig().CreateNotificationConfig(newConfig)
+
+		if err != nil {
+			c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+			return
+		}
+
+		release.NotificationConfig = newConfig.ID
+
+		release, err = c.Repo().Release().UpdateRelease(release)
+	} else {
+		newConfig.ID = release.NotificationConfig
+		newConfig, err = c.Repo().NotificationConfig().UpdateNotificationConfig(newConfig)
+	}
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+}

+ 59 - 0
api/server/router/release.go

@@ -202,5 +202,64 @@ func getReleaseRoutes(
 		Router:   r,
 	})
 
+	// POST /api/projects/{project_id}/clusters/{cluster_id}/namespaces/{namespace}/releases/{name}/notifications -> release.NewUpdateNotificationHandler
+	updateNotifsEndpoint := factory.NewAPIEndpoint(
+		&types.APIRequestMetadata{
+			Verb:   types.APIVerbUpdate,
+			Method: types.HTTPVerbPost,
+			Path: &types.Path{
+				Parent:       basePath,
+				RelativePath: "/releases/{name}/notifications",
+			},
+			Scopes: []types.PermissionScope{
+				types.UserScope,
+				types.ProjectScope,
+				types.ClusterScope,
+				types.NamespaceScope,
+			},
+		},
+	)
+
+	updateNotifsHandler := release.NewUpdateNotificationHandler(
+		config,
+		factory.GetDecoderValidator(),
+		factory.GetResultWriter(),
+	)
+
+	routes = append(routes, &Route{
+		Endpoint: updateNotifsEndpoint,
+		Handler:  updateNotifsHandler,
+		Router:   r,
+	})
+
+	// GET /api/projects/{project_id}/clusters/{cluster_id}/namespaces/{namespace}/releases/{name}/notifications -> release.NewGetNotificationHandler
+	getNotifsEndpoint := factory.NewAPIEndpoint(
+		&types.APIRequestMetadata{
+			Verb:   types.APIVerbGet,
+			Method: types.HTTPVerbGet,
+			Path: &types.Path{
+				Parent:       basePath,
+				RelativePath: "/releases/{name}/notifications",
+			},
+			Scopes: []types.PermissionScope{
+				types.UserScope,
+				types.ProjectScope,
+				types.ClusterScope,
+				types.NamespaceScope,
+			},
+		},
+	)
+
+	getNotifsHandler := release.NewGetNotificationHandler(
+		config,
+		factory.GetResultWriter(),
+	)
+
+	routes = append(routes, &Route{
+		Endpoint: getNotifsEndpoint,
+		Handler:  getNotifsHandler,
+		Router:   r,
+	})
+
 	return routes, newPath
 }

+ 8 - 0
api/types/release.go

@@ -13,3 +13,11 @@ type Release struct {
 }
 
 type GetReleaseResponse Release
+
+type UpdateNotificationConfigRequest struct {
+	Payload struct {
+		Enabled bool `json:"enabled"`
+		Success bool `json:"success"`
+		Failure bool `json:"failure"`
+	} `json:"payload"`
+}

+ 4 - 4
dashboard/src/main/home/cluster-dashboard/expanded-chart/NotificationSettingsSection.tsx

@@ -38,11 +38,11 @@ const NotificationSettingsSection: React.FC<Props> = (props) => {
       .getNotificationConfig(
         "<token>",
         {
-          namespace: props.currentChart.namespace,
-          cluster_id: currentCluster.id,
         },
         {
           project_id: currentProject.id,
+          namespace: props.currentChart.namespace,
+          cluster_id: currentCluster.id,
           name: props.currentChart.name,
         }
       )
@@ -83,12 +83,12 @@ const NotificationSettingsSection: React.FC<Props> = (props) => {
       .updateNotificationConfig(
         "<token>",
         {
-          namespace: props.currentChart.namespace,
-          cluster_id: currentCluster.id,
           payload,
         },
         {
           project_id: currentProject.id,
+          namespace: props.currentChart.namespace,
+          cluster_id: currentCluster.id,
           name: props.currentChart.name,
         }
       )

+ 10 - 6
dashboard/src/shared/api.tsx

@@ -249,28 +249,32 @@ const deleteSlackIntegration = baseApi<
 const updateNotificationConfig = baseApi<
   {
     payload: any;
-    namespace: string;
-    cluster_id: number;
   },
   {
     project_id: number;
+    cluster_id: number;
+    namespace: string;
     name: string;
   }
 >("POST", (pathParams) => {
-  return `/api/projects/${pathParams.project_id}/releases/${pathParams.name}/notifications`;
+  let { project_id, cluster_id, namespace, name } = pathParams
+
+  return `/api/projects/${project_id}/clusters/${cluster_id}/namespaces/${namespace}/releases/${name}/notifications`;
 });
 
 const getNotificationConfig = baseApi<
   {
-    namespace: string;
-    cluster_id: number;
   },
   {
     project_id: number;
+    cluster_id: number;
+    namespace: string;
     name: string;
   }
 >("GET", (pathParams) => {
-  return `/api/projects/${pathParams.project_id}/releases/${pathParams.name}/notifications`;
+  let { project_id, cluster_id, namespace, name } = pathParams
+
+  return `/api/projects/${project_id}/clusters/${cluster_id}/namespaces/${namespace}/releases/${name}/notifications`;
 });
 
 const generateGHAWorkflow = baseApi<

+ 2 - 2
docs/developing/backend-refactor-status.md

@@ -126,8 +126,8 @@
 | <li>- [x] `GET /api/projects/{project_id}/releases`                                                                         | AS          | yes             |             | yes              |
 | <li>- [ ] `POST /api/projects/{project_id}/releases/image/update/batch`                                                     |             |                 |             |                  |
 | <li>- [X] `GET /api/projects/{project_id}/releases/{name}/history`                                                          | AB          |                 |             |                  |
-| <li>- [ ] `POST /api/projects/{project_id}/releases/{name}/notifications`                                                   |             |                 |             |                  |
-| <li>- [ ] `GET /api/projects/{project_id}/releases/{name}/notifications`                                                    |             |                 |             |                  |
+| <li>- [X] `POST /api/projects/{project_id}/releases/{name}/notifications`                                                   | AB          |                 |             |                  |
+| <li>- [X] `GET /api/projects/{project_id}/releases/{name}/notifications`                                                    | AB          |                 |             |                  |
 | <li>- [ ] `POST /api/projects/{project_id}/releases/{name}/rollback`                                                        |             |                 |             |                  |
 | <li>- [ ] `POST /api/projects/{project_id}/releases/{name}/upgrade`                                                         |             |                 |             |                  |
 | <li>- [ ] `GET /api/projects/{project_id}/releases/{name}/webhook_token`                                                    |             |                 |             |                  |