Add vendor risk assement

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
Bryan Frimin
2025-04-22 08:03:35 -07:00
parent f038642ece
commit e2e8f38f97
17 changed files with 1275 additions and 582 deletions

View File

@@ -0,0 +1,3 @@
ALTER TABLE risk_assessments RENAME TO vendor_risk_assessments;
ALTER TABLE vendor_risk_assessments ADD COLUMN assessed_at TIMESTAMP WITH TIME ZONE NOT NULL;

View File

@@ -0,0 +1 @@
ALTER TABLE vendor_risk_assessments ADD COLUMN assessed_by TEXT NOT NULL;

View File

@@ -90,7 +90,7 @@ func (r VendorRiskAssessment) Insert(
) error {
q := `
INSERT INTO
risk_assessments (
vendor_risk_assessments (
tenant_id,
id,
vendor_id,
@@ -165,7 +165,7 @@ SELECT
created_at,
updated_at
FROM
risk_assessments
vendor_risk_assessments
WHERE
%s
AND id = @id
@@ -216,7 +216,7 @@ SELECT
created_at,
updated_at
FROM
risk_assessments
vendor_risk_assessments
WHERE
%s
AND vendor_id = @vendor_id
@@ -270,7 +270,7 @@ SELECT
created_at,
updated_at
FROM
risk_assessments
vendor_risk_assessments
WHERE
%s
AND vendor_id = @vendor_id

View File

@@ -19,6 +19,7 @@ import (
"fmt"
"net/http"
"github.com/getprobo/probo/pkg/probo"
"github.com/getprobo/probo/pkg/usrmgr"
"go.gearno.de/kit/httpserver"
)
@@ -33,7 +34,7 @@ type (
}
)
func InvitationConfirmationHandler(usrmgrSvc *usrmgr.Service, authCfg AuthConfig) http.HandlerFunc {
func InvitationConfirmationHandler(usrmgrSvc *usrmgr.Service, proboSvc *probo.Service, authCfg AuthConfig) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req InvitationConfirmationRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
@@ -41,7 +42,7 @@ func InvitationConfirmationHandler(usrmgrSvc *usrmgr.Service, authCfg AuthConfig
return
}
err := usrmgrSvc.ConfirmInvitation(r.Context(), req.Token, req.Password)
_, err := usrmgrSvc.ConfirmInvitation(r.Context(), req.Token, req.Password)
if err != nil {
httpserver.RenderError(w, http.StatusInternalServerError, err)
return

View File

@@ -80,7 +80,7 @@ func NewMux(proboSvc *probo.Service, usrmgrSvc *usrmgr.Service, authCfg AuthConf
r.Post("/auth/register", SignUpHandler(usrmgrSvc, authCfg))
r.Post("/auth/login", SignInHandler(usrmgrSvc, authCfg))
r.Delete("/auth/logout", SignOutHandler(usrmgrSvc, authCfg))
r.Post("/auth/invitation", InvitationConfirmationHandler(usrmgrSvc, authCfg))
r.Post("/auth/invitation", InvitationConfirmationHandler(usrmgrSvc, proboSvc, authCfg))
r.Post("/auth/forget-password", ForgetPasswordHandler(usrmgrSvc, authCfg))
r.Post("/auth/reset-password", ResetPasswordHandler(usrmgrSvc, authCfg))

View File

@@ -1585,7 +1585,27 @@ func (r *vendorResolver) ComplianceReports(ctx context.Context, obj *types.Vendo
// RiskAssessments is the resolver for the riskAssessments field.
func (r *vendorResolver) RiskAssessments(ctx context.Context, obj *types.Vendor, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorRiskAssessmentOrder) (*types.VendorRiskAssessmentConnection, error) {
panic(fmt.Errorf("not implemented: RiskAssessments - riskAssessments"))
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
pageOrderBy := page.OrderBy[coredata.VendorRiskAssessmentOrderField]{
Field: coredata.VendorRiskAssessmentOrderFieldCreatedAt,
Direction: page.OrderDirectionDesc,
}
if orderBy != nil {
pageOrderBy = page.OrderBy[coredata.VendorRiskAssessmentOrderField]{
Field: orderBy.Field,
Direction: orderBy.Direction,
}
}
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
page, err := svc.Vendors.ListRiskAssessments(ctx, obj.ID, cursor)
if err != nil {
panic(fmt.Errorf("failed to list vendor risk assessments: %w", err))
}
return types.NewVendorRiskAssessmentConnection(page), nil
}
// BusinessOwner is the resolver for the businessOwner field.

View File

@@ -710,31 +710,32 @@ func (s Service) InviteUser(
)
}
func (s Service) ConfirmInvitation(ctx context.Context, tokenString string, password string) error {
func (s Service) ConfirmInvitation(ctx context.Context, tokenString string, password string) (*coredata.User, error) {
token, err := statelesstoken.ValidateToken[InvitationData](
s.tokenSecret,
TokenTypeOrganizationInvitation,
tokenString,
)
if err != nil {
return fmt.Errorf("cannot validate organization invitation token: %w", err)
return nil, fmt.Errorf("cannot validate organization invitation token: %w", err)
}
if len(password) < 8 {
return &ErrInvalidPassword{len(password)}
return nil, &ErrInvalidPassword{len(password)}
}
now := time.Now()
hashedPassword, err := s.hp.HashPassword([]byte(password))
if err != nil {
return fmt.Errorf("cannot hash password: %w", err)
return nil, fmt.Errorf("cannot hash password: %w", err)
}
return s.pg.WithTx(
user := &coredata.User{}
err = s.pg.WithTx(
ctx,
func(tx pg.Conn) error {
user := &coredata.User{}
if err := user.LoadByEmail(ctx, tx, token.Data.Email); err != nil {
var errUserNotFound *coredata.ErrUserNotFound
@@ -766,9 +767,31 @@ func (s Service) ConfirmInvitation(ctx context.Context, tokenString string, pass
return fmt.Errorf("cannot insert user organization: %w", err)
}
people := coredata.People{
OrganizationID: token.Data.OrganizationID,
UserID: &user.ID,
FullName: token.Data.FullName,
PrimaryEmailAddress: token.Data.Email,
Kind: coredata.PeopleKindEmployee,
CreatedAt: now,
UpdatedAt: now,
}
scope := coredata.NewScope(token.Data.OrganizationID.TenantID())
if err := people.Insert(ctx, tx, scope); err != nil {
return fmt.Errorf("cannot insert people: %w", err)
}
return nil
},
)
if err != nil {
return nil, err
}
return user, nil
}
func (s Service) RemoveUser(ctx context.Context, organizationID gid.GID, userID gid.GID) error {