Skip to content

Commit f7a102e

Browse files
committed
Update template method API
Signed-off-by: Danny Kopping <danny@coder.com>
1 parent 6f4f3e4 commit f7a102e

File tree

9 files changed

+231
-1
lines changed

9 files changed

+231
-1
lines changed

coderd/apidoc/docs.go

Lines changed: 22 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/apidoc/swagger.json

Lines changed: 18 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package httpmw
2+
3+
import (
4+
"context"
5+
"net/http"
6+
7+
"github.com/coder/coder/v2/coderd/database"
8+
"github.com/coder/coder/v2/coderd/httpapi"
9+
"github.com/coder/coder/v2/codersdk"
10+
)
11+
12+
type notificationTemplateParamContextKey struct{}
13+
14+
// NotificationTemplateParam returns the template from the ExtractNotificationTemplateParam handler.
15+
func NotificationTemplateParam(r *http.Request) database.NotificationTemplate {
16+
template, ok := r.Context().Value(notificationTemplateParamContextKey{}).(database.NotificationTemplate)
17+
if !ok {
18+
panic("developer error: notification template param middleware not provided")
19+
}
20+
return template
21+
}
22+
23+
// ExtractNotificationTemplateParam grabs a notification template from the "notification_template" URL parameter.
24+
func ExtractNotificationTemplateParam(db database.Store) func(http.Handler) http.Handler {
25+
return func(next http.Handler) http.Handler {
26+
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
27+
ctx := r.Context()
28+
notifTemplateID, parsed := ParseUUIDParam(rw, r, "notification_template")
29+
if !parsed {
30+
return
31+
}
32+
nt, err := db.GetNotificationTemplateById(r.Context(), notifTemplateID)
33+
if httpapi.Is404Error(err) {
34+
httpapi.ResourceNotFound(rw)
35+
return
36+
}
37+
if err != nil {
38+
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
39+
Message: "Internal error fetching notification template.",
40+
Detail: err.Error(),
41+
})
42+
return
43+
}
44+
45+
ctx = context.WithValue(ctx, notificationTemplateParamContextKey{}, nt)
46+
next.ServeHTTP(rw, r.WithContext(ctx))
47+
})
48+
}
49+
}

coderd/notifications/methods.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package notifications
2+
3+
import "github.com/coder/coder/v2/coderd/database"
4+
5+
func ValidNotificationMethods() []string {
6+
return []string{
7+
string(database.NotificationMethodSmtp),
8+
string(database.NotificationMethodWebhook),
9+
}
10+
}

codersdk/notifications.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,7 @@ func (c *Client) PutNotificationsSettings(ctx context.Context, settings Notifica
3838
}
3939
return nil
4040
}
41+
42+
type UpdateNotificationTemplateMethod struct {
43+
Method string `json:"method,omitempty" example:"webhook"`
44+
}

docs/api/enterprise.md

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

enterprise/coderd/coderd.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,6 @@ func New(ctx context.Context, options *Options) (_ *API, err error) {
368368
r.Put("/", api.putAppearance)
369369
})
370370
})
371-
372371
r.Route("/users/{user}/quiet-hours", func(r chi.Router) {
373372
r.Use(
374373
api.autostopRequirementEnabledMW,
@@ -388,6 +387,15 @@ func New(ctx context.Context, options *Options) (_ *API, err error) {
388387
r.Post("/jfrog/xray-scan", api.postJFrogXrayScan)
389388
r.Get("/jfrog/xray-scan", api.jFrogXrayScan)
390389
})
390+
r.Route("/notifications/templates", func(r chi.Router) {
391+
r.Use(apiKeyMiddleware)
392+
r.Route("/{notification_template}", func(r chi.Router) {
393+
r.Use(
394+
httpmw.ExtractNotificationTemplateParam(options.Database),
395+
)
396+
r.Post("/method", api.updateNotificationTemplateMethod)
397+
})
398+
})
391399
})
392400

393401
if len(options.SCIMAPIKey) != 0 {

enterprise/coderd/notifications.go

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package coderd
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
"strings"
7+
8+
"golang.org/x/xerrors"
9+
10+
"github.com/coder/coder/v2/coderd/audit"
11+
"github.com/coder/coder/v2/coderd/database"
12+
"github.com/coder/coder/v2/coderd/httpapi"
13+
"github.com/coder/coder/v2/coderd/httpmw"
14+
"github.com/coder/coder/v2/coderd/notifications"
15+
"github.com/coder/coder/v2/codersdk"
16+
)
17+
18+
// @Summary Update notification template dispatch method
19+
// @ID post-notification-template-method
20+
// @Security CoderSessionToken
21+
// @Produce json
22+
// @Tags Enterprise
23+
// @Success 200
24+
// @Router /notifications/templates/{notification_template}/method [post]
25+
func (api *API) updateNotificationTemplateMethod(rw http.ResponseWriter, r *http.Request) {
26+
// TODO: authorization (admin/template admin)
27+
// auth := httpmw.UserAuthorization(r)
28+
29+
var (
30+
ctx = r.Context()
31+
template = httpmw.NotificationTemplateParam(r)
32+
auditor = api.AGPL.Auditor.Load()
33+
aReq, commitAudit = audit.InitRequest[database.NotificationTemplate](rw, &audit.RequestParams{
34+
Audit: *auditor,
35+
Log: api.Logger,
36+
Request: r,
37+
Action: database.AuditActionWrite,
38+
})
39+
)
40+
41+
var req codersdk.UpdateNotificationTemplateMethod
42+
if !httpapi.Read(ctx, rw, r, &req) {
43+
return
44+
}
45+
46+
var nm database.NullNotificationMethod
47+
if err := nm.Scan(req.Method); err != nil || !nm.Valid || string(nm.NotificationMethod) == "" {
48+
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
49+
Message: "Invalid request to update notification template method",
50+
Validations: []codersdk.ValidationError{
51+
{
52+
Field: "method",
53+
Detail: fmt.Sprintf("%q is not a valid method; %s are the available options",
54+
req.Method, strings.Join(notifications.ValidNotificationMethods(), ", "),
55+
),
56+
},
57+
},
58+
})
59+
return
60+
}
61+
62+
if template.Method == nm {
63+
httpapi.Write(ctx, rw, http.StatusNotModified, codersdk.Response{
64+
Message: "Notification template method unchanged.",
65+
})
66+
return
67+
}
68+
69+
defer commitAudit()
70+
aReq.Old = template
71+
72+
err := api.Database.InTx(func(tx database.Store) error {
73+
var err error
74+
template, err = api.Database.UpdateNotificationTemplateMethodById(r.Context(), database.UpdateNotificationTemplateMethodByIdParams{
75+
ID: template.ID,
76+
Method: nm,
77+
})
78+
if err != nil {
79+
return xerrors.Errorf("failed to update notification template ID: %w", err)
80+
}
81+
82+
return err
83+
}, nil)
84+
if err != nil {
85+
httpapi.InternalServerError(rw, err)
86+
return
87+
}
88+
89+
aReq.New = template
90+
91+
httpapi.Write(ctx, rw, http.StatusOK, codersdk.Response{
92+
Message: "Successfully updated notification template method.",
93+
})
94+
}

site/src/api/typesGenerated.ts

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)