Change document version
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
41
pkg/agents/agents.go
Normal file
41
pkg/agents/agents.go
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package agents
|
||||
|
||||
import (
|
||||
"github.com/openai/openai-go"
|
||||
"github.com/openai/openai-go/option"
|
||||
"go.gearno.de/kit/log"
|
||||
)
|
||||
|
||||
type (
|
||||
Agent struct {
|
||||
l *log.Logger
|
||||
cfg Config
|
||||
client *openai.Client
|
||||
}
|
||||
|
||||
Config struct {
|
||||
OpenAIAPIKey string
|
||||
Temperature float64
|
||||
ModelName string
|
||||
}
|
||||
)
|
||||
|
||||
func NewAgent(l *log.Logger, cfg Config) *Agent {
|
||||
client := openai.NewClient(option.WithAPIKey(cfg.OpenAIAPIKey))
|
||||
|
||||
return &Agent{l: l, cfg: cfg, client: &client}
|
||||
}
|
||||
70
pkg/agents/changelog_generator.go
Normal file
70
pkg/agents/changelog_generator.go
Normal file
@@ -0,0 +1,70 @@
|
||||
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package agents
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/openai/openai-go"
|
||||
"github.com/openai/openai-go/packages/param"
|
||||
)
|
||||
|
||||
const (
|
||||
changelogGeneratorSystemPrompt = `
|
||||
# Role:You are an assistant that creates clear and concise changelogs.
|
||||
|
||||
# Objective
|
||||
Given two versions of a document — the "old version" and the "new version" — identify and summarize all meaningful changes between them.
|
||||
Focus on additions, deletions, modifications, and restructuring.
|
||||
|
||||
# Response Format
|
||||
Respond with simple and short phrases that describe the changes, if possible use a single phrase.
|
||||
|
||||
# Change types
|
||||
Change types can include: "Added", "Removed", "Updated", "Reworded", "Reorganized", "Fixed", etc.
|
||||
|
||||
# SOP
|
||||
- Be objective and neutral in tone.
|
||||
- Do not comment on the quality of the change.
|
||||
- Use the language of the document.
|
||||
|
||||
**Example output format:**
|
||||
Respond ONLY with the phrase that describes the changes. No explanation, no markdown, no preamble. Like this:
|
||||
Added Clause about sharing personal information with trusted partners
|
||||
`
|
||||
)
|
||||
|
||||
func (a *Agent) GenerateChangelog(ctx context.Context, oldContent string, newContent string) (*string, error) {
|
||||
model := openai.ChatModel(a.cfg.ModelName)
|
||||
chatCompletion, err := a.client.Chat.Completions.New(ctx, openai.ChatCompletionNewParams{
|
||||
Messages: []openai.ChatCompletionMessageParamUnion{
|
||||
openai.SystemMessage(changelogGeneratorSystemPrompt),
|
||||
openai.UserMessage(fmt.Sprintf(`Old content: %s`, oldContent)),
|
||||
openai.UserMessage(fmt.Sprintf(`New content: %s`, newContent)),
|
||||
},
|
||||
Model: model,
|
||||
Temperature: param.NewOpt(a.cfg.Temperature),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse vendor info: %w", err)
|
||||
}
|
||||
|
||||
if len(chatCompletion.Choices) == 0 {
|
||||
return nil, fmt.Errorf("no completion choices returned from API")
|
||||
}
|
||||
|
||||
return &chatCompletion.Choices[0].Message.Content, nil
|
||||
}
|
||||
@@ -20,24 +20,10 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/openai/openai-go"
|
||||
"github.com/openai/openai-go/option"
|
||||
"github.com/openai/openai-go/packages/param"
|
||||
"go.gearno.de/kit/log"
|
||||
)
|
||||
|
||||
type (
|
||||
VendorAssessment struct {
|
||||
l *log.Logger
|
||||
cfg Config
|
||||
client *openai.Client
|
||||
}
|
||||
|
||||
Config struct {
|
||||
OpenAIAPIKey string
|
||||
Temperature float64
|
||||
ModelName string
|
||||
}
|
||||
|
||||
vendorInfo struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
@@ -58,7 +44,7 @@ type (
|
||||
)
|
||||
|
||||
const (
|
||||
systemPrompt = `
|
||||
assessVendorSystemPrompt = `
|
||||
# Role: You are a compliance assistant.
|
||||
|
||||
# Objective
|
||||
@@ -136,21 +122,15 @@ const (
|
||||
`
|
||||
)
|
||||
|
||||
func NewVendorAssessment(l *log.Logger, cfg Config) *VendorAssessment {
|
||||
client := openai.NewClient(option.WithAPIKey(cfg.OpenAIAPIKey))
|
||||
|
||||
return &VendorAssessment{l: l, cfg: cfg, client: &client}
|
||||
}
|
||||
|
||||
func (va *VendorAssessment) Fetch(ctx context.Context, websiteURL string) (*vendorInfo, error) {
|
||||
model := openai.ChatModel(va.cfg.ModelName)
|
||||
chatCompletion, err := va.client.Chat.Completions.New(ctx, openai.ChatCompletionNewParams{
|
||||
func (a *Agent) AssessVendor(ctx context.Context, websiteURL string) (*vendorInfo, error) {
|
||||
model := openai.ChatModel(a.cfg.ModelName)
|
||||
chatCompletion, err := a.client.Chat.Completions.New(ctx, openai.ChatCompletionNewParams{
|
||||
Messages: []openai.ChatCompletionMessageParamUnion{
|
||||
openai.SystemMessage(systemPrompt),
|
||||
openai.SystemMessage(assessVendorSystemPrompt),
|
||||
openai.UserMessage(websiteURL),
|
||||
},
|
||||
Model: model,
|
||||
Temperature: param.NewOpt(va.cfg.Temperature),
|
||||
Temperature: param.NewOpt(a.cfg.Temperature),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse vendor info: %w", err)
|
||||
|
||||
@@ -30,6 +30,8 @@ type (
|
||||
DocumentVersion struct {
|
||||
ID gid.GID `db:"id"`
|
||||
DocumentID gid.GID `db:"document_id"`
|
||||
Title string `db:"title"`
|
||||
OwnerID gid.GID `db:"owner_id"`
|
||||
VersionNumber int `db:"version_number"`
|
||||
Content string `db:"content"`
|
||||
Changelog string `db:"changelog"`
|
||||
@@ -55,6 +57,8 @@ func (p *DocumentVersions) LoadByDocumentID(
|
||||
SELECT
|
||||
id,
|
||||
document_id,
|
||||
title,
|
||||
owner_id,
|
||||
version_number,
|
||||
content,
|
||||
changelog,
|
||||
@@ -71,10 +75,11 @@ WHERE
|
||||
AND document_id = @document_id
|
||||
AND %s
|
||||
`
|
||||
|
||||
q = fmt.Sprintf(q, scope.SQLFragment(), cursor.SQLFragment())
|
||||
|
||||
args := pgx.StrictNamedArgs{"document_id": documentID}
|
||||
args := pgx.StrictNamedArgs{
|
||||
"document_id": documentID,
|
||||
}
|
||||
maps.Copy(args, scope.SQLArguments())
|
||||
maps.Copy(args, cursor.SQLArguments())
|
||||
|
||||
@@ -112,6 +117,8 @@ func (p *DocumentVersion) LoadByID(
|
||||
SELECT
|
||||
id,
|
||||
document_id,
|
||||
title,
|
||||
owner_id,
|
||||
version_number,
|
||||
content,
|
||||
changelog,
|
||||
@@ -131,7 +138,9 @@ LIMIT 1;
|
||||
|
||||
q = fmt.Sprintf(q, scope.SQLFragment())
|
||||
|
||||
args := pgx.StrictNamedArgs{"document_version_id": documentVersionID}
|
||||
args := pgx.StrictNamedArgs{
|
||||
"document_version_id": documentVersionID,
|
||||
}
|
||||
maps.Copy(args, scope.SQLArguments())
|
||||
|
||||
rows, err := conn.Query(ctx, q, args)
|
||||
@@ -159,6 +168,8 @@ INSERT INTO document_versions (
|
||||
tenant_id,
|
||||
id,
|
||||
document_id,
|
||||
title,
|
||||
owner_id,
|
||||
version_number,
|
||||
content,
|
||||
changelog,
|
||||
@@ -166,10 +177,13 @@ INSERT INTO document_versions (
|
||||
status,
|
||||
created_at,
|
||||
updated_at
|
||||
) VALUES (
|
||||
)
|
||||
VALUES (
|
||||
@tenant_id,
|
||||
@id,
|
||||
@document_id,
|
||||
@title,
|
||||
@owner_id,
|
||||
@version_number,
|
||||
@content,
|
||||
@changelog,
|
||||
@@ -179,24 +193,24 @@ INSERT INTO document_versions (
|
||||
@updated_at
|
||||
)
|
||||
`
|
||||
|
||||
now := time.Now()
|
||||
args := pgx.StrictNamedArgs{
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"id": p.ID,
|
||||
"document_id": p.DocumentID,
|
||||
"title": p.Title,
|
||||
"owner_id": p.OwnerID,
|
||||
"version_number": p.VersionNumber,
|
||||
"content": p.Content,
|
||||
"changelog": p.Changelog,
|
||||
"created_by": p.CreatedBy,
|
||||
"status": p.Status,
|
||||
"created_at": now,
|
||||
"updated_at": now,
|
||||
"created_at": p.CreatedAt,
|
||||
"updated_at": p.UpdatedAt,
|
||||
}
|
||||
|
||||
_, err := conn.Exec(ctx, q, args)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating/updating document version: %w", err)
|
||||
return fmt.Errorf("error creating document version: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -213,6 +227,8 @@ func (p *DocumentVersion) LoadByDocumentIDAndVersionNumber(
|
||||
SELECT
|
||||
id,
|
||||
document_id,
|
||||
title,
|
||||
owner_id,
|
||||
version_number,
|
||||
content,
|
||||
changelog,
|
||||
@@ -237,7 +253,6 @@ LIMIT 1;
|
||||
"document_id": documentID,
|
||||
"version_number": versionNumber,
|
||||
}
|
||||
|
||||
maps.Copy(args, scope.SQLArguments())
|
||||
|
||||
rows, err := conn.Query(ctx, q, args)
|
||||
@@ -265,6 +280,8 @@ func (p *DocumentVersion) LoadLatestVersion(
|
||||
SELECT
|
||||
id,
|
||||
document_id,
|
||||
title,
|
||||
owner_id,
|
||||
version_number,
|
||||
content,
|
||||
changelog,
|
||||
@@ -282,13 +299,11 @@ WHERE
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 1;
|
||||
`
|
||||
|
||||
q = fmt.Sprintf(q, scope.SQLFragment())
|
||||
|
||||
args := pgx.StrictNamedArgs{
|
||||
"document_id": documentID,
|
||||
}
|
||||
|
||||
maps.Copy(args, scope.SQLArguments())
|
||||
|
||||
rows, err := conn.Query(ctx, q, args)
|
||||
@@ -313,6 +328,8 @@ func (p DocumentVersion) Update(
|
||||
) error {
|
||||
q := `
|
||||
UPDATE document_versions SET
|
||||
title = @title,
|
||||
owner_id = @owner_id,
|
||||
changelog = @changelog,
|
||||
status = @status,
|
||||
content = @content,
|
||||
@@ -320,12 +337,15 @@ UPDATE document_versions SET
|
||||
published_at = @published_at,
|
||||
updated_at = @updated_at
|
||||
WHERE %s
|
||||
AND id = @document_version_id;`
|
||||
AND id = @document_version_id
|
||||
`
|
||||
|
||||
q = fmt.Sprintf(q, scope.SQLFragment())
|
||||
|
||||
args := pgx.StrictNamedArgs{
|
||||
"document_version_id": p.ID,
|
||||
"title": p.Title,
|
||||
"owner_id": p.OwnerID,
|
||||
"changelog": p.Changelog,
|
||||
"status": p.Status,
|
||||
"content": p.Content,
|
||||
|
||||
35
pkg/coredata/migrations/20250603T231005Z.sql
Normal file
35
pkg/coredata/migrations/20250603T231005Z.sql
Normal file
@@ -0,0 +1,35 @@
|
||||
ALTER INDEX policy_versions_pkey RENAME TO document_versions_pkey;
|
||||
|
||||
ALTER TABLE document_versions
|
||||
RENAME CONSTRAINT policy_versions_policy_id_version_number_key
|
||||
TO document_versions_document_id_version_number_key;
|
||||
|
||||
ALTER TABLE document_versions
|
||||
RENAME CONSTRAINT policy_versions_published_by_fkey
|
||||
TO document_versions_published_by_fkey;
|
||||
|
||||
ALTER TABLE document_versions
|
||||
ADD CONSTRAINT document_versions_created_by_fkey
|
||||
FOREIGN KEY (created_by) REFERENCES peoples(id)
|
||||
ON DELETE RESTRICT
|
||||
ON UPDATE CASCADE;
|
||||
|
||||
ALTER TABLE document_versions
|
||||
ADD COLUMN title TEXT,
|
||||
ADD COLUMN owner_id TEXT;
|
||||
|
||||
UPDATE document_versions dv
|
||||
SET title = d.title,
|
||||
owner_id = d.owner_id
|
||||
FROM documents d
|
||||
WHERE dv.document_id = d.id;
|
||||
|
||||
ALTER TABLE document_versions
|
||||
ALTER COLUMN title SET NOT NULL,
|
||||
ALTER COLUMN owner_id SET NOT NULL;
|
||||
|
||||
ALTER TABLE document_versions
|
||||
ADD CONSTRAINT document_versions_owner_id_fkey
|
||||
FOREIGN KEY (owner_id) REFERENCES peoples(id)
|
||||
ON DELETE RESTRICT
|
||||
ON UPDATE CASCADE;
|
||||
@@ -69,10 +69,58 @@ func (s *DocumentService) Get(
|
||||
return document, nil
|
||||
}
|
||||
|
||||
func (s DocumentService) GenerateChangelog(
|
||||
ctx context.Context,
|
||||
documentID gid.GID,
|
||||
) (*string, error) {
|
||||
draftVersion := &coredata.DocumentVersion{}
|
||||
publishedVersion := &coredata.DocumentVersion{}
|
||||
|
||||
err := s.svc.pg.WithConn(
|
||||
ctx,
|
||||
func(conn pg.Conn) error {
|
||||
if err := draftVersion.LoadLatestVersion(ctx, conn, s.svc.scope, documentID); err != nil {
|
||||
return fmt.Errorf("cannot load draft version: %w", err)
|
||||
}
|
||||
|
||||
if draftVersion.Status != coredata.DocumentStatusDraft {
|
||||
return fmt.Errorf("latest version is not a draft")
|
||||
}
|
||||
|
||||
document := &coredata.Document{}
|
||||
if err := document.LoadByID(ctx, conn, s.svc.scope, documentID); err != nil {
|
||||
return fmt.Errorf("cannot load document: %w", err)
|
||||
}
|
||||
|
||||
if document.CurrentPublishedVersion == nil {
|
||||
publishedVersion.Content = ""
|
||||
} else {
|
||||
if err := publishedVersion.LoadByDocumentIDAndVersionNumber(ctx, conn, s.svc.scope, documentID, *document.CurrentPublishedVersion); err != nil {
|
||||
return fmt.Errorf("cannot load published version: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
changelog, err := s.svc.agent.GenerateChangelog(ctx, publishedVersion.Content, draftVersion.Content)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to generate changelog: %w", err)
|
||||
}
|
||||
|
||||
return changelog, nil
|
||||
}
|
||||
|
||||
func (s *DocumentService) PublishVersion(
|
||||
ctx context.Context,
|
||||
documentID gid.GID,
|
||||
publishedBy gid.GID,
|
||||
changelog *string,
|
||||
) (*coredata.Document, *coredata.DocumentVersion, error) {
|
||||
document := &coredata.Document{}
|
||||
documentVersion := &coredata.DocumentVersion{}
|
||||
@@ -93,6 +141,10 @@ func (s *DocumentService) PublishVersion(
|
||||
return fmt.Errorf("cannot publish version")
|
||||
}
|
||||
|
||||
if changelog != nil {
|
||||
documentVersion.Changelog = *changelog
|
||||
}
|
||||
|
||||
document.CurrentPublishedVersion = &documentVersion.VersionNumber
|
||||
document.UpdatedAt = now
|
||||
|
||||
@@ -142,6 +194,8 @@ func (s *DocumentService) Create(
|
||||
documentVersion := &coredata.DocumentVersion{
|
||||
ID: documentVersionID,
|
||||
DocumentID: documentID,
|
||||
Title: req.Title,
|
||||
OwnerID: req.OwnerID,
|
||||
VersionNumber: 1,
|
||||
Content: req.Content,
|
||||
Status: coredata.DocumentStatusDraft,
|
||||
@@ -149,6 +203,7 @@ func (s *DocumentService) Create(
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
|
||||
err := s.svc.pg.WithTx(
|
||||
ctx,
|
||||
func(conn pg.Conn) error {
|
||||
@@ -348,6 +403,7 @@ func (s *DocumentService) UpdateVersion(
|
||||
req UpdateDocumentVersionRequest,
|
||||
) (*coredata.DocumentVersion, error) {
|
||||
documentVersion := &coredata.DocumentVersion{}
|
||||
document := &coredata.Document{}
|
||||
|
||||
err := s.svc.pg.WithTx(
|
||||
ctx,
|
||||
@@ -356,10 +412,16 @@ func (s *DocumentService) UpdateVersion(
|
||||
return fmt.Errorf("cannot load document version %q: %w", req.ID, err)
|
||||
}
|
||||
|
||||
if err := document.LoadByID(ctx, conn, s.svc.scope, documentVersion.DocumentID); err != nil {
|
||||
return fmt.Errorf("cannot load document %q: %w", documentVersion.DocumentID, err)
|
||||
}
|
||||
|
||||
if documentVersion.Status != coredata.DocumentStatusDraft {
|
||||
return fmt.Errorf("cannot update published version")
|
||||
}
|
||||
|
||||
documentVersion.Title = document.Title
|
||||
documentVersion.OwnerID = document.OwnerID
|
||||
documentVersion.Content = req.Content
|
||||
documentVersion.UpdatedAt = time.Now()
|
||||
|
||||
@@ -473,12 +535,17 @@ func (s *DocumentService) CreateDraft(
|
||||
draftVersionID := gid.New(s.svc.scope.GetTenantID(), coredata.DocumentVersionEntityType)
|
||||
|
||||
latestVersion := &coredata.DocumentVersion{}
|
||||
document := &coredata.Document{}
|
||||
draftVersion := &coredata.DocumentVersion{}
|
||||
now := time.Now()
|
||||
|
||||
err := s.svc.pg.WithTx(
|
||||
ctx,
|
||||
func(conn pg.Conn) error {
|
||||
if err := document.LoadByID(ctx, conn, s.svc.scope, documentID); err != nil {
|
||||
return fmt.Errorf("cannot load document: %w", err)
|
||||
}
|
||||
|
||||
if err := latestVersion.LoadLatestVersion(ctx, conn, s.svc.scope, documentID); err != nil {
|
||||
return fmt.Errorf("cannot load latest version: %w", err)
|
||||
}
|
||||
@@ -489,6 +556,8 @@ func (s *DocumentService) CreateDraft(
|
||||
|
||||
draftVersion.ID = draftVersionID
|
||||
draftVersion.DocumentID = documentID
|
||||
draftVersion.Title = document.Title
|
||||
draftVersion.OwnerID = document.OwnerID
|
||||
draftVersion.VersionNumber = latestVersion.VersionNumber + 1
|
||||
draftVersion.Content = latestVersion.Content
|
||||
draftVersion.Status = coredata.DocumentStatusDraft
|
||||
@@ -640,6 +709,7 @@ func (s *DocumentService) Update(
|
||||
documentID gid.GID,
|
||||
newOwnerID *gid.GID,
|
||||
documentType *coredata.DocumentType,
|
||||
title *string,
|
||||
) (*coredata.Document, error) {
|
||||
document := &coredata.Document{}
|
||||
people := &coredata.People{}
|
||||
@@ -662,6 +732,11 @@ func (s *DocumentService) Update(
|
||||
if documentType != nil {
|
||||
document.DocumentType = *documentType
|
||||
}
|
||||
|
||||
if title != nil {
|
||||
document.Title = *title
|
||||
}
|
||||
|
||||
document.UpdatedAt = now
|
||||
|
||||
if err := document.Update(ctx, tx, s.svc.scope); err != nil {
|
||||
|
||||
@@ -29,13 +29,13 @@ import (
|
||||
|
||||
type (
|
||||
Service struct {
|
||||
pg *pg.Client
|
||||
s3 *s3.Client
|
||||
bucket string
|
||||
encryptionKey cipher.EncryptionKey
|
||||
hostname string
|
||||
tokenSecret string
|
||||
vendorAssessment agents.Config
|
||||
pg *pg.Client
|
||||
s3 *s3.Client
|
||||
bucket string
|
||||
encryptionKey cipher.EncryptionKey
|
||||
hostname string
|
||||
tokenSecret string
|
||||
agentConfig agents.Config
|
||||
}
|
||||
|
||||
TenantService struct {
|
||||
@@ -46,7 +46,7 @@ type (
|
||||
scope coredata.Scoper
|
||||
hostname string
|
||||
tokenSecret string
|
||||
vendorAssessment *agents.VendorAssessment
|
||||
agent *agents.Agent
|
||||
Frameworks *FrameworkService
|
||||
Measures *MeasureService
|
||||
Tasks *TaskService
|
||||
@@ -72,20 +72,20 @@ func NewService(
|
||||
bucket string,
|
||||
hostname string,
|
||||
tokenSecret string,
|
||||
vendorAssessment agents.Config,
|
||||
agentConfig agents.Config,
|
||||
) (*Service, error) {
|
||||
if bucket == "" {
|
||||
return nil, fmt.Errorf("bucket is required")
|
||||
}
|
||||
|
||||
svc := &Service{
|
||||
pg: pgClient,
|
||||
s3: s3Client,
|
||||
bucket: bucket,
|
||||
encryptionKey: encryptionKey,
|
||||
hostname: hostname,
|
||||
tokenSecret: tokenSecret,
|
||||
vendorAssessment: vendorAssessment,
|
||||
pg: pgClient,
|
||||
s3: s3Client,
|
||||
bucket: bucket,
|
||||
encryptionKey: encryptionKey,
|
||||
hostname: hostname,
|
||||
tokenSecret: tokenSecret,
|
||||
agentConfig: agentConfig,
|
||||
}
|
||||
|
||||
return svc, nil
|
||||
@@ -93,14 +93,14 @@ func NewService(
|
||||
|
||||
func (s *Service) WithTenant(tenantID gid.TenantID) *TenantService {
|
||||
tenantService := &TenantService{
|
||||
pg: s.pg,
|
||||
s3: s.s3,
|
||||
bucket: s.bucket,
|
||||
encryptionKey: s.encryptionKey,
|
||||
hostname: s.hostname,
|
||||
scope: coredata.NewScope(tenantID),
|
||||
tokenSecret: s.tokenSecret,
|
||||
vendorAssessment: agents.NewVendorAssessment(nil, s.vendorAssessment),
|
||||
pg: s.pg,
|
||||
s3: s.s3,
|
||||
bucket: s.bucket,
|
||||
encryptionKey: s.encryptionKey,
|
||||
hostname: s.hostname,
|
||||
scope: coredata.NewScope(tenantID),
|
||||
tokenSecret: s.tokenSecret,
|
||||
agent: agents.NewAgent(nil, s.agentConfig),
|
||||
}
|
||||
|
||||
tenantService.Frameworks = &FrameworkService{svc: tenantService}
|
||||
|
||||
@@ -447,7 +447,7 @@ func (s VendorService) Assess(
|
||||
ctx context.Context,
|
||||
req AssessVendorRequest,
|
||||
) (*coredata.Vendor, error) {
|
||||
vendorInfo, err := s.svc.vendorAssessment.Fetch(ctx, req.WebsiteURL)
|
||||
vendorInfo, err := s.svc.agent.AssessVendor(ctx, req.WebsiteURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to assess vendor info: %w", err)
|
||||
}
|
||||
|
||||
@@ -187,13 +187,13 @@ func (impl *Implm) Run(
|
||||
}
|
||||
}
|
||||
|
||||
vendorAssessmentConfig := agents.Config{
|
||||
agentConfig := agents.Config{
|
||||
OpenAIAPIKey: impl.cfg.OpenAI.APIKey,
|
||||
Temperature: impl.cfg.OpenAI.Temperature,
|
||||
ModelName: impl.cfg.OpenAI.ModelName,
|
||||
}
|
||||
|
||||
vendorAssessment := agents.NewVendorAssessment(l.Named("vendor-assessment"), vendorAssessmentConfig)
|
||||
agent := agents.NewAgent(l.Named("agent"), agentConfig)
|
||||
|
||||
usrmgrService, err := usrmgr.NewService(
|
||||
ctx,
|
||||
@@ -215,7 +215,7 @@ func (impl *Implm) Run(
|
||||
impl.cfg.AWS.Bucket,
|
||||
impl.cfg.Hostname,
|
||||
impl.cfg.Auth.Cookie.Secret,
|
||||
vendorAssessmentConfig,
|
||||
agentConfig,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot create probo service: %w", err)
|
||||
@@ -227,7 +227,7 @@ func (impl *Implm) Run(
|
||||
Probo: proboService,
|
||||
Usrmgr: usrmgrService,
|
||||
ConnectorRegistry: defaultConnectorRegistry,
|
||||
VendorAssessment: vendorAssessment,
|
||||
Agent: agent,
|
||||
SafeRedirect: &saferedirect.SafeRedirect{AllowedHost: impl.cfg.Hostname},
|
||||
Logger: l.Named("http.server"),
|
||||
Auth: console_v1.AuthConfig{
|
||||
|
||||
@@ -1157,6 +1157,9 @@ type Mutation {
|
||||
publishDocumentVersion(
|
||||
input: PublishDocumentVersionInput!
|
||||
): PublishDocumentVersionPayload!
|
||||
generateDocumentChangelog(
|
||||
input: GenerateDocumentChangelogInput!
|
||||
): GenerateDocumentChangelogPayload!
|
||||
createDraftDocumentVersion(
|
||||
input: CreateDraftDocumentVersionInput!
|
||||
): CreateDraftDocumentVersionPayload!
|
||||
@@ -1746,6 +1749,8 @@ type DocumentVersion implements Node {
|
||||
version: Int!
|
||||
content: String!
|
||||
changelog: String!
|
||||
title: String!
|
||||
owner: People! @goField(forceResolver: true)
|
||||
|
||||
signatures(
|
||||
first: Int
|
||||
@@ -1827,6 +1832,7 @@ type RequestSignaturePayload {
|
||||
|
||||
input PublishDocumentVersionInput {
|
||||
documentId: ID!
|
||||
changelog: String
|
||||
}
|
||||
|
||||
type PublishDocumentVersionPayload {
|
||||
@@ -1885,6 +1891,14 @@ type ExportAuditPayload {
|
||||
url: String!
|
||||
}
|
||||
|
||||
input GenerateDocumentChangelogInput {
|
||||
documentId: ID!
|
||||
}
|
||||
|
||||
type GenerateDocumentChangelogPayload {
|
||||
changelog: String!
|
||||
}
|
||||
|
||||
input AssessVendorInput {
|
||||
id: ID!
|
||||
websiteUrl: String!
|
||||
|
||||
@@ -343,10 +343,12 @@ type ComplexityRoot struct {
|
||||
CreatedAt func(childComplexity int) int
|
||||
Document func(childComplexity int) int
|
||||
ID func(childComplexity int) int
|
||||
Owner func(childComplexity int) int
|
||||
PublishedAt func(childComplexity int) int
|
||||
PublishedBy func(childComplexity int) int
|
||||
Signatures func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentVersionSignatureOrder) int
|
||||
Status func(childComplexity int) int
|
||||
Title func(childComplexity int) int
|
||||
UpdatedAt func(childComplexity int) int
|
||||
Version func(childComplexity int) int
|
||||
}
|
||||
@@ -437,6 +439,10 @@ type ComplexityRoot struct {
|
||||
EvidenceEdge func(childComplexity int) int
|
||||
}
|
||||
|
||||
GenerateDocumentChangelogPayload struct {
|
||||
Changelog func(childComplexity int) int
|
||||
}
|
||||
|
||||
ImportFrameworkPayload struct {
|
||||
FrameworkEdge func(childComplexity int) int
|
||||
}
|
||||
@@ -513,6 +519,7 @@ type ComplexityRoot struct {
|
||||
DeleteVendorComplianceReport func(childComplexity int, input types.DeleteVendorComplianceReportInput) int
|
||||
ExportAudit func(childComplexity int, input types.ExportAuditInput) int
|
||||
FulfillEvidence func(childComplexity int, input types.FulfillEvidenceInput) int
|
||||
GenerateDocumentChangelog func(childComplexity int, input types.GenerateDocumentChangelogInput) int
|
||||
ImportFramework func(childComplexity int, input types.ImportFrameworkInput) int
|
||||
ImportMeasure func(childComplexity int, input types.ImportMeasureInput) int
|
||||
InviteUser func(childComplexity int, input types.InviteUserInput) int
|
||||
@@ -889,6 +896,7 @@ type DocumentResolver interface {
|
||||
type DocumentVersionResolver interface {
|
||||
Document(ctx context.Context, obj *types.DocumentVersion) (*types.Document, error)
|
||||
|
||||
Owner(ctx context.Context, obj *types.DocumentVersion) (*types.People, error)
|
||||
Signatures(ctx context.Context, obj *types.DocumentVersion, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentVersionSignatureOrder) (*types.DocumentVersionSignatureConnection, error)
|
||||
PublishedBy(ctx context.Context, obj *types.DocumentVersion) (*types.People, error)
|
||||
}
|
||||
@@ -963,6 +971,7 @@ type MutationResolver interface {
|
||||
UpdateDocument(ctx context.Context, input types.UpdateDocumentInput) (*types.UpdateDocumentPayload, error)
|
||||
DeleteDocument(ctx context.Context, input types.DeleteDocumentInput) (*types.DeleteDocumentPayload, error)
|
||||
PublishDocumentVersion(ctx context.Context, input types.PublishDocumentVersionInput) (*types.PublishDocumentVersionPayload, error)
|
||||
GenerateDocumentChangelog(ctx context.Context, input types.GenerateDocumentChangelogInput) (*types.GenerateDocumentChangelogPayload, error)
|
||||
CreateDraftDocumentVersion(ctx context.Context, input types.CreateDraftDocumentVersionInput) (*types.CreateDraftDocumentVersionPayload, error)
|
||||
UpdateDocumentVersion(ctx context.Context, input types.UpdateDocumentVersionInput) (*types.UpdateDocumentVersionPayload, error)
|
||||
RequestSignature(ctx context.Context, input types.RequestSignatureInput) (*types.RequestSignaturePayload, error)
|
||||
@@ -1897,6 +1906,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
|
||||
|
||||
return e.complexity.DocumentVersion.ID(childComplexity), true
|
||||
|
||||
case "DocumentVersion.owner":
|
||||
if e.complexity.DocumentVersion.Owner == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.DocumentVersion.Owner(childComplexity), true
|
||||
|
||||
case "DocumentVersion.publishedAt":
|
||||
if e.complexity.DocumentVersion.PublishedAt == nil {
|
||||
break
|
||||
@@ -1930,6 +1946,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
|
||||
|
||||
return e.complexity.DocumentVersion.Status(childComplexity), true
|
||||
|
||||
case "DocumentVersion.title":
|
||||
if e.complexity.DocumentVersion.Title == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.DocumentVersion.Title(childComplexity), true
|
||||
|
||||
case "DocumentVersion.updatedAt":
|
||||
if e.complexity.DocumentVersion.UpdatedAt == nil {
|
||||
break
|
||||
@@ -2278,6 +2301,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
|
||||
|
||||
return e.complexity.FulfillEvidencePayload.EvidenceEdge(childComplexity), true
|
||||
|
||||
case "GenerateDocumentChangelogPayload.changelog":
|
||||
if e.complexity.GenerateDocumentChangelogPayload.Changelog == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.GenerateDocumentChangelogPayload.Changelog(childComplexity), true
|
||||
|
||||
case "ImportFrameworkPayload.frameworkEdge":
|
||||
if e.complexity.ImportFrameworkPayload.FrameworkEdge == nil {
|
||||
break
|
||||
@@ -2892,6 +2922,18 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
|
||||
|
||||
return e.complexity.Mutation.FulfillEvidence(childComplexity, args["input"].(types.FulfillEvidenceInput)), true
|
||||
|
||||
case "Mutation.generateDocumentChangelog":
|
||||
if e.complexity.Mutation.GenerateDocumentChangelog == nil {
|
||||
break
|
||||
}
|
||||
|
||||
args, err := ec.field_Mutation_generateDocumentChangelog_args(ctx, rawArgs)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
return e.complexity.Mutation.GenerateDocumentChangelog(childComplexity, args["input"].(types.GenerateDocumentChangelogInput)), true
|
||||
|
||||
case "Mutation.importFramework":
|
||||
if e.complexity.Mutation.ImportFramework == nil {
|
||||
break
|
||||
@@ -4547,6 +4589,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
|
||||
ec.unmarshalInputExportAuditInput,
|
||||
ec.unmarshalInputFrameworkOrder,
|
||||
ec.unmarshalInputFulfillEvidenceInput,
|
||||
ec.unmarshalInputGenerateDocumentChangelogInput,
|
||||
ec.unmarshalInputImportFrameworkInput,
|
||||
ec.unmarshalInputImportMeasureInput,
|
||||
ec.unmarshalInputInviteUserInput,
|
||||
@@ -5837,6 +5880,9 @@ type Mutation {
|
||||
publishDocumentVersion(
|
||||
input: PublishDocumentVersionInput!
|
||||
): PublishDocumentVersionPayload!
|
||||
generateDocumentChangelog(
|
||||
input: GenerateDocumentChangelogInput!
|
||||
): GenerateDocumentChangelogPayload!
|
||||
createDraftDocumentVersion(
|
||||
input: CreateDraftDocumentVersionInput!
|
||||
): CreateDraftDocumentVersionPayload!
|
||||
@@ -6426,6 +6472,8 @@ type DocumentVersion implements Node {
|
||||
version: Int!
|
||||
content: String!
|
||||
changelog: String!
|
||||
title: String!
|
||||
owner: People! @goField(forceResolver: true)
|
||||
|
||||
signatures(
|
||||
first: Int
|
||||
@@ -6507,6 +6555,7 @@ type RequestSignaturePayload {
|
||||
|
||||
input PublishDocumentVersionInput {
|
||||
documentId: ID!
|
||||
changelog: String
|
||||
}
|
||||
|
||||
type PublishDocumentVersionPayload {
|
||||
@@ -6565,6 +6614,14 @@ type ExportAuditPayload {
|
||||
url: String!
|
||||
}
|
||||
|
||||
input GenerateDocumentChangelogInput {
|
||||
documentId: ID!
|
||||
}
|
||||
|
||||
type GenerateDocumentChangelogPayload {
|
||||
changelog: String!
|
||||
}
|
||||
|
||||
input AssessVendorInput {
|
||||
id: ID!
|
||||
websiteUrl: String!
|
||||
@@ -8799,6 +8856,29 @@ func (ec *executionContext) field_Mutation_fulfillEvidence_argsInput(
|
||||
return zeroVal, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) field_Mutation_generateDocumentChangelog_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
|
||||
var err error
|
||||
args := map[string]any{}
|
||||
arg0, err := ec.field_Mutation_generateDocumentChangelog_argsInput(ctx, rawArgs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
args["input"] = arg0
|
||||
return args, nil
|
||||
}
|
||||
func (ec *executionContext) field_Mutation_generateDocumentChangelog_argsInput(
|
||||
ctx context.Context,
|
||||
rawArgs map[string]any,
|
||||
) (types.GenerateDocumentChangelogInput, error) {
|
||||
ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("input"))
|
||||
if tmp, ok := rawArgs["input"]; ok {
|
||||
return ec.unmarshalNGenerateDocumentChangelogInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐGenerateDocumentChangelogInput(ctx, tmp)
|
||||
}
|
||||
|
||||
var zeroVal types.GenerateDocumentChangelogInput
|
||||
return zeroVal, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) field_Mutation_importFramework_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
|
||||
var err error
|
||||
args := map[string]any{}
|
||||
@@ -17134,6 +17214,116 @@ func (ec *executionContext) fieldContext_DocumentVersion_changelog(_ context.Con
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _DocumentVersion_title(ctx context.Context, field graphql.CollectedField, obj *types.DocumentVersion) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_DocumentVersion_title(ctx, field)
|
||||
if err != nil {
|
||||
return graphql.Null
|
||||
}
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = graphql.Null
|
||||
}
|
||||
}()
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return obj.Title, nil
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
if !graphql.HasFieldError(ctx, fc) {
|
||||
ec.Errorf(ctx, "must not be null")
|
||||
}
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(string)
|
||||
fc.Result = res
|
||||
return ec.marshalNString2string(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_DocumentVersion_title(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "DocumentVersion",
|
||||
Field: field,
|
||||
IsMethod: false,
|
||||
IsResolver: false,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
return nil, errors.New("field of type String does not have child fields")
|
||||
},
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _DocumentVersion_owner(ctx context.Context, field graphql.CollectedField, obj *types.DocumentVersion) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_DocumentVersion_owner(ctx, field)
|
||||
if err != nil {
|
||||
return graphql.Null
|
||||
}
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = graphql.Null
|
||||
}
|
||||
}()
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return ec.resolvers.DocumentVersion().Owner(rctx, obj)
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
if !graphql.HasFieldError(ctx, fc) {
|
||||
ec.Errorf(ctx, "must not be null")
|
||||
}
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(*types.People)
|
||||
fc.Result = res
|
||||
return ec.marshalNPeople2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐPeople(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_DocumentVersion_owner(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "DocumentVersion",
|
||||
Field: field,
|
||||
IsMethod: true,
|
||||
IsResolver: true,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
switch field.Name {
|
||||
case "id":
|
||||
return ec.fieldContext_People_id(ctx, field)
|
||||
case "fullName":
|
||||
return ec.fieldContext_People_fullName(ctx, field)
|
||||
case "primaryEmailAddress":
|
||||
return ec.fieldContext_People_primaryEmailAddress(ctx, field)
|
||||
case "additionalEmailAddresses":
|
||||
return ec.fieldContext_People_additionalEmailAddresses(ctx, field)
|
||||
case "kind":
|
||||
return ec.fieldContext_People_kind(ctx, field)
|
||||
case "position":
|
||||
return ec.fieldContext_People_position(ctx, field)
|
||||
case "contractStartDate":
|
||||
return ec.fieldContext_People_contractStartDate(ctx, field)
|
||||
case "contractEndDate":
|
||||
return ec.fieldContext_People_contractEndDate(ctx, field)
|
||||
case "createdAt":
|
||||
return ec.fieldContext_People_createdAt(ctx, field)
|
||||
case "updatedAt":
|
||||
return ec.fieldContext_People_updatedAt(ctx, field)
|
||||
}
|
||||
return nil, fmt.Errorf("no field named %q was found under type People", field.Name)
|
||||
},
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _DocumentVersion_signatures(ctx context.Context, field graphql.CollectedField, obj *types.DocumentVersion) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_DocumentVersion_signatures(ctx, field)
|
||||
if err != nil {
|
||||
@@ -17586,6 +17776,10 @@ func (ec *executionContext) fieldContext_DocumentVersionEdge_node(_ context.Cont
|
||||
return ec.fieldContext_DocumentVersion_content(ctx, field)
|
||||
case "changelog":
|
||||
return ec.fieldContext_DocumentVersion_changelog(ctx, field)
|
||||
case "title":
|
||||
return ec.fieldContext_DocumentVersion_title(ctx, field)
|
||||
case "owner":
|
||||
return ec.fieldContext_DocumentVersion_owner(ctx, field)
|
||||
case "signatures":
|
||||
return ec.fieldContext_DocumentVersion_signatures(ctx, field)
|
||||
case "publishedBy":
|
||||
@@ -17698,6 +17892,10 @@ func (ec *executionContext) fieldContext_DocumentVersionSignature_documentVersio
|
||||
return ec.fieldContext_DocumentVersion_content(ctx, field)
|
||||
case "changelog":
|
||||
return ec.fieldContext_DocumentVersion_changelog(ctx, field)
|
||||
case "title":
|
||||
return ec.fieldContext_DocumentVersion_title(ctx, field)
|
||||
case "owner":
|
||||
return ec.fieldContext_DocumentVersion_owner(ctx, field)
|
||||
case "signatures":
|
||||
return ec.fieldContext_DocumentVersion_signatures(ctx, field)
|
||||
case "publishedBy":
|
||||
@@ -19768,6 +19966,50 @@ func (ec *executionContext) fieldContext_FulfillEvidencePayload_evidenceEdge(_ c
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _GenerateDocumentChangelogPayload_changelog(ctx context.Context, field graphql.CollectedField, obj *types.GenerateDocumentChangelogPayload) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_GenerateDocumentChangelogPayload_changelog(ctx, field)
|
||||
if err != nil {
|
||||
return graphql.Null
|
||||
}
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = graphql.Null
|
||||
}
|
||||
}()
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return obj.Changelog, nil
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
if !graphql.HasFieldError(ctx, fc) {
|
||||
ec.Errorf(ctx, "must not be null")
|
||||
}
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(string)
|
||||
fc.Result = res
|
||||
return ec.marshalNString2string(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_GenerateDocumentChangelogPayload_changelog(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "GenerateDocumentChangelogPayload",
|
||||
Field: field,
|
||||
IsMethod: false,
|
||||
IsResolver: false,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
return nil, errors.New("field of type String does not have child fields")
|
||||
},
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _ImportFrameworkPayload_frameworkEdge(ctx context.Context, field graphql.CollectedField, obj *types.ImportFrameworkPayload) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_ImportFrameworkPayload_frameworkEdge(ctx, field)
|
||||
if err != nil {
|
||||
@@ -23473,6 +23715,65 @@ func (ec *executionContext) fieldContext_Mutation_publishDocumentVersion(ctx con
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Mutation_generateDocumentChangelog(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_Mutation_generateDocumentChangelog(ctx, field)
|
||||
if err != nil {
|
||||
return graphql.Null
|
||||
}
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = graphql.Null
|
||||
}
|
||||
}()
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return ec.resolvers.Mutation().GenerateDocumentChangelog(rctx, fc.Args["input"].(types.GenerateDocumentChangelogInput))
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
if !graphql.HasFieldError(ctx, fc) {
|
||||
ec.Errorf(ctx, "must not be null")
|
||||
}
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(*types.GenerateDocumentChangelogPayload)
|
||||
fc.Result = res
|
||||
return ec.marshalNGenerateDocumentChangelogPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐGenerateDocumentChangelogPayload(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_Mutation_generateDocumentChangelog(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "Mutation",
|
||||
Field: field,
|
||||
IsMethod: true,
|
||||
IsResolver: true,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
switch field.Name {
|
||||
case "changelog":
|
||||
return ec.fieldContext_GenerateDocumentChangelogPayload_changelog(ctx, field)
|
||||
}
|
||||
return nil, fmt.Errorf("no field named %q was found under type GenerateDocumentChangelogPayload", field.Name)
|
||||
},
|
||||
}
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = ec.Recover(ctx, r)
|
||||
ec.Error(ctx, err)
|
||||
}
|
||||
}()
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
if fc.Args, err = ec.field_Mutation_generateDocumentChangelog_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return fc, err
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Mutation_createDraftDocumentVersion(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_Mutation_createDraftDocumentVersion(ctx, field)
|
||||
if err != nil {
|
||||
@@ -26456,6 +26757,10 @@ func (ec *executionContext) fieldContext_PublishDocumentVersionPayload_documentV
|
||||
return ec.fieldContext_DocumentVersion_content(ctx, field)
|
||||
case "changelog":
|
||||
return ec.fieldContext_DocumentVersion_changelog(ctx, field)
|
||||
case "title":
|
||||
return ec.fieldContext_DocumentVersion_title(ctx, field)
|
||||
case "owner":
|
||||
return ec.fieldContext_DocumentVersion_owner(ctx, field)
|
||||
case "signatures":
|
||||
return ec.fieldContext_DocumentVersion_signatures(ctx, field)
|
||||
case "publishedBy":
|
||||
@@ -29462,6 +29767,10 @@ func (ec *executionContext) fieldContext_UpdateDocumentVersionPayload_documentVe
|
||||
return ec.fieldContext_DocumentVersion_content(ctx, field)
|
||||
case "changelog":
|
||||
return ec.fieldContext_DocumentVersion_changelog(ctx, field)
|
||||
case "title":
|
||||
return ec.fieldContext_DocumentVersion_title(ctx, field)
|
||||
case "owner":
|
||||
return ec.fieldContext_DocumentVersion_owner(ctx, field)
|
||||
case "signatures":
|
||||
return ec.fieldContext_DocumentVersion_signatures(ctx, field)
|
||||
case "publishedBy":
|
||||
@@ -37516,6 +37825,33 @@ func (ec *executionContext) unmarshalInputFulfillEvidenceInput(ctx context.Conte
|
||||
return it, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalInputGenerateDocumentChangelogInput(ctx context.Context, obj any) (types.GenerateDocumentChangelogInput, error) {
|
||||
var it types.GenerateDocumentChangelogInput
|
||||
asMap := map[string]any{}
|
||||
for k, v := range obj.(map[string]any) {
|
||||
asMap[k] = v
|
||||
}
|
||||
|
||||
fieldsInOrder := [...]string{"documentId"}
|
||||
for _, k := range fieldsInOrder {
|
||||
v, ok := asMap[k]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
switch k {
|
||||
case "documentId":
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("documentId"))
|
||||
data, err := ec.unmarshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
it.DocumentID = data
|
||||
}
|
||||
}
|
||||
|
||||
return it, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalInputImportFrameworkInput(ctx context.Context, obj any) (types.ImportFrameworkInput, error) {
|
||||
var it types.ImportFrameworkInput
|
||||
asMap := map[string]any{}
|
||||
@@ -37734,7 +38070,7 @@ func (ec *executionContext) unmarshalInputPublishDocumentVersionInput(ctx contex
|
||||
asMap[k] = v
|
||||
}
|
||||
|
||||
fieldsInOrder := [...]string{"documentId"}
|
||||
fieldsInOrder := [...]string{"documentId", "changelog"}
|
||||
for _, k := range fieldsInOrder {
|
||||
v, ok := asMap[k]
|
||||
if !ok {
|
||||
@@ -37748,6 +38084,13 @@ func (ec *executionContext) unmarshalInputPublishDocumentVersionInput(ctx contex
|
||||
return it, err
|
||||
}
|
||||
it.DocumentID = data
|
||||
case "changelog":
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("changelog"))
|
||||
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
it.Changelog = data
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42067,6 +42410,47 @@ func (ec *executionContext) _DocumentVersion(ctx context.Context, sel ast.Select
|
||||
if out.Values[i] == graphql.Null {
|
||||
atomic.AddUint32(&out.Invalids, 1)
|
||||
}
|
||||
case "title":
|
||||
out.Values[i] = ec._DocumentVersion_title(ctx, field, obj)
|
||||
if out.Values[i] == graphql.Null {
|
||||
atomic.AddUint32(&out.Invalids, 1)
|
||||
}
|
||||
case "owner":
|
||||
field := field
|
||||
|
||||
innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
}
|
||||
}()
|
||||
res = ec._DocumentVersion_owner(ctx, field, obj)
|
||||
if res == graphql.Null {
|
||||
atomic.AddUint32(&fs.Invalids, 1)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
if field.Deferrable != nil {
|
||||
dfs, ok := deferred[field.Deferrable.Label]
|
||||
di := 0
|
||||
if ok {
|
||||
dfs.AddField(field)
|
||||
di = len(dfs.Values) - 1
|
||||
} else {
|
||||
dfs = graphql.NewFieldSet([]graphql.CollectedField{field})
|
||||
deferred[field.Deferrable.Label] = dfs
|
||||
}
|
||||
dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler {
|
||||
return innerFunc(ctx, dfs)
|
||||
})
|
||||
|
||||
// don't run the out.Concurrently() call below
|
||||
out.Values[i] = graphql.Null
|
||||
continue
|
||||
}
|
||||
|
||||
out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
|
||||
case "signatures":
|
||||
field := field
|
||||
|
||||
@@ -43084,6 +43468,45 @@ func (ec *executionContext) _FulfillEvidencePayload(ctx context.Context, sel ast
|
||||
return out
|
||||
}
|
||||
|
||||
var generateDocumentChangelogPayloadImplementors = []string{"GenerateDocumentChangelogPayload"}
|
||||
|
||||
func (ec *executionContext) _GenerateDocumentChangelogPayload(ctx context.Context, sel ast.SelectionSet, obj *types.GenerateDocumentChangelogPayload) graphql.Marshaler {
|
||||
fields := graphql.CollectFields(ec.OperationContext, sel, generateDocumentChangelogPayloadImplementors)
|
||||
|
||||
out := graphql.NewFieldSet(fields)
|
||||
deferred := make(map[string]*graphql.FieldSet)
|
||||
for i, field := range fields {
|
||||
switch field.Name {
|
||||
case "__typename":
|
||||
out.Values[i] = graphql.MarshalString("GenerateDocumentChangelogPayload")
|
||||
case "changelog":
|
||||
out.Values[i] = ec._GenerateDocumentChangelogPayload_changelog(ctx, field, obj)
|
||||
if out.Values[i] == graphql.Null {
|
||||
out.Invalids++
|
||||
}
|
||||
default:
|
||||
panic("unknown field " + strconv.Quote(field.Name))
|
||||
}
|
||||
}
|
||||
out.Dispatch(ctx)
|
||||
if out.Invalids > 0 {
|
||||
return graphql.Null
|
||||
}
|
||||
|
||||
atomic.AddInt32(&ec.deferred, int32(len(deferred)))
|
||||
|
||||
for label, dfs := range deferred {
|
||||
ec.processDeferredGroup(graphql.DeferredGroup{
|
||||
Label: label,
|
||||
Path: graphql.GetPath(ctx),
|
||||
FieldSet: dfs,
|
||||
Context: ctx,
|
||||
})
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
var importFrameworkPayloadImplementors = []string{"ImportFrameworkPayload"}
|
||||
|
||||
func (ec *executionContext) _ImportFrameworkPayload(ctx context.Context, sel ast.SelectionSet, obj *types.ImportFrameworkPayload) graphql.Marshaler {
|
||||
@@ -43850,6 +44273,13 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
|
||||
if out.Values[i] == graphql.Null {
|
||||
out.Invalids++
|
||||
}
|
||||
case "generateDocumentChangelog":
|
||||
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
|
||||
return ec._Mutation_generateDocumentChangelog(ctx, field)
|
||||
})
|
||||
if out.Values[i] == graphql.Null {
|
||||
out.Invalids++
|
||||
}
|
||||
case "createDraftDocumentVersion":
|
||||
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
|
||||
return ec._Mutation_createDraftDocumentVersion(ctx, field)
|
||||
@@ -49850,6 +50280,25 @@ func (ec *executionContext) marshalNFulfillEvidencePayload2ᚖgithubᚗcomᚋget
|
||||
return ec._FulfillEvidencePayload(ctx, sel, v)
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalNGenerateDocumentChangelogInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐGenerateDocumentChangelogInput(ctx context.Context, v any) (types.GenerateDocumentChangelogInput, error) {
|
||||
res, err := ec.unmarshalInputGenerateDocumentChangelogInput(ctx, v)
|
||||
return res, graphql.ErrorOnPath(ctx, err)
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalNGenerateDocumentChangelogPayload2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐGenerateDocumentChangelogPayload(ctx context.Context, sel ast.SelectionSet, v types.GenerateDocumentChangelogPayload) graphql.Marshaler {
|
||||
return ec._GenerateDocumentChangelogPayload(ctx, sel, &v)
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalNGenerateDocumentChangelogPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐGenerateDocumentChangelogPayload(ctx context.Context, sel ast.SelectionSet, v *types.GenerateDocumentChangelogPayload) graphql.Marshaler {
|
||||
if v == nil {
|
||||
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
|
||||
ec.Errorf(ctx, "the requested element is null which the schema does not allow")
|
||||
}
|
||||
return graphql.Null
|
||||
}
|
||||
return ec._GenerateDocumentChangelogPayload(ctx, sel, v)
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx context.Context, v any) (gid.GID, error) {
|
||||
res, err := types.UnmarshalGIDScalar(v)
|
||||
return res, graphql.ErrorOnPath(ctx, err)
|
||||
|
||||
@@ -46,6 +46,7 @@ func NewDocumentVersion(documentVersion *coredata.DocumentVersion) *DocumentVers
|
||||
return &DocumentVersion{
|
||||
ID: documentVersion.ID,
|
||||
Version: documentVersion.VersionNumber,
|
||||
Title: documentVersion.Title,
|
||||
Content: documentVersion.Content,
|
||||
Status: documentVersion.Status,
|
||||
PublishedAt: documentVersion.PublishedAt,
|
||||
|
||||
@@ -557,6 +557,8 @@ type DocumentVersion struct {
|
||||
Version int `json:"version"`
|
||||
Content string `json:"content"`
|
||||
Changelog string `json:"changelog"`
|
||||
Title string `json:"title"`
|
||||
Owner *People `json:"owner"`
|
||||
Signatures *DocumentVersionSignatureConnection `json:"signatures"`
|
||||
PublishedBy *People `json:"publishedBy,omitempty"`
|
||||
PublishedAt *time.Time `json:"publishedAt,omitempty"`
|
||||
@@ -682,6 +684,14 @@ type FulfillEvidencePayload struct {
|
||||
EvidenceEdge *EvidenceEdge `json:"evidenceEdge"`
|
||||
}
|
||||
|
||||
type GenerateDocumentChangelogInput struct {
|
||||
DocumentID gid.GID `json:"documentId"`
|
||||
}
|
||||
|
||||
type GenerateDocumentChangelogPayload struct {
|
||||
Changelog string `json:"changelog"`
|
||||
}
|
||||
|
||||
type ImportFrameworkInput struct {
|
||||
OrganizationID gid.GID `json:"organizationId"`
|
||||
File graphql.Upload `json:"file"`
|
||||
@@ -812,6 +822,7 @@ type PeopleEdge struct {
|
||||
|
||||
type PublishDocumentVersionInput struct {
|
||||
DocumentID gid.GID `json:"documentId"`
|
||||
Changelog *string `json:"changelog,omitempty"`
|
||||
}
|
||||
|
||||
type PublishDocumentVersionPayload struct {
|
||||
|
||||
@@ -302,6 +302,23 @@ func (r *documentVersionResolver) Document(ctx context.Context, obj *types.Docum
|
||||
return types.NewDocument(document), nil
|
||||
}
|
||||
|
||||
// Owner is the resolver for the owner field.
|
||||
func (r *documentVersionResolver) Owner(ctx context.Context, obj *types.DocumentVersion) (*types.People, error) {
|
||||
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
||||
|
||||
documentVersion, err := svc.Documents.GetVersion(ctx, obj.ID)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("cannot get document version: %w", err))
|
||||
}
|
||||
|
||||
owner, err := svc.Peoples.Get(ctx, documentVersion.OwnerID)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("cannot get owner: %w", err))
|
||||
}
|
||||
|
||||
return types.NewPeople(owner), nil
|
||||
}
|
||||
|
||||
// Signatures is the resolver for the signatures field.
|
||||
func (r *documentVersionResolver) Signatures(ctx context.Context, obj *types.DocumentVersion, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentVersionSignatureOrder) (*types.DocumentVersionSignatureConnection, error) {
|
||||
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
||||
@@ -1491,6 +1508,7 @@ func (r *mutationResolver) UpdateDocument(ctx context.Context, input types.Updat
|
||||
input.ID,
|
||||
input.OwnerID,
|
||||
input.DocumentType,
|
||||
input.Title,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
@@ -1526,7 +1544,7 @@ func (r *mutationResolver) PublishDocumentVersion(ctx context.Context, input typ
|
||||
panic(fmt.Errorf("cannot get people: %w", err))
|
||||
}
|
||||
|
||||
document, documentVersion, err := svc.Documents.PublishVersion(ctx, input.DocumentID, people.ID)
|
||||
document, documentVersion, err := svc.Documents.PublishVersion(ctx, input.DocumentID, people.ID, input.Changelog)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("cannot publish document version: %w", err))
|
||||
}
|
||||
@@ -1537,6 +1555,20 @@ func (r *mutationResolver) PublishDocumentVersion(ctx context.Context, input typ
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GenerateDocumentChangelog is the resolver for the generateDocumentChangelog field.
|
||||
func (r *mutationResolver) GenerateDocumentChangelog(ctx context.Context, input types.GenerateDocumentChangelogInput) (*types.GenerateDocumentChangelogPayload, error) {
|
||||
svc := GetTenantService(ctx, r.proboSvc, input.DocumentID.TenantID())
|
||||
|
||||
changelog, err := svc.Documents.GenerateChangelog(ctx, input.DocumentID)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("cannot generate document changelog: %w", err))
|
||||
}
|
||||
|
||||
return &types.GenerateDocumentChangelogPayload{
|
||||
Changelog: *changelog,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreateDraftDocumentVersion is the resolver for the createDraftDocumentVersion field.
|
||||
func (r *mutationResolver) CreateDraftDocumentVersion(ctx context.Context, input types.CreateDraftDocumentVersionInput) (*types.CreateDraftDocumentVersionPayload, error) {
|
||||
svc := GetTenantService(ctx, r.proboSvc, input.DocumentID.TenantID())
|
||||
|
||||
@@ -38,7 +38,7 @@ type Config struct {
|
||||
Usrmgr *usrmgr.Service
|
||||
Auth console_v1.AuthConfig
|
||||
ConnectorRegistry *connector.ConnectorRegistry
|
||||
VendorAssessment *agents.VendorAssessment
|
||||
Agent *agents.Agent
|
||||
SafeRedirect *saferedirect.SafeRedirect
|
||||
Logger *log.Logger
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user