mirror of
https://github.com/kopia/kopia.git
synced 2026-05-14 17:56:59 -04:00
feat(server): added API to manipulate notification profiles in the UI (#4171)
This commit is contained in:
62
internal/server/api_notification_profile.go
Normal file
62
internal/server/api_notification_profile.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/kopia/kopia/internal/serverapi"
|
||||
"github.com/kopia/kopia/notification/notifyprofile"
|
||||
"github.com/kopia/kopia/repo"
|
||||
)
|
||||
|
||||
func handleNotificationProfileCreate(ctx context.Context, rc requestContext) (any, *apiError) {
|
||||
var cfg notifyprofile.Config
|
||||
|
||||
if err := json.Unmarshal(rc.body, &cfg); err != nil {
|
||||
return nil, requestError(serverapi.ErrorMalformedRequest, "malformed request body: "+string(rc.body))
|
||||
}
|
||||
|
||||
if err := repo.WriteSession(ctx, rc.rep, repo.WriteSessionOptions{
|
||||
Purpose: "NotificationProfileCreate",
|
||||
}, func(ctx context.Context, w repo.RepositoryWriter) error {
|
||||
return notifyprofile.SaveProfile(ctx, w, cfg)
|
||||
}); err != nil {
|
||||
return nil, internalServerError(err)
|
||||
}
|
||||
|
||||
return &serverapi.Empty{}, nil
|
||||
}
|
||||
|
||||
func handleNotificationProfileGet(ctx context.Context, rc requestContext) (any, *apiError) {
|
||||
cfg, ok, err := notifyprofile.GetProfile(ctx, rc.rep, rc.muxVar("profileName"))
|
||||
if err != nil {
|
||||
return nil, internalServerError(err)
|
||||
}
|
||||
|
||||
if !ok {
|
||||
return nil, notFoundError("profile not found")
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func handleNotificationProfileDelete(ctx context.Context, rc requestContext) (any, *apiError) {
|
||||
if err := repo.WriteSession(ctx, rc.rep, repo.WriteSessionOptions{
|
||||
Purpose: "NotificationProfileDelete",
|
||||
}, func(ctx context.Context, w repo.RepositoryWriter) error {
|
||||
return notifyprofile.DeleteProfile(ctx, w, rc.muxVar("profileName"))
|
||||
}); err != nil {
|
||||
return nil, internalServerError(err)
|
||||
}
|
||||
|
||||
return &serverapi.Empty{}, nil
|
||||
}
|
||||
|
||||
func handleNotificationProfileList(ctx context.Context, rc requestContext) (any, *apiError) {
|
||||
profiles, err := notifyprofile.ListProfiles(ctx, rc.rep)
|
||||
if err != nil {
|
||||
return nil, internalServerError(err)
|
||||
}
|
||||
|
||||
return profiles, nil
|
||||
}
|
||||
87
internal/server/api_notification_profile_test.go
Normal file
87
internal/server/api_notification_profile_test.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package server_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/kopia/kopia/internal/apiclient"
|
||||
"github.com/kopia/kopia/internal/repotesting"
|
||||
"github.com/kopia/kopia/internal/serverapi"
|
||||
"github.com/kopia/kopia/internal/servertesting"
|
||||
"github.com/kopia/kopia/notification/notifyprofile"
|
||||
"github.com/kopia/kopia/notification/sender"
|
||||
"github.com/kopia/kopia/notification/sender/testsender"
|
||||
)
|
||||
|
||||
func TestNotificationProfile(t *testing.T) {
|
||||
ctx, env := repotesting.NewEnvironment(t, repotesting.FormatNotImportant)
|
||||
srvInfo := servertesting.StartServer(t, env, false)
|
||||
|
||||
cli, err := apiclient.NewKopiaAPIClient(apiclient.Options{
|
||||
BaseURL: srvInfo.BaseURL,
|
||||
TrustedServerCertificateFingerprint: srvInfo.TrustedServerCertificateFingerprint,
|
||||
Username: servertesting.TestUIUsername,
|
||||
Password: servertesting.TestUIPassword,
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, cli.FetchCSRFTokenForTesting(ctx))
|
||||
|
||||
var profiles []notifyprofile.Config
|
||||
|
||||
require.NoError(t, cli.Get(ctx, "notificationProfiles", nil, &profiles))
|
||||
require.Empty(t, profiles)
|
||||
|
||||
// define new profile
|
||||
require.NoError(t, cli.Post(ctx, "notificationProfiles", ¬ifyprofile.Config{
|
||||
ProfileName: "profile1",
|
||||
MethodConfig: sender.MethodConfig{
|
||||
Type: "testsender",
|
||||
Config: testsender.Options{
|
||||
Format: "txt",
|
||||
},
|
||||
},
|
||||
MinSeverity: 3,
|
||||
}, &serverapi.Empty{}))
|
||||
|
||||
// define invalid profile
|
||||
require.ErrorContains(t, cli.Post(ctx, "notificationProfiles", ¬ifyprofile.Config{
|
||||
ProfileName: "profile2",
|
||||
MethodConfig: sender.MethodConfig{
|
||||
Type: "no-such-type",
|
||||
Config: testsender.Options{
|
||||
Format: "txt",
|
||||
},
|
||||
},
|
||||
MinSeverity: 3,
|
||||
}, &serverapi.Empty{}), "malformed request body")
|
||||
|
||||
var cfg notifyprofile.Config
|
||||
|
||||
// get profile and verify
|
||||
require.NoError(t, cli.Get(ctx, "notificationProfiles/profile1", nil, &cfg))
|
||||
require.Equal(t, "profile1", cfg.ProfileName)
|
||||
require.Equal(t, sender.Method("testsender"), cfg.MethodConfig.Type)
|
||||
|
||||
opt, ok := cfg.MethodConfig.Config.(map[string]any)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, "txt", opt["format"])
|
||||
|
||||
// get non-existent profile
|
||||
require.ErrorContains(t, cli.Get(ctx, "notificationProfiles/profile2", nil, &cfg), "profile not found")
|
||||
|
||||
// list profiles
|
||||
require.NoError(t, cli.Get(ctx, "notificationProfiles", nil, &profiles))
|
||||
require.Len(t, profiles, 1)
|
||||
require.Equal(t, "profile1", profiles[0].ProfileName)
|
||||
|
||||
// delete the profile, ensure idempotent
|
||||
require.NoError(t, cli.Delete(ctx, "notificationProfiles/profile1", nil, nil, &serverapi.Empty{}))
|
||||
require.NoError(t, cli.Delete(ctx, "notificationProfiles/profile1", nil, nil, &serverapi.Empty{}))
|
||||
|
||||
// verify it's gone
|
||||
require.NoError(t, cli.Get(ctx, "notificationProfiles", nil, &profiles))
|
||||
require.Empty(t, profiles)
|
||||
}
|
||||
@@ -158,6 +158,11 @@ func (s *Server) SetupHTMLUIAPIHandlers(m *mux.Router) {
|
||||
m.HandleFunc("/api/v1/tasks/{taskID}", s.handleUIPossiblyNotConnected(handleTaskInfo)).Methods(http.MethodGet)
|
||||
m.HandleFunc("/api/v1/tasks/{taskID}/logs", s.handleUIPossiblyNotConnected(handleTaskLogs)).Methods(http.MethodGet)
|
||||
m.HandleFunc("/api/v1/tasks/{taskID}/cancel", s.handleUIPossiblyNotConnected(handleTaskCancel)).Methods(http.MethodPost)
|
||||
|
||||
m.HandleFunc("/api/v1/notificationProfiles", s.handleUI(handleNotificationProfileCreate)).Methods(http.MethodPost)
|
||||
m.HandleFunc("/api/v1/notificationProfiles/{profileName}", s.handleUI(handleNotificationProfileDelete)).Methods(http.MethodDelete)
|
||||
m.HandleFunc("/api/v1/notificationProfiles/{profileName}", s.handleUI(handleNotificationProfileGet)).Methods(http.MethodGet)
|
||||
m.HandleFunc("/api/v1/notificationProfiles", s.handleUI(handleNotificationProfileList)).Methods(http.MethodGet)
|
||||
}
|
||||
|
||||
// SetupControlAPIHandlers registers control API handlers.
|
||||
|
||||
Reference in New Issue
Block a user