feat:pull the slack message service out to slack pkg
Signed-off-by: manish-singh-bisht <mthefool218@gmail.com>
This commit is contained in:
committed by
Émile Ré
parent
7cb6edcbb5
commit
8eeab0a6d0
@@ -92,6 +92,8 @@ INSERT INTO slack_messages (
|
||||
requester_email,
|
||||
metadata,
|
||||
initial_slack_message_id,
|
||||
message_ts,
|
||||
channel_id,
|
||||
created_at,
|
||||
updated_at
|
||||
)
|
||||
@@ -104,6 +106,8 @@ VALUES (
|
||||
@requester_email,
|
||||
@metadata,
|
||||
@initial_slack_message_id,
|
||||
@message_ts,
|
||||
@channel_id,
|
||||
@created_at,
|
||||
@updated_at
|
||||
)
|
||||
@@ -118,6 +122,8 @@ VALUES (
|
||||
"requester_email": s.RequesterEmail,
|
||||
"metadata": s.Metadata,
|
||||
"initial_slack_message_id": s.InitialSlackMessageID,
|
||||
"message_ts": s.MessageTS,
|
||||
"channel_id": s.ChannelID,
|
||||
"created_at": s.CreatedAt,
|
||||
"updated_at": s.UpdatedAt,
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import (
|
||||
"go.probo.inc/probo/pkg/filevalidation"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/html2pdf"
|
||||
"go.probo.inc/probo/pkg/slack"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -68,6 +69,7 @@ type (
|
||||
auth *auth.Service
|
||||
authz *authz.Service
|
||||
logger *log.Logger
|
||||
slack *slack.Service
|
||||
}
|
||||
|
||||
TenantService struct {
|
||||
@@ -113,6 +115,7 @@ type (
|
||||
ProcessingActivities *ProcessingActivityService
|
||||
Files *FileService
|
||||
CustomDomains *CustomDomainService
|
||||
Slack *slack.TenantService
|
||||
}
|
||||
)
|
||||
|
||||
@@ -132,6 +135,7 @@ func NewService(
|
||||
authService *auth.Service,
|
||||
authzService *authz.Service,
|
||||
logger *log.Logger,
|
||||
slackService *slack.Service,
|
||||
) (*Service, error) {
|
||||
if bucket == "" {
|
||||
return nil, fmt.Errorf("bucket is required")
|
||||
@@ -152,6 +156,7 @@ func NewService(
|
||||
auth: authService,
|
||||
authz: authzService,
|
||||
logger: logger,
|
||||
slack: slackService,
|
||||
}
|
||||
|
||||
return svc, nil
|
||||
@@ -169,6 +174,7 @@ func (s *Service) WithTenant(tenantID gid.TenantID) *TenantService {
|
||||
trustConfig: s.trustConfig,
|
||||
agent: agents.NewAgent(nil, s.agentConfig),
|
||||
fileManager: s.fileManager,
|
||||
Slack: s.slack.WithTenant(tenantID),
|
||||
}
|
||||
|
||||
tenantService.Frameworks = &FrameworkService{
|
||||
|
||||
@@ -273,6 +273,8 @@ func (s TrustCenterAccessService) Update(
|
||||
|
||||
now := time.Now()
|
||||
var access *coredata.TrustCenterAccess
|
||||
var trustCenterAcessActivated bool
|
||||
var shouldUpdateSlackMessage bool
|
||||
err := s.svc.pg.WithTx(
|
||||
ctx,
|
||||
func(tx pg.Conn) error {
|
||||
@@ -282,7 +284,7 @@ func (s TrustCenterAccessService) Update(
|
||||
return fmt.Errorf("cannot load trust center access: %w", err)
|
||||
}
|
||||
|
||||
shouldSendEmail := req.Active != nil && *req.Active && !access.Active
|
||||
trustCenterAcessActivated = req.Active != nil && *req.Active && !access.Active
|
||||
if req.Name != nil {
|
||||
access.Name = *req.Name
|
||||
}
|
||||
@@ -339,12 +341,18 @@ func (s TrustCenterAccessService) Update(
|
||||
}
|
||||
}
|
||||
|
||||
if shouldSendEmail {
|
||||
if trustCenterAcessActivated {
|
||||
if err := s.sendAccessEmail(ctx, tx, access); err != nil {
|
||||
return fmt.Errorf("cannot send access email: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
shouldUpdateSlackMessage = trustCenterAcessActivated ||
|
||||
len(req.DocumentAccesses) > 0 ||
|
||||
len(req.ReportAccesses) > 0 ||
|
||||
len(req.TrustCenterFileAccesses) > 0 ||
|
||||
req.Name != nil
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
@@ -353,6 +361,12 @@ func (s TrustCenterAccessService) Update(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if shouldUpdateSlackMessage {
|
||||
if err := s.svc.Slack.GetSlackMessageService().QueueSlackAccessMessageUpdate(ctx, access.Email, access.TrustCenterID); err != nil {
|
||||
return nil, fmt.Errorf("cannot queue slack access message update: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return access, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -342,6 +342,15 @@ func (impl *Implm) Run(
|
||||
return fmt.Errorf("cannot initialize ACME service: %w", err)
|
||||
}
|
||||
|
||||
slackService := slack.NewService(
|
||||
pgClient,
|
||||
impl.cfg.GetSlackSigningSecret(),
|
||||
impl.cfg.BaseURL.String(),
|
||||
impl.cfg.EncryptionKey,
|
||||
impl.cfg.Auth.Cookie.Secret,
|
||||
l.Named("slack"),
|
||||
)
|
||||
|
||||
proboService, err := probo.NewService(
|
||||
ctx,
|
||||
impl.cfg.EncryptionKey,
|
||||
@@ -358,6 +367,7 @@ func (impl *Implm) Run(
|
||||
authService,
|
||||
authzService,
|
||||
l.Named("probo"),
|
||||
slackService,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot create probo service: %w", err)
|
||||
@@ -370,7 +380,6 @@ func (impl *Implm) Run(
|
||||
impl.cfg.BaseURL.String(),
|
||||
impl.cfg.EncryptionKey,
|
||||
impl.cfg.TrustAuth.TokenSecret,
|
||||
impl.cfg.GetSlackSigningSecret(),
|
||||
authService,
|
||||
html2pdfConverter,
|
||||
fileManagerService,
|
||||
@@ -380,6 +389,7 @@ func (impl *Implm) Run(
|
||||
TokenDuration: time.Duration(impl.cfg.TrustAuth.TokenDuration) * time.Hour,
|
||||
TokenType: impl.cfg.TrustAuth.TokenType,
|
||||
},
|
||||
slackService,
|
||||
)
|
||||
|
||||
serverHandler, err := server.NewServer(
|
||||
@@ -390,6 +400,7 @@ func (impl *Implm) Run(
|
||||
Auth: authService,
|
||||
Authz: authzService,
|
||||
Trust: trustService,
|
||||
Slack: slackService,
|
||||
SAML: samlService,
|
||||
ConnectorRegistry: defaultConnectorRegistry,
|
||||
Agent: agent,
|
||||
|
||||
@@ -31,7 +31,9 @@ import (
|
||||
"go.probo.inc/probo/pkg/saferedirect"
|
||||
console_v1 "go.probo.inc/probo/pkg/server/api/console/v1"
|
||||
mcp_v1 "go.probo.inc/probo/pkg/server/api/mcp/v1"
|
||||
slack_v1 "go.probo.inc/probo/pkg/server/api/slack/v1"
|
||||
trust_v1 "go.probo.inc/probo/pkg/server/api/trust/v1"
|
||||
"go.probo.inc/probo/pkg/slack"
|
||||
"go.probo.inc/probo/pkg/trust"
|
||||
)
|
||||
|
||||
@@ -62,6 +64,7 @@ type (
|
||||
Auth *auth.Service
|
||||
Authz *authz.Service
|
||||
Trust *trust.Service
|
||||
Slack *slack.Service
|
||||
SAML *auth.SAMLService
|
||||
ConsoleAuth ConsoleAuthConfig
|
||||
TrustAuth TrustAuthConfig
|
||||
@@ -83,6 +86,7 @@ type (
|
||||
trustAPIHandler http.Handler
|
||||
consoleAPIHandler http.Handler
|
||||
mcpAPIHandler http.Handler
|
||||
slackAPIHandler http.Handler
|
||||
}
|
||||
)
|
||||
|
||||
@@ -157,6 +161,7 @@ func NewServer(cfg Config) (*Server, error) {
|
||||
TokenType: cfg.TrustAuth.TokenType,
|
||||
CookieSecure: cfg.TrustAuth.CookieSecure,
|
||||
},
|
||||
cfg.Slack,
|
||||
)
|
||||
|
||||
consoleAPIHandler := console_v1.NewMux(
|
||||
@@ -189,11 +194,18 @@ func NewServer(cfg Config) (*Server, error) {
|
||||
},
|
||||
)
|
||||
|
||||
slackAPIHandler := slack_v1.NewMux(
|
||||
cfg.Logger.Named("slack.v1"),
|
||||
cfg.Slack,
|
||||
cfg.Trust,
|
||||
)
|
||||
|
||||
return &Server{
|
||||
cfg: cfg,
|
||||
trustAPIHandler: trustAPIHandler,
|
||||
consoleAPIHandler: consoleAPIHandler,
|
||||
mcpAPIHandler: mcpAPIHandler,
|
||||
slackAPIHandler: slackAPIHandler,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -229,6 +241,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
router.Mount("/console/v1", s.consoleAPIHandler)
|
||||
router.Mount("/trust/v1", s.trustAPIHandler)
|
||||
router.Mount("/mcp/v1", s.mcpAPIHandler)
|
||||
router.Mount("/slack/v1", s.slackAPIHandler)
|
||||
|
||||
router.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
26
pkg/server/api/slack/v1/resolver.go
Normal file
26
pkg/server/api/slack/v1/resolver.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package slack_v1
|
||||
|
||||
import (
|
||||
"github.com/go-chi/chi/v5"
|
||||
"go.gearno.de/kit/log"
|
||||
"go.probo.inc/probo/pkg/slack"
|
||||
"go.probo.inc/probo/pkg/trust"
|
||||
)
|
||||
|
||||
func NewMux(
|
||||
logger *log.Logger,
|
||||
slackSvc *slack.Service,
|
||||
trustSvc *trust.Service,
|
||||
) *chi.Mux {
|
||||
r := chi.NewMux()
|
||||
logger.Info("Registering Slack interactive endpoint")
|
||||
|
||||
r.Post("/interactive", SlackHandler(
|
||||
slackSvc,
|
||||
slackSvc.GetSlackSigningSecret(),
|
||||
logger,
|
||||
trustSvc,
|
||||
))
|
||||
|
||||
return r
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package trust_v1
|
||||
package slack_v1
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -57,7 +57,7 @@ const (
|
||||
StatusReject = "reject"
|
||||
)
|
||||
|
||||
func slackHandler(trustSvc *trust.Service, slackSigningSecret string, logger *log.Logger) http.HandlerFunc {
|
||||
func SlackHandler(slackSvc *slack.Service, slackSigningSecret string, logger *log.Logger, trustSvc *trust.Service) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
@@ -132,7 +132,7 @@ func slackHandler(trustSvc *trust.Service, slackSigningSecret string, logger *lo
|
||||
return
|
||||
}
|
||||
|
||||
initialSlackMessage, err := trustSvc.GetInitialSlackMessageByChannelAndTS(ctx, slackPayload.Container.ChannelID, slackPayload.Container.MessageTS)
|
||||
initialSlackMessage, err := slackSvc.GetInitialSlackMessageByChannelAndTS(ctx, slackPayload.Container.ChannelID, slackPayload.Container.MessageTS)
|
||||
if err != nil {
|
||||
logger.ErrorCtx(ctx, "cannot load slack message", log.Error(err))
|
||||
httpserver.RenderJSON(w, http.StatusInternalServerError, SlackInteractiveResponse{Success: false, Message: "internal server error"})
|
||||
@@ -168,7 +168,7 @@ func slackHandler(trustSvc *trust.Service, slackSigningSecret string, logger *lo
|
||||
return
|
||||
}
|
||||
|
||||
documentIDs, reportIDs, fileIDs, err = tenantSvc.SlackMessages.GetSlackMessageDocumentIDs(ctx, currentMessageId)
|
||||
documentIDs, reportIDs, fileIDs, err = slackSvc.WithTenant(initialSlackMessage.OrganizationID.TenantID()).GetSlackMessageService().GetSlackMessageDocumentIDs(ctx, currentMessageId)
|
||||
if err != nil {
|
||||
logger.ErrorCtx(ctx, "cannot load slack message document ids", log.Error(err))
|
||||
httpserver.RenderJSON(w, http.StatusInternalServerError, SlackInteractiveResponse{Success: false, Message: "internal server error"})
|
||||
@@ -261,7 +261,7 @@ func slackHandler(trustSvc *trust.Service, slackSigningSecret string, logger *lo
|
||||
return
|
||||
}
|
||||
|
||||
if err := tenantSvc.SlackMessages.UpdateSlackAccessMessage(
|
||||
if err := slackSvc.WithTenant(initialSlackMessage.OrganizationID.TenantID()).GetSlackMessageService().UpdateSlackAccessMessage(
|
||||
ctx,
|
||||
initialSlackMessage.ID,
|
||||
slackPayload.ResponseURL,
|
||||
@@ -34,10 +34,12 @@ import (
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/probo"
|
||||
console_v1 "go.probo.inc/probo/pkg/server/api/console/v1"
|
||||
slack_v1 "go.probo.inc/probo/pkg/server/api/slack/v1"
|
||||
"go.probo.inc/probo/pkg/server/api/trust/v1/schema"
|
||||
"go.probo.inc/probo/pkg/server/api/trust/v1/trustauth"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils"
|
||||
"go.probo.inc/probo/pkg/server/session"
|
||||
"go.probo.inc/probo/pkg/slack"
|
||||
"go.probo.inc/probo/pkg/statelesstoken"
|
||||
"go.probo.inc/probo/pkg/trust"
|
||||
)
|
||||
@@ -103,6 +105,9 @@ func NewMux(
|
||||
trustSvc *trust.Service,
|
||||
authCfg console_v1.AuthConfig,
|
||||
trustAuthCfg TrustAuthConfig,
|
||||
|
||||
// TODO: Remove this after successful migration to /slack/v1.
|
||||
slackSvc *slack.Service,
|
||||
) *chi.Mux {
|
||||
r := chi.NewMux()
|
||||
|
||||
@@ -111,7 +116,9 @@ func NewMux(
|
||||
r.Post("/auth/authenticate", authTokenHandler(trustSvc, trustAuthCfg))
|
||||
r.Delete("/auth/logout", trustCenterLogoutHandler(authCfg, trustAuthCfg))
|
||||
|
||||
r.Post("/slack", slackHandler(trustSvc, trustSvc.GetSlackSigningSecret(), logger))
|
||||
// Backward compatibility: support old /trust/v1/slack endpoint
|
||||
// TODO: Remove this after successful migration to /slack/v1 and then make SlackHandler PRIVATE in slack_v1 package.
|
||||
r.Post("/slack", slack_v1.SlackHandler(slackSvc, slackSvc.GetSlackSigningSecret(), logger, trustSvc))
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ import (
|
||||
authz_server "go.probo.inc/probo/pkg/server/authz"
|
||||
"go.probo.inc/probo/pkg/server/trust"
|
||||
"go.probo.inc/probo/pkg/server/web"
|
||||
"go.probo.inc/probo/pkg/slack"
|
||||
trust_pkg "go.probo.inc/probo/pkg/trust"
|
||||
)
|
||||
|
||||
@@ -48,6 +49,7 @@ type Config struct {
|
||||
Auth *auth.Service
|
||||
Authz *authz.Service
|
||||
Trust *trust_pkg.Service
|
||||
Slack *slack.Service
|
||||
SAML *auth.SAMLService
|
||||
ConsoleAuth api.ConsoleAuthConfig
|
||||
TrustAuth api.TrustAuthConfig
|
||||
@@ -80,6 +82,7 @@ func NewServer(cfg Config) (*Server, error) {
|
||||
Auth: cfg.Auth,
|
||||
Authz: cfg.Authz,
|
||||
Trust: cfg.Trust,
|
||||
Slack: cfg.Slack,
|
||||
SAML: cfg.SAML,
|
||||
ConsoleAuth: cfg.ConsoleAuth,
|
||||
TrustAuth: cfg.TrustAuth,
|
||||
|
||||
31
pkg/slack/connector_config.go
Normal file
31
pkg/slack/connector_config.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package slack
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
var (
|
||||
accessRequestTemplate = template.Must(
|
||||
template.New("access-request.json.tmpl").
|
||||
Funcs(template.FuncMap{
|
||||
"jsonEscape": func(s string) string {
|
||||
b, _ := json.Marshal(s)
|
||||
return string(b[1 : len(b)-1])
|
||||
},
|
||||
"buildAcceptAllValue": func(docIDs, repIDs []string) string {
|
||||
value := map[string][]string{
|
||||
"document_ids": docIDs,
|
||||
"report_ids": repIDs,
|
||||
}
|
||||
b, _ := json.Marshal(value)
|
||||
s := string(b)
|
||||
s = strings.ReplaceAll(s, `\`, `\\`)
|
||||
s = strings.ReplaceAll(s, `"`, `\"`)
|
||||
return s
|
||||
},
|
||||
}).
|
||||
ParseFS(Templates, "templates/access-request.json.tmpl"),
|
||||
)
|
||||
)
|
||||
95
pkg/slack/service.go
Normal file
95
pkg/slack/service.go
Normal file
@@ -0,0 +1,95 @@
|
||||
package slack
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"go.gearno.de/kit/log"
|
||||
"go.gearno.de/kit/pg"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/crypto/cipher"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
pg *pg.Client
|
||||
logger *log.Logger
|
||||
slackSigningSecret string
|
||||
baseURL string
|
||||
encryptionKey cipher.EncryptionKey
|
||||
tokenSecret string
|
||||
}
|
||||
|
||||
type TenantService struct {
|
||||
pg *pg.Client
|
||||
scope coredata.Scoper
|
||||
logger *log.Logger
|
||||
baseURL string
|
||||
encryptionKey cipher.EncryptionKey
|
||||
tokenSecret string
|
||||
}
|
||||
|
||||
func NewService(
|
||||
pg *pg.Client,
|
||||
slackSigningSecret string,
|
||||
baseURL string,
|
||||
encryptionKey cipher.EncryptionKey,
|
||||
tokenSecret string,
|
||||
logger *log.Logger,
|
||||
) *Service {
|
||||
return &Service{
|
||||
pg: pg,
|
||||
logger: logger,
|
||||
slackSigningSecret: slackSigningSecret,
|
||||
baseURL: baseURL,
|
||||
encryptionKey: encryptionKey,
|
||||
tokenSecret: tokenSecret,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) WithTenant(tenantID gid.TenantID) *TenantService {
|
||||
tenantService := &TenantService{
|
||||
pg: s.pg,
|
||||
scope: coredata.NewScope(tenantID),
|
||||
logger: s.logger,
|
||||
baseURL: s.baseURL,
|
||||
encryptionKey: s.encryptionKey,
|
||||
tokenSecret: s.tokenSecret,
|
||||
}
|
||||
|
||||
return tenantService
|
||||
}
|
||||
|
||||
func (s *TenantService) GetSlackClient() *Client {
|
||||
return NewClient(s.logger)
|
||||
}
|
||||
|
||||
func (s *TenantService) GetSlackMessageService() *SlackMessageService {
|
||||
return &SlackMessageService{svc: s}
|
||||
}
|
||||
|
||||
func (s *Service) GetSlackSigningSecret() string {
|
||||
return s.slackSigningSecret
|
||||
}
|
||||
|
||||
func (s *Service) GetInitialSlackMessageByChannelAndTS(
|
||||
ctx context.Context,
|
||||
channelID string,
|
||||
messageTS string,
|
||||
) (*coredata.SlackMessage, error) {
|
||||
var slackMessage coredata.SlackMessage
|
||||
|
||||
err := s.pg.WithConn(ctx, func(conn pg.Conn) error {
|
||||
if err := slackMessage.LoadInitialByChannelAndTS(ctx, conn, coredata.NewNoScope(), channelID, messageTS); err != nil {
|
||||
return fmt.Errorf("cannot load slack message: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &slackMessage, nil
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package trust
|
||||
package slack
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -26,7 +26,6 @@ import (
|
||||
"go.probo.inc/probo/pkg/baseurl"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/slack"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -35,8 +34,7 @@ const (
|
||||
|
||||
type (
|
||||
SlackMessageService struct {
|
||||
svc *TenantService
|
||||
slackClient *slack.Client
|
||||
svc *TenantService
|
||||
}
|
||||
|
||||
SlackMessageDocument struct {
|
||||
@@ -74,28 +72,6 @@ func (m SlackMessageMetadata) toMap() map[string]any {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) GetInitialSlackMessageByChannelAndTS(
|
||||
ctx context.Context,
|
||||
channelID string,
|
||||
messageTS string,
|
||||
) (*coredata.SlackMessage, error) {
|
||||
var slackMessage coredata.SlackMessage
|
||||
|
||||
err := s.pg.WithConn(ctx, func(conn pg.Conn) error {
|
||||
if err := slackMessage.LoadInitialByChannelAndTS(ctx, conn, coredata.NewNoScope(), channelID, messageTS); err != nil {
|
||||
return fmt.Errorf("cannot load slack message: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &slackMessage, nil
|
||||
}
|
||||
|
||||
func (s *SlackMessageService) GetSlackMessageDocumentIDs(
|
||||
ctx context.Context,
|
||||
slackMessageID gid.GID,
|
||||
@@ -132,7 +108,6 @@ func (s *SlackMessageService) UpdateSlackAccessMessage(
|
||||
if err := slackMessage.LoadById(ctx, tx, s.svc.scope, slackMessageID); err != nil {
|
||||
return fmt.Errorf("cannot load slack message: %w", err)
|
||||
}
|
||||
|
||||
var trustCenter coredata.TrustCenter
|
||||
if err := trustCenter.LoadByOrganizationID(ctx, tx, s.svc.scope, slackMessage.OrganizationID); err != nil {
|
||||
return fmt.Errorf("cannot load trust center: %w", err)
|
||||
@@ -189,7 +164,7 @@ func (s *SlackMessageService) UpdateSlackAccessMessage(
|
||||
return fmt.Errorf("cannot insert slack message: %w", err)
|
||||
}
|
||||
|
||||
if err := s.slackClient.UpdateInteractiveMessage(ctx, responseURL, updatedBody); err != nil {
|
||||
if err := s.svc.GetSlackClient().UpdateInteractiveMessage(ctx, responseURL, updatedBody); err != nil {
|
||||
return fmt.Errorf("cannot update Slack message: %w", err)
|
||||
}
|
||||
|
||||
@@ -310,6 +285,102 @@ func (s *SlackMessageService) QueueSlackNotification(
|
||||
})
|
||||
}
|
||||
|
||||
func (s *SlackMessageService) QueueSlackAccessMessageUpdate(
|
||||
ctx context.Context,
|
||||
requesterEmail string,
|
||||
trustCenterID gid.GID,
|
||||
) error {
|
||||
return s.svc.pg.WithTx(ctx, func(tx pg.Conn) error {
|
||||
var trustCenter coredata.TrustCenter
|
||||
if err := trustCenter.LoadByID(ctx, tx, s.svc.scope, trustCenterID); err != nil {
|
||||
return fmt.Errorf("cannot load trust center: %w", err)
|
||||
}
|
||||
|
||||
var trustCenterAccess coredata.TrustCenterAccess
|
||||
if err := trustCenterAccess.LoadByTrustCenterIDAndEmail(ctx, tx, s.svc.scope, trustCenterID, requesterEmail); err != nil {
|
||||
return fmt.Errorf("cannot load trust center access: %w", err)
|
||||
}
|
||||
|
||||
var existingMessage coredata.SlackMessage
|
||||
err := existingMessage.LoadLatestByRequesterEmailAndType(
|
||||
ctx,
|
||||
tx,
|
||||
s.svc.scope,
|
||||
trustCenter.OrganizationID,
|
||||
requesterEmail,
|
||||
coredata.SlackMessageTypeTrustCenterAccessRequest,
|
||||
time.Time{},
|
||||
)
|
||||
if err != nil {
|
||||
var notFoundErr coredata.ErrSlackMessageNotFound
|
||||
if errors.Is(err, notFoundErr) {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("cannot load existing slack message: %w", err)
|
||||
}
|
||||
|
||||
if existingMessage.MessageTS == nil || existingMessage.ChannelID == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if existingMessage.ID != existingMessage.InitialSlackMessageID {
|
||||
var originalMessage coredata.SlackMessage
|
||||
if err := originalMessage.LoadById(ctx, tx, s.svc.scope, existingMessage.InitialSlackMessageID); err != nil {
|
||||
return nil
|
||||
}
|
||||
existingMessage = originalMessage
|
||||
}
|
||||
|
||||
documents, reports, files, err := s.loadDocumentsReportsAndFilesFromAccesses(ctx, tx, trustCenterAccess.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot load documents, reports and files: %w", err)
|
||||
}
|
||||
|
||||
newSlackMessageID := gid.New(s.svc.scope.GetTenantID(), coredata.SlackMessageEntityType)
|
||||
|
||||
updatedBody, err := s.buildAccessRequestMessage(
|
||||
newSlackMessageID,
|
||||
trustCenterAccess.Name,
|
||||
requesterEmail,
|
||||
trustCenter.OrganizationID,
|
||||
documents,
|
||||
reports,
|
||||
files,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot build access request message: %w", err)
|
||||
}
|
||||
|
||||
metadata := SlackMessageMetadata{
|
||||
Documents: documents,
|
||||
Reports: reports,
|
||||
Files: files,
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
newSlackMessage := &coredata.SlackMessage{
|
||||
ID: newSlackMessageID,
|
||||
OrganizationID: existingMessage.OrganizationID,
|
||||
Type: existingMessage.Type,
|
||||
Body: updatedBody,
|
||||
MessageTS: existingMessage.MessageTS,
|
||||
ChannelID: existingMessage.ChannelID,
|
||||
RequesterEmail: existingMessage.RequesterEmail,
|
||||
Metadata: metadata.toMap(),
|
||||
InitialSlackMessageID: existingMessage.InitialSlackMessageID,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
SentAt: nil,
|
||||
}
|
||||
|
||||
if err := newSlackMessage.Insert(ctx, tx, s.svc.scope); err != nil {
|
||||
return fmt.Errorf("cannot insert slack message: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (s *SlackMessageService) loadDocumentsReportsAndFilesFromAccesses(
|
||||
ctx context.Context,
|
||||
conn pg.Conn,
|
||||
@@ -12,7 +12,7 @@
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package trust
|
||||
package slack
|
||||
|
||||
import (
|
||||
"embed"
|
||||
@@ -18,6 +18,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||
"go.gearno.de/kit/log"
|
||||
"go.gearno.de/kit/pg"
|
||||
"go.probo.inc/probo/pkg/auth"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/crypto/cipher"
|
||||
@@ -26,8 +28,6 @@ import (
|
||||
"go.probo.inc/probo/pkg/html2pdf"
|
||||
"go.probo.inc/probo/pkg/probo"
|
||||
"go.probo.inc/probo/pkg/slack"
|
||||
"go.gearno.de/kit/log"
|
||||
"go.gearno.de/kit/pg"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -38,19 +38,19 @@ type (
|
||||
}
|
||||
|
||||
Service struct {
|
||||
pg *pg.Client
|
||||
s3 *s3.Client
|
||||
bucket string
|
||||
proboSvc *probo.Service
|
||||
encryptionKey cipher.EncryptionKey
|
||||
tokenSecret string
|
||||
slackSigningSecret string
|
||||
baseURL string
|
||||
auth *auth.Service
|
||||
html2pdfConverter *html2pdf.Converter
|
||||
fileManager *filemanager.Service
|
||||
logger *log.Logger
|
||||
trustConfig TrustConfig
|
||||
pg *pg.Client
|
||||
s3 *s3.Client
|
||||
bucket string
|
||||
proboSvc *probo.Service
|
||||
encryptionKey cipher.EncryptionKey
|
||||
tokenSecret string
|
||||
baseURL string
|
||||
auth *auth.Service
|
||||
html2pdfConverter *html2pdf.Converter
|
||||
fileManager *filemanager.Service
|
||||
logger *log.Logger
|
||||
trustConfig TrustConfig
|
||||
slack *slack.Service
|
||||
}
|
||||
|
||||
TenantService struct {
|
||||
@@ -77,7 +77,7 @@ type (
|
||||
TrustCenterFiles *TrustCenterFileService
|
||||
Reports *ReportService
|
||||
Organizations *OrganizationService
|
||||
SlackMessages *SlackMessageService
|
||||
slack *slack.TenantService
|
||||
}
|
||||
)
|
||||
|
||||
@@ -88,26 +88,26 @@ func NewService(
|
||||
baseURL string,
|
||||
encryptionKey cipher.EncryptionKey,
|
||||
tokenSecret string,
|
||||
slackSigningSecret string,
|
||||
auth *auth.Service,
|
||||
html2pdfConverter *html2pdf.Converter,
|
||||
fileManagerService *filemanager.Service,
|
||||
logger *log.Logger,
|
||||
trustConfig TrustConfig,
|
||||
slack *slack.Service,
|
||||
) *Service {
|
||||
return &Service{
|
||||
pg: pgClient,
|
||||
s3: s3Client,
|
||||
bucket: bucket,
|
||||
encryptionKey: encryptionKey,
|
||||
tokenSecret: tokenSecret,
|
||||
slackSigningSecret: slackSigningSecret,
|
||||
baseURL: baseURL,
|
||||
auth: auth,
|
||||
html2pdfConverter: html2pdfConverter,
|
||||
fileManager: fileManagerService,
|
||||
logger: logger,
|
||||
trustConfig: trustConfig,
|
||||
pg: pgClient,
|
||||
s3: s3Client,
|
||||
bucket: bucket,
|
||||
encryptionKey: encryptionKey,
|
||||
tokenSecret: tokenSecret,
|
||||
baseURL: baseURL,
|
||||
auth: auth,
|
||||
html2pdfConverter: html2pdfConverter,
|
||||
fileManager: fileManagerService,
|
||||
logger: logger,
|
||||
trustConfig: trustConfig,
|
||||
slack: slack,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,10 +126,9 @@ func (s *Service) WithTenant(tenantID gid.TenantID) *TenantService {
|
||||
fileManager: s.fileManager,
|
||||
logger: s.logger,
|
||||
trustConfig: s.trustConfig,
|
||||
slack: s.slack.WithTenant(tenantID),
|
||||
}
|
||||
|
||||
slackClient := slack.NewClient(s.logger)
|
||||
|
||||
tenantService.TrustCenters = &TrustCenterService{svc: tenantService}
|
||||
tenantService.Documents = &DocumentService{svc: tenantService, html2pdfConverter: s.html2pdfConverter}
|
||||
tenantService.Audits = &AuditService{svc: tenantService}
|
||||
@@ -140,7 +139,6 @@ func (s *Service) WithTenant(tenantID gid.TenantID) *TenantService {
|
||||
tenantService.TrustCenterFiles = &TrustCenterFileService{svc: tenantService}
|
||||
tenantService.Reports = &ReportService{svc: tenantService}
|
||||
tenantService.Organizations = &OrganizationService{svc: tenantService}
|
||||
tenantService.SlackMessages = &SlackMessageService{svc: tenantService, slackClient: slackClient}
|
||||
|
||||
return tenantService
|
||||
}
|
||||
@@ -148,7 +146,3 @@ func (s *Service) WithTenant(tenantID gid.TenantID) *TenantService {
|
||||
func (s *Service) GetTokenSecret() string {
|
||||
return s.tokenSecret
|
||||
}
|
||||
|
||||
func (s *Service) GetSlackSigningSecret() string {
|
||||
return s.slackSigningSecret
|
||||
}
|
||||
|
||||
@@ -21,8 +21,6 @@ import (
|
||||
"fmt"
|
||||
"net/mail"
|
||||
"net/url"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"go.gearno.de/kit/log"
|
||||
@@ -35,30 +33,6 @@ import (
|
||||
"go.probo.inc/probo/pkg/statelesstoken"
|
||||
)
|
||||
|
||||
var (
|
||||
accessRequestTemplate = template.Must(
|
||||
template.New("access-request.json.tmpl").
|
||||
Funcs(template.FuncMap{
|
||||
"jsonEscape": func(s string) string {
|
||||
b, _ := json.Marshal(s)
|
||||
return string(b[1 : len(b)-1])
|
||||
},
|
||||
"buildAcceptAllValue": func(docIDs, repIDs []string) string {
|
||||
value := map[string][]string{
|
||||
"document_ids": docIDs,
|
||||
"report_ids": repIDs,
|
||||
}
|
||||
b, _ := json.Marshal(value)
|
||||
s := string(b)
|
||||
s = strings.ReplaceAll(s, `\`, `\\`)
|
||||
s = strings.ReplaceAll(s, `"`, `\"`)
|
||||
return s
|
||||
},
|
||||
}).
|
||||
ParseFS(Templates, "templates/access-request.json.tmpl"),
|
||||
)
|
||||
)
|
||||
|
||||
type (
|
||||
TrustCenterAccessService struct {
|
||||
svc *TenantService
|
||||
@@ -258,7 +232,8 @@ func (s TrustCenterAccessService) Request(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := s.svc.SlackMessages.QueueSlackNotification(ctx, access.Email, req.TrustCenterID); err != nil {
|
||||
slackMessageService := s.svc.slack.GetSlackMessageService()
|
||||
if err := slackMessageService.QueueSlackNotification(ctx, access.Email, req.TrustCenterID); err != nil {
|
||||
s.logger.ErrorCtx(ctx, "cannot queue slack notification", log.Error(err))
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user