Expose missing console capabilities on MCP
Add MCP tools and filters for mailing lists, detected trackers, compliance portal frameworks, and document/control/framework mutations that were available in the console but missing from MCP. Signed-off-by: Sacha Al Himdani <sacha@probo.com>
This commit is contained in:
@@ -112,10 +112,11 @@ type (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrMissingProboService = errors.New("server configuration requires a valid probo.Service instance")
|
ErrMissingProboService = errors.New("server configuration requires a valid probo.Service instance")
|
||||||
ErrMissingIAMService = errors.New("server configuration requires a valid iam.Service instance")
|
ErrMissingIAMService = errors.New("server configuration requires a valid iam.Service instance")
|
||||||
ErrMissingSlackService = errors.New("server configuration requires a valid slack.Service instance")
|
ErrMissingSlackService = errors.New("server configuration requires a valid slack.Service instance")
|
||||||
ErrMissingITAMService = errors.New("server configuration requires a valid itam.Service instance")
|
ErrMissingITAMService = errors.New("server configuration requires a valid itam.Service instance")
|
||||||
|
ErrMissingMailmanService = errors.New("server configuration requires a valid mailman.Service instance")
|
||||||
)
|
)
|
||||||
|
|
||||||
func methodNotAllowed(w http.ResponseWriter, r *http.Request) {
|
func methodNotAllowed(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -159,6 +160,10 @@ func NewServer(cfg Config) (*Server, error) {
|
|||||||
return nil, ErrMissingITAMService
|
return nil, ErrMissingITAMService
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cfg.Mailman == nil {
|
||||||
|
return nil, ErrMissingMailmanService
|
||||||
|
}
|
||||||
|
|
||||||
csrf := http.NewCrossOriginProtection()
|
csrf := http.NewCrossOriginProtection()
|
||||||
for _, origin := range cfg.AllowedOrigins {
|
for _, origin := range cfg.AllowedOrigins {
|
||||||
if err := csrf.AddTrustedOrigin(origin); err != nil {
|
if err := csrf.AddTrustedOrigin(origin); err != nil {
|
||||||
@@ -246,6 +251,7 @@ func NewServer(cfg Config) (*Server, error) {
|
|||||||
cfg.CookieBanner,
|
cfg.CookieBanner,
|
||||||
cfg.RiskManagement,
|
cfg.RiskManagement,
|
||||||
cfg.ITAM,
|
cfg.ITAM,
|
||||||
|
cfg.Mailman,
|
||||||
cfg.TokenSecret,
|
cfg.TokenSecret,
|
||||||
cfg.File,
|
cfg.File,
|
||||||
cfg.BaseURL,
|
cfg.BaseURL,
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import (
|
|||||||
"go.probo.inc/probo/pkg/gid"
|
"go.probo.inc/probo/pkg/gid"
|
||||||
"go.probo.inc/probo/pkg/iam"
|
"go.probo.inc/probo/pkg/iam"
|
||||||
"go.probo.inc/probo/pkg/itam"
|
"go.probo.inc/probo/pkg/itam"
|
||||||
|
"go.probo.inc/probo/pkg/mailman"
|
||||||
"go.probo.inc/probo/pkg/probo"
|
"go.probo.inc/probo/pkg/probo"
|
||||||
"go.probo.inc/probo/pkg/prosemirror"
|
"go.probo.inc/probo/pkg/prosemirror"
|
||||||
"go.probo.inc/probo/pkg/resourcealias"
|
"go.probo.inc/probo/pkg/resourcealias"
|
||||||
@@ -63,6 +64,7 @@ type Resolver struct {
|
|||||||
cookieBanner *cookiebanner.Service
|
cookieBanner *cookiebanner.Service
|
||||||
riskManagement *riskmanagement.Service
|
riskManagement *riskmanagement.Service
|
||||||
itamSvc *itam.Service
|
itamSvc *itam.Service
|
||||||
|
mailman *mailman.Service
|
||||||
logger *log.Logger
|
logger *log.Logger
|
||||||
fileManager *filemanager.Service
|
fileManager *filemanager.Service
|
||||||
baseURL *baseurl.BaseURL
|
baseURL *baseurl.BaseURL
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import (
|
|||||||
"go.probo.inc/probo/pkg/iam"
|
"go.probo.inc/probo/pkg/iam"
|
||||||
"go.probo.inc/probo/pkg/itam"
|
"go.probo.inc/probo/pkg/itam"
|
||||||
"go.probo.inc/probo/pkg/mail"
|
"go.probo.inc/probo/pkg/mail"
|
||||||
|
"go.probo.inc/probo/pkg/mailman"
|
||||||
"go.probo.inc/probo/pkg/page"
|
"go.probo.inc/probo/pkg/page"
|
||||||
"go.probo.inc/probo/pkg/probo"
|
"go.probo.inc/probo/pkg/probo"
|
||||||
"go.probo.inc/probo/pkg/resourcealias"
|
"go.probo.inc/probo/pkg/resourcealias"
|
||||||
@@ -7645,3 +7646,479 @@ func (r *Resolver) CreateDeviceTool(ctx context.Context, req *mcp.CallToolReques
|
|||||||
EnrollmentURL: urls.EnrollmentURL,
|
EnrollmentURL: urls.EnrollmentURL,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Resolver) GetThirdPartyTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetThirdPartyInput) (*mcp.CallToolResult, types.GetThirdPartyOutput, error) {
|
||||||
|
scope, err := r.Authorize(ctx, input.ID, probo.ActionThirdPartyGet)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.GetThirdPartyOutput{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
thirdParty, err := r.proboSvc.ThirdParties.Get(ctx, scope, input.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.GetThirdPartyOutput{}, fmt.Errorf("cannot get third party: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, types.GetThirdPartyOutput{
|
||||||
|
ThirdParty: types.NewThirdParty(thirdParty),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resolver) DeleteEvidenceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteEvidenceInput) (*mcp.CallToolResult, types.DeleteEvidenceOutput, error) {
|
||||||
|
scope, err := r.Authorize(ctx, input.ID, probo.ActionEvidenceDelete)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.DeleteEvidenceOutput{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = r.proboSvc.Evidences.Delete(ctx, scope, input.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.DeleteEvidenceOutput{}, fmt.Errorf("cannot delete evidence: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, types.DeleteEvidenceOutput{
|
||||||
|
DeletedEvidenceID: input.ID,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resolver) DeleteFrameworkTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteFrameworkInput) (*mcp.CallToolResult, types.DeleteFrameworkOutput, error) {
|
||||||
|
scope, err := r.Authorize(ctx, input.ID, probo.ActionFrameworkDelete)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.DeleteFrameworkOutput{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = r.proboSvc.Frameworks.Delete(ctx, scope, input.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.DeleteFrameworkOutput{}, fmt.Errorf("cannot delete framework: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, types.DeleteFrameworkOutput{
|
||||||
|
DeletedFrameworkID: input.ID,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resolver) DeleteAuditReportTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteAuditReportInput) (*mcp.CallToolResult, types.DeleteAuditReportOutput, error) {
|
||||||
|
scope, err := r.Authorize(ctx, input.ID, probo.ActionAuditReportDelete)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.DeleteAuditReportOutput{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
audit, err := r.proboSvc.Audits.DeleteReport(ctx, scope, input.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.DeleteAuditReportOutput{}, fmt.Errorf("cannot delete audit report: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, types.DeleteAuditReportOutput{
|
||||||
|
Audit: types.NewAudit(audit, nil),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resolver) DeleteControlTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteControlInput) (*mcp.CallToolResult, types.DeleteControlOutput, error) {
|
||||||
|
scope, err := r.Authorize(ctx, input.ID, probo.ActionControlDelete)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.DeleteControlOutput{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = r.proboSvc.Controls.Delete(ctx, scope, input.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.DeleteControlOutput{}, fmt.Errorf("cannot delete control: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, types.DeleteControlOutput{
|
||||||
|
DeletedControlID: input.ID,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resolver) ApproveDocumentVersionTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ApproveDocumentVersionInput) (*mcp.CallToolResult, types.ApproveDocumentVersionOutput, error) {
|
||||||
|
scope, err := r.Authorize(ctx, input.DocumentVersionID, probo.ActionDocumentVersionApprove)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.ApproveDocumentVersionOutput{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
identity := authn.IdentityFromContext(ctx)
|
||||||
|
signer := signerMetadataFromToolRequest(req)
|
||||||
|
|
||||||
|
decision, err := r.proboSvc.DocumentApprovals.Approve(
|
||||||
|
ctx,
|
||||||
|
scope,
|
||||||
|
probo.ApproveDocumentVersionRequest{
|
||||||
|
DocumentVersionID: input.DocumentVersionID,
|
||||||
|
IdentityID: identity.ID,
|
||||||
|
Comment: input.Comment,
|
||||||
|
SignerFullName: identity.FullName,
|
||||||
|
SignerEmail: identity.EmailAddress,
|
||||||
|
SignerIPAddr: signer.IPAddr,
|
||||||
|
SignerUA: signer.UA,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.ApproveDocumentVersionOutput{}, fmt.Errorf("cannot approve document version: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, types.ApproveDocumentVersionOutput{
|
||||||
|
DocumentVersionApprovalDecision: types.NewDocumentVersionApprovalDecision(decision),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resolver) RejectDocumentVersionTool(ctx context.Context, req *mcp.CallToolRequest, input *types.RejectDocumentVersionInput) (*mcp.CallToolResult, types.RejectDocumentVersionOutput, error) {
|
||||||
|
scope, err := r.Authorize(ctx, input.DocumentVersionID, probo.ActionDocumentVersionReject)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.RejectDocumentVersionOutput{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
identity := authn.IdentityFromContext(ctx)
|
||||||
|
|
||||||
|
decision, err := r.proboSvc.DocumentApprovals.Reject(
|
||||||
|
ctx,
|
||||||
|
scope,
|
||||||
|
probo.RejectDocumentVersionRequest{
|
||||||
|
DocumentVersionID: input.DocumentVersionID,
|
||||||
|
IdentityID: identity.ID,
|
||||||
|
Comment: input.Comment,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.RejectDocumentVersionOutput{}, fmt.Errorf("cannot reject document version: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, types.RejectDocumentVersionOutput{
|
||||||
|
DocumentVersionApprovalDecision: types.NewDocumentVersionApprovalDecision(decision),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resolver) SignDocumentTool(ctx context.Context, req *mcp.CallToolRequest, input *types.SignDocumentInput) (*mcp.CallToolResult, types.SignDocumentOutput, error) {
|
||||||
|
scope, err := r.Authorize(ctx, input.DocumentVersionID, probo.ActionDocumentVersionSign)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.SignDocumentOutput{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
identity := authn.IdentityFromContext(ctx)
|
||||||
|
signer := signerMetadataFromToolRequest(req)
|
||||||
|
|
||||||
|
signature, err := r.proboSvc.Documents.SignDocumentVersionByIdentity(
|
||||||
|
ctx,
|
||||||
|
scope,
|
||||||
|
probo.SignDocumentVersionRequest{
|
||||||
|
DocumentVersionID: input.DocumentVersionID,
|
||||||
|
IdentityID: identity.ID,
|
||||||
|
SignerFullName: identity.FullName,
|
||||||
|
SignerEmail: identity.EmailAddress,
|
||||||
|
SignerIPAddr: signer.IPAddr,
|
||||||
|
SignerUA: signer.UA,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.SignDocumentOutput{}, fmt.Errorf("cannot sign document: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, types.SignDocumentOutput{
|
||||||
|
DocumentVersionSignature: types.NewDocumentVersionSignature(signature),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resolver) GetMailingListTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetMailingListInput) (*mcp.CallToolResult, types.GetMailingListOutput, error) {
|
||||||
|
scope, err := r.Authorize(ctx, input.CompliancePortalID, management.ActionMailingListSubscriberList)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.GetMailingListOutput{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
mailingList, err := r.management.GetMailingList(ctx, scope, input.CompliancePortalID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.GetMailingListOutput{}, fmt.Errorf("cannot get mailing list: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, types.GetMailingListOutput{MailingList: types.NewMailingList(mailingList)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resolver) UpdateMailingListTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateMailingListInput) (*mcp.CallToolResult, types.UpdateMailingListOutput, error) {
|
||||||
|
if _, err := r.Authorize(ctx, input.ID, management.ActionMailingListUpdate); err != nil {
|
||||||
|
return nil, types.UpdateMailingListOutput{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
mailingList, err := r.mailman.UpdateMailingList(ctx, input.ID, input.ReplyTo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.UpdateMailingListOutput{}, fmt.Errorf("cannot update mailing list: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, types.UpdateMailingListOutput{MailingList: types.NewMailingList(mailingList)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resolver) ListMailingListSubscribersTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListMailingListSubscribersInput) (*mcp.CallToolResult, types.ListMailingListSubscribersOutput, error) {
|
||||||
|
if _, err := r.Authorize(ctx, input.MailingListID, management.ActionMailingListSubscriberList); err != nil {
|
||||||
|
return nil, types.ListMailingListSubscribersOutput{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pageOrderBy := page.OrderBy[coredata.MailingListSubscriberOrderField]{
|
||||||
|
Field: coredata.MailingListSubscriberOrderFieldCreatedAt,
|
||||||
|
Direction: page.OrderDirectionDesc,
|
||||||
|
}
|
||||||
|
if input.OrderBy != nil {
|
||||||
|
pageOrderBy = page.OrderBy[coredata.MailingListSubscriberOrderField]{
|
||||||
|
Field: input.OrderBy.Field,
|
||||||
|
Direction: input.OrderBy.Direction,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy)
|
||||||
|
|
||||||
|
p, err := r.mailman.ListSubscribers(ctx, input.MailingListID, cursor)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.ListMailingListSubscribersOutput{}, fmt.Errorf("cannot list mailing list subscribers: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, types.NewListMailingListSubscribersOutput(p), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resolver) AddMailingListSubscriberTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddMailingListSubscriberInput) (*mcp.CallToolResult, types.AddMailingListSubscriberOutput, error) {
|
||||||
|
if _, err := r.Authorize(ctx, input.MailingListID, management.ActionMailingListSubscriberCreate); err != nil {
|
||||||
|
return nil, types.AddMailingListSubscriberOutput{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
subscriber, err := r.mailman.CreateSubscriber(
|
||||||
|
ctx,
|
||||||
|
&mailman.CreateSubscriberRequest{
|
||||||
|
MailingListID: input.MailingListID,
|
||||||
|
Email: input.Email,
|
||||||
|
FullName: input.FullName,
|
||||||
|
Confirmed: input.Confirmed != nil && *input.Confirmed,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.AddMailingListSubscriberOutput{}, fmt.Errorf("cannot add mailing list subscriber: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, types.AddMailingListSubscriberOutput{
|
||||||
|
MailingListSubscriber: types.NewMailingListSubscriber(subscriber),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resolver) DeleteMailingListSubscriberTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteMailingListSubscriberInput) (*mcp.CallToolResult, types.DeleteMailingListSubscriberOutput, error) {
|
||||||
|
if _, err := r.Authorize(ctx, input.ID, management.ActionMailingListSubscriberDelete); err != nil {
|
||||||
|
return nil, types.DeleteMailingListSubscriberOutput{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := r.mailman.DeleteSubscriber(ctx, input.ID); err != nil {
|
||||||
|
return nil, types.DeleteMailingListSubscriberOutput{}, fmt.Errorf("cannot delete mailing list subscriber: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, types.DeleteMailingListSubscriberOutput{
|
||||||
|
DeletedMailingListSubscriberID: input.ID,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resolver) ListMailingListUpdatesTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListMailingListUpdatesInput) (*mcp.CallToolResult, types.ListMailingListUpdatesOutput, error) {
|
||||||
|
if _, err := r.Authorize(ctx, input.MailingListID, management.ActionMailingListUpdateList); err != nil {
|
||||||
|
return nil, types.ListMailingListUpdatesOutput{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pageOrderBy := page.OrderBy[coredata.MailingListUpdateOrderField]{
|
||||||
|
Field: coredata.MailingListUpdateOrderFieldUpdatedAt,
|
||||||
|
Direction: page.OrderDirectionDesc,
|
||||||
|
}
|
||||||
|
if input.OrderBy != nil {
|
||||||
|
pageOrderBy = page.OrderBy[coredata.MailingListUpdateOrderField]{
|
||||||
|
Field: input.OrderBy.Field,
|
||||||
|
Direction: input.OrderBy.Direction,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy)
|
||||||
|
|
||||||
|
p, err := r.mailman.ListMailingListUpdates(ctx, input.MailingListID, cursor)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.ListMailingListUpdatesOutput{}, fmt.Errorf("cannot list mailing list updates: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, types.NewListMailingListUpdatesOutput(p), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resolver) AddMailingListUpdateTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddMailingListUpdateInput) (*mcp.CallToolResult, types.AddMailingListUpdateOutput, error) {
|
||||||
|
if _, err := r.Authorize(ctx, input.MailingListID, management.ActionMailingListUpdateCreate); err != nil {
|
||||||
|
return nil, types.AddMailingListUpdateOutput{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
update, err := r.mailman.CreateMailingListUpdate(
|
||||||
|
ctx,
|
||||||
|
&mailman.CreateMailingListUpdateRequest{
|
||||||
|
MailingListID: input.MailingListID,
|
||||||
|
Title: input.Title,
|
||||||
|
Body: input.Body,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.AddMailingListUpdateOutput{}, fmt.Errorf("cannot add mailing list update: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, types.AddMailingListUpdateOutput{
|
||||||
|
MailingListUpdate: types.NewMailingListUpdate(update),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resolver) UpdateMailingListUpdateTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateMailingListUpdateInput) (*mcp.CallToolResult, types.UpdateMailingListUpdateOutput, error) {
|
||||||
|
if _, err := r.Authorize(ctx, input.ID, management.ActionMailingListUpdateUpdate); err != nil {
|
||||||
|
return nil, types.UpdateMailingListUpdateOutput{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
update, err := r.mailman.UpdateMailingListUpdate(
|
||||||
|
ctx,
|
||||||
|
&mailman.UpdateMailingListUpdateRequest{
|
||||||
|
ID: input.ID,
|
||||||
|
Title: input.Title,
|
||||||
|
Body: input.Body,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.UpdateMailingListUpdateOutput{}, fmt.Errorf("cannot update mailing list update: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, types.UpdateMailingListUpdateOutput{
|
||||||
|
MailingListUpdate: types.NewMailingListUpdate(update),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resolver) SendMailingListUpdateTool(ctx context.Context, req *mcp.CallToolRequest, input *types.SendMailingListUpdateInput) (*mcp.CallToolResult, types.SendMailingListUpdateOutput, error) {
|
||||||
|
if _, err := r.Authorize(ctx, input.ID, management.ActionMailingListUpdateUpdate); err != nil {
|
||||||
|
return nil, types.SendMailingListUpdateOutput{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
update, err := r.mailman.SendMailingListUpdate(ctx, input.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.SendMailingListUpdateOutput{}, fmt.Errorf("cannot send mailing list update: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, types.SendMailingListUpdateOutput{
|
||||||
|
MailingListUpdate: types.NewMailingListUpdate(update),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resolver) DeleteMailingListUpdateTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteMailingListUpdateInput) (*mcp.CallToolResult, types.DeleteMailingListUpdateOutput, error) {
|
||||||
|
if _, err := r.Authorize(ctx, input.ID, management.ActionMailingListUpdateDelete); err != nil {
|
||||||
|
return nil, types.DeleteMailingListUpdateOutput{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := r.mailman.DeleteMailingListUpdate(ctx, input.ID); err != nil {
|
||||||
|
return nil, types.DeleteMailingListUpdateOutput{}, fmt.Errorf("cannot delete mailing list update: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, types.DeleteMailingListUpdateOutput{
|
||||||
|
DeletedMailingListUpdateID: input.ID,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resolver) ListDetectedTrackersTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListDetectedTrackersInput) (*mcp.CallToolResult, types.ListDetectedTrackersOutput, error) {
|
||||||
|
scope, err := r.Authorize(ctx, input.TrackerPatternID, probo.ActionTrackerPatternGet)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.ListDetectedTrackersOutput{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pageOrderBy := page.OrderBy[coredata.DetectedTrackerOrderField]{
|
||||||
|
Field: coredata.DetectedTrackerOrderFieldLastDetectedAt,
|
||||||
|
Direction: page.OrderDirectionDesc,
|
||||||
|
}
|
||||||
|
if input.OrderBy != nil {
|
||||||
|
pageOrderBy = page.OrderBy[coredata.DetectedTrackerOrderField]{
|
||||||
|
Field: input.OrderBy.Field,
|
||||||
|
Direction: input.OrderBy.Direction,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy)
|
||||||
|
|
||||||
|
trackers, err := r.cookieBanner.ListDetectedTrackersForPattern(ctx, scope, input.TrackerPatternID, cursor)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.ListDetectedTrackersOutput{}, fmt.Errorf("cannot list detected trackers: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, types.NewListDetectedTrackersOutput(page.NewPage(trackers, cursor)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resolver) ListCompliancePortalFrameworksTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListCompliancePortalFrameworksInput) (*mcp.CallToolResult, types.ListCompliancePortalFrameworksOutput, error) {
|
||||||
|
scope, err := r.Authorize(ctx, input.CompliancePortalID, management.ActionComplianceFrameworkList)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.ListCompliancePortalFrameworksOutput{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pageOrderBy := page.OrderBy[coredata.ComplianceFrameworkOrderField]{
|
||||||
|
Field: coredata.ComplianceFrameworkOrderFieldRank,
|
||||||
|
Direction: page.OrderDirectionAsc,
|
||||||
|
}
|
||||||
|
if input.OrderBy != nil {
|
||||||
|
pageOrderBy = page.OrderBy[coredata.ComplianceFrameworkOrderField]{
|
||||||
|
Field: input.OrderBy.Field,
|
||||||
|
Direction: input.OrderBy.Direction,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy)
|
||||||
|
|
||||||
|
p, err := r.management.ListFrameworksWithHidden(ctx, scope, input.CompliancePortalID, cursor)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.ListCompliancePortalFrameworksOutput{}, fmt.Errorf("cannot list compliance portal frameworks: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, types.NewListCompliancePortalFrameworksOutput(p), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resolver) AddCompliancePortalFrameworkTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddCompliancePortalFrameworkInput) (*mcp.CallToolResult, types.AddCompliancePortalFrameworkOutput, error) {
|
||||||
|
scope, err := r.Authorize(ctx, input.CompliancePortalID, management.ActionComplianceFrameworkCreate)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.AddCompliancePortalFrameworkOutput{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
framework, err := r.management.CreateFramework(
|
||||||
|
ctx,
|
||||||
|
scope,
|
||||||
|
&management.CreateFrameworkRequest{
|
||||||
|
CompliancePortalID: input.CompliancePortalID,
|
||||||
|
FrameworkID: input.FrameworkID,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.AddCompliancePortalFrameworkOutput{}, fmt.Errorf("cannot add compliance portal framework: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, types.AddCompliancePortalFrameworkOutput{
|
||||||
|
CompliancePortalFramework: types.NewCompliancePortalFramework(framework),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resolver) UpdateCompliancePortalFrameworkTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateCompliancePortalFrameworkInput) (*mcp.CallToolResult, types.UpdateCompliancePortalFrameworkOutput, error) {
|
||||||
|
scope, err := r.Authorize(ctx, input.ID, management.ActionComplianceFrameworkUpdateRank)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.UpdateCompliancePortalFrameworkOutput{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
framework, err := r.management.UpdateFramework(
|
||||||
|
ctx,
|
||||||
|
scope,
|
||||||
|
&management.UpdateFrameworkRequest{
|
||||||
|
ID: input.ID,
|
||||||
|
Rank: input.Rank,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.UpdateCompliancePortalFrameworkOutput{}, fmt.Errorf("cannot update compliance portal framework: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, types.UpdateCompliancePortalFrameworkOutput{
|
||||||
|
CompliancePortalFramework: types.NewCompliancePortalFramework(framework),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resolver) DeleteCompliancePortalFrameworkTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteCompliancePortalFrameworkInput) (*mcp.CallToolResult, types.DeleteCompliancePortalFrameworkOutput, error) {
|
||||||
|
scope, err := r.Authorize(ctx, input.ID, management.ActionComplianceFrameworkDelete)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.DeleteCompliancePortalFrameworkOutput{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = r.management.DeleteFramework(
|
||||||
|
ctx,
|
||||||
|
scope,
|
||||||
|
&management.DeleteFrameworkRequest{ID: input.ID},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, types.DeleteCompliancePortalFrameworkOutput{}, fmt.Errorf("cannot delete compliance portal framework: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, types.DeleteCompliancePortalFrameworkOutput{
|
||||||
|
DeletedCompliancePortalFrameworkID: input.ID,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|||||||
46
pkg/server/api/mcp/v1/signer_metadata.go
Normal file
46
pkg/server/api/mcp/v1/signer_metadata.go
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
// Copyright (c) 2026 Probo Inc <hello@probo.com>.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
|
||||||
|
package mcp_v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||||
|
"go.probo.inc/probo/pkg/server/api/clientip"
|
||||||
|
)
|
||||||
|
|
||||||
|
type signerMetadata struct {
|
||||||
|
IPAddr string
|
||||||
|
UA string
|
||||||
|
}
|
||||||
|
|
||||||
|
func signerMetadataFromToolRequest(req *mcp.CallToolRequest) signerMetadata {
|
||||||
|
if req == nil || req.Extra == nil || req.Extra.Header == nil {
|
||||||
|
return signerMetadata{}
|
||||||
|
}
|
||||||
|
|
||||||
|
httpReq := &http.Request{Header: req.Extra.Header}
|
||||||
|
|
||||||
|
return signerMetadata{
|
||||||
|
IPAddr: clientip.Extract(httpReq),
|
||||||
|
UA: req.Extra.Header.Get("User-Agent"),
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
60
pkg/server/api/mcp/v1/types/compliance_portal_framework.go
Normal file
60
pkg/server/api/mcp/v1/types/compliance_portal_framework.go
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
// Copyright (c) 2026 Probo Inc <hello@probo.com>.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
|
||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go.probo.inc/probo/pkg/coredata"
|
||||||
|
"go.probo.inc/probo/pkg/page"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewCompliancePortalFramework(cf *coredata.ComplianceFramework) *CompliancePortalFramework {
|
||||||
|
return &CompliancePortalFramework{
|
||||||
|
ID: cf.ID,
|
||||||
|
OrganizationID: cf.OrganizationID,
|
||||||
|
CompliancePortalID: cf.CompliancePortalID,
|
||||||
|
FrameworkID: cf.FrameworkID,
|
||||||
|
Rank: cf.Rank,
|
||||||
|
Visibility: cf.Visibility,
|
||||||
|
CreatedAt: cf.CreatedAt,
|
||||||
|
UpdatedAt: cf.UpdatedAt,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewListCompliancePortalFrameworksOutput(
|
||||||
|
p *page.Page[*coredata.ComplianceFramework, coredata.ComplianceFrameworkOrderField],
|
||||||
|
) ListCompliancePortalFrameworksOutput {
|
||||||
|
frameworks := make([]*CompliancePortalFramework, 0, len(p.Data))
|
||||||
|
for _, cf := range p.Data {
|
||||||
|
frameworks = append(frameworks, NewCompliancePortalFramework(cf))
|
||||||
|
}
|
||||||
|
|
||||||
|
var nextCursor *page.CursorKey
|
||||||
|
|
||||||
|
if len(p.Data) > 0 {
|
||||||
|
cursorKey := p.Data[len(p.Data)-1].CursorKey(p.Cursor.OrderBy.Field)
|
||||||
|
nextCursor = &cursorKey
|
||||||
|
}
|
||||||
|
|
||||||
|
return ListCompliancePortalFrameworksOutput{
|
||||||
|
NextCursor: nextCursor,
|
||||||
|
CompliancePortalFrameworks: frameworks,
|
||||||
|
}
|
||||||
|
}
|
||||||
66
pkg/server/api/mcp/v1/types/detected_tracker.go
Normal file
66
pkg/server/api/mcp/v1/types/detected_tracker.go
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
// Copyright (c) 2026 Probo Inc <hello@probo.com>.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
|
||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go.probo.inc/probo/pkg/coredata"
|
||||||
|
"go.probo.inc/probo/pkg/page"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewDetectedTracker(dt *coredata.DetectedTracker) *DetectedTracker {
|
||||||
|
var source *DetectedTrackerSource
|
||||||
|
|
||||||
|
if dt.Source != nil {
|
||||||
|
s := DetectedTrackerSource(string(*dt.Source))
|
||||||
|
source = &s
|
||||||
|
}
|
||||||
|
|
||||||
|
return &DetectedTracker{
|
||||||
|
ID: dt.ID,
|
||||||
|
Identifier: dt.Identifier,
|
||||||
|
InitiatorURL: dt.InitiatorURL,
|
||||||
|
MaxAgeSeconds: dt.MaxAgeSeconds,
|
||||||
|
Source: source,
|
||||||
|
LastDetectedAt: dt.LastDetectedAt,
|
||||||
|
CreatedAt: dt.CreatedAt,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewListDetectedTrackersOutput(
|
||||||
|
p *page.Page[*coredata.DetectedTracker, coredata.DetectedTrackerOrderField],
|
||||||
|
) ListDetectedTrackersOutput {
|
||||||
|
trackers := make([]*DetectedTracker, 0, len(p.Data))
|
||||||
|
for _, dt := range p.Data {
|
||||||
|
trackers = append(trackers, NewDetectedTracker(dt))
|
||||||
|
}
|
||||||
|
|
||||||
|
var nextCursor *page.CursorKey
|
||||||
|
|
||||||
|
if len(p.Data) > 0 {
|
||||||
|
cursorKey := p.Data[len(p.Data)-1].CursorKey(p.Cursor.OrderBy.Field)
|
||||||
|
nextCursor = &cursorKey
|
||||||
|
}
|
||||||
|
|
||||||
|
return ListDetectedTrackersOutput{
|
||||||
|
NextCursor: nextCursor,
|
||||||
|
DetectedTrackers: trackers,
|
||||||
|
}
|
||||||
|
}
|
||||||
108
pkg/server/api/mcp/v1/types/mailing_list.go
Normal file
108
pkg/server/api/mcp/v1/types/mailing_list.go
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
// Copyright (c) 2026 Probo Inc <hello@probo.com>.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
|
||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go.probo.inc/probo/pkg/coredata"
|
||||||
|
"go.probo.inc/probo/pkg/page"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewMailingList(ml *coredata.MailingList) *MailingList {
|
||||||
|
if ml == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &MailingList{
|
||||||
|
ID: ml.ID,
|
||||||
|
OrganizationID: ml.OrganizationID,
|
||||||
|
ReplyTo: ml.ReplyTo,
|
||||||
|
CreatedAt: ml.CreatedAt,
|
||||||
|
UpdatedAt: ml.UpdatedAt,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMailingListSubscriber(s *coredata.MailingListSubscriber) *MailingListSubscriber {
|
||||||
|
return &MailingListSubscriber{
|
||||||
|
ID: s.ID,
|
||||||
|
OrganizationID: s.OrganizationID,
|
||||||
|
MailingListID: s.MailingListID,
|
||||||
|
FullName: s.FullName,
|
||||||
|
Email: s.Email,
|
||||||
|
Status: s.Status,
|
||||||
|
CreatedAt: s.CreatedAt,
|
||||||
|
UpdatedAt: s.UpdatedAt,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewListMailingListSubscribersOutput(
|
||||||
|
p *page.Page[*coredata.MailingListSubscriber, coredata.MailingListSubscriberOrderField],
|
||||||
|
) ListMailingListSubscribersOutput {
|
||||||
|
subscribers := make([]*MailingListSubscriber, 0, len(p.Data))
|
||||||
|
for _, s := range p.Data {
|
||||||
|
subscribers = append(subscribers, NewMailingListSubscriber(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
var nextCursor *page.CursorKey
|
||||||
|
|
||||||
|
if len(p.Data) > 0 {
|
||||||
|
cursorKey := p.Data[len(p.Data)-1].CursorKey(p.Cursor.OrderBy.Field)
|
||||||
|
nextCursor = &cursorKey
|
||||||
|
}
|
||||||
|
|
||||||
|
return ListMailingListSubscribersOutput{
|
||||||
|
NextCursor: nextCursor,
|
||||||
|
MailingListSubscribers: subscribers,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMailingListUpdate(u *coredata.MailingListUpdate) *MailingListUpdate {
|
||||||
|
return &MailingListUpdate{
|
||||||
|
ID: u.ID,
|
||||||
|
OrganizationID: u.OrganizationID,
|
||||||
|
MailingListID: u.MailingListID,
|
||||||
|
Title: u.Title,
|
||||||
|
Body: u.Body,
|
||||||
|
Status: u.Status,
|
||||||
|
CreatedAt: u.CreatedAt,
|
||||||
|
UpdatedAt: u.UpdatedAt,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewListMailingListUpdatesOutput(
|
||||||
|
p *page.Page[*coredata.MailingListUpdate, coredata.MailingListUpdateOrderField],
|
||||||
|
) ListMailingListUpdatesOutput {
|
||||||
|
updates := make([]*MailingListUpdate, 0, len(p.Data))
|
||||||
|
for _, u := range p.Data {
|
||||||
|
updates = append(updates, NewMailingListUpdate(u))
|
||||||
|
}
|
||||||
|
|
||||||
|
var nextCursor *page.CursorKey
|
||||||
|
|
||||||
|
if len(p.Data) > 0 {
|
||||||
|
cursorKey := p.Data[len(p.Data)-1].CursorKey(p.Cursor.OrderBy.Field)
|
||||||
|
nextCursor = &cursorKey
|
||||||
|
}
|
||||||
|
|
||||||
|
return ListMailingListUpdatesOutput{
|
||||||
|
NextCursor: nextCursor,
|
||||||
|
MailingListUpdates: updates,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -35,6 +35,7 @@ import (
|
|||||||
"go.probo.inc/probo/pkg/filemanager"
|
"go.probo.inc/probo/pkg/filemanager"
|
||||||
"go.probo.inc/probo/pkg/iam"
|
"go.probo.inc/probo/pkg/iam"
|
||||||
"go.probo.inc/probo/pkg/itam"
|
"go.probo.inc/probo/pkg/itam"
|
||||||
|
"go.probo.inc/probo/pkg/mailman"
|
||||||
"go.probo.inc/probo/pkg/probo"
|
"go.probo.inc/probo/pkg/probo"
|
||||||
"go.probo.inc/probo/pkg/resourcealias"
|
"go.probo.inc/probo/pkg/resourcealias"
|
||||||
"go.probo.inc/probo/pkg/riskmanagement"
|
"go.probo.inc/probo/pkg/riskmanagement"
|
||||||
@@ -56,6 +57,7 @@ func NewMux(
|
|||||||
cookieBannerSvc *cookiebanner.Service,
|
cookieBannerSvc *cookiebanner.Service,
|
||||||
riskManagementSvc *riskmanagement.Service,
|
riskManagementSvc *riskmanagement.Service,
|
||||||
itamSvc *itam.Service,
|
itamSvc *itam.Service,
|
||||||
|
mailmanSvc *mailman.Service,
|
||||||
tokenSecret string,
|
tokenSecret string,
|
||||||
fileManagerSvc *filemanager.Service,
|
fileManagerSvc *filemanager.Service,
|
||||||
baseURL *baseurl.BaseURL,
|
baseURL *baseurl.BaseURL,
|
||||||
@@ -75,6 +77,7 @@ func NewMux(
|
|||||||
cookieBanner: cookieBannerSvc,
|
cookieBanner: cookieBannerSvc,
|
||||||
riskManagement: riskManagementSvc,
|
riskManagement: riskManagementSvc,
|
||||||
itamSvc: itamSvc,
|
itamSvc: itamSvc,
|
||||||
|
mailman: mailmanSvc,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
fileManager: fileManagerSvc,
|
fileManager: fileManagerSvc,
|
||||||
baseURL: baseURL,
|
baseURL: baseURL,
|
||||||
|
|||||||
Reference in New Issue
Block a user