mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: add notification preferences database & audit support (#14100)
This commit is contained in:
@@ -33,6 +33,7 @@ const (
|
||||
ResourceTypeOAuth2ProviderAppSecret ResourceType = "oauth2_provider_app_secret"
|
||||
ResourceTypeCustomRole ResourceType = "custom_role"
|
||||
ResourceTypeOrganizationMember = "organization_member"
|
||||
ResourceTypeNotificationTemplate = "notification_template"
|
||||
)
|
||||
|
||||
func (r ResourceType) FriendlyString() string {
|
||||
@@ -75,6 +76,8 @@ func (r ResourceType) FriendlyString() string {
|
||||
return "custom role"
|
||||
case ResourceTypeOrganizationMember:
|
||||
return "organization member"
|
||||
case ResourceTypeNotificationTemplate:
|
||||
return "notification template"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
@@ -3,13 +3,43 @@ package codersdk
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
type NotificationsSettings struct {
|
||||
NotifierPaused bool `json:"notifier_paused"`
|
||||
}
|
||||
|
||||
type NotificationTemplate struct {
|
||||
ID uuid.UUID `json:"id" format:"uuid"`
|
||||
Name string `json:"name"`
|
||||
TitleTemplate string `json:"title_template"`
|
||||
BodyTemplate string `json:"body_template"`
|
||||
Actions string `json:"actions" format:""`
|
||||
Group string `json:"group"`
|
||||
Method string `json:"method"`
|
||||
Kind string `json:"kind"`
|
||||
}
|
||||
|
||||
type NotificationMethodsResponse struct {
|
||||
AvailableNotificationMethods []string `json:"available"`
|
||||
DefaultNotificationMethod string `json:"default"`
|
||||
}
|
||||
|
||||
type NotificationPreference struct {
|
||||
NotificationTemplateID uuid.UUID `json:"id" format:"uuid"`
|
||||
Disabled bool `json:"disabled"`
|
||||
UpdatedAt time.Time `json:"updated_at" format:"date-time"`
|
||||
}
|
||||
|
||||
// GetNotificationsSettings retrieves the notifications settings, which currently just describes whether all
|
||||
// notifications are paused from sending.
|
||||
func (c *Client) GetNotificationsSettings(ctx context.Context) (NotificationsSettings, error) {
|
||||
res, err := c.Request(ctx, http.MethodGet, "/api/v2/notifications/settings", nil)
|
||||
if err != nil {
|
||||
@@ -23,6 +53,8 @@ func (c *Client) GetNotificationsSettings(ctx context.Context) (NotificationsSet
|
||||
return settings, json.NewDecoder(res.Body).Decode(&settings)
|
||||
}
|
||||
|
||||
// PutNotificationsSettings modifies the notifications settings, which currently just controls whether all
|
||||
// notifications are paused from sending.
|
||||
func (c *Client) PutNotificationsSettings(ctx context.Context, settings NotificationsSettings) error {
|
||||
res, err := c.Request(ctx, http.MethodPut, "/api/v2/notifications/settings", settings)
|
||||
if err != nil {
|
||||
@@ -38,3 +70,132 @@ func (c *Client) PutNotificationsSettings(ctx context.Context, settings Notifica
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateNotificationTemplateMethod modifies a notification template to use a specific notification method, overriding
|
||||
// the method set in the deployment configuration.
|
||||
func (c *Client) UpdateNotificationTemplateMethod(ctx context.Context, notificationTemplateID uuid.UUID, method string) error {
|
||||
res, err := c.Request(ctx, http.MethodPut,
|
||||
fmt.Sprintf("/api/v2/notifications/templates/%s/method", notificationTemplateID),
|
||||
UpdateNotificationTemplateMethod{Method: method},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.StatusCode == http.StatusNotModified {
|
||||
return nil
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return ReadBodyAsError(res)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetSystemNotificationTemplates retrieves all notification templates pertaining to internal system events.
|
||||
func (c *Client) GetSystemNotificationTemplates(ctx context.Context) ([]NotificationTemplate, error) {
|
||||
res, err := c.Request(ctx, http.MethodGet, "/api/v2/notifications/templates/system", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return nil, ReadBodyAsError(res)
|
||||
}
|
||||
|
||||
var templates []NotificationTemplate
|
||||
body, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("read response body: %w", err)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(body, &templates); err != nil {
|
||||
return nil, xerrors.Errorf("unmarshal response body: %w", err)
|
||||
}
|
||||
|
||||
return templates, nil
|
||||
}
|
||||
|
||||
// GetUserNotificationPreferences retrieves notification preferences for a given user.
|
||||
func (c *Client) GetUserNotificationPreferences(ctx context.Context, userID uuid.UUID) ([]NotificationPreference, error) {
|
||||
res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/users/%s/notifications/preferences", userID.String()), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return nil, ReadBodyAsError(res)
|
||||
}
|
||||
|
||||
var prefs []NotificationPreference
|
||||
body, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("read response body: %w", err)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(body, &prefs); err != nil {
|
||||
return nil, xerrors.Errorf("unmarshal response body: %w", err)
|
||||
}
|
||||
|
||||
return prefs, nil
|
||||
}
|
||||
|
||||
// UpdateUserNotificationPreferences updates notification preferences for a given user.
|
||||
func (c *Client) UpdateUserNotificationPreferences(ctx context.Context, userID uuid.UUID, req UpdateUserNotificationPreferences) ([]NotificationPreference, error) {
|
||||
res, err := c.Request(ctx, http.MethodPut, fmt.Sprintf("/api/v2/users/%s/notifications/preferences", userID.String()), req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return nil, ReadBodyAsError(res)
|
||||
}
|
||||
|
||||
var prefs []NotificationPreference
|
||||
body, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("read response body: %w", err)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(body, &prefs); err != nil {
|
||||
return nil, xerrors.Errorf("unmarshal response body: %w", err)
|
||||
}
|
||||
|
||||
return prefs, nil
|
||||
}
|
||||
|
||||
// GetNotificationDispatchMethods the available and default notification dispatch methods.
|
||||
func (c *Client) GetNotificationDispatchMethods(ctx context.Context) (NotificationMethodsResponse, error) {
|
||||
res, err := c.Request(ctx, http.MethodGet, "/api/v2/notifications/dispatch-methods", nil)
|
||||
if err != nil {
|
||||
return NotificationMethodsResponse{}, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return NotificationMethodsResponse{}, ReadBodyAsError(res)
|
||||
}
|
||||
|
||||
var resp NotificationMethodsResponse
|
||||
body, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return NotificationMethodsResponse{}, xerrors.Errorf("read response body: %w", err)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(body, &resp); err != nil {
|
||||
return NotificationMethodsResponse{}, xerrors.Errorf("unmarshal response body: %w", err)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
type UpdateNotificationTemplateMethod struct {
|
||||
Method string `json:"method,omitempty" example:"webhook"`
|
||||
}
|
||||
|
||||
type UpdateUserNotificationPreferences struct {
|
||||
TemplateDisabledMap map[string]bool `json:"template_disabled_map"`
|
||||
}
|
||||
|
||||
@@ -4,32 +4,34 @@ package codersdk
|
||||
type RBACResource string
|
||||
|
||||
const (
|
||||
ResourceWildcard RBACResource = "*"
|
||||
ResourceApiKey RBACResource = "api_key"
|
||||
ResourceAssignOrgRole RBACResource = "assign_org_role"
|
||||
ResourceAssignRole RBACResource = "assign_role"
|
||||
ResourceAuditLog RBACResource = "audit_log"
|
||||
ResourceDebugInfo RBACResource = "debug_info"
|
||||
ResourceDeploymentConfig RBACResource = "deployment_config"
|
||||
ResourceDeploymentStats RBACResource = "deployment_stats"
|
||||
ResourceFile RBACResource = "file"
|
||||
ResourceGroup RBACResource = "group"
|
||||
ResourceLicense RBACResource = "license"
|
||||
ResourceOauth2App RBACResource = "oauth2_app"
|
||||
ResourceOauth2AppCodeToken RBACResource = "oauth2_app_code_token"
|
||||
ResourceOauth2AppSecret RBACResource = "oauth2_app_secret"
|
||||
ResourceOrganization RBACResource = "organization"
|
||||
ResourceOrganizationMember RBACResource = "organization_member"
|
||||
ResourceProvisionerDaemon RBACResource = "provisioner_daemon"
|
||||
ResourceProvisionerKeys RBACResource = "provisioner_keys"
|
||||
ResourceReplicas RBACResource = "replicas"
|
||||
ResourceSystem RBACResource = "system"
|
||||
ResourceTailnetCoordinator RBACResource = "tailnet_coordinator"
|
||||
ResourceTemplate RBACResource = "template"
|
||||
ResourceUser RBACResource = "user"
|
||||
ResourceWorkspace RBACResource = "workspace"
|
||||
ResourceWorkspaceDormant RBACResource = "workspace_dormant"
|
||||
ResourceWorkspaceProxy RBACResource = "workspace_proxy"
|
||||
ResourceWildcard RBACResource = "*"
|
||||
ResourceApiKey RBACResource = "api_key"
|
||||
ResourceAssignOrgRole RBACResource = "assign_org_role"
|
||||
ResourceAssignRole RBACResource = "assign_role"
|
||||
ResourceAuditLog RBACResource = "audit_log"
|
||||
ResourceDebugInfo RBACResource = "debug_info"
|
||||
ResourceDeploymentConfig RBACResource = "deployment_config"
|
||||
ResourceDeploymentStats RBACResource = "deployment_stats"
|
||||
ResourceFile RBACResource = "file"
|
||||
ResourceGroup RBACResource = "group"
|
||||
ResourceLicense RBACResource = "license"
|
||||
ResourceNotificationPreference RBACResource = "notification_preference"
|
||||
ResourceNotificationTemplate RBACResource = "notification_template"
|
||||
ResourceOauth2App RBACResource = "oauth2_app"
|
||||
ResourceOauth2AppCodeToken RBACResource = "oauth2_app_code_token"
|
||||
ResourceOauth2AppSecret RBACResource = "oauth2_app_secret"
|
||||
ResourceOrganization RBACResource = "organization"
|
||||
ResourceOrganizationMember RBACResource = "organization_member"
|
||||
ResourceProvisionerDaemon RBACResource = "provisioner_daemon"
|
||||
ResourceProvisionerKeys RBACResource = "provisioner_keys"
|
||||
ResourceReplicas RBACResource = "replicas"
|
||||
ResourceSystem RBACResource = "system"
|
||||
ResourceTailnetCoordinator RBACResource = "tailnet_coordinator"
|
||||
ResourceTemplate RBACResource = "template"
|
||||
ResourceUser RBACResource = "user"
|
||||
ResourceWorkspace RBACResource = "workspace"
|
||||
ResourceWorkspaceDormant RBACResource = "workspace_dormant"
|
||||
ResourceWorkspaceProxy RBACResource = "workspace_proxy"
|
||||
)
|
||||
|
||||
type RBACAction string
|
||||
@@ -53,30 +55,32 @@ const (
|
||||
// RBACResourceActions is the mapping of resources to which actions are valid for
|
||||
// said resource type.
|
||||
var RBACResourceActions = map[RBACResource][]RBACAction{
|
||||
ResourceWildcard: {},
|
||||
ResourceApiKey: {ActionCreate, ActionDelete, ActionRead, ActionUpdate},
|
||||
ResourceAssignOrgRole: {ActionAssign, ActionCreate, ActionDelete, ActionRead},
|
||||
ResourceAssignRole: {ActionAssign, ActionCreate, ActionDelete, ActionRead},
|
||||
ResourceAuditLog: {ActionCreate, ActionRead},
|
||||
ResourceDebugInfo: {ActionRead},
|
||||
ResourceDeploymentConfig: {ActionRead, ActionUpdate},
|
||||
ResourceDeploymentStats: {ActionRead},
|
||||
ResourceFile: {ActionCreate, ActionRead},
|
||||
ResourceGroup: {ActionCreate, ActionDelete, ActionRead, ActionUpdate},
|
||||
ResourceLicense: {ActionCreate, ActionDelete, ActionRead},
|
||||
ResourceOauth2App: {ActionCreate, ActionDelete, ActionRead, ActionUpdate},
|
||||
ResourceOauth2AppCodeToken: {ActionCreate, ActionDelete, ActionRead},
|
||||
ResourceOauth2AppSecret: {ActionCreate, ActionDelete, ActionRead, ActionUpdate},
|
||||
ResourceOrganization: {ActionCreate, ActionDelete, ActionRead, ActionUpdate},
|
||||
ResourceOrganizationMember: {ActionCreate, ActionDelete, ActionRead, ActionUpdate},
|
||||
ResourceProvisionerDaemon: {ActionCreate, ActionDelete, ActionRead, ActionUpdate},
|
||||
ResourceProvisionerKeys: {ActionCreate, ActionDelete, ActionRead},
|
||||
ResourceReplicas: {ActionRead},
|
||||
ResourceSystem: {ActionCreate, ActionDelete, ActionRead, ActionUpdate},
|
||||
ResourceTailnetCoordinator: {ActionCreate, ActionDelete, ActionRead, ActionUpdate},
|
||||
ResourceTemplate: {ActionCreate, ActionDelete, ActionRead, ActionUpdate, ActionViewInsights},
|
||||
ResourceUser: {ActionCreate, ActionDelete, ActionRead, ActionReadPersonal, ActionUpdate, ActionUpdatePersonal},
|
||||
ResourceWorkspace: {ActionApplicationConnect, ActionCreate, ActionDelete, ActionRead, ActionSSH, ActionWorkspaceStart, ActionWorkspaceStop, ActionUpdate},
|
||||
ResourceWorkspaceDormant: {ActionApplicationConnect, ActionCreate, ActionDelete, ActionRead, ActionSSH, ActionWorkspaceStart, ActionWorkspaceStop, ActionUpdate},
|
||||
ResourceWorkspaceProxy: {ActionCreate, ActionDelete, ActionRead, ActionUpdate},
|
||||
ResourceWildcard: {},
|
||||
ResourceApiKey: {ActionCreate, ActionDelete, ActionRead, ActionUpdate},
|
||||
ResourceAssignOrgRole: {ActionAssign, ActionCreate, ActionDelete, ActionRead},
|
||||
ResourceAssignRole: {ActionAssign, ActionCreate, ActionDelete, ActionRead},
|
||||
ResourceAuditLog: {ActionCreate, ActionRead},
|
||||
ResourceDebugInfo: {ActionRead},
|
||||
ResourceDeploymentConfig: {ActionRead, ActionUpdate},
|
||||
ResourceDeploymentStats: {ActionRead},
|
||||
ResourceFile: {ActionCreate, ActionRead},
|
||||
ResourceGroup: {ActionCreate, ActionDelete, ActionRead, ActionUpdate},
|
||||
ResourceLicense: {ActionCreate, ActionDelete, ActionRead},
|
||||
ResourceNotificationPreference: {ActionRead, ActionUpdate},
|
||||
ResourceNotificationTemplate: {ActionRead, ActionUpdate},
|
||||
ResourceOauth2App: {ActionCreate, ActionDelete, ActionRead, ActionUpdate},
|
||||
ResourceOauth2AppCodeToken: {ActionCreate, ActionDelete, ActionRead},
|
||||
ResourceOauth2AppSecret: {ActionCreate, ActionDelete, ActionRead, ActionUpdate},
|
||||
ResourceOrganization: {ActionCreate, ActionDelete, ActionRead, ActionUpdate},
|
||||
ResourceOrganizationMember: {ActionCreate, ActionDelete, ActionRead, ActionUpdate},
|
||||
ResourceProvisionerDaemon: {ActionCreate, ActionDelete, ActionRead, ActionUpdate},
|
||||
ResourceProvisionerKeys: {ActionCreate, ActionDelete, ActionRead},
|
||||
ResourceReplicas: {ActionRead},
|
||||
ResourceSystem: {ActionCreate, ActionDelete, ActionRead, ActionUpdate},
|
||||
ResourceTailnetCoordinator: {ActionCreate, ActionDelete, ActionRead, ActionUpdate},
|
||||
ResourceTemplate: {ActionCreate, ActionDelete, ActionRead, ActionUpdate, ActionViewInsights},
|
||||
ResourceUser: {ActionCreate, ActionDelete, ActionRead, ActionReadPersonal, ActionUpdate, ActionUpdatePersonal},
|
||||
ResourceWorkspace: {ActionApplicationConnect, ActionCreate, ActionDelete, ActionRead, ActionSSH, ActionWorkspaceStart, ActionWorkspaceStop, ActionUpdate},
|
||||
ResourceWorkspaceDormant: {ActionApplicationConnect, ActionCreate, ActionDelete, ActionRead, ActionSSH, ActionWorkspaceStart, ActionWorkspaceStop, ActionUpdate},
|
||||
ResourceWorkspaceProxy: {ActionCreate, ActionDelete, ActionRead, ActionUpdate},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user