Split GraphQL schemas into per-entity files
Split each API's monolithic schema.graphql into per-coredata-model
files under graphql/ subdirectories. gqlgen's follow-schema layout
with {name}.resolvers.go template generates one resolver file per
schema file. Relay uses schema + schemaExtensions to load the split
files.
Connect API: 8 files (base, session, organization, profile,
personal_api_key, saml, scim, audit_log)
Trust API: 5 files (base, trust_center, auth, nda, mailing_list)
Console API: 25 files covering all domain entities
Types extended across files (Organization, Mutation, Viewer,
TrustCenter, Identity) are defined in base.graphql as required by
Relay's schemaExtensions.
Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
@@ -1,6 +1,15 @@
|
||||
# GraphQL (Go Backend — gqlgen)
|
||||
|
||||
Schema-first GraphQL using [gqlgen](https://gqlgen.com/). The schema is hand-written; Go types and resolvers are generated.
|
||||
Schema-first GraphQL using [gqlgen](https://gqlgen.com/). The schema is hand-written and split into per-entity files under `graphql/`; Go types and resolvers are generated.
|
||||
|
||||
## Schema file organization
|
||||
|
||||
Each API's schema lives in `pkg/server/api/{api}/v1/graphql/` as multiple `.graphql` files, one per coredata model:
|
||||
|
||||
- `base.graphql` — directives, scalars, Node interface, PageInfo, OrderDirection, root Query/Mutation/Organization types
|
||||
- Entity files (e.g., `vendor.graphql`, `control.graphql`) — use `extend type Organization`, `extend type Mutation`, etc.
|
||||
|
||||
gqlgen's `follow-schema` layout generates one resolver file per schema file (e.g., `vendor.resolvers.go`). Types that get extended across files (Organization, Mutation, Viewer, TrustCenter) must be defined in `base.graphql`.
|
||||
|
||||
## Connection types and `@goModel`
|
||||
|
||||
@@ -40,13 +49,15 @@ enum VendorOrderField
|
||||
|
||||
## Schema directives
|
||||
|
||||
| Directive | Target | Purpose |
|
||||
|-----------|--------|---------|
|
||||
| `@goModel(model: "...")` | `OBJECT`, `ENUM`, `INPUT_OBJECT`, `SCALAR`, `INTERFACE`, `UNION` | Map GraphQL type to existing Go type |
|
||||
| `@goEnum(value: "...")` | `ENUM_VALUE` | Map enum value to Go constant |
|
||||
| `@goField(forceResolver: true)` | `FIELD_DEFINITION` | Force a resolver function instead of struct field |
|
||||
| `@goField(name: "...")` | `FIELD_DEFINITION`, `INPUT_FIELD_DEFINITION` | Override Go field name |
|
||||
| `@goField(omittable: true)` | `INPUT_FIELD_DEFINITION` | Use `graphql.Omittable[T]` for distinguishing null vs absent |
|
||||
|
||||
| Directive | Target | Purpose |
|
||||
| ------------------------------- | ---------------------------------------------------------------- | ------------------------------------------------------------ |
|
||||
| `@goModel(model: "...")` | `OBJECT`, `ENUM`, `INPUT_OBJECT`, `SCALAR`, `INTERFACE`, `UNION` | Map GraphQL type to existing Go type |
|
||||
| `@goEnum(value: "...")` | `ENUM_VALUE` | Map enum value to Go constant |
|
||||
| `@goField(forceResolver: true)` | `FIELD_DEFINITION` | Force a resolver function instead of struct field |
|
||||
| `@goField(name: "...")` | `FIELD_DEFINITION`, `INPUT_FIELD_DEFINITION` | Override Go field name |
|
||||
| `@goField(omittable: true)` | `INPUT_FIELD_DEFINITION` | Use `graphql.Omittable[T]` for distinguishing null vs absent |
|
||||
|
||||
|
||||
## Cursor pagination schema types
|
||||
|
||||
@@ -158,7 +169,8 @@ Default page size is **25** when neither `first` nor `last` is provided.
|
||||
## Adding a new paginated field — checklist
|
||||
|
||||
1. **Schema** — add `enum XxxOrderField` (with `@goModel`/`@goEnum`), `input XxxOrder`, `type XxxConnection` (with `@goModel` and `totalCount` using `@goField(forceResolver: true)`), `type XxxEdge`, and the connection field with Relay arguments on the parent type
|
||||
2. **Coredata** — add `*_order_field.go` (with `Column()`, `IsValid()`, marshaling), `CursorKey(field)` method on the entity, and the `LoadAllBy*` query using cursor SQL fragments + `page.NewPage()`
|
||||
2. **Coredata** — add `*_order_field.go` (with `Column()`, `IsValid()`, marshaling), `CursorKey(field)` method on the entity, and the `LoadAllBy`* query using cursor SQL fragments + `page.NewPage()`
|
||||
3. **API types** — add `*_connection.go` with `OrderBy` alias, connection struct, `NewXxxConnection`, `NewXxxEdge`
|
||||
4. **Resolver** — implement the resolver (authorize, build order, build cursor, call service, build connection)
|
||||
5. **Codegen** — run `go generate` for the relevant API package
|
||||
|
||||
|
||||
@@ -6,16 +6,18 @@ The console app uses [Relay](https://relay.dev/) as its GraphQL client. All Grap
|
||||
|
||||
Two Relay environments connect to two separate GraphQL APIs:
|
||||
|
||||
| Environment | Endpoint | Purpose |
|
||||
|-------------|----------|---------|
|
||||
| `coreEnvironment` | `/api/console/v1/graphql` | Main application data |
|
||||
| `iamEnvironment` | `/api/connect/v1/graphql` | Authentication / identity |
|
||||
|
||||
| Environment | Endpoint | Purpose |
|
||||
| ----------------- | ------------------------- | ------------------------- |
|
||||
| `coreEnvironment` | `/api/console/v1/graphql` | Main application data |
|
||||
| `iamEnvironment` | `/api/connect/v1/graphql` | Authentication / identity |
|
||||
|
||||
|
||||
Configured in `apps/console/src/environments.ts`. Each has its own store with 1-minute query cache expiration.
|
||||
|
||||
## Relay compiler
|
||||
|
||||
Config lives in `relay.config.json` at the repo root with three projects (`core`, `iam`, `trust`) mapped to different source directories and schemas. Generated files go into `__generated__/` directories.
|
||||
Config lives in `relay.config.json` at the repo root with three projects (`core`, `iam`, `trust`) mapped to different source directories and schemas. Each project uses `schema` pointing to `base.graphql` and `schemaExtensions` pointing to the `graphql/` directory containing the per-entity schema files. Generated files go into `__generated__/` directories.
|
||||
|
||||
```sh
|
||||
npm run relay # clean + compile (from repo root)
|
||||
@@ -381,7 +383,7 @@ return () => {
|
||||
|
||||
## File organization
|
||||
|
||||
GraphQL operations are colocated with the components that use them. See [`contrib/claude/app-arborescence.md`](app-arborescence.md) for the full folder layout.
|
||||
GraphQL operations are colocated with the components that use them. See `[contrib/claude/app-arborescence.md](app-arborescence.md)` for the full folder layout.
|
||||
|
||||
```
|
||||
pages/organizations/vendors/
|
||||
@@ -394,4 +396,4 @@ pages/organizations/vendors/
|
||||
VendorComplianceTab.tsx
|
||||
```
|
||||
|
||||
Component-specific operations (queries, fragments, mutations) are defined inline in the component file that uses them. Shared sub-components live in `_components/` next to the page (scoped to the nearest common ancestor).
|
||||
Component-specific operations (queries, fragments, mutations) are defined inline in the component file that uses them. Shared sub-components live in `_components/` next to the page (scoped to the nearest common ancestor).
|
||||
100
pkg/server/api/connect/v1/audit_log.resolvers.go
Normal file
100
pkg/server/api/connect/v1/audit_log.resolvers.go
Normal file
@@ -0,0 +1,100 @@
|
||||
package connect_v1
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver
|
||||
// implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.87
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.gearno.de/kit/log"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/iam"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"go.probo.inc/probo/pkg/server/api/connect/v1/schema"
|
||||
"go.probo.inc/probo/pkg/server/api/connect/v1/types"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils/types/cursor"
|
||||
)
|
||||
|
||||
// Organization is the resolver for the organization field.
|
||||
func (r *auditLogEntryResolver) Organization(ctx context.Context, obj *types.AuditLogEntry) (*types.Organization, error) {
|
||||
return obj.Organization, nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *auditLogEntryResolver) Permission(ctx context.Context, obj *types.AuditLogEntry, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// TotalCount is the resolver for the totalCount field.
|
||||
func (r *auditLogEntryConnectionResolver) TotalCount(ctx context.Context, obj *types.AuditLogEntryConnection) (int, error) {
|
||||
filter := coredata.NewAuditLogEntryFilter()
|
||||
if obj.Filter != nil {
|
||||
filter = obj.Filter
|
||||
}
|
||||
|
||||
count, err := r.iam.OrganizationService.CountAuditLogEntries(ctx, obj.ParentID, filter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count audit log entries", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// AuditLogEntries is the resolver for the auditLogEntries field.
|
||||
func (r *organizationResolver) AuditLogEntries(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.AuditLogEntryOrderBy, filter *types.AuditLogEntryFilter) (*types.AuditLogEntryConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, iam.ActionAuditLogEntryList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.AuditLogEntryOrderField]{
|
||||
Field: coredata.AuditLogEntryOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.AuditLogEntryOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
c := cursor.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
coredataFilter := coredata.NewAuditLogEntryFilter()
|
||||
if filter != nil {
|
||||
if filter.Action != nil {
|
||||
coredataFilter.WithAction(*filter.Action)
|
||||
}
|
||||
if filter.ActorID != nil {
|
||||
coredataFilter.WithActorID(*filter.ActorID)
|
||||
}
|
||||
if filter.ResourceType != nil {
|
||||
coredataFilter.WithResourceType(*filter.ResourceType)
|
||||
}
|
||||
if filter.ResourceID != nil {
|
||||
coredataFilter.WithResourceID(*filter.ResourceID)
|
||||
}
|
||||
}
|
||||
|
||||
p, err := r.iam.OrganizationService.ListAuditLogEntries(ctx, obj.ID, c, coredataFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list audit log entries", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewAuditLogEntryConnection(p, r, obj.ID, coredataFilter), nil
|
||||
}
|
||||
|
||||
// AuditLogEntry returns schema.AuditLogEntryResolver implementation.
|
||||
func (r *Resolver) AuditLogEntry() schema.AuditLogEntryResolver { return &auditLogEntryResolver{r} }
|
||||
|
||||
// AuditLogEntryConnection returns schema.AuditLogEntryConnectionResolver implementation.
|
||||
func (r *Resolver) AuditLogEntryConnection() schema.AuditLogEntryConnectionResolver {
|
||||
return &auditLogEntryConnectionResolver{r}
|
||||
}
|
||||
|
||||
type auditLogEntryResolver struct{ *Resolver }
|
||||
type auditLogEntryConnectionResolver struct{ *Resolver }
|
||||
809
pkg/server/api/connect/v1/base.resolvers.go
Normal file
809
pkg/server/api/connect/v1/base.resolvers.go
Normal file
@@ -0,0 +1,809 @@
|
||||
package connect_v1
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver
|
||||
// implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.87
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
"go.gearno.de/kit/log"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/iam"
|
||||
"go.probo.inc/probo/pkg/mail"
|
||||
"go.probo.inc/probo/pkg/server/api/authn"
|
||||
"go.probo.inc/probo/pkg/server/api/authz"
|
||||
"go.probo.inc/probo/pkg/server/api/connect/v1/schema"
|
||||
"go.probo.inc/probo/pkg/server/api/connect/v1/types"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils"
|
||||
)
|
||||
|
||||
// SsoLoginURL is the resolver for the ssoLoginURL field.
|
||||
func (r *identityResolver) SsoLoginURL(ctx context.Context, obj *types.Identity) (*string, error) {
|
||||
if err := r.authorize(ctx, obj.ID, iam.ActionIdentityGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
|
||||
count, err := r.iam.AccountService.CountSAMLConfigurationsForEmail(ctx, identity.EmailAddress)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count SAML configurations for email", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
if count != 1 {
|
||||
if count == 0 {
|
||||
return nil, graphql.ErrorOnPath(
|
||||
ctx,
|
||||
fmt.Errorf("no SAML configuration for email"),
|
||||
)
|
||||
}
|
||||
|
||||
return nil, graphql.ErrorOnPath(
|
||||
ctx,
|
||||
fmt.Errorf("multiple SSO configurations found for this domain. Please use your organization-specific SSO login URL"),
|
||||
)
|
||||
}
|
||||
|
||||
samlConfigs, err := r.iam.AccountService.ListSAMLConfigurationsForEmail(ctx, identity.EmailAddress)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list SAML configurations for email", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
if len(samlConfigs) == 0 {
|
||||
r.logger.ErrorCtx(ctx, "cannot find SAML config")
|
||||
return nil, gqlutils.NotFoundf(ctx, "cannot find SAML config")
|
||||
}
|
||||
samlConfig := samlConfigs[0]
|
||||
|
||||
loginURL := r.SSOLoginURL(samlConfig.ID)
|
||||
return &loginURL, nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *identityResolver) Permission(ctx context.Context, obj *types.Identity, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// SignIn is the resolver for the signIn field.
|
||||
func (r *mutationResolver) SignIn(ctx context.Context, input types.SignInInput) (*types.SignInPayload, error) {
|
||||
identity, err := r.iam.AuthService.CheckCredentials(ctx, input.Email, input.Password)
|
||||
if err != nil {
|
||||
var errInvalidPassword *iam.ErrInvalidPassword
|
||||
if errors.As(err, &errInvalidPassword) {
|
||||
return nil, gqlutils.Invalid(ctx, err)
|
||||
}
|
||||
|
||||
var errInvalidCredentials *iam.ErrInvalidCredentials
|
||||
if errors.As(err, &errInvalidCredentials) {
|
||||
return nil, &gqlerror.Error{
|
||||
Message: err.Error(),
|
||||
Extensions: map[string]any{
|
||||
"code": "INVALID_CREDENTIALS",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot check credentials", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
session := authn.SessionFromContext(ctx)
|
||||
|
||||
switch {
|
||||
case session == nil:
|
||||
var err error
|
||||
session, err = r.iam.AuthService.OpenSessionWithPassword(
|
||||
ctx,
|
||||
identity.ID,
|
||||
)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot create session", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
case session.IdentityID != identity.ID:
|
||||
if err := r.iam.SessionService.CloseSession(ctx, session.ID); err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot close session", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
session, err = r.iam.AuthService.OpenSessionWithPassword(
|
||||
ctx,
|
||||
identity.ID,
|
||||
)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot create session", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
w := gqlutils.HTTPResponseWriterFromContext(ctx)
|
||||
r.sessionCookie.Set(w, session)
|
||||
|
||||
if input.OrganizationID != nil {
|
||||
var err error
|
||||
_, _, err = r.iam.SessionService.OpenPasswordChildSessionForOrganization(ctx, session.ID, *input.OrganizationID)
|
||||
if err != nil {
|
||||
// Here session middleware already took care of expired/nil root session so we only handle membership related errors
|
||||
var errMembershipNotFound *iam.ErrMembershipNotFound
|
||||
var errUserInactive *iam.ErrUserInactive
|
||||
|
||||
if errors.As(err, &errMembershipNotFound) || errors.As(err, &errUserInactive) {
|
||||
return nil, gqlutils.Forbiddenf(ctx, "forbidden")
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot assume organization", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
return &types.SignInPayload{
|
||||
Identity: types.NewIdentity(identity),
|
||||
Session: types.NewSession(session),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SignUp is the resolver for the signUp field.
|
||||
func (r *mutationResolver) SignUp(ctx context.Context, input types.SignUpInput) (*types.SignUpPayload, error) {
|
||||
identity, session, err := r.iam.AuthService.CreateIdentityWithPassword(
|
||||
ctx,
|
||||
&iam.CreateIdentityWithPasswordRequest{
|
||||
Email: input.Email,
|
||||
Password: input.Password,
|
||||
FullName: input.FullName,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
var errIdentityAlreadyExists *iam.ErrIdentityAlreadyExists
|
||||
if errors.As(err, &errIdentityAlreadyExists) {
|
||||
return nil, gqlutils.Invalid(ctx, err)
|
||||
}
|
||||
|
||||
var errSignupDisabled *iam.ErrSignupDisabled
|
||||
if errors.As(err, &errSignupDisabled) {
|
||||
return nil, gqlutils.Forbidden(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot create identity with password", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
w := gqlutils.HTTPResponseWriterFromContext(ctx)
|
||||
r.sessionCookie.Set(w, session)
|
||||
|
||||
return &types.SignUpPayload{
|
||||
Identity: types.NewIdentity(identity),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SignOut is the resolver for the signOut field.
|
||||
func (r *mutationResolver) SignOut(ctx context.Context) (*types.SignOutPayload, error) {
|
||||
session := authn.SessionFromContext(ctx)
|
||||
|
||||
err := r.iam.SessionService.CloseSession(ctx, session.ID)
|
||||
if err != nil {
|
||||
var ErrSessionNotFound *iam.ErrSessionNotFound
|
||||
if errors.As(err, &ErrSessionNotFound) {
|
||||
return &types.SignOutPayload{}, nil
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot close session", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
w := gqlutils.HTTPResponseWriterFromContext(ctx)
|
||||
r.sessionCookie.Clear(w)
|
||||
|
||||
return &types.SignOutPayload{Success: true}, nil
|
||||
}
|
||||
|
||||
// ActivateAccount is the resolver for the activateAccount field.
|
||||
func (r *mutationResolver) ActivateAccount(ctx context.Context, input types.ActivateAccountInput) (*types.ActivateAccountPayload, error) {
|
||||
session := authn.SessionFromContext(ctx)
|
||||
|
||||
if session != nil {
|
||||
// Sign out any other account before activating a new one
|
||||
err := r.iam.SessionService.CloseSession(ctx, session.ID)
|
||||
if err != nil {
|
||||
var ErrSessionNotFound *iam.ErrSessionNotFound
|
||||
if !errors.As(err, &ErrSessionNotFound) {
|
||||
r.logger.ErrorCtx(ctx, "cannot close session", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
w := gqlutils.HTTPResponseWriterFromContext(ctx)
|
||||
r.sessionCookie.Clear(w)
|
||||
}
|
||||
|
||||
identity, user, err := r.iam.AuthService.ActivateAccount(
|
||||
ctx,
|
||||
&iam.ActivateAccountRequest{
|
||||
InvitationToken: input.Token,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
var (
|
||||
errInvalidToken *iam.ErrInvalidToken
|
||||
errInvitationNotFound *iam.ErrInvitationNotFound
|
||||
errInvitationExpired *iam.ErrInvitationExpired
|
||||
|
||||
isInvalidErr = errors.As(err, &errInvalidToken) ||
|
||||
errors.As(err, &errInvitationNotFound) ||
|
||||
errors.As(err, &errInvitationExpired)
|
||||
)
|
||||
|
||||
if isInvalidErr {
|
||||
return nil, gqlutils.Invalid(ctx, err)
|
||||
}
|
||||
|
||||
if _, ok := errors.AsType[*iam.ErrInvitationAlreadyAccepted](err); ok {
|
||||
return nil, gqlutils.AccountAlreadyActivated(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot activate account from invitation", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
var ssoLoginURL *string
|
||||
samlConfigs, err := r.iam.AccountService.ListSAMLConfigurationsForEmail(ctx, user.EmailAddress)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list saml configurations", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
for _, samlConfig := range samlConfigs {
|
||||
if samlConfig.OrganizationID != user.OrganizationID {
|
||||
continue
|
||||
}
|
||||
|
||||
ssoLoginURL = new(r.SSOLoginURL(samlConfig.ID))
|
||||
}
|
||||
|
||||
if ssoLoginURL != nil {
|
||||
return &types.ActivateAccountPayload{
|
||||
CreatePasswordToken: nil,
|
||||
SsoLoginURL: ssoLoginURL,
|
||||
Profile: types.NewProfile(user),
|
||||
}, nil
|
||||
}
|
||||
|
||||
var createPasswordToken *string
|
||||
if identity.HashedPassword == nil {
|
||||
token, err := r.iam.AuthService.GetResetPasswordToken(ctx, identity.EmailAddress)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot generate password create token", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
createPasswordToken = &token
|
||||
}
|
||||
|
||||
return &types.ActivateAccountPayload{
|
||||
CreatePasswordToken: createPasswordToken,
|
||||
SsoLoginURL: nil,
|
||||
Profile: types.NewProfile(user),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ForgotPassword is the resolver for the forgotPassword field.
|
||||
func (r *mutationResolver) ForgotPassword(ctx context.Context, input types.ForgotPasswordInput) (*types.ForgotPasswordPayload, error) {
|
||||
err := r.iam.AuthService.SendPasswordResetInstructionByEmail(
|
||||
ctx,
|
||||
input.Email,
|
||||
)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot send password reset instruction by email", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.ForgotPasswordPayload{
|
||||
Success: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ResetPassword is the resolver for the resetPassword field.
|
||||
func (r *mutationResolver) ResetPassword(ctx context.Context, input types.ResetPasswordInput) (*types.ResetPasswordPayload, error) {
|
||||
err := r.iam.AuthService.ResetPassword(
|
||||
ctx,
|
||||
&iam.ResetPasswordRequest{
|
||||
Token: input.Token,
|
||||
Password: input.Password,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
var errInvalidToken *iam.ErrInvalidToken
|
||||
if errors.As(err, &errInvalidToken) {
|
||||
return nil, gqlutils.Invalid(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot reset password", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.ResetPasswordPayload{
|
||||
Success: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// VerifyEmail is the resolver for the verifyEmail field.
|
||||
func (r *mutationResolver) VerifyEmail(ctx context.Context, input types.VerifyEmailInput) (*types.VerifyEmailPayload, error) {
|
||||
err := r.iam.AccountService.VerifyEmail(ctx, input.Token)
|
||||
if err != nil {
|
||||
var (
|
||||
errInvalidToken *iam.ErrInvalidToken
|
||||
errIdentityNotFound *iam.ErrIdentityNotFound
|
||||
errEmailAlreadyVerified *iam.ErrEmailAlreadyVerified
|
||||
errEmailVerificationMismatch *iam.ErrEmailVerificationMismatch
|
||||
|
||||
isInvalidErr = errors.As(err, &errInvalidToken) ||
|
||||
errors.As(err, &errEmailVerificationMismatch)
|
||||
)
|
||||
|
||||
if isInvalidErr {
|
||||
return nil, gqlutils.Invalid(ctx, err)
|
||||
}
|
||||
|
||||
if errors.As(err, &errEmailAlreadyVerified) {
|
||||
return nil, gqlutils.Conflict(ctx, err)
|
||||
}
|
||||
|
||||
if errors.As(err, &errIdentityNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot verify email", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.VerifyEmailPayload{
|
||||
Success: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ChangePassword is the resolver for the changePassword field.
|
||||
func (r *mutationResolver) ChangePassword(ctx context.Context, input types.ChangePasswordInput) (*types.ChangePasswordPayload, error) {
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
|
||||
err := r.iam.AccountService.ChangePassword(
|
||||
ctx,
|
||||
identity.ID,
|
||||
&iam.ChangePasswordRequest{
|
||||
CurrentPassword: input.CurrentPassword,
|
||||
NewPassword: input.NewPassword,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
var (
|
||||
errInvalidPassword *iam.ErrInvalidPassword
|
||||
errIdentityNotFound *iam.ErrIdentityNotFound
|
||||
)
|
||||
|
||||
if errors.As(err, &errInvalidPassword) {
|
||||
return nil, gqlutils.Invalid(ctx, err)
|
||||
}
|
||||
|
||||
if errors.As(err, &errIdentityNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot change password", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.ChangePasswordPayload{
|
||||
Success: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ChangeEmail is the resolver for the changeEmail field.
|
||||
func (r *mutationResolver) ChangeEmail(ctx context.Context, input types.ChangeEmailInput) (*types.ChangeEmailPayload, error) {
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
|
||||
err := r.iam.AccountService.ChangeEmail(
|
||||
ctx,
|
||||
identity.ID,
|
||||
&iam.ChangeEmailRequest{
|
||||
NewEmail: input.NewEmail,
|
||||
Password: input.Password,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
var (
|
||||
errInvalidPassword *iam.ErrInvalidPassword
|
||||
errIdentityNotFound *iam.ErrIdentityNotFound
|
||||
)
|
||||
|
||||
if errors.As(err, &errInvalidPassword) {
|
||||
return nil, gqlutils.Invalid(ctx, err)
|
||||
}
|
||||
|
||||
if errors.As(err, &errIdentityNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot change email", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.ChangeEmailPayload{
|
||||
Success: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// AssumeOrganizationSession is the resolver for the assumeOrganizationSession field.
|
||||
func (r *mutationResolver) AssumeOrganizationSession(ctx context.Context, input types.AssumeOrganizationSessionInput) (*types.AssumeOrganizationSessionPayload, error) {
|
||||
rootSession := authn.SessionFromContext(ctx)
|
||||
|
||||
childSession, membership, err := r.iam.SessionService.AssumeOrganizationSession(ctx, rootSession.ID, input.OrganizationID, input.Continue)
|
||||
if err != nil {
|
||||
var (
|
||||
errMembershipNotFound *iam.ErrMembershipNotFound
|
||||
errPasswordAuthenticationRequired *iam.ErrPasswordAuthenticationRequired
|
||||
errSAMLAuthenticationRequired *iam.ErrSAMLAuthenticationRequired
|
||||
)
|
||||
|
||||
switch {
|
||||
case errors.As(err, &errMembershipNotFound):
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
|
||||
case errors.As(err, &errPasswordAuthenticationRequired):
|
||||
return &types.AssumeOrganizationSessionPayload{
|
||||
Result: types.PasswordRequired{
|
||||
Reason: types.ReauthenticationReason(errPasswordAuthenticationRequired.Reason),
|
||||
},
|
||||
}, nil
|
||||
|
||||
case errors.As(err, &errSAMLAuthenticationRequired):
|
||||
return &types.AssumeOrganizationSessionPayload{
|
||||
Result: types.SAMLAuthenticationRequired{
|
||||
Reason: types.ReauthenticationReason(errSAMLAuthenticationRequired.Reason),
|
||||
},
|
||||
}, nil
|
||||
|
||||
default:
|
||||
r.logger.ErrorCtx(ctx, "cannot assume organization session", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
return &types.AssumeOrganizationSessionPayload{
|
||||
Result: types.OrganizationSessionCreated{
|
||||
Session: types.NewSession(childSession),
|
||||
Membership: types.NewMembership(membership),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// RevokeSession is the resolver for the revokeSession field.
|
||||
func (r *mutationResolver) RevokeSession(ctx context.Context, input types.RevokeSessionInput) (*types.RevokeSessionPayload, error) {
|
||||
if err := r.authorize(ctx, input.SessionID, iam.ActionSessionRevoke); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
|
||||
err := r.iam.SessionService.RevokeSession(ctx, identity.ID, input.SessionID)
|
||||
if err != nil {
|
||||
var ErrSessionExpired *iam.ErrSessionExpired
|
||||
if errors.As(err, &ErrSessionExpired) {
|
||||
return &types.RevokeSessionPayload{Success: true}, nil
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot revoke session", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.RevokeSessionPayload{Success: true}, nil
|
||||
}
|
||||
|
||||
// RevokeAllSessions is the resolver for the revokeAllSessions field.
|
||||
func (r *mutationResolver) RevokeAllSessions(ctx context.Context) (*types.RevokeAllSessionsPayload, error) {
|
||||
if err := r.authorize(ctx, authn.SessionFromContext(ctx).ID, iam.ActionSessionRevokeAll); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
session := authn.SessionFromContext(ctx)
|
||||
|
||||
revokedCount, err := r.iam.SessionService.RevokeAllSessions(ctx, session.ID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot revoke all sessions", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.RevokeAllSessionsPayload{RevokedCount: int(revokedCount)}, nil
|
||||
}
|
||||
|
||||
// LogoURL is the resolver for the logoUrl field.
|
||||
func (r *organizationResolver) LogoURL(ctx context.Context, obj *types.Organization) (*string, error) {
|
||||
if err := r.authorize(ctx, obj.ID, iam.ActionOrganizationGet, authz.WithSkipAssumptionCheck()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
presignedURL, err := r.iam.OrganizationService.GenerateLogoURL(ctx, obj.ID, 1*time.Hour)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot generate logo URL", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return presignedURL, nil
|
||||
}
|
||||
|
||||
// HorizontalLogoURL is the resolver for the horizontalLogoUrl field.
|
||||
func (r *organizationResolver) HorizontalLogoURL(ctx context.Context, obj *types.Organization) (*string, error) {
|
||||
if err := r.authorize(ctx, obj.ID, iam.ActionOrganizationGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
presignedURL, err := r.iam.OrganizationService.GenerateHorizontalLogoURL(ctx, obj.ID, 1*time.Hour)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot generate horizontal logo URL", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return presignedURL, nil
|
||||
}
|
||||
|
||||
// Viewer is the resolver for the viewer field.
|
||||
func (r *organizationResolver) Viewer(ctx context.Context, obj *types.Organization) (*types.Profile, error) {
|
||||
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
|
||||
profile, err := r.iam.OrganizationService.GetProfileForIdentityAndOrganization(ctx, identity.ID, obj.ID)
|
||||
if err != nil {
|
||||
var errNotFound *iam.ErrProfileNotFound
|
||||
if errors.As(err, &errNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get profile", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewProfile(profile), nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *organizationResolver) Permission(ctx context.Context, obj *types.Organization, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// Node is the resolver for the node field.
|
||||
func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
var (
|
||||
loadNode func(ctx context.Context, id gid.GID) (types.Node, error)
|
||||
action string
|
||||
)
|
||||
|
||||
switch id.EntityType() {
|
||||
case coredata.OrganizationEntityType:
|
||||
action = iam.ActionOrganizationGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
organization, err := r.iam.OrganizationService.GetOrganization(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewOrganization(organization), nil
|
||||
}
|
||||
case coredata.IdentityEntityType:
|
||||
action = iam.ActionIdentityGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
identity, err := r.iam.AccountService.GetIdentity(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return types.NewIdentity(identity), nil
|
||||
}
|
||||
case coredata.SessionEntityType:
|
||||
action = iam.ActionSessionGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
session, err := r.iam.GetSession(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return types.NewSession(session), nil
|
||||
}
|
||||
case coredata.MembershipProfileEntityType:
|
||||
action = iam.ActionMembershipGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
profile, err := r.iam.OrganizationService.GetProfile(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return types.NewProfile(profile), nil
|
||||
}
|
||||
case coredata.MembershipEntityType:
|
||||
action = iam.ActionMembershipGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
membership, err := r.iam.GetMembership(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return types.NewMembership(membership), nil
|
||||
}
|
||||
case coredata.InvitationEntityType:
|
||||
action = iam.ActionInvitationGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
invitation, err := r.iam.GetInvitation(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return types.NewInvitation(invitation), nil
|
||||
}
|
||||
case coredata.SAMLConfigurationEntityType:
|
||||
action = iam.ActionSAMLConfigurationGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
samlConfiguration, err := r.iam.GetSAMLconfiguration(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return types.NewSAMLConfiguration(samlConfiguration), nil
|
||||
}
|
||||
case coredata.PersonalAPIKeyEntityType:
|
||||
action = iam.ActionPersonalAPIKeyGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
personalAPIKey, err := r.iam.GetPersonalAPIKey(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewPersonalAPIKey(personalAPIKey), nil
|
||||
}
|
||||
case coredata.SCIMConfigurationEntityType:
|
||||
action = iam.ActionSCIMConfigurationGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
scimConfiguration, err := r.iam.GetSCIMConfiguration(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewSCIMConfiguration(scimConfiguration), nil
|
||||
}
|
||||
case coredata.SCIMEventEntityType:
|
||||
action = iam.ActionSCIMEventGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
scimEvent, err := r.iam.GetSCIMEvent(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewSCIMEvent(scimEvent), nil
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported entity type: %d", id.EntityType())
|
||||
}
|
||||
|
||||
if err := r.authorize(ctx, id, action); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
node, err := loadNode(ctx, id)
|
||||
if err != nil {
|
||||
var (
|
||||
errOrganizationNotFound *iam.ErrOrganizationNotFound
|
||||
errIdentityNotFound *iam.ErrIdentityNotFound
|
||||
errSessionNotFound *iam.ErrSessionNotFound
|
||||
errProfileNotFound *iam.ErrProfileNotFound
|
||||
errMembershipNotFound *iam.ErrMembershipNotFound
|
||||
errInvitationNotFound *iam.ErrInvitationNotFound
|
||||
|
||||
isNotFoundErr = errors.As(err, &errOrganizationNotFound) ||
|
||||
errors.As(err, &errIdentityNotFound) ||
|
||||
errors.As(err, &errSessionNotFound) ||
|
||||
errors.As(err, &errProfileNotFound) ||
|
||||
errors.As(err, &errMembershipNotFound) ||
|
||||
errors.As(err, &errInvitationNotFound)
|
||||
)
|
||||
|
||||
if isNotFoundErr {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot load node", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return node, nil
|
||||
}
|
||||
|
||||
// Viewer is the resolver for the viewer field.
|
||||
func (r *queryResolver) Viewer(ctx context.Context) (*types.Identity, error) {
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
|
||||
return &types.Identity{
|
||||
ID: identity.ID,
|
||||
Email: identity.EmailAddress,
|
||||
EmailVerified: identity.EmailAddressVerified,
|
||||
FullName: identity.FullName,
|
||||
CreatedAt: identity.CreatedAt,
|
||||
UpdatedAt: identity.UpdatedAt,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SsoLoginURL is the resolver for the ssoLoginURL field.
|
||||
func (r *queryResolver) SsoLoginURL(ctx context.Context, email mail.Addr) (*string, error) {
|
||||
count, err := r.iam.AccountService.CountSAMLConfigurationsForEmail(ctx, email)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count SAML configurations for email", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
if count != 1 {
|
||||
if count == 0 {
|
||||
return nil, graphql.ErrorOnPath(
|
||||
ctx,
|
||||
fmt.Errorf("no SAML configuration for email"),
|
||||
)
|
||||
}
|
||||
|
||||
return nil, graphql.ErrorOnPath(
|
||||
ctx,
|
||||
fmt.Errorf("multiple SSO configurations found for this domain. Please use your organization-specific SSO login URL"),
|
||||
)
|
||||
}
|
||||
|
||||
samlConfigs, err := r.iam.AccountService.ListSAMLConfigurationsForEmail(ctx, email)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list SAML configurations for email", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
samlConfig := samlConfigs[0]
|
||||
loginURL := r.SSOLoginURL(samlConfig.ID)
|
||||
|
||||
return &loginURL, nil
|
||||
}
|
||||
|
||||
// OidcProviders is the resolver for the oidcProviders field.
|
||||
func (r *queryResolver) OidcProviders(ctx context.Context) ([]*types.OIDCProviderInfo, error) {
|
||||
providers := r.iam.OIDCService.EnabledProviders()
|
||||
result := make([]*types.OIDCProviderInfo, 0, len(providers))
|
||||
|
||||
for _, p := range providers {
|
||||
result = append(result, &types.OIDCProviderInfo{
|
||||
Name: strings.ToLower(p.String()),
|
||||
LoginURL: r.baseURL.WithPath("/api/connect/v1/oidc/" + strings.ToLower(p.String()) + "/login").MustString(),
|
||||
})
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// SignUpEnabled is the resolver for the signUpEnabled field.
|
||||
func (r *queryResolver) SignUpEnabled(ctx context.Context) (bool, error) {
|
||||
return r.iam.IsSignUpEnabled(), nil
|
||||
}
|
||||
|
||||
// Identity returns schema.IdentityResolver implementation.
|
||||
func (r *Resolver) Identity() schema.IdentityResolver { return &identityResolver{r} }
|
||||
|
||||
// Mutation returns schema.MutationResolver implementation.
|
||||
func (r *Resolver) Mutation() schema.MutationResolver { return &mutationResolver{r} }
|
||||
|
||||
// Organization returns schema.OrganizationResolver implementation.
|
||||
func (r *Resolver) Organization() schema.OrganizationResolver { return &organizationResolver{r} }
|
||||
|
||||
// Query returns schema.QueryResolver implementation.
|
||||
func (r *Resolver) Query() schema.QueryResolver { return &queryResolver{r} }
|
||||
|
||||
type identityResolver struct{ *Resolver }
|
||||
type mutationResolver struct{ *Resolver }
|
||||
type organizationResolver struct{ *Resolver }
|
||||
type queryResolver struct{ *Resolver }
|
||||
@@ -1,5 +1,5 @@
|
||||
schema:
|
||||
- "schema.graphql"
|
||||
- "graphql/*.graphql"
|
||||
- "../../../gqlutils/directives/session/schema.graphql"
|
||||
|
||||
exec:
|
||||
@@ -14,7 +14,7 @@ resolver:
|
||||
layout: "follow-schema"
|
||||
dir: "."
|
||||
package: "connect_v1"
|
||||
filename_template: "v1_resolver.go"
|
||||
filename_template: "{name}.resolvers.go"
|
||||
|
||||
autobind: []
|
||||
call_argument_directives_with_null: true
|
||||
|
||||
83
pkg/server/api/connect/v1/graphql/audit_log.graphql
Normal file
83
pkg/server/api/connect/v1/graphql/audit_log.graphql
Normal file
@@ -0,0 +1,83 @@
|
||||
extend type Organization {
|
||||
auditLogEntries(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: AuditLogEntryOrder
|
||||
filter: AuditLogEntryFilter
|
||||
): AuditLogEntryConnection! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
enum AuditLogActorType
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.AuditLogActorType"
|
||||
) {
|
||||
USER
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AuditLogActorTypeUser"
|
||||
)
|
||||
API_KEY
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AuditLogActorTypeAPIKey"
|
||||
)
|
||||
SYSTEM
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AuditLogActorTypeSystem"
|
||||
)
|
||||
}
|
||||
|
||||
enum AuditLogEntryOrderField
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.AuditLogEntryOrderField"
|
||||
) {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AuditLogEntryOrderFieldCreatedAt"
|
||||
)
|
||||
}
|
||||
|
||||
input AuditLogEntryOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/connect/v1/types.AuditLogEntryOrderBy"
|
||||
) {
|
||||
field: AuditLogEntryOrderField!
|
||||
direction: OrderDirection!
|
||||
}
|
||||
|
||||
input AuditLogEntryFilter {
|
||||
action: String
|
||||
actorId: ID
|
||||
resourceType: String
|
||||
resourceId: ID
|
||||
}
|
||||
|
||||
type AuditLogEntry implements Node {
|
||||
id: ID!
|
||||
organization: Organization @goField(forceResolver: true)
|
||||
actorId: ID!
|
||||
actorType: AuditLogActorType!
|
||||
action: String!
|
||||
resourceType: String!
|
||||
resourceId: ID!
|
||||
metadata: String
|
||||
createdAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean!
|
||||
@goField(forceResolver: true)
|
||||
@session(required: PRESENT)
|
||||
}
|
||||
|
||||
type AuditLogEntryConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/connect/v1/types.AuditLogEntryConnection"
|
||||
) {
|
||||
edges: [AuditLogEntryEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type AuditLogEntryEdge {
|
||||
cursor: CursorKey!
|
||||
node: AuditLogEntry!
|
||||
}
|
||||
121
pkg/server/api/connect/v1/graphql/base.graphql
Normal file
121
pkg/server/api/connect/v1/graphql/base.graphql
Normal file
@@ -0,0 +1,121 @@
|
||||
directive @goField(
|
||||
forceResolver: Boolean
|
||||
name: String
|
||||
omittable: Boolean
|
||||
) on INPUT_FIELD_DEFINITION | FIELD_DEFINITION
|
||||
|
||||
directive @goModel(
|
||||
model: String
|
||||
models: [String!]
|
||||
) on OBJECT | INPUT_OBJECT | SCALAR | ENUM | INTERFACE | UNION
|
||||
|
||||
directive @goEnum(value: String) on ENUM_VALUE
|
||||
|
||||
scalar CursorKey
|
||||
scalar Datetime
|
||||
scalar Upload
|
||||
scalar EmailAddr
|
||||
|
||||
enum OrderDirection
|
||||
@goModel(model: "go.probo.inc/probo/pkg/page.OrderDirection") {
|
||||
ASC @goEnum(value: "go.probo.inc/probo/pkg/page.OrderDirectionAsc")
|
||||
DESC @goEnum(value: "go.probo.inc/probo/pkg/page.OrderDirectionDesc")
|
||||
}
|
||||
|
||||
interface Node {
|
||||
id: ID!
|
||||
}
|
||||
|
||||
type PageInfo {
|
||||
hasNextPage: Boolean!
|
||||
hasPreviousPage: Boolean!
|
||||
startCursor: CursorKey
|
||||
endCursor: CursorKey
|
||||
}
|
||||
|
||||
type OIDCProviderInfo {
|
||||
name: String!
|
||||
loginURL: String!
|
||||
}
|
||||
|
||||
enum ReauthenticationReason {
|
||||
SESSION_EXPIRED
|
||||
SENSITIVE_ACTION
|
||||
POLICY_REQUIREMENT
|
||||
}
|
||||
|
||||
type Query {
|
||||
node(id: ID!): Node @session(required: PRESENT)
|
||||
viewer: Identity @session(required: PRESENT)
|
||||
ssoLoginURL(email: EmailAddr!): String
|
||||
@goField(forceResolver: true)
|
||||
@session(required: OPTIONAL)
|
||||
oidcProviders: [OIDCProviderInfo!]!
|
||||
@goField(forceResolver: true)
|
||||
@session(required: OPTIONAL)
|
||||
signUpEnabled: Boolean!
|
||||
@goField(forceResolver: true)
|
||||
@session(required: OPTIONAL)
|
||||
}
|
||||
|
||||
type Identity implements Node {
|
||||
id: ID!
|
||||
email: EmailAddr!
|
||||
fullName: String!
|
||||
emailVerified: Boolean!
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
ssoLoginURL: String
|
||||
@goField(forceResolver: true)
|
||||
@session(required: PRESENT)
|
||||
|
||||
permission(action: String!): Boolean!
|
||||
@goField(forceResolver: true)
|
||||
@session(required: PRESENT)
|
||||
}
|
||||
|
||||
type Organization implements Node {
|
||||
id: ID!
|
||||
name: String!
|
||||
logoUrl: String @goField(forceResolver: true)
|
||||
horizontalLogoUrl: String @goField(forceResolver: true)
|
||||
email: String
|
||||
description: String
|
||||
websiteUrl: String
|
||||
headquarterAddress: String
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
viewer: Profile @goField(forceResolver: true)
|
||||
|
||||
permission(action: String!): Boolean!
|
||||
@goField(forceResolver: true)
|
||||
@session(required: PRESENT)
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
signIn(input: SignInInput!): SignInPayload @session(required: OPTIONAL)
|
||||
signUp(input: SignUpInput!): SignUpPayload @session(required: NONE)
|
||||
signOut: SignOutPayload @session(required: PRESENT)
|
||||
activateAccount(
|
||||
input: ActivateAccountInput!
|
||||
): ActivateAccountPayload @session(required: OPTIONAL)
|
||||
forgotPassword(input: ForgotPasswordInput!): ForgotPasswordPayload
|
||||
@session(required: NONE)
|
||||
resetPassword(input: ResetPasswordInput!): ResetPasswordPayload
|
||||
@session(required: NONE)
|
||||
verifyEmail(input: VerifyEmailInput!): VerifyEmailPayload
|
||||
@session(required: OPTIONAL)
|
||||
changePassword(input: ChangePasswordInput!): ChangePasswordPayload
|
||||
@session(required: PRESENT)
|
||||
changeEmail(input: ChangeEmailInput!): ChangeEmailPayload
|
||||
@session(required: PRESENT)
|
||||
assumeOrganizationSession(
|
||||
input: AssumeOrganizationSessionInput!
|
||||
): AssumeOrganizationSessionPayload @session(required: PRESENT)
|
||||
|
||||
revokeSession(input: RevokeSessionInput!): RevokeSessionPayload!
|
||||
@session(required: PRESENT)
|
||||
revokeAllSessions: RevokeAllSessionsPayload @session(required: PRESENT)
|
||||
}
|
||||
56
pkg/server/api/connect/v1/graphql/organization.graphql
Normal file
56
pkg/server/api/connect/v1/graphql/organization.graphql
Normal file
@@ -0,0 +1,56 @@
|
||||
extend type Mutation {
|
||||
createOrganization(
|
||||
input: CreateOrganizationInput!
|
||||
): CreateOrganizationPayload @session(required: PRESENT)
|
||||
updateOrganization(
|
||||
input: UpdateOrganizationInput!
|
||||
): UpdateOrganizationPayload @session(required: PRESENT)
|
||||
deleteOrganization(
|
||||
input: DeleteOrganizationInput!
|
||||
): DeleteOrganizationPayload @session(required: PRESENT)
|
||||
deleteOrganizationHorizontalLogo(
|
||||
input: DeleteOrganizationHorizontalLogoInput!
|
||||
): DeleteOrganizationHorizontalLogoPayload @session(required: PRESENT)
|
||||
}
|
||||
|
||||
input CreateOrganizationInput {
|
||||
name: String!
|
||||
logoFile: Upload
|
||||
horizontalLogoFile: Upload
|
||||
}
|
||||
|
||||
input UpdateOrganizationInput {
|
||||
organizationId: ID!
|
||||
name: String
|
||||
logoFile: Upload
|
||||
horizontalLogoFile: Upload
|
||||
description: String @goField(omittable: true)
|
||||
websiteUrl: String @goField(omittable: true)
|
||||
email: String @goField(omittable: true)
|
||||
headquarterAddress: String @goField(omittable: true)
|
||||
}
|
||||
|
||||
input DeleteOrganizationInput {
|
||||
organizationId: ID!
|
||||
}
|
||||
|
||||
input DeleteOrganizationHorizontalLogoInput {
|
||||
organizationId: ID!
|
||||
}
|
||||
|
||||
type CreateOrganizationPayload {
|
||||
organization: Organization
|
||||
profile: Profile!
|
||||
}
|
||||
|
||||
type UpdateOrganizationPayload {
|
||||
organization: Organization
|
||||
}
|
||||
|
||||
type DeleteOrganizationPayload {
|
||||
deletedOrganizationId: ID!
|
||||
}
|
||||
|
||||
type DeleteOrganizationHorizontalLogoPayload {
|
||||
organization: Organization!
|
||||
}
|
||||
63
pkg/server/api/connect/v1/graphql/personal_api_key.graphql
Normal file
63
pkg/server/api/connect/v1/graphql/personal_api_key.graphql
Normal file
@@ -0,0 +1,63 @@
|
||||
extend type Identity {
|
||||
personalAPIKeys(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
): PersonalAPIKeyConnection @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type PersonalAPIKey implements Node {
|
||||
id: ID!
|
||||
name: String!
|
||||
expiresAt: Datetime!
|
||||
lastUsedAt: Datetime
|
||||
createdAt: Datetime!
|
||||
|
||||
token: String @goField(forceResolver: true)
|
||||
|
||||
permission(action: String!): Boolean!
|
||||
@goField(forceResolver: true)
|
||||
@session(required: PRESENT)
|
||||
}
|
||||
|
||||
type PersonalAPIKeyConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/connect/v1/types.PersonalAPIKeyConnection"
|
||||
) {
|
||||
edges: [PersonalAPIKeyEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
totalCount: Int @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type PersonalAPIKeyEdge {
|
||||
node: PersonalAPIKey!
|
||||
cursor: CursorKey!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
createPersonalAPIKey(
|
||||
input: CreatePersonalAPIKeyInput!
|
||||
): CreatePersonalAPIKeyPayload @session(required: PRESENT)
|
||||
revokePersonalAPIKey(
|
||||
input: RevokePersonalAPIKeyInput!
|
||||
): RevokePersonalAPIKeyPayload @session(required: PRESENT)
|
||||
}
|
||||
|
||||
input CreatePersonalAPIKeyInput {
|
||||
name: String!
|
||||
expiresAt: Datetime!
|
||||
}
|
||||
|
||||
input RevokePersonalAPIKeyInput {
|
||||
personalAPIKeyId: ID!
|
||||
}
|
||||
|
||||
type CreatePersonalAPIKeyPayload {
|
||||
personalAPIKeyEdge: PersonalAPIKeyEdge!
|
||||
token: String!
|
||||
}
|
||||
|
||||
type RevokePersonalAPIKeyPayload {
|
||||
personalAPIKeyId: ID!
|
||||
}
|
||||
271
pkg/server/api/connect/v1/graphql/profile.graphql
Normal file
271
pkg/server/api/connect/v1/graphql/profile.graphql
Normal file
@@ -0,0 +1,271 @@
|
||||
extend type Identity {
|
||||
profiles(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: ProfileOrder
|
||||
filter: ProfileFilter
|
||||
): ProfileConnection @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
extend type Organization {
|
||||
profiles(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: ProfileOrder
|
||||
): ProfileConnection @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type Profile implements Node {
|
||||
id: ID!
|
||||
fullName: String!
|
||||
emailAddress: EmailAddr!
|
||||
source: String!
|
||||
state: ProfileState!
|
||||
additionalEmailAddresses: [EmailAddr!]!
|
||||
kind: String
|
||||
position: String
|
||||
contractStartDate: Datetime
|
||||
contractEndDate: Datetime
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
identity: Identity @goField(forceResolver: true)
|
||||
organization: Organization @goField(forceResolver: true)
|
||||
membership: Membership @goField(forceResolver: true)
|
||||
pendingInvitations(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: InvitationOrder
|
||||
): InvitationConnection @goField(forceResolver: true)
|
||||
|
||||
permission(action: String!): Boolean!
|
||||
@goField(forceResolver: true)
|
||||
@session(required: PRESENT)
|
||||
}
|
||||
|
||||
enum ProfileState
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.ProfileState") {
|
||||
ACTIVE @goEnum(value: "go.probo.inc/probo/pkg/coredata.ProfileStateActive")
|
||||
INACTIVE
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.ProfileStateInactive")
|
||||
}
|
||||
|
||||
enum ProfileSource
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.ProfileSource") {
|
||||
MANUAL
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.ProfileSourceManual")
|
||||
SAML @goEnum(value: "go.probo.inc/probo/pkg/coredata.ProfileSourceSAML")
|
||||
SCIM @goEnum(value: "go.probo.inc/probo/pkg/coredata.ProfileSourceSCIM")
|
||||
}
|
||||
|
||||
enum MembershipRole
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.MembershipRole") {
|
||||
OWNER @goEnum(value: "go.probo.inc/probo/pkg/coredata.MembershipRoleOwner")
|
||||
ADMIN @goEnum(value: "go.probo.inc/probo/pkg/coredata.MembershipRoleAdmin")
|
||||
EMPLOYEE
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.MembershipRoleEmployee")
|
||||
VIEWER @goEnum(value: "go.probo.inc/probo/pkg/coredata.MembershipRoleViewer")
|
||||
AUDITOR
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.MembershipRoleAuditor")
|
||||
}
|
||||
|
||||
type Membership implements Node {
|
||||
id: ID!
|
||||
createdAt: Datetime!
|
||||
role: MembershipRole!
|
||||
|
||||
lastSession: Session @goField(forceResolver: true)
|
||||
|
||||
permission(action: String!): Boolean!
|
||||
@goField(forceResolver: true)
|
||||
@session(required: PRESENT)
|
||||
}
|
||||
|
||||
type Invitation implements Node {
|
||||
id: ID!
|
||||
expiresAt: Datetime!
|
||||
acceptedAt: Datetime
|
||||
createdAt: Datetime!
|
||||
status: InvitationStatus!
|
||||
|
||||
permission(action: String!): Boolean!
|
||||
@goField(forceResolver: true)
|
||||
@session(required: PRESENT)
|
||||
}
|
||||
|
||||
enum InvitationStatus
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.InvitationStatus") {
|
||||
PENDING
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.InvitationStatusPending")
|
||||
ACCEPTED
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.InvitationStatusAccepted")
|
||||
EXPIRED
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.InvitationStatusExpired")
|
||||
}
|
||||
|
||||
enum InvitationOrderField
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.InvitationOrderField") {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.InvitationOrderFieldCreatedAt"
|
||||
)
|
||||
}
|
||||
|
||||
input InvitationOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/connect/v1/types.InvitationOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: InvitationOrderField!
|
||||
}
|
||||
|
||||
type InvitationConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/connect/v1/types.InvitationConnection"
|
||||
) {
|
||||
edges: [InvitationEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type InvitationEdge {
|
||||
node: Invitation!
|
||||
cursor: CursorKey!
|
||||
}
|
||||
|
||||
enum ProfileOrderField
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.MembershipProfileOrderField") {
|
||||
FULL_NAME
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.MembershipProfileOrderFieldFullName"
|
||||
)
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.MembershipProfileOrderFieldCreatedAt"
|
||||
)
|
||||
KIND @goEnum(value: "go.probo.inc/probo/pkg/coredata.MembershipProfileOrderFieldKind")
|
||||
ORGANIZATION_NAME
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.MembershipProfileOrderFieldOrganizationName"
|
||||
)
|
||||
STATE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.MembershipProfileOrderFieldState"
|
||||
)
|
||||
}
|
||||
|
||||
input ProfileFilter {
|
||||
excludeContractEnded: Boolean
|
||||
state: ProfileState
|
||||
}
|
||||
|
||||
input ProfileOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/connect/v1/types.ProfileOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: ProfileOrderField!
|
||||
}
|
||||
|
||||
type ProfileConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/connect/v1/types.ProfileConnection"
|
||||
) {
|
||||
totalCount: Int @goField(forceResolver: true)
|
||||
edges: [ProfileEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type ProfileEdge {
|
||||
cursor: CursorKey!
|
||||
node: Profile!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
createUser(input: CreateUserInput!): CreateUserPayload
|
||||
@session(required: PRESENT)
|
||||
inviteUser(input: InviteUserInput!): InviteUserPayload
|
||||
@session(required: PRESENT)
|
||||
deactivateUser(input: DeactivateUserInput!): DeactivateUserPayload
|
||||
updateUser(input: UpdateUserInput!): UpdateUserPayload!
|
||||
updateMembership(input: UpdateMembershipInput!): UpdateMembershipPayload!
|
||||
removeUser(input: RemoveUserInput!): RemoveUserPayload
|
||||
@session(required: PRESENT)
|
||||
}
|
||||
|
||||
input CreateUserInput {
|
||||
organizationId: ID!
|
||||
fullName: String!
|
||||
emailAddress: EmailAddr!
|
||||
role: MembershipRole!
|
||||
additionalEmailAddresses: [EmailAddr!]
|
||||
kind: String
|
||||
position: String
|
||||
contractStartDate: Datetime @goField(omittable: true)
|
||||
contractEndDate: Datetime @goField(omittable: true)
|
||||
}
|
||||
|
||||
input InviteUserInput {
|
||||
organizationId: ID!
|
||||
profileId: ID!
|
||||
}
|
||||
|
||||
input ActivateUserInput {
|
||||
organizationId: ID!
|
||||
profileId: ID!
|
||||
}
|
||||
|
||||
input DeactivateUserInput {
|
||||
organizationId: ID!
|
||||
profileId: ID!
|
||||
}
|
||||
|
||||
input UpdateUserInput {
|
||||
id: ID!
|
||||
fullName: String!
|
||||
additionalEmailAddresses: [EmailAddr!]
|
||||
kind: String
|
||||
position: String
|
||||
contractStartDate: Datetime @goField(omittable: true)
|
||||
contractEndDate: Datetime @goField(omittable: true)
|
||||
}
|
||||
|
||||
input UpdateMembershipInput {
|
||||
organizationId: ID!
|
||||
membershipId: ID!
|
||||
role: MembershipRole!
|
||||
}
|
||||
|
||||
input RemoveUserInput {
|
||||
organizationId: ID!
|
||||
profileId: ID!
|
||||
}
|
||||
|
||||
type CreateUserPayload {
|
||||
profileEdge: ProfileEdge!
|
||||
}
|
||||
|
||||
type InviteUserPayload {
|
||||
invitationEdge: InvitationEdge!
|
||||
}
|
||||
|
||||
type DeactivateUserPayload {
|
||||
success: Boolean!
|
||||
}
|
||||
|
||||
type UpdateUserPayload {
|
||||
profile: Profile!
|
||||
}
|
||||
|
||||
type UpdateMembershipPayload {
|
||||
membership: Membership!
|
||||
}
|
||||
|
||||
type RemoveUserPayload {
|
||||
deletedProfileId: ID!
|
||||
}
|
||||
119
pkg/server/api/connect/v1/graphql/saml.graphql
Normal file
119
pkg/server/api/connect/v1/graphql/saml.graphql
Normal file
@@ -0,0 +1,119 @@
|
||||
extend type Organization {
|
||||
samlConfigurations(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
): SAMLConfigurationConnection @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type SAMLConfiguration implements Node {
|
||||
id: ID!
|
||||
emailDomain: String!
|
||||
enforcementPolicy: SAMLEnforcementPolicy!
|
||||
domainVerifiedAt: Datetime
|
||||
domainVerificationToken: String
|
||||
idpEntityId: String!
|
||||
idpSsoUrl: String!
|
||||
idpCertificate: String!
|
||||
autoSignupEnabled: Boolean!
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
testLoginUrl: String! @goField(forceResolver: true)
|
||||
attributeMappings: SAMLAttributeMappings!
|
||||
|
||||
permission(action: String!): Boolean!
|
||||
@goField(forceResolver: true)
|
||||
@session(required: PRESENT)
|
||||
}
|
||||
|
||||
type SAMLAttributeMappings {
|
||||
email: String!
|
||||
firstName: String!
|
||||
lastName: String!
|
||||
role: String!
|
||||
}
|
||||
|
||||
enum SAMLEnforcementPolicy
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.SAMLEnforcementPolicy") {
|
||||
OFF @goEnum(value: "go.probo.inc/probo/pkg/coredata.SAMLEnforcementPolicyOff")
|
||||
OPTIONAL
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.SAMLEnforcementPolicyOptional"
|
||||
)
|
||||
REQUIRED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.SAMLEnforcementPolicyRequired"
|
||||
)
|
||||
}
|
||||
|
||||
type SAMLConfigurationConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/connect/v1/types.SAMLConfigurationConnection"
|
||||
) {
|
||||
edges: [SAMLConfigurationEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
totalCount: Int @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type SAMLConfigurationEdge {
|
||||
node: SAMLConfiguration!
|
||||
cursor: CursorKey!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
createSAMLConfiguration(
|
||||
input: CreateSAMLConfigurationInput!
|
||||
): CreateSAMLConfigurationPayload @session(required: PRESENT)
|
||||
updateSAMLConfiguration(
|
||||
input: UpdateSAMLConfigurationInput!
|
||||
): UpdateSAMLConfigurationPayload @session(required: PRESENT)
|
||||
deleteSAMLConfiguration(
|
||||
input: DeleteSAMLConfigurationInput!
|
||||
): DeleteSAMLConfigurationPayload @session(required: PRESENT)
|
||||
}
|
||||
|
||||
input CreateSAMLConfigurationInput {
|
||||
organizationId: ID!
|
||||
emailDomain: String!
|
||||
idpEntityId: String!
|
||||
idpSsoUrl: String!
|
||||
idpCertificate: String!
|
||||
autoSignupEnabled: Boolean!
|
||||
attributeMappings: SAMLAttributeMappingsInput
|
||||
}
|
||||
|
||||
input SAMLAttributeMappingsInput {
|
||||
email: String
|
||||
firstName: String
|
||||
lastName: String
|
||||
role: String
|
||||
}
|
||||
|
||||
input UpdateSAMLConfigurationInput {
|
||||
organizationId: ID!
|
||||
samlConfigurationId: ID!
|
||||
idpEntityId: String
|
||||
idpSsoUrl: String
|
||||
idpCertificate: String
|
||||
autoSignupEnabled: Boolean
|
||||
enforcementPolicy: SAMLEnforcementPolicy!
|
||||
attributeMappings: SAMLAttributeMappingsInput
|
||||
}
|
||||
|
||||
input DeleteSAMLConfigurationInput {
|
||||
organizationId: ID!
|
||||
samlConfigurationId: ID!
|
||||
}
|
||||
|
||||
type CreateSAMLConfigurationPayload {
|
||||
samlConfigurationEdge: SAMLConfigurationEdge!
|
||||
}
|
||||
|
||||
type UpdateSAMLConfigurationPayload {
|
||||
samlConfiguration: SAMLConfiguration
|
||||
}
|
||||
|
||||
type DeleteSAMLConfigurationPayload {
|
||||
deletedSamlConfigurationId: ID!
|
||||
}
|
||||
182
pkg/server/api/connect/v1/graphql/scim.graphql
Normal file
182
pkg/server/api/connect/v1/graphql/scim.graphql
Normal file
@@ -0,0 +1,182 @@
|
||||
extend type Organization {
|
||||
scimConfiguration: SCIMConfiguration @goField(forceResolver: true)
|
||||
scimBridgeTypes: [SCIMBridgeTypeInfo!]! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type SCIMConfiguration implements Node {
|
||||
id: ID!
|
||||
endpointUrl: String! @goField(forceResolver: true)
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
organization: Organization @goField(forceResolver: true)
|
||||
|
||||
bridge: SCIMBridge @goField(forceResolver: true)
|
||||
|
||||
events(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: SCIMEventOrder
|
||||
): SCIMEventConnection @goField(forceResolver: true)
|
||||
|
||||
permission(action: String!): Boolean!
|
||||
@goField(forceResolver: true)
|
||||
@session(required: PRESENT)
|
||||
}
|
||||
|
||||
type SCIMBridge implements Node {
|
||||
id: ID!
|
||||
state: SCIMBridgeState!
|
||||
scimConfiguration: SCIMConfiguration @goField(forceResolver: true)
|
||||
connector: Connector @goField(forceResolver: true)
|
||||
type: SCIMBridgeType!
|
||||
excludedUserNames: [String!]!
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean!
|
||||
@goField(forceResolver: true)
|
||||
@session(required: PRESENT)
|
||||
}
|
||||
|
||||
type Connector implements Node {
|
||||
id: ID!
|
||||
provider: ConnectorProvider!
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean!
|
||||
@goField(forceResolver: true)
|
||||
@session(required: PRESENT)
|
||||
}
|
||||
|
||||
enum ConnectorProvider
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.ConnectorProvider") {
|
||||
SLACK @goEnum(value: "go.probo.inc/probo/pkg/coredata.ConnectorProviderSlack")
|
||||
GOOGLE_WORKSPACE
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.ConnectorProviderGoogleWorkspace")
|
||||
BREX @goEnum(value: "go.probo.inc/probo/pkg/coredata.ConnectorProviderBrex")
|
||||
TALLY @goEnum(value: "go.probo.inc/probo/pkg/coredata.ConnectorProviderTally")
|
||||
CLOUDFLARE
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.ConnectorProviderCloudflare")
|
||||
}
|
||||
|
||||
enum SCIMBridgeType
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.SCIMBridgeType") {
|
||||
GOOGLE_WORKSPACE @goEnum(value: "go.probo.inc/probo/pkg/coredata.SCIMBridgeTypeGoogleWorkspace")
|
||||
}
|
||||
|
||||
type SCIMBridgeTypeInfo {
|
||||
type: SCIMBridgeType!
|
||||
oauth2Scopes: [String!]!
|
||||
}
|
||||
|
||||
enum SCIMBridgeState
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.SCIMBridgeState") {
|
||||
PENDING @goEnum(value: "go.probo.inc/probo/pkg/coredata.SCIMBridgeStatePending")
|
||||
ACTIVE @goEnum(value: "go.probo.inc/probo/pkg/coredata.SCIMBridgeStateActive")
|
||||
FAILED @goEnum(value: "go.probo.inc/probo/pkg/coredata.SCIMBridgeStateFailed")
|
||||
}
|
||||
|
||||
type SCIMEvent implements Node {
|
||||
id: ID!
|
||||
method: String!
|
||||
path: String!
|
||||
statusCode: Int!
|
||||
requestBody: String
|
||||
responseBody: String
|
||||
errorMessage: String
|
||||
userName: String!
|
||||
ipAddress: String!
|
||||
createdAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean!
|
||||
@goField(forceResolver: true)
|
||||
@session(required: PRESENT)
|
||||
}
|
||||
|
||||
enum SCIMEventOrderField
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.SCIMEventOrderField") {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.SCIMEventOrderFieldCreatedAt"
|
||||
)
|
||||
}
|
||||
|
||||
input SCIMEventOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/connect/v1/types.SCIMEventOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: SCIMEventOrderField!
|
||||
}
|
||||
|
||||
type SCIMEventConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/connect/v1/types.SCIMEventConnection"
|
||||
) {
|
||||
edges: [SCIMEventEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
totalCount: Int @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type SCIMEventEdge {
|
||||
node: SCIMEvent!
|
||||
cursor: CursorKey!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
createSCIMConfiguration(
|
||||
input: CreateSCIMConfigurationInput!
|
||||
): CreateSCIMConfigurationPayload @session(required: PRESENT)
|
||||
deleteSCIMConfiguration(
|
||||
input: DeleteSCIMConfigurationInput!
|
||||
): DeleteSCIMConfigurationPayload @session(required: PRESENT)
|
||||
regenerateSCIMToken(
|
||||
input: RegenerateSCIMTokenInput!
|
||||
): RegenerateSCIMTokenPayload @session(required: PRESENT)
|
||||
updateSCIMBridge(
|
||||
input: UpdateSCIMBridgeInput!
|
||||
): UpdateSCIMBridgePayload @session(required: PRESENT)
|
||||
}
|
||||
|
||||
input CreateSCIMConfigurationInput {
|
||||
organizationId: ID!
|
||||
connectorId: ID
|
||||
}
|
||||
|
||||
input DeleteSCIMConfigurationInput {
|
||||
organizationId: ID!
|
||||
scimConfigurationId: ID!
|
||||
}
|
||||
|
||||
input RegenerateSCIMTokenInput {
|
||||
organizationId: ID!
|
||||
scimConfigurationId: ID!
|
||||
}
|
||||
|
||||
input UpdateSCIMBridgeInput {
|
||||
organizationId: ID!
|
||||
scimBridgeId: ID!
|
||||
excludedUserNames: [String!]!
|
||||
}
|
||||
|
||||
type CreateSCIMConfigurationPayload {
|
||||
scimConfiguration: SCIMConfiguration!
|
||||
scimBridge: SCIMBridge
|
||||
token: String!
|
||||
}
|
||||
|
||||
type DeleteSCIMConfigurationPayload {
|
||||
deletedScimConfigurationId: ID!
|
||||
}
|
||||
|
||||
type RegenerateSCIMTokenPayload {
|
||||
scimConfiguration: SCIMConfiguration!
|
||||
token: String!
|
||||
}
|
||||
|
||||
type UpdateSCIMBridgePayload {
|
||||
scimBridge: SCIMBridge!
|
||||
}
|
||||
169
pkg/server/api/connect/v1/graphql/session.graphql
Normal file
169
pkg/server/api/connect/v1/graphql/session.graphql
Normal file
@@ -0,0 +1,169 @@
|
||||
enum SessionOrderField
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.SessionOrderField") {
|
||||
CREATED_AT
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.SessionOrderFieldCreatedAt")
|
||||
EXPIRED_AT
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.SessionOrderFieldExpiredAt")
|
||||
UPDATED_AT
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.SessionOrderFieldUpdatedAt")
|
||||
}
|
||||
|
||||
input SessionOrder {
|
||||
direction: OrderDirection!
|
||||
field: SessionOrderField!
|
||||
}
|
||||
|
||||
extend type Identity {
|
||||
sessions(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: SessionOrder
|
||||
): SessionConnection @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type Session implements Node {
|
||||
id: ID!
|
||||
identity: Identity @goField(forceResolver: true)
|
||||
ipAddress: String!
|
||||
userAgent: String!
|
||||
updatedAt: Datetime!
|
||||
createdAt: Datetime!
|
||||
expiresAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean!
|
||||
@goField(forceResolver: true)
|
||||
@session(required: PRESENT)
|
||||
}
|
||||
|
||||
type SessionConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/connect/v1/types.SessionConnection"
|
||||
) {
|
||||
edges: [SessionEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
totalCount: Int @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type SessionEdge {
|
||||
node: Session!
|
||||
cursor: CursorKey!
|
||||
}
|
||||
|
||||
input SignInInput {
|
||||
organizationId: ID
|
||||
email: EmailAddr!
|
||||
password: String!
|
||||
}
|
||||
|
||||
input SignUpInput {
|
||||
email: EmailAddr!
|
||||
password: String!
|
||||
fullName: String!
|
||||
}
|
||||
|
||||
input ActivateAccountInput {
|
||||
token: String!
|
||||
}
|
||||
|
||||
input ForgotPasswordInput {
|
||||
email: EmailAddr!
|
||||
}
|
||||
|
||||
input ResetPasswordInput {
|
||||
token: String!
|
||||
password: String!
|
||||
}
|
||||
|
||||
input VerifyEmailInput {
|
||||
token: String!
|
||||
}
|
||||
|
||||
input ChangePasswordInput {
|
||||
currentPassword: String!
|
||||
newPassword: String!
|
||||
}
|
||||
|
||||
input ChangeEmailInput {
|
||||
newEmail: EmailAddr!
|
||||
password: String!
|
||||
}
|
||||
|
||||
input AssumeOrganizationSessionInput {
|
||||
organizationId: ID!
|
||||
continue: String!
|
||||
}
|
||||
|
||||
input RevokeSessionInput {
|
||||
sessionId: ID!
|
||||
}
|
||||
|
||||
type SignInPayload {
|
||||
identity: Identity
|
||||
session: Session
|
||||
}
|
||||
|
||||
type SignUpPayload {
|
||||
identity: Identity
|
||||
}
|
||||
|
||||
type SignOutPayload {
|
||||
success: Boolean!
|
||||
}
|
||||
|
||||
type ActivateAccountPayload {
|
||||
createPasswordToken: String
|
||||
ssoLoginUrl: String
|
||||
profile: Profile
|
||||
}
|
||||
|
||||
type ForgotPasswordPayload {
|
||||
success: Boolean!
|
||||
}
|
||||
|
||||
type ResetPasswordPayload {
|
||||
success: Boolean!
|
||||
}
|
||||
|
||||
type VerifyEmailPayload {
|
||||
success: Boolean!
|
||||
}
|
||||
|
||||
type ChangePasswordPayload {
|
||||
success: Boolean!
|
||||
}
|
||||
|
||||
type ChangeEmailPayload {
|
||||
success: Boolean!
|
||||
}
|
||||
|
||||
union AssumeOrganizationSessionResult =
|
||||
| OrganizationSessionCreated
|
||||
| PasswordRequired
|
||||
| SAMLAuthenticationRequired
|
||||
|
||||
type OrganizationSessionCreated {
|
||||
session: Session!
|
||||
membership: Membership!
|
||||
}
|
||||
|
||||
type PasswordRequired {
|
||||
reason: ReauthenticationReason!
|
||||
}
|
||||
|
||||
type SAMLAuthenticationRequired {
|
||||
reason: ReauthenticationReason!
|
||||
}
|
||||
|
||||
type AssumeOrganizationSessionPayload {
|
||||
result: AssumeOrganizationSessionResult!
|
||||
}
|
||||
|
||||
type RevokeSessionPayload {
|
||||
success: Boolean!
|
||||
}
|
||||
|
||||
type RevokeAllSessionsPayload {
|
||||
revokedCount: Int!
|
||||
}
|
||||
150
pkg/server/api/connect/v1/organization.resolvers.go
Normal file
150
pkg/server/api/connect/v1/organization.resolvers.go
Normal file
@@ -0,0 +1,150 @@
|
||||
package connect_v1
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver
|
||||
// implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.87
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"go.gearno.de/kit/log"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/iam"
|
||||
"go.probo.inc/probo/pkg/server/api/authn"
|
||||
"go.probo.inc/probo/pkg/server/api/connect/v1/types"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils"
|
||||
)
|
||||
|
||||
// CreateOrganization is the resolver for the createOrganization field.
|
||||
func (r *mutationResolver) CreateOrganization(ctx context.Context, input types.CreateOrganizationInput) (*types.CreateOrganizationPayload, error) {
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
|
||||
// FIXME check email domain and related IDP config
|
||||
// if ok := r.authorize(ctx, identity.ID, iam.ActionOrganizationCreate); !ok {
|
||||
// return nil, nil
|
||||
// }
|
||||
|
||||
var (
|
||||
logoFile *iam.UploadedFile
|
||||
horizontalLogoFile *iam.UploadedFile
|
||||
)
|
||||
|
||||
if input.LogoFile != nil {
|
||||
logoFile = &iam.UploadedFile{
|
||||
Content: input.LogoFile.File,
|
||||
Filename: input.LogoFile.Filename,
|
||||
ContentType: input.LogoFile.ContentType,
|
||||
Size: input.LogoFile.Size,
|
||||
}
|
||||
}
|
||||
|
||||
if input.HorizontalLogoFile != nil {
|
||||
horizontalLogoFile = &iam.UploadedFile{
|
||||
Content: input.HorizontalLogoFile.File,
|
||||
Filename: input.HorizontalLogoFile.Filename,
|
||||
ContentType: input.HorizontalLogoFile.ContentType,
|
||||
Size: input.HorizontalLogoFile.Size,
|
||||
}
|
||||
}
|
||||
organization, profile, err := r.iam.OrganizationService.CreateOrganization(
|
||||
ctx,
|
||||
identity.ID,
|
||||
&iam.CreateOrganizationRequest{
|
||||
Name: input.Name,
|
||||
LogoFile: logoFile,
|
||||
HorizontalLogoFile: horizontalLogoFile,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceAlreadyExists) {
|
||||
return nil, gqlutils.Conflict(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot create organization", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.CreateOrganizationPayload{
|
||||
Organization: types.NewOrganization(organization),
|
||||
Profile: types.NewProfile(profile),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateOrganization is the resolver for the updateOrganization field.
|
||||
func (r *mutationResolver) UpdateOrganization(ctx context.Context, input types.UpdateOrganizationInput) (*types.UpdateOrganizationPayload, error) {
|
||||
if err := r.authorize(ctx, input.OrganizationID, iam.ActionOrganizationUpdate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req := &iam.UpdateOrganizationRequest{
|
||||
Name: input.Name,
|
||||
Description: gqlutils.UnwrapOmittable(input.Description),
|
||||
WebsiteURL: gqlutils.UnwrapOmittable(input.WebsiteURL),
|
||||
Email: gqlutils.UnwrapOmittable(input.Email),
|
||||
HeadquarterAddress: gqlutils.UnwrapOmittable(input.HeadquarterAddress),
|
||||
}
|
||||
|
||||
if input.LogoFile != nil {
|
||||
req.LogoFile = &iam.UploadedFile{
|
||||
Filename: input.LogoFile.Filename,
|
||||
ContentType: input.LogoFile.ContentType,
|
||||
Size: input.LogoFile.Size,
|
||||
Content: input.LogoFile.File,
|
||||
}
|
||||
}
|
||||
|
||||
if input.HorizontalLogoFile != nil {
|
||||
req.HorizontalLogoFile = &iam.UploadedFile{
|
||||
Filename: input.HorizontalLogoFile.Filename,
|
||||
ContentType: input.HorizontalLogoFile.ContentType,
|
||||
Size: input.HorizontalLogoFile.Size,
|
||||
Content: input.HorizontalLogoFile.File,
|
||||
}
|
||||
}
|
||||
|
||||
organization, err := r.iam.OrganizationService.UpdateOrganization(
|
||||
ctx,
|
||||
input.OrganizationID,
|
||||
req,
|
||||
)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot update organization", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.UpdateOrganizationPayload{
|
||||
Organization: &types.Organization{
|
||||
ID: organization.ID,
|
||||
Name: organization.Name,
|
||||
Description: organization.Description,
|
||||
WebsiteURL: organization.WebsiteURL,
|
||||
Email: organization.Email,
|
||||
HeadquarterAddress: organization.HeadquarterAddress,
|
||||
CreatedAt: organization.CreatedAt,
|
||||
UpdatedAt: organization.UpdatedAt,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteOrganization is the resolver for the deleteOrganization field.
|
||||
func (r *mutationResolver) DeleteOrganization(ctx context.Context, input types.DeleteOrganizationInput) (*types.DeleteOrganizationPayload, error) {
|
||||
if err := r.authorize(ctx, input.OrganizationID, iam.ActionOrganizationDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err := r.iam.OrganizationService.DeleteOrganization(ctx, input.OrganizationID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot delete organization", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DeleteOrganizationPayload{DeletedOrganizationID: input.OrganizationID}, nil
|
||||
}
|
||||
|
||||
// DeleteOrganizationHorizontalLogo is the resolver for the deleteOrganizationHorizontalLogo field.
|
||||
func (r *mutationResolver) DeleteOrganizationHorizontalLogo(ctx context.Context, input types.DeleteOrganizationHorizontalLogoInput) (*types.DeleteOrganizationHorizontalLogoPayload, error) {
|
||||
panic(fmt.Errorf("not implemented: DeleteOrganizationHorizontalLogo - deleteOrganizationHorizontalLogo"))
|
||||
}
|
||||
145
pkg/server/api/connect/v1/personal_api_key.resolvers.go
Normal file
145
pkg/server/api/connect/v1/personal_api_key.resolvers.go
Normal file
@@ -0,0 +1,145 @@
|
||||
package connect_v1
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver
|
||||
// implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.87
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.gearno.de/kit/log"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/iam"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"go.probo.inc/probo/pkg/server/api/authn"
|
||||
"go.probo.inc/probo/pkg/server/api/connect/v1/schema"
|
||||
"go.probo.inc/probo/pkg/server/api/connect/v1/types"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils/types/cursor"
|
||||
)
|
||||
|
||||
// PersonalAPIKeys is the resolver for the personalAPIKeys field.
|
||||
func (r *identityResolver) PersonalAPIKeys(ctx context.Context, obj *types.Identity, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.PersonalAPIKeyConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, iam.ActionPersonalAPIKeyList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if gqlutils.OnlyTotalCountSelected(ctx) {
|
||||
return &types.PersonalAPIKeyConnection{
|
||||
Resolver: r,
|
||||
ParentID: obj.ID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.PersonalAPIKeyOrderField]{
|
||||
Field: coredata.PersonalAPIKeyOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
|
||||
cursor := cursor.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
page, err := r.iam.AccountService.ListPersonalAPIKeys(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list personal api keys", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewPersonalAPIKeyConnection(page, r, obj.ID), nil
|
||||
}
|
||||
|
||||
// CreatePersonalAPIKey is the resolver for the createPersonalAPIKey field.
|
||||
func (r *mutationResolver) CreatePersonalAPIKey(ctx context.Context, input types.CreatePersonalAPIKeyInput) (*types.CreatePersonalAPIKeyPayload, error) {
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
|
||||
if err := r.authorize(ctx, identity.ID, iam.ActionPersonalAPIKeyCreate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userAPIKey, token, err := r.iam.AccountService.CreatePersonalAPIKey(
|
||||
ctx,
|
||||
identity.ID,
|
||||
input.Name,
|
||||
input.ExpiresAt,
|
||||
)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot create personal api key", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.CreatePersonalAPIKeyPayload{
|
||||
PersonalAPIKeyEdge: types.NewPersonalAPIKeyEdge(userAPIKey, coredata.PersonalAPIKeyOrderFieldCreatedAt),
|
||||
Token: token,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// RevokePersonalAPIKey is the resolver for the revokePersonalAPIKey field.
|
||||
func (r *mutationResolver) RevokePersonalAPIKey(ctx context.Context, input types.RevokePersonalAPIKeyInput) (*types.RevokePersonalAPIKeyPayload, error) {
|
||||
if err := r.authorize(ctx, input.PersonalAPIKeyID, iam.ActionPersonalAPIKeyDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
|
||||
err := r.iam.AccountService.DeletePersonalAPIKey(ctx, identity.ID, input.PersonalAPIKeyID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot delete personal api key", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.RevokePersonalAPIKeyPayload{PersonalAPIKeyID: input.PersonalAPIKeyID}, nil
|
||||
}
|
||||
|
||||
// Token is the resolver for the token field.
|
||||
func (r *personalAPIKeyResolver) Token(ctx context.Context, obj *types.PersonalAPIKey) (*string, error) {
|
||||
if err := r.authorize(ctx, obj.ID, iam.ActionPersonalAPIKeyGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
|
||||
token, err := r.iam.AccountService.RevealPersonalAPIKeyToken(ctx, identity.ID, obj.ID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot reveal personal api key token", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &token, nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *personalAPIKeyResolver) Permission(ctx context.Context, obj *types.PersonalAPIKey, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// TotalCount is the resolver for the totalCount field.
|
||||
func (r *personalAPIKeyConnectionResolver) TotalCount(ctx context.Context, obj *types.PersonalAPIKeyConnection) (*int, error) {
|
||||
switch obj.Resolver.(type) {
|
||||
case *identityResolver:
|
||||
if err := r.authorize(ctx, obj.ParentID, iam.ActionPersonalAPIKeyList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
count, err := r.iam.AccountService.CountPersonalAPIKeys(ctx, obj.ParentID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count personal api keys", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &count, nil
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "unsupported resolver", log.Any("resolver", obj.Resolver))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
// PersonalAPIKey returns schema.PersonalAPIKeyResolver implementation.
|
||||
func (r *Resolver) PersonalAPIKey() schema.PersonalAPIKeyResolver { return &personalAPIKeyResolver{r} }
|
||||
|
||||
// PersonalAPIKeyConnection returns schema.PersonalAPIKeyConnectionResolver implementation.
|
||||
func (r *Resolver) PersonalAPIKeyConnection() schema.PersonalAPIKeyConnectionResolver {
|
||||
return &personalAPIKeyConnectionResolver{r}
|
||||
}
|
||||
|
||||
type personalAPIKeyResolver struct{ *Resolver }
|
||||
type personalAPIKeyConnectionResolver struct{ *Resolver }
|
||||
441
pkg/server/api/connect/v1/profile.resolvers.go
Normal file
441
pkg/server/api/connect/v1/profile.resolvers.go
Normal file
@@ -0,0 +1,441 @@
|
||||
package connect_v1
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver
|
||||
// implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.87
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"go.gearno.de/kit/log"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/iam"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"go.probo.inc/probo/pkg/server/api/authn"
|
||||
"go.probo.inc/probo/pkg/server/api/authz"
|
||||
"go.probo.inc/probo/pkg/server/api/connect/v1/schema"
|
||||
"go.probo.inc/probo/pkg/server/api/connect/v1/types"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils/types/cursor"
|
||||
)
|
||||
|
||||
// Profiles is the resolver for the profiles field.
|
||||
func (r *identityResolver) Profiles(ctx context.Context, obj *types.Identity, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ProfileOrderBy, filter *types.ProfileFilter) (*types.ProfileConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileList, authz.WithSkipAssumptionCheck()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
filters := coredata.NewMembershipProfileFilter(nil).WithMembership()
|
||||
if filter != nil {
|
||||
filters = coredata.NewMembershipProfileFilter(filter.ExcludeContractEnded).WithMembership()
|
||||
if filter.State != nil {
|
||||
filters.WithState(*filter.State)
|
||||
}
|
||||
}
|
||||
|
||||
if gqlutils.OnlyTotalCountSelected(ctx) {
|
||||
return &types.ProfileConnection{
|
||||
Resolver: r,
|
||||
ParentID: obj.ID,
|
||||
Filters: filters,
|
||||
}, nil
|
||||
}
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.MembershipProfileOrderField]{
|
||||
Field: coredata.MembershipProfileOrderFieldFullName,
|
||||
Direction: page.OrderDirectionAsc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.MembershipProfileOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := cursor.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
page, err := r.iam.AccountService.ListProfilesForIdentity(ctx, obj.ID, cursor, filters)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list profiles", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewProfileConnection(page, r, obj.ID, filters), nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *invitationResolver) Permission(ctx context.Context, obj *types.Invitation, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// LastSession is the resolver for the lastSession field.
|
||||
func (r *membershipResolver) LastSession(ctx context.Context, obj *types.Membership) (*types.Session, error) {
|
||||
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipGet, authz.WithSkipAssumptionCheck()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
session := authn.SessionFromContext(ctx)
|
||||
if session == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
childSession, err := r.iam.SessionService.GetActiveSessionForMembership(ctx, session.ID, obj.ID)
|
||||
if err != nil {
|
||||
var errSessionNotFound *iam.ErrSessionNotFound
|
||||
if errors.As(err, &errSessionNotFound) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get active session for membership", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewSession(childSession), nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *membershipResolver) Permission(ctx context.Context, obj *types.Membership, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// CreateUser is the resolver for the createUser field.
|
||||
func (r *mutationResolver) CreateUser(ctx context.Context, input types.CreateUserInput) (*types.CreateUserPayload, error) {
|
||||
if err := r.authorize(ctx, input.OrganizationID, iam.ActionMembershipProfileCreate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
profile, err := r.iam.OrganizationService.CreateUser(
|
||||
ctx,
|
||||
&iam.CreateUserRequest{
|
||||
OrganizationID: input.OrganizationID,
|
||||
EmailAddress: input.EmailAddress,
|
||||
Role: input.Role,
|
||||
FullName: input.FullName,
|
||||
AdditionalEmailAddresses: input.AdditionalEmailAddresses,
|
||||
Kind: input.Kind,
|
||||
Position: input.Position,
|
||||
ContractStartDate: gqlutils.UnwrapOmittable(input.ContractStartDate),
|
||||
ContractEndDate: gqlutils.UnwrapOmittable(input.ContractEndDate),
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
var errAlreadyExists *iam.ErrUserAlreadyExists
|
||||
if errors.As(err, &errAlreadyExists) {
|
||||
return nil, gqlutils.Conflict(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot create user", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.CreateUserPayload{
|
||||
ProfileEdge: types.NewProfileEdge(profile, coredata.MembershipProfileOrderFieldCreatedAt),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// InviteUser is the resolver for the inviteUser field.
|
||||
func (r *mutationResolver) InviteUser(ctx context.Context, input types.InviteUserInput) (*types.InviteUserPayload, error) {
|
||||
if err := r.authorize(ctx, input.ProfileID, iam.ActionInvitationCreate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
invitation, err := r.iam.OrganizationService.InviteUser(
|
||||
ctx,
|
||||
&iam.CreateInvitationRequest{
|
||||
OrganizationID: input.OrganizationID,
|
||||
ProfileID: input.ProfileID,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
var errOrganizationNotFound *iam.ErrOrganizationNotFound
|
||||
var errUserAlreadyExists *iam.ErrUserAlreadyExists
|
||||
|
||||
if errors.As(err, &errOrganizationNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
if errors.As(err, &errUserAlreadyExists) {
|
||||
return nil, gqlutils.Conflict(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot invite user", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.InviteUserPayload{
|
||||
InvitationEdge: types.NewInvitationEdge(invitation, coredata.InvitationOrderFieldCreatedAt),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeactivateUser is the resolver for the deactivateUser field.
|
||||
func (r *mutationResolver) DeactivateUser(ctx context.Context, input types.DeactivateUserInput) (*types.DeactivateUserPayload, error) {
|
||||
if err := r.authorize(ctx, input.ProfileID, iam.ActionMembershipProfileDeactivate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err := r.iam.OrganizationService.UpdateUserState(
|
||||
ctx,
|
||||
input.ProfileID,
|
||||
coredata.ProfileStateInactive,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot deactivate profile", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DeactivateUserPayload{
|
||||
Success: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateUser is the resolver for the updateUser field.
|
||||
func (r *mutationResolver) UpdateUser(ctx context.Context, input types.UpdateUserInput) (*types.UpdateUserPayload, error) {
|
||||
if err := r.authorize(ctx, input.ID, iam.ActionMembershipProfileUpdate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
profile, err := r.iam.OrganizationService.UpdateUser(
|
||||
ctx,
|
||||
&iam.UpdateUserRequest{
|
||||
ID: input.ID,
|
||||
FullName: input.FullName,
|
||||
AdditionalEmailAddresses: input.AdditionalEmailAddresses,
|
||||
Kind: input.Kind,
|
||||
Position: input.Position,
|
||||
ContractStartDate: gqlutils.UnwrapOmittable(input.ContractStartDate),
|
||||
ContractEndDate: gqlutils.UnwrapOmittable(input.ContractEndDate),
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot update profile", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.UpdateUserPayload{
|
||||
Profile: types.NewProfile(profile),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateMembership is the resolver for the updateMembership field.
|
||||
func (r *mutationResolver) UpdateMembership(ctx context.Context, input types.UpdateMembershipInput) (*types.UpdateMembershipPayload, error) {
|
||||
if err := r.authorize(ctx, input.MembershipID, iam.ActionMembershipUpdate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if input.Role == coredata.MembershipRoleOwner {
|
||||
if err := r.authorize(ctx, input.MembershipID, iam.ActionMembershipRoleSetOwner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
membership, err := r.iam.OrganizationService.UpdateMempership(ctx, input.OrganizationID, input.MembershipID, input.Role)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot update membership", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.UpdateMembershipPayload{
|
||||
Membership: types.NewMembership(membership),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// RemoveUser is the resolver for the removeUser field.
|
||||
func (r *mutationResolver) RemoveUser(ctx context.Context, input types.RemoveUserInput) (*types.RemoveUserPayload, error) {
|
||||
if err := r.authorize(ctx, input.ProfileID, iam.ActionMembershipProfileDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err := r.iam.OrganizationService.RemoveUser(ctx, input.OrganizationID, input.ProfileID)
|
||||
if err != nil {
|
||||
var errManagedBySCIM *iam.ErrUserManagedBySCIM
|
||||
var errLastActiveOwner *iam.ErrLastActiveOwner
|
||||
|
||||
if errors.As(err, &errManagedBySCIM) {
|
||||
return nil, gqlutils.Conflict(ctx, err)
|
||||
}
|
||||
|
||||
if errors.As(err, &errLastActiveOwner) {
|
||||
return nil, gqlutils.Conflict(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot remove user from organization", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.RemoveUserPayload{DeletedProfileID: input.ProfileID}, nil
|
||||
}
|
||||
|
||||
// Profiles is the resolver for the profiles field.
|
||||
func (r *organizationResolver) Profiles(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ProfileOrderBy) (*types.ProfileConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
filter := coredata.NewMembershipProfileFilter(nil).WithMembership()
|
||||
|
||||
if gqlutils.OnlyTotalCountSelected(ctx) {
|
||||
return &types.ProfileConnection{
|
||||
Resolver: r,
|
||||
ParentID: obj.ID,
|
||||
Filters: filter,
|
||||
}, nil
|
||||
}
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.MembershipProfileOrderField]{
|
||||
Field: coredata.MembershipProfileOrderFieldFullName,
|
||||
Direction: page.OrderDirectionAsc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.MembershipProfileOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := cursor.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
page, err := r.iam.OrganizationService.ListProfiles(ctx, obj.ID, cursor, filter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list profiles", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewProfileConnection(page, r, obj.ID, filter), nil
|
||||
}
|
||||
|
||||
// Identity is the resolver for the identity field.
|
||||
func (r *profileResolver) Identity(ctx context.Context, obj *types.Profile) (*types.Identity, error) {
|
||||
if err := r.authorize(
|
||||
ctx,
|
||||
obj.ID,
|
||||
iam.ActionMembershipProfileGet,
|
||||
authz.WithSkipAssumptionCheck(),
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
identity, err := r.iam.AccountService.GetIdentity(ctx, obj.Identity.ID)
|
||||
if err != nil {
|
||||
var errNotFound *iam.ErrIdentityNotFound
|
||||
if errors.As(err, &errNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get identity", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewIdentity(identity), nil
|
||||
}
|
||||
|
||||
// Organization is the resolver for the organization field.
|
||||
func (r *profileResolver) Organization(ctx context.Context, obj *types.Profile) (*types.Organization, error) {
|
||||
if err := r.authorize(ctx, obj.Organization.ID, iam.ActionOrganizationGet, authz.WithSkipAssumptionCheck()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
organization, err := r.iam.OrganizationService.GetOrganization(ctx, obj.Organization.ID)
|
||||
if err != nil {
|
||||
var errNotFound *iam.ErrOrganizationNotFound
|
||||
if errors.As(err, &errNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get organization", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewOrganization(organization), nil
|
||||
}
|
||||
|
||||
// Membership is the resolver for the membership field.
|
||||
func (r *profileResolver) Membership(ctx context.Context, obj *types.Profile) (*types.Membership, error) {
|
||||
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipGet, authz.WithSkipAssumptionCheck()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
membership, err := r.iam.AccountService.GetMembershipForOrganization(ctx, obj.Identity.ID, obj.Organization.ID)
|
||||
if err != nil {
|
||||
var errNotFound *iam.ErrMembershipNotFound
|
||||
if errors.As(err, &errNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get membership", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewMembership(membership), nil
|
||||
}
|
||||
|
||||
// PendingInvitations is the resolver for the pendingInvitations field.
|
||||
func (r *profileResolver) PendingInvitations(ctx context.Context, obj *types.Profile, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.InvitationOrderBy) (*types.InvitationConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, iam.ActionInvitationList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.InvitationOrderField]{
|
||||
Field: coredata.InvitationOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
|
||||
cursor := cursor.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
page, err := r.iam.AccountService.ListPendingInvitations(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list pending invitations", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewInvitationConnection(page, r, obj.ID, nil), nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *profileResolver) Permission(ctx context.Context, obj *types.Profile, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// TotalCount is the resolver for the totalCount field.
|
||||
func (r *profileConnectionResolver) TotalCount(ctx context.Context, obj *types.ProfileConnection) (*int, error) {
|
||||
switch obj.Resolver.(type) {
|
||||
case *identityResolver:
|
||||
count, err := r.iam.AccountService.CountProfiles(ctx, obj.ParentID, obj.Filters)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count profiles", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
return &count, nil
|
||||
case *organizationResolver:
|
||||
count, err := r.iam.OrganizationService.CountProfiles(ctx, obj.ParentID, obj.Filters)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count profiles", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
return &count, nil
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "unsupported resolver", log.Any("resolver", obj.Resolver))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
// Invitation returns schema.InvitationResolver implementation.
|
||||
func (r *Resolver) Invitation() schema.InvitationResolver { return &invitationResolver{r} }
|
||||
|
||||
// Membership returns schema.MembershipResolver implementation.
|
||||
func (r *Resolver) Membership() schema.MembershipResolver { return &membershipResolver{r} }
|
||||
|
||||
// Profile returns schema.ProfileResolver implementation.
|
||||
func (r *Resolver) Profile() schema.ProfileResolver { return &profileResolver{r} }
|
||||
|
||||
// ProfileConnection returns schema.ProfileConnectionResolver implementation.
|
||||
func (r *Resolver) ProfileConnection() schema.ProfileConnectionResolver {
|
||||
return &profileConnectionResolver{r}
|
||||
}
|
||||
|
||||
type invitationResolver struct{ *Resolver }
|
||||
type membershipResolver struct{ *Resolver }
|
||||
type profileResolver struct{ *Resolver }
|
||||
type profileConnectionResolver struct{ *Resolver }
|
||||
185
pkg/server/api/connect/v1/saml.resolvers.go
Normal file
185
pkg/server/api/connect/v1/saml.resolvers.go
Normal file
@@ -0,0 +1,185 @@
|
||||
package connect_v1
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver
|
||||
// implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.87
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"go.gearno.de/kit/log"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/iam"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"go.probo.inc/probo/pkg/server/api/connect/v1/schema"
|
||||
"go.probo.inc/probo/pkg/server/api/connect/v1/types"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils/types/cursor"
|
||||
)
|
||||
|
||||
// CreateSAMLConfiguration is the resolver for the createSAMLConfiguration field.
|
||||
func (r *mutationResolver) CreateSAMLConfiguration(ctx context.Context, input types.CreateSAMLConfigurationInput) (*types.CreateSAMLConfigurationPayload, error) {
|
||||
if err := r.authorize(ctx, input.OrganizationID, iam.ActionSAMLConfigurationCreate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req := &iam.CreateSAMLConfigurationRequest{
|
||||
EmailDomain: input.EmailDomain,
|
||||
IdPEntityID: input.IdpEntityID,
|
||||
IdPSsoURL: input.IdpSsoURL,
|
||||
IdPCertificate: input.IdpCertificate,
|
||||
AutoSignupEnabled: input.AutoSignupEnabled,
|
||||
}
|
||||
|
||||
if input.AttributeMappings != nil {
|
||||
req.AttributeEmail = input.AttributeMappings.Email
|
||||
req.AttributeFirstname = input.AttributeMappings.FirstName
|
||||
req.AttributeLastname = input.AttributeMappings.LastName
|
||||
req.AttributeRole = input.AttributeMappings.Role
|
||||
}
|
||||
|
||||
samlConfiguration, err := r.iam.OrganizationService.CreateSAMLConfiguration(
|
||||
ctx,
|
||||
input.OrganizationID,
|
||||
req,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
var errSAMLConfigurationEmailDomainAlreadyExists *iam.ErrSAMLConfigurationEmailDomainAlreadyExists
|
||||
if errors.As(err, &errSAMLConfigurationEmailDomainAlreadyExists) {
|
||||
return nil, gqlutils.Conflict(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot create saml configuration", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.CreateSAMLConfigurationPayload{
|
||||
SamlConfigurationEdge: types.NewSAMLConfigurationEdge(
|
||||
samlConfiguration,
|
||||
coredata.SAMLConfigurationOrderFieldCreatedAt,
|
||||
),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateSAMLConfiguration is the resolver for the updateSAMLConfiguration field.
|
||||
func (r *mutationResolver) UpdateSAMLConfiguration(ctx context.Context, input types.UpdateSAMLConfigurationInput) (*types.UpdateSAMLConfigurationPayload, error) {
|
||||
if err := r.authorize(ctx, input.SamlConfigurationID, iam.ActionSAMLConfigurationUpdate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req := &iam.UpdateSAMLConfigurationRequest{
|
||||
IdPEntityID: input.IdpEntityID,
|
||||
IdPSsoURL: input.IdpSsoURL,
|
||||
IdPCertificate: input.IdpCertificate,
|
||||
AutoSignupEnabled: input.AutoSignupEnabled,
|
||||
EnforcementPolicy: &input.EnforcementPolicy,
|
||||
}
|
||||
|
||||
if input.AttributeMappings != nil {
|
||||
req.AttributeEmail = input.AttributeMappings.Email
|
||||
req.AttributeFirstname = input.AttributeMappings.FirstName
|
||||
req.AttributeLastname = input.AttributeMappings.LastName
|
||||
req.AttributeRole = input.AttributeMappings.Role
|
||||
}
|
||||
|
||||
samlConfiguration, err := r.iam.OrganizationService.UpdateSAMLConfiguration(
|
||||
ctx,
|
||||
input.OrganizationID,
|
||||
input.SamlConfigurationID,
|
||||
req,
|
||||
)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot update saml configuration", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.UpdateSAMLConfigurationPayload{
|
||||
SamlConfiguration: types.NewSAMLConfiguration(samlConfiguration),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteSAMLConfiguration is the resolver for the deleteSAMLConfiguration field.
|
||||
func (r *mutationResolver) DeleteSAMLConfiguration(ctx context.Context, input types.DeleteSAMLConfigurationInput) (*types.DeleteSAMLConfigurationPayload, error) {
|
||||
if err := r.authorize(ctx, input.OrganizationID, iam.ActionSAMLConfigurationDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err := r.iam.OrganizationService.DeleteSAMLConfiguration(ctx, input.OrganizationID, input.SamlConfigurationID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot delete saml configuration", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DeleteSAMLConfigurationPayload{DeletedSamlConfigurationID: input.SamlConfigurationID}, nil
|
||||
}
|
||||
|
||||
// SamlConfigurations is the resolver for the samlConfigurations field.
|
||||
func (r *organizationResolver) SamlConfigurations(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.SAMLConfigurationConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, iam.ActionSAMLConfigurationList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if gqlutils.OnlyTotalCountSelected(ctx) {
|
||||
return &types.SAMLConfigurationConnection{
|
||||
Resolver: r,
|
||||
ParentID: obj.ID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.SAMLConfigurationOrderField]{
|
||||
Field: coredata.SAMLConfigurationOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
|
||||
cursor := cursor.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
page, err := r.iam.OrganizationService.ListSAMLConfigurations(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list saml configurations", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewSAMLConfigurationConnection(page, r, obj.ID), nil
|
||||
}
|
||||
|
||||
// TestLoginURL is the resolver for the testLoginUrl field.
|
||||
func (r *sAMLConfigurationResolver) TestLoginURL(ctx context.Context, obj *types.SAMLConfiguration) (string, error) {
|
||||
return r.baseURL.WithPath("/api/connect/v1/saml/2.0/" + obj.ID.String()).MustString(), nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *sAMLConfigurationResolver) Permission(ctx context.Context, obj *types.SAMLConfiguration, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// TotalCount is the resolver for the totalCount field.
|
||||
func (r *sAMLConfigurationConnectionResolver) TotalCount(ctx context.Context, obj *types.SAMLConfigurationConnection) (*int, error) {
|
||||
switch obj.Resolver.(type) {
|
||||
case *organizationResolver:
|
||||
count, err := r.iam.OrganizationService.CountSAMLConfigurations(ctx, obj.ParentID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count saml configurations", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
return &count, nil
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "unsupported resolver", log.Any("resolver", obj.Resolver))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
// SAMLConfiguration returns schema.SAMLConfigurationResolver implementation.
|
||||
func (r *Resolver) SAMLConfiguration() schema.SAMLConfigurationResolver {
|
||||
return &sAMLConfigurationResolver{r}
|
||||
}
|
||||
|
||||
// SAMLConfigurationConnection returns schema.SAMLConfigurationConnectionResolver implementation.
|
||||
func (r *Resolver) SAMLConfigurationConnection() schema.SAMLConfigurationConnectionResolver {
|
||||
return &sAMLConfigurationConnectionResolver{r}
|
||||
}
|
||||
|
||||
type sAMLConfigurationResolver struct{ *Resolver }
|
||||
type sAMLConfigurationConnectionResolver struct{ *Resolver }
|
||||
File diff suppressed because it is too large
Load Diff
331
pkg/server/api/connect/v1/scim.resolvers.go
Normal file
331
pkg/server/api/connect/v1/scim.resolvers.go
Normal file
@@ -0,0 +1,331 @@
|
||||
package connect_v1
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver
|
||||
// implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.87
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"go.gearno.de/kit/log"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/iam"
|
||||
"go.probo.inc/probo/pkg/iam/scim/bridge/provider/googleworkspace"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"go.probo.inc/probo/pkg/server/api/connect/v1/schema"
|
||||
"go.probo.inc/probo/pkg/server/api/connect/v1/types"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils/types/cursor"
|
||||
)
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *connectorResolver) Permission(ctx context.Context, obj *types.Connector, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// CreateSCIMConfiguration is the resolver for the createSCIMConfiguration field.
|
||||
func (r *mutationResolver) CreateSCIMConfiguration(ctx context.Context, input types.CreateSCIMConfigurationInput) (*types.CreateSCIMConfigurationPayload, error) {
|
||||
if err := r.authorize(ctx, input.OrganizationID, iam.ActionSCIMConfigurationCreate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config, token, err := r.iam.OrganizationService.CreateSCIMConfiguration(ctx, input.OrganizationID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot create scim configuration", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
var bridge *types.SCIMBridge
|
||||
|
||||
if input.ConnectorID != nil {
|
||||
scimBridge, err := r.iam.OrganizationService.CreateSCIMBridge(ctx, input.OrganizationID, config.ID, *input.ConnectorID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot create scim bridge", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
bridge = types.NewSCIMBridge(scimBridge)
|
||||
}
|
||||
|
||||
payload := &types.CreateSCIMConfigurationPayload{
|
||||
ScimConfiguration: types.NewSCIMConfiguration(config),
|
||||
ScimBridge: bridge,
|
||||
Token: token,
|
||||
}
|
||||
|
||||
return payload, nil
|
||||
}
|
||||
|
||||
// DeleteSCIMConfiguration is the resolver for the deleteSCIMConfiguration field.
|
||||
func (r *mutationResolver) DeleteSCIMConfiguration(ctx context.Context, input types.DeleteSCIMConfigurationInput) (*types.DeleteSCIMConfigurationPayload, error) {
|
||||
if err := r.authorize(ctx, input.OrganizationID, iam.ActionSCIMConfigurationDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err := r.iam.OrganizationService.DeleteSCIMConfiguration(ctx, input.OrganizationID, input.ScimConfigurationID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot delete scim configuration", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DeleteSCIMConfigurationPayload{DeletedScimConfigurationID: input.ScimConfigurationID}, nil
|
||||
}
|
||||
|
||||
// RegenerateSCIMToken is the resolver for the regenerateSCIMToken field.
|
||||
func (r *mutationResolver) RegenerateSCIMToken(ctx context.Context, input types.RegenerateSCIMTokenInput) (*types.RegenerateSCIMTokenPayload, error) {
|
||||
if err := r.authorize(ctx, input.ScimConfigurationID, iam.ActionSCIMConfigurationUpdate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config, token, err := r.iam.OrganizationService.RegenerateSCIMToken(ctx, input.OrganizationID, input.ScimConfigurationID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot regenerate scim token", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.RegenerateSCIMTokenPayload{
|
||||
ScimConfiguration: types.NewSCIMConfiguration(config),
|
||||
Token: token,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateSCIMBridge is the resolver for the updateSCIMBridge field.
|
||||
func (r *mutationResolver) UpdateSCIMBridge(ctx context.Context, input types.UpdateSCIMBridgeInput) (*types.UpdateSCIMBridgePayload, error) {
|
||||
if err := r.authorize(ctx, input.ScimBridgeID, iam.ActionSCIMBridgeUpdate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bridge, err := r.iam.OrganizationService.UpdateSCIMBridge(ctx, input.OrganizationID, input.ScimBridgeID, input.ExcludedUserNames)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot update scim bridge excluded user names", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.UpdateSCIMBridgePayload{
|
||||
ScimBridge: types.NewSCIMBridge(bridge),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ScimConfiguration is the resolver for the scimConfiguration field.
|
||||
func (r *organizationResolver) ScimConfiguration(ctx context.Context, obj *types.Organization) (*types.SCIMConfiguration, error) {
|
||||
if err := r.authorize(ctx, obj.ID, iam.ActionSCIMConfigurationGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config, err := r.iam.OrganizationService.GetSCIMConfiguration(ctx, obj.ID)
|
||||
if err != nil {
|
||||
var notFound *iam.ErrNoSCIMConfigurationFound
|
||||
if errors.As(err, ¬Found) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get scim configuration", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewSCIMConfiguration(config), nil
|
||||
}
|
||||
|
||||
// ScimBridgeTypes is the resolver for the scimBridgeTypes field.
|
||||
func (r *organizationResolver) ScimBridgeTypes(ctx context.Context, obj *types.Organization) ([]*types.SCIMBridgeTypeInfo, error) {
|
||||
return []*types.SCIMBridgeTypeInfo{
|
||||
{
|
||||
Type: coredata.SCIMBridgeTypeGoogleWorkspace,
|
||||
Oauth2Scopes: googleworkspace.OAuth2Scopes,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ScimConfiguration is the resolver for the scimConfiguration field.
|
||||
func (r *sCIMBridgeResolver) ScimConfiguration(ctx context.Context, obj *types.SCIMBridge) (*types.SCIMConfiguration, error) {
|
||||
if err := r.authorize(ctx, obj.ScimConfiguration.ID, iam.ActionSCIMConfigurationGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if gqlutils.OnlyIDSelected(ctx) {
|
||||
return &types.SCIMConfiguration{
|
||||
ID: obj.ScimConfiguration.ID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
scimConfiguration, err := r.iam.GetSCIMConfiguration(ctx, obj.ScimConfiguration.ID)
|
||||
if err != nil {
|
||||
var errNoSCIMConfigurationFound *iam.ErrNoSCIMConfigurationFound
|
||||
if errors.As(err, &errNoSCIMConfigurationFound) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return types.NewSCIMConfiguration(scimConfiguration), nil
|
||||
}
|
||||
|
||||
// Connector is the resolver for the connector field.
|
||||
func (r *sCIMBridgeResolver) Connector(ctx context.Context, obj *types.SCIMBridge) (*types.Connector, error) {
|
||||
if obj.Connector == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Authorize based on the SCIM configuration (connector accessed via bridge is a sub-resource)
|
||||
if err := r.authorize(ctx, obj.ScimConfiguration.ID, iam.ActionSCIMConfigurationGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if gqlutils.OnlyIDSelected(ctx) {
|
||||
return &types.Connector{
|
||||
ID: obj.Connector.ID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Use metadata-only loading since we don't need the encrypted connection data
|
||||
connector, err := r.iam.OrganizationService.GetConnectorMetadataByID(ctx, obj.Connector.ID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot get connector", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewConnector(connector), nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *sCIMBridgeResolver) Permission(ctx context.Context, obj *types.SCIMBridge, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// EndpointURL is the resolver for the endpointUrl field.
|
||||
func (r *sCIMConfigurationResolver) EndpointURL(ctx context.Context, obj *types.SCIMConfiguration) (string, error) {
|
||||
return r.baseURL.WithPath("/api/connect/v1/scim/2.0").MustString(), nil
|
||||
}
|
||||
|
||||
// Organization is the resolver for the organization field.
|
||||
func (r *sCIMConfigurationResolver) Organization(ctx context.Context, obj *types.SCIMConfiguration) (*types.Organization, error) {
|
||||
if err := r.authorize(ctx, obj.Organization.ID, iam.ActionOrganizationGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if gqlutils.OnlyIDSelected(ctx) {
|
||||
return &types.Organization{
|
||||
ID: obj.Organization.ID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
organization, err := r.iam.OrganizationService.GetOrganization(ctx, obj.Organization.ID)
|
||||
if err != nil {
|
||||
var errOrganizationNotFound *iam.ErrOrganizationNotFound
|
||||
if errors.As(err, &errOrganizationNotFound) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get organization for scim configuration", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewOrganization(organization), nil
|
||||
}
|
||||
|
||||
// Bridge is the resolver for the bridge field.
|
||||
func (r *sCIMConfigurationResolver) Bridge(ctx context.Context, obj *types.SCIMConfiguration) (*types.SCIMBridge, error) {
|
||||
if obj.Bridge == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if err := r.authorize(ctx, obj.ID, iam.ActionSCIMConfigurationGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bridge, err := r.iam.OrganizationService.GetSCIMBridgeByID(ctx, obj.Bridge.ID)
|
||||
if err != nil {
|
||||
var errSCIMBridgeNotFound *iam.ErrSCIMBridgeNotFound
|
||||
if errors.As(err, &errSCIMBridgeNotFound) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get scim bridge", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewSCIMBridge(bridge), nil
|
||||
}
|
||||
|
||||
// Events is the resolver for the events field.
|
||||
func (r *sCIMConfigurationResolver) Events(ctx context.Context, obj *types.SCIMConfiguration, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.SCIMEventOrderBy) (*types.SCIMEventConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, iam.ActionSCIMEventList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.SCIMEventOrderField]{
|
||||
Field: coredata.SCIMEventOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy.Field = coredata.SCIMEventOrderField(orderBy.Field)
|
||||
pageOrderBy.Direction = page.OrderDirection(orderBy.Direction)
|
||||
}
|
||||
|
||||
cursor := cursor.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
events, err := r.iam.OrganizationService.ListSCIMEventsByConfigID(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list scim events", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewSCIMEventConnection(events, r, obj.ID), nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *sCIMConfigurationResolver) Permission(ctx context.Context, obj *types.SCIMConfiguration, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *sCIMEventResolver) Permission(ctx context.Context, obj *types.SCIMEvent, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// TotalCount is the resolver for the totalCount field.
|
||||
func (r *sCIMEventConnectionResolver) TotalCount(ctx context.Context, obj *types.SCIMEventConnection) (*int, error) {
|
||||
if err := r.authorize(ctx, obj.ParentID, iam.ActionSCIMEventList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch obj.Resolver.(type) {
|
||||
case *sCIMConfigurationResolver:
|
||||
count, err := r.iam.OrganizationService.CountSCIMEvents(ctx, obj.ParentID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count scim events", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
return &count, nil
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "unsupported resolver", log.Any("resolver", obj.Resolver))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
// Connector returns schema.ConnectorResolver implementation.
|
||||
func (r *Resolver) Connector() schema.ConnectorResolver { return &connectorResolver{r} }
|
||||
|
||||
// SCIMBridge returns schema.SCIMBridgeResolver implementation.
|
||||
func (r *Resolver) SCIMBridge() schema.SCIMBridgeResolver { return &sCIMBridgeResolver{r} }
|
||||
|
||||
// SCIMConfiguration returns schema.SCIMConfigurationResolver implementation.
|
||||
func (r *Resolver) SCIMConfiguration() schema.SCIMConfigurationResolver {
|
||||
return &sCIMConfigurationResolver{r}
|
||||
}
|
||||
|
||||
// SCIMEvent returns schema.SCIMEventResolver implementation.
|
||||
func (r *Resolver) SCIMEvent() schema.SCIMEventResolver { return &sCIMEventResolver{r} }
|
||||
|
||||
// SCIMEventConnection returns schema.SCIMEventConnectionResolver implementation.
|
||||
func (r *Resolver) SCIMEventConnection() schema.SCIMEventConnectionResolver {
|
||||
return &sCIMEventConnectionResolver{r}
|
||||
}
|
||||
|
||||
type connectorResolver struct{ *Resolver }
|
||||
type sCIMBridgeResolver struct{ *Resolver }
|
||||
type sCIMConfigurationResolver struct{ *Resolver }
|
||||
type sCIMEventResolver struct{ *Resolver }
|
||||
type sCIMEventConnectionResolver struct{ *Resolver }
|
||||
104
pkg/server/api/connect/v1/session.resolvers.go
Normal file
104
pkg/server/api/connect/v1/session.resolvers.go
Normal file
@@ -0,0 +1,104 @@
|
||||
package connect_v1
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver
|
||||
// implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.87
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.gearno.de/kit/log"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/iam"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"go.probo.inc/probo/pkg/server/api/connect/v1/schema"
|
||||
"go.probo.inc/probo/pkg/server/api/connect/v1/types"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils/types/cursor"
|
||||
)
|
||||
|
||||
// Sessions is the resolver for the sessions field.
|
||||
func (r *identityResolver) Sessions(ctx context.Context, obj *types.Identity, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.SessionOrder) (*types.SessionConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, iam.ActionSessionList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if gqlutils.OnlyTotalCountSelected(ctx) {
|
||||
return &types.SessionConnection{
|
||||
Resolver: r,
|
||||
ParentID: obj.ID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.SessionOrderField]{
|
||||
Field: coredata.SessionOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.SessionOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := cursor.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
page, err := r.iam.AccountService.ListSessions(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list sessions", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewSessionConnection(page, r, obj.ID), nil
|
||||
}
|
||||
|
||||
// Identity is the resolver for the identity field.
|
||||
func (r *sessionResolver) Identity(ctx context.Context, obj *types.Session) (*types.Identity, error) {
|
||||
if gqlutils.OnlyIDSelected(ctx) {
|
||||
return &types.Identity{
|
||||
ID: obj.Identity.ID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
identity, err := r.iam.AccountService.GetIdentity(ctx, obj.Identity.ID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot get identity for session", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewIdentity(identity), nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *sessionResolver) Permission(ctx context.Context, obj *types.Session, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// TotalCount is the resolver for the totalCount field.
|
||||
func (r *sessionConnectionResolver) TotalCount(ctx context.Context, obj *types.SessionConnection) (*int, error) {
|
||||
switch obj.Resolver.(type) {
|
||||
case *identityResolver:
|
||||
count, err := r.iam.AccountService.CountSessions(ctx, obj.ParentID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count sessions", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &count, nil
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "unsupported resolver", log.Any("resolver", obj.Resolver))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
// Session returns schema.SessionResolver implementation.
|
||||
func (r *Resolver) Session() schema.SessionResolver { return &sessionResolver{r} }
|
||||
|
||||
// SessionConnection returns schema.SessionConnectionResolver implementation.
|
||||
func (r *Resolver) SessionConnection() schema.SessionConnectionResolver {
|
||||
return &sessionConnectionResolver{r}
|
||||
}
|
||||
|
||||
type sessionResolver struct{ *Resolver }
|
||||
type sessionConnectionResolver struct{ *Resolver }
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,18 +6,26 @@ GraphQL API using `gqlgen`. Schema-first approach.
|
||||
|
||||
| File | Type | Notes |
|
||||
|------|------|-------|
|
||||
| `schema.graphql` | Hand-written | GraphQL schema definition |
|
||||
| `graphql/*.graphql` | Hand-written | GraphQL schema split by entity (one file per coredata model) |
|
||||
| `gqlgen.yaml` | Hand-written | Codegen config |
|
||||
| `resolver.go` | Hand-written | Root `Resolver` struct and `NewMux` |
|
||||
| `graphql_handler.go` | Hand-written | Handler setup |
|
||||
| `v1_resolver.go` | Generated stubs | Resolver method implementations (edit the bodies) |
|
||||
| `*.resolvers.go` | Generated stubs | Per-entity resolver files (edit the bodies) |
|
||||
| `schema/schema.go` | **Generated — DO NOT EDIT** | Executable schema |
|
||||
| `types/types.go` | **Generated — DO NOT EDIT** | Type definitions |
|
||||
|
||||
## Schema file organization
|
||||
|
||||
Schema files live in `graphql/` and are split by coredata model:
|
||||
- `base.graphql` — directives, scalars, Node, PageInfo, root Query/Mutation/Organization/Viewer types
|
||||
- Entity files (e.g., `vendor.graphql`, `control.graphql`) — use `extend type Organization`, `extend type Mutation`, etc. to add fields
|
||||
|
||||
When adding a new entity, create a new `.graphql` file in `graphql/`. Types that get extended across files (Organization, Mutation, Viewer) must be defined in `base.graphql`.
|
||||
|
||||
## Important rules
|
||||
|
||||
- **Never edit generated files** (`schema/schema.go`, `types/types.go`). Only edit `schema.graphql` and resolver bodies.
|
||||
- **After any change to `schema.graphql`**, always run codegen:
|
||||
- **Never edit generated files** (`schema/schema.go`, `types/types.go`). Only edit `graphql/*.graphql` and resolver bodies.
|
||||
- **After any change to `graphql/*.graphql`**, always run codegen:
|
||||
|
||||
```
|
||||
go generate ./pkg/server/api/console/v1
|
||||
|
||||
1057
pkg/server/api/console/v1/access_review_campaign.resolvers.go
Normal file
1057
pkg/server/api/console/v1/access_review_campaign.resolvers.go
Normal file
File diff suppressed because it is too large
Load Diff
497
pkg/server/api/console/v1/asset.resolvers.go
Normal file
497
pkg/server/api/console/v1/asset.resolvers.go
Normal file
@@ -0,0 +1,497 @@
|
||||
package console_v1
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver
|
||||
// implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.87
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/vikstrous/dataloadgen"
|
||||
"go.gearno.de/kit/log"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/iam"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"go.probo.inc/probo/pkg/probo"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/dataloader"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/schema"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/types"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils"
|
||||
"go.probo.inc/probo/pkg/validator"
|
||||
)
|
||||
|
||||
// Owner is the resolver for the owner field.
|
||||
func (r *assetResolver) Owner(ctx context.Context, obj *types.Asset) (*types.Profile, error) {
|
||||
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
loaders := dataloader.FromContext(ctx)
|
||||
|
||||
owner, err := loaders.Profile.Load(ctx, obj.Owner.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get owner", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewProfile(owner), nil
|
||||
}
|
||||
|
||||
// Vendors is the resolver for the vendors field.
|
||||
func (r *assetResolver) Vendors(ctx context.Context, obj *types.Asset, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorOrderBy) (*types.VendorConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionVendorList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.VendorOrderField]{
|
||||
Field: coredata.VendorOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.VendorOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
page, err := prb.Vendors.ListForAssetID(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list asset vendors", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewVendorConnection(page, r, obj.ID), nil
|
||||
}
|
||||
|
||||
// Organization is the resolver for the organization field.
|
||||
func (r *assetResolver) Organization(ctx context.Context, obj *types.Asset) (*types.Organization, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
asset, err := prb.Assets.Get(ctx, obj.ID)
|
||||
if err != nil {
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot load audit", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
org, err := prb.Organizations.Get(ctx, asset.OrganizationID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get organization", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewOrganization(org), nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *assetResolver) Permission(ctx context.Context, obj *types.Asset, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// TotalCount is the resolver for the totalCount field.
|
||||
func (r *assetConnectionResolver) TotalCount(ctx context.Context, obj *types.AssetConnection) (int, error) {
|
||||
if err := r.authorize(ctx, obj.ParentID, probo.ActionAssetList); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
||||
|
||||
switch obj.Resolver.(type) {
|
||||
case *organizationResolver:
|
||||
assetFilter := coredata.NewAssetFilter(nil)
|
||||
if obj.Filter != nil {
|
||||
assetFilter = coredata.NewAssetFilter(&obj.Filter.SnapshotID)
|
||||
}
|
||||
|
||||
count, err := prb.Assets.CountForOrganizationID(ctx, obj.ParentID, assetFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count assets", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "unsupported resolver")
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
// Owner is the resolver for the owner field.
|
||||
func (r *datumResolver) Owner(ctx context.Context, obj *types.Datum) (*types.Profile, error) {
|
||||
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
loaders := dataloader.FromContext(ctx)
|
||||
|
||||
owner, err := loaders.Profile.Load(ctx, obj.Owner.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("cannot get owner: %w", err)
|
||||
}
|
||||
|
||||
return types.NewProfile(owner), nil
|
||||
}
|
||||
|
||||
// Vendors is the resolver for the vendors field.
|
||||
func (r *datumResolver) Vendors(ctx context.Context, obj *types.Datum, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorOrderBy) (*types.VendorConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionVendorList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.VendorOrderField]{
|
||||
Field: coredata.VendorOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.VendorOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
page, err := prb.Data.ListVendors(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list data vendors", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewVendorConnection(page, r, obj.ID), nil
|
||||
}
|
||||
|
||||
// Organization is the resolver for the organization field.
|
||||
func (r *datumResolver) Organization(ctx context.Context, obj *types.Datum) (*types.Organization, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
loaders := dataloader.FromContext(ctx)
|
||||
|
||||
org, err := loaders.Organization.Load(ctx, obj.OrganizationID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get organization", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewOrganization(org), nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *datumResolver) Permission(ctx context.Context, obj *types.Datum, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// TotalCount is the resolver for the totalCount field.
|
||||
func (r *datumConnectionResolver) TotalCount(ctx context.Context, obj *types.DatumConnection) (int, error) {
|
||||
if err := r.authorize(ctx, obj.ParentID, probo.ActionDatumList); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
||||
|
||||
switch obj.Resolver.(type) {
|
||||
case *organizationResolver:
|
||||
datumFilter := coredata.NewDatumFilter(nil)
|
||||
if obj.Filter != nil {
|
||||
datumFilter = coredata.NewDatumFilter(&obj.Filter.SnapshotID)
|
||||
}
|
||||
|
||||
count, err := prb.Data.CountForOrganizationID(ctx, obj.ParentID, datumFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count data", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "unsupported resolver")
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
// CreateAsset is the resolver for the createAsset field.
|
||||
func (r *mutationResolver) CreateAsset(ctx context.Context, input types.CreateAssetInput) (*types.CreateAssetPayload, error) {
|
||||
if err := r.authorize(ctx, input.OrganizationID, probo.ActionAssetCreate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
||||
|
||||
asset, err := prb.Assets.Create(
|
||||
ctx,
|
||||
probo.CreateAssetRequest{
|
||||
OrganizationID: input.OrganizationID,
|
||||
Name: input.Name,
|
||||
Amount: input.Amount,
|
||||
OwnerID: input.OwnerID,
|
||||
AssetType: input.AssetType,
|
||||
DataTypesStored: input.DataTypesStored,
|
||||
VendorIDs: input.VendorIds,
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot create asset", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.CreateAssetPayload{
|
||||
AssetEdge: types.NewAssetEdge(asset, coredata.AssetOrderFieldCreatedAt),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateAsset is the resolver for the updateAsset field.
|
||||
func (r *mutationResolver) UpdateAsset(ctx context.Context, input types.UpdateAssetInput) (*types.UpdateAssetPayload, error) {
|
||||
if err := r.authorize(ctx, input.ID, probo.ActionAssetUpdate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.ID.TenantID())
|
||||
|
||||
asset, err := prb.Assets.Update(
|
||||
ctx,
|
||||
probo.UpdateAssetRequest{
|
||||
ID: input.ID,
|
||||
Name: input.Name,
|
||||
Amount: input.Amount,
|
||||
OwnerID: input.OwnerID,
|
||||
AssetType: input.AssetType,
|
||||
DataTypesStored: input.DataTypesStored,
|
||||
VendorIDs: input.VendorIds,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot update asset", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.UpdateAssetPayload{
|
||||
Asset: types.NewAsset(asset),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteAsset is the resolver for the deleteAsset field.
|
||||
func (r *mutationResolver) DeleteAsset(ctx context.Context, input types.DeleteAssetInput) (*types.DeleteAssetPayload, error) {
|
||||
if err := r.authorize(ctx, input.AssetID, probo.ActionAssetDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.AssetID.TenantID())
|
||||
|
||||
err := prb.Assets.Delete(ctx, input.AssetID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot delete asset", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DeleteAssetPayload{
|
||||
DeletedAssetID: input.AssetID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreateDatum is the resolver for the createDatum field.
|
||||
func (r *mutationResolver) CreateDatum(ctx context.Context, input types.CreateDatumInput) (*types.CreateDatumPayload, error) {
|
||||
if err := r.authorize(ctx, input.OrganizationID, probo.ActionDatumCreate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
||||
|
||||
data, err := prb.Data.Create(
|
||||
ctx,
|
||||
probo.CreateDatumRequest{
|
||||
OrganizationID: input.OrganizationID,
|
||||
Name: input.Name,
|
||||
DataClassification: input.DataClassification,
|
||||
OwnerID: input.OwnerID,
|
||||
VendorIDs: input.VendorIds,
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot create datum", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.CreateDatumPayload{
|
||||
DatumEdge: types.NewDatumEdge(data, coredata.DatumOrderFieldCreatedAt),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateDatum is the resolver for the updateDatum field.
|
||||
func (r *mutationResolver) UpdateDatum(ctx context.Context, input types.UpdateDatumInput) (*types.UpdateDatumPayload, error) {
|
||||
if err := r.authorize(ctx, input.ID, probo.ActionDatumUpdate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.ID.TenantID())
|
||||
|
||||
datum, err := prb.Data.Update(
|
||||
ctx,
|
||||
probo.UpdateDatumRequest{
|
||||
ID: input.ID,
|
||||
Name: input.Name,
|
||||
DataClassification: input.DataClassification,
|
||||
OwnerID: input.OwnerID,
|
||||
VendorIDs: input.VendorIds,
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot update datum", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.UpdateDatumPayload{
|
||||
Datum: types.NewDatum(datum),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteDatum is the resolver for the deleteDatum field.
|
||||
func (r *mutationResolver) DeleteDatum(ctx context.Context, input types.DeleteDatumInput) (*types.DeleteDatumPayload, error) {
|
||||
if err := r.authorize(ctx, input.DatumID, probo.ActionDatumDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.DatumID.TenantID())
|
||||
|
||||
if err := prb.Data.Delete(ctx, input.DatumID); err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot delete datum", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DeleteDatumPayload{
|
||||
DeletedDatumID: input.DatumID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Assets is the resolver for the assets field.
|
||||
func (r *organizationResolver) Assets(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.AssetOrderBy, filter *types.AssetFilter) (*types.AssetConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionAssetList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.AssetOrderField]{
|
||||
Field: coredata.AssetOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.AssetOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
assetFilter := coredata.NewAssetFilter(nil)
|
||||
if filter != nil {
|
||||
assetFilter = coredata.NewAssetFilter(&filter.SnapshotID)
|
||||
}
|
||||
|
||||
page, err := prb.Assets.ListForOrganizationID(ctx, obj.ID, cursor, assetFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list organization assets", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewAssetConnection(page, r, obj.ID, filter), nil
|
||||
}
|
||||
|
||||
// Assets is the resolver for the assets field.
|
||||
func (r *organizationResolver) Data(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DatumOrderBy, filter *types.DatumFilter) (*types.DatumConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionDatumList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.DatumOrderField]{
|
||||
Field: coredata.DatumOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.DatumOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
datumFilter := coredata.NewDatumFilter(nil)
|
||||
if filter != nil {
|
||||
datumFilter = coredata.NewDatumFilter(&filter.SnapshotID)
|
||||
}
|
||||
|
||||
page, err := prb.Data.ListForOrganizationID(ctx, obj.ID, cursor, datumFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list organization data", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewDataConnection(page, r, obj.ID, filter), nil
|
||||
}
|
||||
|
||||
// Asset returns schema.AssetResolver implementation.
|
||||
func (r *Resolver) Asset() schema.AssetResolver { return &assetResolver{r} }
|
||||
|
||||
// AssetConnection returns schema.AssetConnectionResolver implementation.
|
||||
func (r *Resolver) AssetConnection() schema.AssetConnectionResolver {
|
||||
return &assetConnectionResolver{r}
|
||||
}
|
||||
|
||||
// Datum returns schema.DatumResolver implementation.
|
||||
func (r *Resolver) Datum() schema.DatumResolver { return &datumResolver{r} }
|
||||
|
||||
// DatumConnection returns schema.DatumConnectionResolver implementation.
|
||||
func (r *Resolver) DatumConnection() schema.DatumConnectionResolver {
|
||||
return &datumConnectionResolver{r}
|
||||
}
|
||||
|
||||
type assetResolver struct{ *Resolver }
|
||||
type assetConnectionResolver struct{ *Resolver }
|
||||
type datumResolver struct{ *Resolver }
|
||||
type datumConnectionResolver struct{ *Resolver }
|
||||
821
pkg/server/api/console/v1/audit.resolvers.go
Normal file
821
pkg/server/api/console/v1/audit.resolvers.go
Normal file
@@ -0,0 +1,821 @@
|
||||
package console_v1
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver
|
||||
// implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.87
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/vikstrous/dataloadgen"
|
||||
"go.gearno.de/kit/log"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/iam"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"go.probo.inc/probo/pkg/probo"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/dataloader"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/schema"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/types"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils"
|
||||
"go.probo.inc/probo/pkg/validator"
|
||||
)
|
||||
|
||||
// Organization is the resolver for the organization field.
|
||||
func (r *auditResolver) Organization(ctx context.Context, obj *types.Audit) (*types.Organization, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
loaders := dataloader.FromContext(ctx)
|
||||
|
||||
organization, err := loaders.Organization.Load(ctx, obj.Organization.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot load organization", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewOrganization(organization), nil
|
||||
}
|
||||
|
||||
// Framework is the resolver for the framework field.
|
||||
func (r *auditResolver) Framework(ctx context.Context, obj *types.Audit) (*types.Framework, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionFrameworkGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
loaders := dataloader.FromContext(ctx)
|
||||
|
||||
framework, err := loaders.Framework.Load(ctx, obj.Framework.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot load framework", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewFramework(framework), nil
|
||||
}
|
||||
|
||||
// Report is the resolver for the report field.
|
||||
func (r *auditResolver) Report(ctx context.Context, obj *types.Audit) (*types.Report, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionReportGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if obj.Report == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
loaders := dataloader.FromContext(ctx)
|
||||
|
||||
report, err := loaders.Report.Load(ctx, obj.Report.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, dataloadgen.ErrNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot load report", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewReport(report), nil
|
||||
}
|
||||
|
||||
// ReportURL is the resolver for the reportUrl field.
|
||||
func (r *auditResolver) ReportURL(ctx context.Context, obj *types.Audit) (*string, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionReportGetReportUrl); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if obj.Report == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
url, err := prb.Audits.GenerateReportURL(ctx, obj.ID, 15*time.Minute)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot generate report URL", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return url, nil
|
||||
}
|
||||
|
||||
// Controls is the resolver for the controls field.
|
||||
func (r *auditResolver) Controls(ctx context.Context, obj *types.Audit, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ControlOrderBy, filter *types.ControlFilter) (*types.ControlConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionControlList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.ControlOrderField]{
|
||||
Field: coredata.ControlOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.ControlOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
var controlFilter = coredata.NewControlFilter(nil)
|
||||
if filter != nil {
|
||||
controlFilter = coredata.NewControlFilter(filter.Query)
|
||||
}
|
||||
|
||||
page, err := prb.Controls.ListForAuditID(ctx, obj.ID, cursor, controlFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list audit controls", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewControlConnection(page, r, obj.ID, controlFilter), nil
|
||||
}
|
||||
|
||||
// Findings is the resolver for the findings field.
|
||||
func (r *auditResolver) Findings(ctx context.Context, obj *types.Audit, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.FindingOrder, filter *types.FindingFilter) (*types.FindingConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionFindingList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.FindingOrderField]{
|
||||
Field: coredata.FindingOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.FindingOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
var (
|
||||
kind *coredata.FindingKind
|
||||
status *coredata.FindingStatus
|
||||
priority *coredata.FindingPriority
|
||||
ownerID *gid.GID
|
||||
)
|
||||
if filter != nil {
|
||||
kind = filter.Kind
|
||||
status = filter.Status
|
||||
priority = filter.Priority
|
||||
ownerID = filter.OwnerID
|
||||
}
|
||||
|
||||
findingFilter := coredata.NewFindingFilter(nil, kind, status, priority, ownerID)
|
||||
if filter != nil {
|
||||
findingFilter = coredata.NewFindingFilter(&filter.SnapshotID, kind, status, priority, ownerID)
|
||||
}
|
||||
|
||||
p, err := prb.Findings.ListForAuditID(ctx, obj.ID, cursor, findingFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list audit findings", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewFindingConnection(p, r, obj.ID, filter), nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *auditResolver) Permission(ctx context.Context, obj *types.Audit, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// TotalCount is the resolver for the totalCount field.
|
||||
func (r *auditConnectionResolver) TotalCount(ctx context.Context, obj *types.AuditConnection) (int, error) {
|
||||
if err := r.authorize(ctx, obj.ParentID, probo.ActionAuditList); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
||||
|
||||
switch obj.Resolver.(type) {
|
||||
case *organizationResolver:
|
||||
count, err := prb.Audits.CountForOrganizationID(ctx, obj.ParentID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count audits", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
case *findingResolver:
|
||||
count, err := prb.Audits.CountForFindingID(ctx, obj.ParentID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count audits", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
case *controlResolver:
|
||||
count, err := prb.Audits.CountForControlID(ctx, obj.ParentID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count audits", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
default:
|
||||
r.logger.ErrorCtx(ctx, "unsupported resolver", log.Any("resolver", obj.Resolver))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
// Organization is the resolver for the organization field.
|
||||
func (r *findingResolver) Organization(ctx context.Context, obj *types.Finding) (*types.Organization, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
loaders := dataloader.FromContext(ctx)
|
||||
|
||||
organization, err := loaders.Organization.Load(ctx, obj.Organization.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get finding organization", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewOrganization(organization), nil
|
||||
}
|
||||
|
||||
// Audits is the resolver for the audits field.
|
||||
func (r *findingResolver) Audits(ctx context.Context, obj *types.Finding, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.AuditOrderBy) (*types.AuditConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionAuditList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.AuditOrderField]{
|
||||
Field: coredata.AuditOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.AuditOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
p, err := prb.Audits.ListForFindingID(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list finding audits", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewAuditConnection(p, r, obj.ID), nil
|
||||
}
|
||||
|
||||
// Owner is the resolver for the owner field.
|
||||
func (r *findingResolver) Owner(ctx context.Context, obj *types.Finding) (*types.Profile, error) {
|
||||
if obj.Owner == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
loaders := dataloader.FromContext(ctx)
|
||||
|
||||
owner, err := loaders.Profile.Load(ctx, obj.Owner.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get finding owner", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewProfile(owner), nil
|
||||
}
|
||||
|
||||
// Risk is the resolver for the risk field.
|
||||
func (r *findingResolver) Risk(ctx context.Context, obj *types.Finding) (*types.Risk, error) {
|
||||
if obj.Risk == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionRiskGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
loaders := dataloader.FromContext(ctx)
|
||||
|
||||
risk, err := loaders.Risk.Load(ctx, obj.Risk.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get finding risk", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewRisk(risk), nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *findingResolver) Permission(ctx context.Context, obj *types.Finding, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// TotalCount is the resolver for the totalCount field.
|
||||
func (r *findingConnectionResolver) TotalCount(ctx context.Context, obj *types.FindingConnection) (int, error) {
|
||||
if err := r.authorize(ctx, obj.ParentID, probo.ActionFindingList); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
||||
|
||||
var (
|
||||
kind *coredata.FindingKind
|
||||
status *coredata.FindingStatus
|
||||
priority *coredata.FindingPriority
|
||||
ownerID *gid.GID
|
||||
)
|
||||
if obj.Filter != nil {
|
||||
kind = obj.Filter.Kind
|
||||
status = obj.Filter.Status
|
||||
priority = obj.Filter.Priority
|
||||
ownerID = obj.Filter.OwnerID
|
||||
}
|
||||
|
||||
findingFilter := coredata.NewFindingFilter(nil, kind, status, priority, ownerID)
|
||||
if obj.Filter != nil {
|
||||
findingFilter = coredata.NewFindingFilter(&obj.Filter.SnapshotID, kind, status, priority, ownerID)
|
||||
}
|
||||
|
||||
switch obj.Resolver.(type) {
|
||||
case *organizationResolver:
|
||||
count, err := prb.Findings.CountForOrganizationID(ctx, obj.ParentID, findingFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count findings", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
case *auditResolver:
|
||||
count, err := prb.Findings.CountForAuditID(ctx, obj.ParentID, findingFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count findings", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "unsupported resolver", log.Any("resolver", obj.Resolver))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
// CreateAudit is the resolver for the createAudit field.
|
||||
func (r *mutationResolver) CreateAudit(ctx context.Context, input types.CreateAuditInput) (*types.CreateAuditPayload, error) {
|
||||
if err := r.authorize(ctx, input.OrganizationID, probo.ActionAuditCreate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
||||
|
||||
req := probo.CreateAuditRequest{
|
||||
OrganizationID: input.OrganizationID,
|
||||
FrameworkID: input.FrameworkID,
|
||||
Name: input.Name,
|
||||
ValidFrom: input.ValidFrom,
|
||||
ValidUntil: input.ValidUntil,
|
||||
State: input.State,
|
||||
TrustCenterVisibility: input.TrustCenterVisibility,
|
||||
}
|
||||
|
||||
audit, err := prb.Audits.Create(ctx, &req)
|
||||
if err != nil {
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot create audit", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
if input.File != nil {
|
||||
uploadReq := probo.UploadAuditReportRequest{
|
||||
AuditID: audit.ID,
|
||||
File: probo.File{
|
||||
Content: input.File.File,
|
||||
Filename: input.File.Filename,
|
||||
Size: input.File.Size,
|
||||
ContentType: input.File.ContentType,
|
||||
},
|
||||
}
|
||||
|
||||
audit, err = prb.Audits.UploadReport(ctx, uploadReq)
|
||||
if err != nil {
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot upload audit report", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
return &types.CreateAuditPayload{
|
||||
AuditEdge: types.NewAuditEdge(audit, coredata.AuditOrderFieldCreatedAt),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateAudit is the resolver for the updateAudit field.
|
||||
func (r *mutationResolver) UpdateAudit(ctx context.Context, input types.UpdateAuditInput) (*types.UpdateAuditPayload, error) {
|
||||
if err := r.authorize(ctx, input.ID, probo.ActionAuditUpdate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.ID.TenantID())
|
||||
|
||||
req := probo.UpdateAuditRequest{
|
||||
ID: input.ID,
|
||||
Name: gqlutils.UnwrapOmittable(input.Name),
|
||||
ValidFrom: input.ValidFrom,
|
||||
ValidUntil: input.ValidUntil,
|
||||
State: input.State,
|
||||
TrustCenterVisibility: input.TrustCenterVisibility,
|
||||
}
|
||||
|
||||
audit, err := prb.Audits.Update(ctx, &req)
|
||||
if err != nil {
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot update audit", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.UpdateAuditPayload{
|
||||
Audit: types.NewAudit(audit),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteAudit is the resolver for the deleteAudit field.
|
||||
func (r *mutationResolver) DeleteAudit(ctx context.Context, input types.DeleteAuditInput) (*types.DeleteAuditPayload, error) {
|
||||
if err := r.authorize(ctx, input.AuditID, probo.ActionAuditDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.AuditID.TenantID())
|
||||
|
||||
err := prb.Audits.Delete(ctx, input.AuditID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot delete audit", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DeleteAuditPayload{
|
||||
DeletedAuditID: &input.AuditID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UploadAuditReport is the resolver for the uploadAuditReport field.
|
||||
func (r *mutationResolver) UploadAuditReport(ctx context.Context, input types.UploadAuditReportInput) (*types.UploadAuditReportPayload, error) {
|
||||
if err := r.authorize(ctx, input.AuditID, probo.ActionAuditReportUpload); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.AuditID.TenantID())
|
||||
|
||||
req := probo.UploadAuditReportRequest{
|
||||
AuditID: input.AuditID,
|
||||
File: probo.File{
|
||||
Content: input.File.File,
|
||||
Filename: input.File.Filename,
|
||||
Size: input.File.Size,
|
||||
ContentType: input.File.ContentType,
|
||||
},
|
||||
}
|
||||
|
||||
audit, err := prb.Audits.UploadReport(ctx, req)
|
||||
if err != nil {
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot upload audit report", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.UploadAuditReportPayload{
|
||||
Audit: types.NewAudit(audit),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteAuditReport is the resolver for the deleteAuditReport field.
|
||||
func (r *mutationResolver) DeleteAuditReport(ctx context.Context, input types.DeleteAuditReportInput) (*types.DeleteAuditReportPayload, error) {
|
||||
if err := r.authorize(ctx, input.AuditID, probo.ActionAuditReportDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.AuditID.TenantID())
|
||||
|
||||
audit, err := prb.Audits.DeleteReport(ctx, input.AuditID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot delete audit report", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DeleteAuditReportPayload{
|
||||
Audit: types.NewAudit(audit),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreateFinding is the resolver for the createFinding field.
|
||||
func (r *mutationResolver) CreateFinding(ctx context.Context, input types.CreateFindingInput) (*types.CreateFindingPayload, error) {
|
||||
if err := r.authorize(ctx, input.OrganizationID, probo.ActionFindingCreate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
||||
|
||||
req := probo.CreateFindingRequest{
|
||||
OrganizationID: input.OrganizationID,
|
||||
Kind: input.Kind,
|
||||
Description: input.Description,
|
||||
Source: input.Source,
|
||||
IdentifiedOn: input.IdentifiedOn,
|
||||
RootCause: input.RootCause,
|
||||
CorrectiveAction: input.CorrectiveAction,
|
||||
OwnerID: input.OwnerID,
|
||||
DueDate: input.DueDate,
|
||||
Status: &input.Status,
|
||||
Priority: &input.Priority,
|
||||
RiskID: input.RiskID,
|
||||
EffectivenessCheck: input.EffectivenessCheck,
|
||||
}
|
||||
|
||||
finding, err := prb.Findings.Create(ctx, &req)
|
||||
if err != nil {
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot create finding", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.CreateFindingPayload{
|
||||
FindingEdge: types.NewFindingEdge(finding, coredata.FindingOrderFieldCreatedAt),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateFinding is the resolver for the updateFinding field.
|
||||
func (r *mutationResolver) UpdateFinding(ctx context.Context, input types.UpdateFindingInput) (*types.UpdateFindingPayload, error) {
|
||||
if err := r.authorize(ctx, input.ID, probo.ActionFindingUpdate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.ID.TenantID())
|
||||
|
||||
req := probo.UpdateFindingRequest{
|
||||
ID: input.ID,
|
||||
Description: gqlutils.UnwrapOmittable(input.Description),
|
||||
Source: gqlutils.UnwrapOmittable(input.Source),
|
||||
IdentifiedOn: gqlutils.UnwrapOmittable(input.IdentifiedOn),
|
||||
RootCause: gqlutils.UnwrapOmittable(input.RootCause),
|
||||
CorrectiveAction: gqlutils.UnwrapOmittable(input.CorrectiveAction),
|
||||
OwnerID: input.OwnerID,
|
||||
DueDate: gqlutils.UnwrapOmittable(input.DueDate),
|
||||
Status: input.Status,
|
||||
Priority: input.Priority,
|
||||
RiskID: gqlutils.UnwrapOmittable(input.RiskID),
|
||||
EffectivenessCheck: gqlutils.UnwrapOmittable(input.EffectivenessCheck),
|
||||
}
|
||||
|
||||
finding, err := prb.Findings.Update(ctx, &req)
|
||||
if err != nil {
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot update finding", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.UpdateFindingPayload{
|
||||
Finding: types.NewFinding(finding),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteFinding is the resolver for the deleteFinding field.
|
||||
func (r *mutationResolver) DeleteFinding(ctx context.Context, input types.DeleteFindingInput) (*types.DeleteFindingPayload, error) {
|
||||
if err := r.authorize(ctx, input.FindingID, probo.ActionFindingDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.FindingID.TenantID())
|
||||
|
||||
err := prb.Findings.Delete(ctx, input.FindingID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot delete finding", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DeleteFindingPayload{
|
||||
DeletedFindingID: &input.FindingID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreateFindingAuditMapping is the resolver for the createFindingAuditMapping field.
|
||||
func (r *mutationResolver) CreateFindingAuditMapping(ctx context.Context, input types.CreateFindingAuditMappingInput) (*types.CreateFindingAuditMappingPayload, error) {
|
||||
if err := r.authorize(ctx, input.FindingID, probo.ActionFindingAuditMappingCreate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.FindingID.TenantID())
|
||||
|
||||
finding, audit, err := prb.Findings.CreateAuditMapping(ctx, input.FindingID, input.AuditID, input.ReferenceID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot create finding audit mapping", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.CreateFindingAuditMappingPayload{
|
||||
FindingEdge: types.NewFindingEdge(finding, coredata.FindingOrderFieldCreatedAt),
|
||||
AuditEdge: types.NewAuditEdge(audit, coredata.AuditOrderFieldCreatedAt),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteFindingAuditMapping is the resolver for the deleteFindingAuditMapping field.
|
||||
func (r *mutationResolver) DeleteFindingAuditMapping(ctx context.Context, input types.DeleteFindingAuditMappingInput) (*types.DeleteFindingAuditMappingPayload, error) {
|
||||
if err := r.authorize(ctx, input.FindingID, probo.ActionFindingAuditMappingDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.FindingID.TenantID())
|
||||
|
||||
finding, audit, err := prb.Findings.DeleteAuditMapping(ctx, input.FindingID, input.AuditID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot delete finding audit mapping", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DeleteFindingAuditMappingPayload{
|
||||
DeletedFindingID: &finding.ID,
|
||||
DeletedAuditID: &audit.ID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Audits is the resolver for the audits field.
|
||||
func (r *organizationResolver) Audits(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.AuditOrderBy) (*types.AuditConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionAuditList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.AuditOrderField]{
|
||||
Field: coredata.AuditOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.AuditOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
page, err := prb.Audits.ListForOrganizationID(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list organization audits", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewAuditConnection(page, r, obj.ID), nil
|
||||
}
|
||||
|
||||
// Findings is the resolver for the findings field.
|
||||
func (r *organizationResolver) Findings(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.FindingOrder, filter *types.FindingFilter) (*types.FindingConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionFindingList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.FindingOrderField]{
|
||||
Field: coredata.FindingOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.FindingOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
var (
|
||||
kind *coredata.FindingKind
|
||||
status *coredata.FindingStatus
|
||||
priority *coredata.FindingPriority
|
||||
ownerID *gid.GID
|
||||
)
|
||||
if filter != nil {
|
||||
kind = filter.Kind
|
||||
status = filter.Status
|
||||
priority = filter.Priority
|
||||
ownerID = filter.OwnerID
|
||||
}
|
||||
|
||||
findingFilter := coredata.NewFindingFilter(nil, kind, status, priority, ownerID)
|
||||
if filter != nil {
|
||||
findingFilter = coredata.NewFindingFilter(&filter.SnapshotID, kind, status, priority, ownerID)
|
||||
}
|
||||
|
||||
page, err := prb.Findings.ListForOrganizationID(ctx, obj.ID, cursor, findingFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list organization findings", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewFindingConnection(page, r, obj.ID, filter), nil
|
||||
}
|
||||
|
||||
// DownloadURL is the resolver for the downloadUrl field.
|
||||
func (r *reportResolver) DownloadURL(ctx context.Context, obj *types.Report) (*string, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionReportDownloadUrlGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
url, err := prb.Reports.GenerateDownloadURL(ctx, obj.ID, 15*time.Minute)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot generate download URL", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return url, nil
|
||||
}
|
||||
|
||||
// Audit is the resolver for the audit field.
|
||||
func (r *reportResolver) Audit(ctx context.Context, obj *types.Report) (*types.Audit, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionAuditGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
audit, err := prb.Audits.GetByReportID(ctx, obj.ID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot load audit for report", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewAudit(audit), nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *reportResolver) Permission(ctx context.Context, obj *types.Report, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// Audit returns schema.AuditResolver implementation.
|
||||
func (r *Resolver) Audit() schema.AuditResolver { return &auditResolver{r} }
|
||||
|
||||
// AuditConnection returns schema.AuditConnectionResolver implementation.
|
||||
func (r *Resolver) AuditConnection() schema.AuditConnectionResolver {
|
||||
return &auditConnectionResolver{r}
|
||||
}
|
||||
|
||||
// Finding returns schema.FindingResolver implementation.
|
||||
func (r *Resolver) Finding() schema.FindingResolver { return &findingResolver{r} }
|
||||
|
||||
// FindingConnection returns schema.FindingConnectionResolver implementation.
|
||||
func (r *Resolver) FindingConnection() schema.FindingConnectionResolver {
|
||||
return &findingConnectionResolver{r}
|
||||
}
|
||||
|
||||
// Report returns schema.ReportResolver implementation.
|
||||
func (r *Resolver) Report() schema.ReportResolver { return &reportResolver{r} }
|
||||
|
||||
type auditResolver struct{ *Resolver }
|
||||
type auditConnectionResolver struct{ *Resolver }
|
||||
type findingResolver struct{ *Resolver }
|
||||
type findingConnectionResolver struct{ *Resolver }
|
||||
type reportResolver struct{ *Resolver }
|
||||
99
pkg/server/api/console/v1/audit_log.resolvers.go
Normal file
99
pkg/server/api/console/v1/audit_log.resolvers.go
Normal file
@@ -0,0 +1,99 @@
|
||||
package console_v1
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver
|
||||
// implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.87
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.gearno.de/kit/log"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/iam"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/schema"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/types"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils"
|
||||
)
|
||||
|
||||
// Organization is the resolver for the organization field.
|
||||
func (r *auditLogEntryResolver) Organization(ctx context.Context, obj *types.AuditLogEntry) (*types.Organization, error) {
|
||||
return obj.Organization, nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *auditLogEntryResolver) Permission(ctx context.Context, obj *types.AuditLogEntry, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// TotalCount is the resolver for the totalCount field.
|
||||
func (r *auditLogEntryConnectionResolver) TotalCount(ctx context.Context, obj *types.AuditLogEntryConnection) (int, error) {
|
||||
filter := coredata.NewAuditLogEntryFilter()
|
||||
if obj.Filter != nil {
|
||||
filter = obj.Filter
|
||||
}
|
||||
|
||||
count, err := r.iam.OrganizationService.CountAuditLogEntries(ctx, obj.ParentID, filter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count audit log entries", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// AuditLogEntries is the resolver for the auditLogEntries field.
|
||||
func (r *organizationResolver) AuditLogEntries(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.AuditLogEntryOrderBy, filter *types.AuditLogEntryFilter) (*types.AuditLogEntryConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, iam.ActionAuditLogEntryList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.AuditLogEntryOrderField]{
|
||||
Field: coredata.AuditLogEntryOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.AuditLogEntryOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
coredataFilter := coredata.NewAuditLogEntryFilter()
|
||||
if filter != nil {
|
||||
if filter.Action != nil {
|
||||
coredataFilter.WithAction(*filter.Action)
|
||||
}
|
||||
if filter.ActorID != nil {
|
||||
coredataFilter.WithActorID(*filter.ActorID)
|
||||
}
|
||||
if filter.ResourceType != nil {
|
||||
coredataFilter.WithResourceType(*filter.ResourceType)
|
||||
}
|
||||
if filter.ResourceID != nil {
|
||||
coredataFilter.WithResourceID(*filter.ResourceID)
|
||||
}
|
||||
}
|
||||
|
||||
p, err := r.iam.OrganizationService.ListAuditLogEntries(ctx, obj.ID, cursor, coredataFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list audit log entries", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewAuditLogEntryConnection(p, r, obj.ID, coredataFilter), nil
|
||||
}
|
||||
|
||||
// AuditLogEntry returns schema.AuditLogEntryResolver implementation.
|
||||
func (r *Resolver) AuditLogEntry() schema.AuditLogEntryResolver { return &auditLogEntryResolver{r} }
|
||||
|
||||
// AuditLogEntryConnection returns schema.AuditLogEntryConnectionResolver implementation.
|
||||
func (r *Resolver) AuditLogEntryConnection() schema.AuditLogEntryConnectionResolver {
|
||||
return &auditLogEntryConnectionResolver{r}
|
||||
}
|
||||
|
||||
type auditLogEntryResolver struct{ *Resolver }
|
||||
type auditLogEntryConnectionResolver struct{ *Resolver }
|
||||
565
pkg/server/api/console/v1/base.resolvers.go
Normal file
565
pkg/server/api/console/v1/base.resolvers.go
Normal file
@@ -0,0 +1,565 @@
|
||||
package console_v1
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver
|
||||
// implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.87
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"go.gearno.de/kit/log"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/iam"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"go.probo.inc/probo/pkg/probo"
|
||||
"go.probo.inc/probo/pkg/server/api/authn"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/schema"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/types"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils/types/cursor"
|
||||
"go.probo.inc/probo/pkg/validator"
|
||||
)
|
||||
|
||||
// DownloadURL is the resolver for the downloadUrl field.
|
||||
func (r *fileResolver) DownloadURL(ctx context.Context, obj *types.File) (string, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionFileDownloadUrl); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
downloadUrl, err := prb.Files.GenerateFileTempURL(ctx, obj.ID, 60*time.Second)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot generate download URL", log.Error(err))
|
||||
return "", gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return downloadUrl, nil
|
||||
}
|
||||
|
||||
// UpdateOrganizationContext is the resolver for the updateOrganizationContext field.
|
||||
func (r *mutationResolver) UpdateOrganizationContext(ctx context.Context, input types.UpdateOrganizationContextInput) (*types.UpdateOrganizationContextPayload, error) {
|
||||
if err := r.authorize(ctx, input.OrganizationID, probo.ActionOrganizationContextUpdate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
||||
|
||||
req := probo.UpdateOrganizationContextRequest{
|
||||
OrganizationID: input.OrganizationID,
|
||||
Product: gqlutils.UnwrapOmittable(input.Product),
|
||||
Architecture: gqlutils.UnwrapOmittable(input.Architecture),
|
||||
Team: gqlutils.UnwrapOmittable(input.Team),
|
||||
Processes: gqlutils.UnwrapOmittable(input.Processes),
|
||||
Customers: gqlutils.UnwrapOmittable(input.Customers),
|
||||
}
|
||||
|
||||
organizationContext, err := prb.Organizations.UpdateContext(ctx, req)
|
||||
if err != nil {
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot update organization context", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.UpdateOrganizationContextPayload{
|
||||
Context: types.NewOrganizationContext(organizationContext),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// LogoURL is the resolver for the logoUrl field.
|
||||
func (r *organizationResolver) LogoURL(ctx context.Context, obj *types.Organization) (*string, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGetLogoUrl); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
logoURL, err := prb.Organizations.GenerateLogoURL(ctx, obj.ID, 1*time.Hour)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot generate logo url", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return logoURL, nil
|
||||
}
|
||||
|
||||
// HorizontalLogoURL is the resolver for the horizontalLogoUrl field.
|
||||
func (r *organizationResolver) HorizontalLogoURL(ctx context.Context, obj *types.Organization) (*string, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGetHorizontalLogoUrl); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
horizontalLogoURL, err := prb.Organizations.GenerateHorizontalLogoURL(ctx, obj.ID, 1*time.Hour)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot generate horizontal logo url", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return horizontalLogoURL, nil
|
||||
}
|
||||
|
||||
// Context is the resolver for the context field.
|
||||
func (r *organizationResolver) Context(ctx context.Context, obj *types.Organization) (*types.OrganizationContext, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationContextGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
orgContext, err := prb.Organizations.GetContext(ctx, obj.ID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot load organization context", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewOrganizationContext(orgContext), nil
|
||||
}
|
||||
|
||||
// Profiles is the resolver for the profiles field.
|
||||
func (r *organizationResolver) Profiles(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ProfileOrderBy, filter *types.ProfileFilter) (*types.ProfileConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if gqlutils.OnlyTotalCountSelected(ctx) {
|
||||
return &types.ProfileConnection{
|
||||
Resolver: r,
|
||||
ParentID: obj.ID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
filters := coredata.NewMembershipProfileFilter(nil).WithMembership()
|
||||
if filter != nil {
|
||||
filters = coredata.NewMembershipProfileFilter(filter.ExcludeContractEnded).WithMembership()
|
||||
}
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.MembershipProfileOrderField]{
|
||||
Field: coredata.MembershipProfileOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy.Field = coredata.MembershipProfileOrderField(orderBy.Field)
|
||||
pageOrderBy.Direction = page.OrderDirection(orderBy.Direction)
|
||||
}
|
||||
|
||||
cursor := cursor.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
page, err := r.iam.OrganizationService.ListProfiles(ctx, obj.ID, cursor, filters)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list profiles", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewProfileConnection(page, r, obj.ID, filters), nil
|
||||
}
|
||||
|
||||
// MeasureCategories is the resolver for the measureCategories field.
|
||||
func (r *organizationResolver) MeasureCategories(ctx context.Context, obj *types.Organization) ([]string, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionMeasureList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
categories, err := prb.Measures.ListDistinctCategoriesForOrganizationID(ctx, obj.ID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list measure categories", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return categories, nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *organizationResolver) Permission(ctx context.Context, obj *types.Organization, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// Node is the resolver for the node field.
|
||||
func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
var (
|
||||
loadNode func(ctx context.Context, id gid.GID) (types.Node, error)
|
||||
action string
|
||||
prb = r.ProboService(ctx, id.TenantID())
|
||||
)
|
||||
|
||||
switch id.EntityType() {
|
||||
case coredata.OrganizationEntityType:
|
||||
action = iam.ActionOrganizationGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
organization, err := prb.Organizations.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewOrganization(organization), nil
|
||||
}
|
||||
case coredata.VendorEntityType:
|
||||
action = probo.ActionVendorGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
vendor, err := prb.Vendors.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewVendor(vendor), nil
|
||||
}
|
||||
case coredata.FrameworkEntityType:
|
||||
action = probo.ActionFrameworkGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
framework, err := prb.Frameworks.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewFramework(framework), nil
|
||||
}
|
||||
case coredata.MeasureEntityType:
|
||||
action = probo.ActionMeasureGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
measure, err := prb.Measures.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewMeasure(measure), nil
|
||||
}
|
||||
case coredata.TaskEntityType:
|
||||
action = probo.ActionTaskGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
task, err := prb.Tasks.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewTask(task), nil
|
||||
}
|
||||
case coredata.EvidenceEntityType:
|
||||
action = probo.ActionEvidenceList
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
evidence, err := prb.Evidences.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewEvidence(evidence), nil
|
||||
}
|
||||
case coredata.DocumentEntityType:
|
||||
action = probo.ActionDocumentGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
document, err := prb.Documents.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewDocument(document), nil
|
||||
}
|
||||
case coredata.ControlEntityType:
|
||||
action = probo.ActionControlList
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
control, err := prb.Controls.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewControl(control), nil
|
||||
}
|
||||
case coredata.RiskEntityType:
|
||||
action = probo.ActionRiskGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
risk, err := prb.Risks.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewRisk(risk), nil
|
||||
}
|
||||
case coredata.VendorComplianceReportEntityType:
|
||||
action = probo.ActionVendorComplianceReportGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
vendorComplianceReport, err := prb.VendorComplianceReports.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewVendorComplianceReport(vendorComplianceReport), nil
|
||||
}
|
||||
case coredata.VendorContactEntityType:
|
||||
action = probo.ActionVendorContactGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
vendorContact, err := prb.VendorContacts.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewVendorContact(vendorContact), nil
|
||||
}
|
||||
case coredata.VendorServiceEntityType:
|
||||
action = probo.ActionVendorServiceGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
vendorService, err := prb.VendorServices.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewVendorService(vendorService), nil
|
||||
}
|
||||
case coredata.DocumentVersionEntityType:
|
||||
action = probo.ActionDocumentVersionList
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
documentVersion, err := prb.Documents.GetVersion(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewDocumentVersion(documentVersion), nil
|
||||
}
|
||||
case coredata.DocumentVersionSignatureEntityType:
|
||||
action = probo.ActionDocumentVersionSignatureList
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
documentVersionSignature, err := prb.Documents.GetVersionSignature(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewDocumentVersionSignature(documentVersionSignature), nil
|
||||
}
|
||||
case coredata.AssetEntityType:
|
||||
action = probo.ActionAssetList
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
asset, err := prb.Assets.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewAsset(asset), nil
|
||||
}
|
||||
case coredata.DatumEntityType:
|
||||
action = probo.ActionDatumList
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
datum, err := prb.Data.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewDatum(datum), nil
|
||||
}
|
||||
case coredata.AuditEntityType:
|
||||
action = probo.ActionAuditList
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
audit, err := prb.Audits.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewAudit(audit), nil
|
||||
}
|
||||
case coredata.FindingEntityType:
|
||||
action = probo.ActionFindingList
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
finding, err := prb.Findings.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewFinding(finding), nil
|
||||
}
|
||||
case coredata.ObligationEntityType:
|
||||
action = probo.ActionObligationList
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
obligation, err := prb.Obligations.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewObligation(obligation), nil
|
||||
}
|
||||
case coredata.ReportEntityType:
|
||||
action = probo.ActionReportGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
report, err := prb.Reports.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewReport(report), nil
|
||||
}
|
||||
case coredata.ProcessingActivityEntityType:
|
||||
action = probo.ActionProcessingActivityList
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
processingActivity, err := prb.ProcessingActivities.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewProcessingActivity(processingActivity), nil
|
||||
}
|
||||
case coredata.DataProtectionImpactAssessmentEntityType:
|
||||
// TODO: add action
|
||||
// action = probo.ActionDataProtectionImpactAssessmentGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
dpia, err := prb.DataProtectionImpactAssessments.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewDataProtectionImpactAssessment(dpia), nil
|
||||
}
|
||||
case coredata.TransferImpactAssessmentEntityType:
|
||||
// TODO: add action
|
||||
//action = probo.ActionTransferImpactAssessmentGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
tia, err := prb.TransferImpactAssessments.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewTransferImpactAssessment(tia), nil
|
||||
}
|
||||
case coredata.SnapshotEntityType:
|
||||
action = probo.ActionSnapshotList
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
snapshot, err := prb.Snapshots.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewSnapshot(snapshot), nil
|
||||
}
|
||||
case coredata.TrustCenterEntityType:
|
||||
action = probo.ActionTrustCenterGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
trustCenter, err := prb.TrustCenters.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var file *coredata.File
|
||||
if trustCenter.NonDisclosureAgreementFileID != nil {
|
||||
file, err = prb.Files.Get(ctx, *trustCenter.NonDisclosureAgreementFileID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot get NDA file: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return types.NewTrustCenter(trustCenter, file), nil
|
||||
}
|
||||
case coredata.TrustCenterAccessEntityType:
|
||||
action = probo.ActionTrustCenterAccessGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
trustCenterAccess, err := prb.TrustCenterAccesses.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewTrustCenterAccess(trustCenterAccess), nil
|
||||
}
|
||||
case coredata.MeetingEntityType:
|
||||
action = probo.ActionMeetingGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
meeting, err := prb.Meetings.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewMeeting(meeting), nil
|
||||
}
|
||||
case coredata.RightsRequestEntityType:
|
||||
action = probo.ActionRightsRequestGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
rightsRequest, err := prb.RightsRequests.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewRightsRequest(rightsRequest), nil
|
||||
}
|
||||
case coredata.StatementOfApplicabilityEntityType:
|
||||
action = probo.ActionStatementOfApplicabilityGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
statementOfApplicability, err := prb.StatementsOfApplicability.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewStatementOfApplicability(statementOfApplicability), nil
|
||||
}
|
||||
case coredata.WebhookSubscriptionEntityType:
|
||||
action = probo.ActionWebhookSubscriptionGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
wc, err := prb.WebhookSubscriptions.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewWebhookSubscription(wc), nil
|
||||
}
|
||||
case coredata.AccessReviewCampaignEntityType:
|
||||
action = probo.ActionAccessReviewCampaignGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
scope := coredata.NewScopeFromObjectID(id)
|
||||
campaign, err := r.accessReview.Campaigns(scope).Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewAccessReviewCampaign(campaign), nil
|
||||
}
|
||||
case coredata.AccessSourceEntityType:
|
||||
action = probo.ActionAccessSourceGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
scope := coredata.NewScopeFromObjectID(id)
|
||||
source, err := r.accessReview.Sources(scope).Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewAccessSource(source), nil
|
||||
}
|
||||
case coredata.AccessEntryEntityType:
|
||||
action = probo.ActionAccessEntryGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
scope := coredata.NewScopeFromObjectID(id)
|
||||
entry, err := r.accessReview.Entries(scope).Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewAccessEntry(entry), nil
|
||||
}
|
||||
default:
|
||||
}
|
||||
|
||||
if err := r.authorize(ctx, id, action); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
node, err := loadNode(ctx, id)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot load node", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return node, nil
|
||||
}
|
||||
|
||||
// Viewer is the resolver for the viewer field.
|
||||
func (r *queryResolver) Viewer(ctx context.Context) (*types.Viewer, error) {
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
|
||||
session := authn.SessionFromContext(ctx)
|
||||
apiKey := authn.APIKeyFromContext(ctx)
|
||||
|
||||
var viewerID gid.GID
|
||||
if session != nil {
|
||||
viewerID = session.ID
|
||||
} else if apiKey != nil {
|
||||
viewerID = apiKey.ID
|
||||
} else {
|
||||
viewerID = identity.ID
|
||||
}
|
||||
|
||||
return &types.Viewer{ID: viewerID}, nil
|
||||
}
|
||||
|
||||
// File returns schema.FileResolver implementation.
|
||||
func (r *Resolver) File() schema.FileResolver { return &fileResolver{r} }
|
||||
|
||||
// Mutation returns schema.MutationResolver implementation.
|
||||
func (r *Resolver) Mutation() schema.MutationResolver { return &mutationResolver{r} }
|
||||
|
||||
// Organization returns schema.OrganizationResolver implementation.
|
||||
func (r *Resolver) Organization() schema.OrganizationResolver { return &organizationResolver{r} }
|
||||
|
||||
// Query returns schema.QueryResolver implementation.
|
||||
func (r *Resolver) Query() schema.QueryResolver { return &queryResolver{r} }
|
||||
|
||||
// Viewer returns schema.ViewerResolver implementation.
|
||||
func (r *Resolver) Viewer() schema.ViewerResolver { return &viewerResolver{r} }
|
||||
|
||||
type fileResolver struct{ *Resolver }
|
||||
type mutationResolver struct{ *Resolver }
|
||||
type organizationResolver struct{ *Resolver }
|
||||
type queryResolver struct{ *Resolver }
|
||||
type viewerResolver struct{ *Resolver }
|
||||
274
pkg/server/api/console/v1/connector.resolvers.go
Normal file
274
pkg/server/api/console/v1/connector.resolvers.go
Normal file
@@ -0,0 +1,274 @@
|
||||
package console_v1
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver
|
||||
// implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.87
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"go.gearno.de/kit/log"
|
||||
"go.probo.inc/probo/pkg/accessreview/drivers"
|
||||
"go.probo.inc/probo/pkg/connector"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"go.probo.inc/probo/pkg/probo"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/schema"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/types"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils"
|
||||
"go.probo.inc/probo/pkg/slack"
|
||||
)
|
||||
|
||||
// Oauth2Scopes is the resolver for the oauth2Scopes field.
|
||||
func (r *connectorResolver) Oauth2Scopes(ctx context.Context, obj *types.Connector) ([]string, error) {
|
||||
scopes := drivers.ProviderOAuth2Scopes(obj.Provider)
|
||||
if scopes == nil {
|
||||
return []string{}, nil
|
||||
}
|
||||
return scopes, nil
|
||||
}
|
||||
|
||||
// CreateAPIKeyConnector is the resolver for the createAPIKeyConnector field.
|
||||
func (r *mutationResolver) CreateAPIKeyConnector(ctx context.Context, input types.CreateAPIKeyConnectorInput) (*types.CreateAPIKeyConnectorPayload, error) {
|
||||
if err := r.authorize(ctx, input.OrganizationID, probo.ActionConnectorCreate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
||||
|
||||
req := probo.CreateConnectorRequest{
|
||||
OrganizationID: input.OrganizationID,
|
||||
Provider: input.Provider,
|
||||
Protocol: coredata.ConnectorProtocolAPIKey,
|
||||
Connection: &connector.APIKeyConnection{APIKey: input.APIKey},
|
||||
}
|
||||
|
||||
if input.TallyOrganizationID != nil {
|
||||
req.TallySettings = &coredata.TallyConnectorSettings{
|
||||
OrganizationID: *input.TallyOrganizationID,
|
||||
}
|
||||
}
|
||||
if input.SentryOrganizationSlug != nil {
|
||||
req.SentrySettings = &coredata.SentryConnectorSettings{
|
||||
OrganizationSlug: *input.SentryOrganizationSlug,
|
||||
}
|
||||
}
|
||||
if input.SupabaseOrganizationSlug != nil {
|
||||
req.SupabaseSettings = &coredata.SupabaseConnectorSettings{
|
||||
OrganizationSlug: *input.SupabaseOrganizationSlug,
|
||||
}
|
||||
}
|
||||
if input.GithubOrganization != nil {
|
||||
req.GitHubSettings = &coredata.GitHubConnectorSettings{
|
||||
Organization: *input.GithubOrganization,
|
||||
}
|
||||
}
|
||||
if input.OnePasswordScimBridgeURL != nil {
|
||||
req.OnePasswordSettings = &coredata.OnePasswordConnectorSettings{
|
||||
SCIMBridgeURL: *input.OnePasswordScimBridgeURL,
|
||||
}
|
||||
}
|
||||
cnnctr, err := prb.Connectors.Create(ctx, req)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceAlreadyExists) {
|
||||
return nil, gqlutils.Conflict(ctx, err)
|
||||
}
|
||||
|
||||
panic(fmt.Errorf("cannot create API key connector: %w", err))
|
||||
}
|
||||
|
||||
return &types.CreateAPIKeyConnectorPayload{
|
||||
Connector: types.NewConnector(cnnctr),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreateClientCredentialsConnector is the resolver for the createClientCredentialsConnector field.
|
||||
func (r *mutationResolver) CreateClientCredentialsConnector(ctx context.Context, input types.CreateClientCredentialsConnectorInput) (*types.CreateClientCredentialsConnectorPayload, error) {
|
||||
if err := r.authorize(ctx, input.OrganizationID, probo.ActionConnectorCreate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
||||
|
||||
oauth2Conn := &connector.OAuth2Connection{
|
||||
GrantType: connector.OAuth2GrantTypeClientCredentials,
|
||||
ClientID: input.ClientID,
|
||||
ClientSecret: input.ClientSecret,
|
||||
TokenURL: input.TokenURL,
|
||||
}
|
||||
if input.Scope != nil {
|
||||
oauth2Conn.Scope = *input.Scope
|
||||
}
|
||||
|
||||
req := probo.CreateConnectorRequest{
|
||||
OrganizationID: input.OrganizationID,
|
||||
Provider: input.Provider,
|
||||
Protocol: coredata.ConnectorProtocolOAuth2,
|
||||
Connection: oauth2Conn,
|
||||
}
|
||||
|
||||
if input.OnePasswordAccountID != nil && input.OnePasswordRegion != nil {
|
||||
req.OnePasswordUsersAPISettings = &coredata.OnePasswordUsersAPISettings{
|
||||
AccountID: *input.OnePasswordAccountID,
|
||||
Region: *input.OnePasswordRegion,
|
||||
}
|
||||
}
|
||||
|
||||
cnnctr, err := prb.Connectors.Create(ctx, req)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceAlreadyExists) {
|
||||
return nil, gqlutils.Conflict(ctx, err)
|
||||
}
|
||||
|
||||
panic(fmt.Errorf("cannot create client credentials connector: %w", err))
|
||||
}
|
||||
|
||||
return &types.CreateClientCredentialsConnectorPayload{
|
||||
Connector: types.NewConnector(cnnctr),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteConnector is the resolver for the deleteConnector field.
|
||||
func (r *mutationResolver) DeleteConnector(ctx context.Context, input types.DeleteConnectorInput) (*types.DeleteConnectorPayload, error) {
|
||||
if err := r.authorize(ctx, input.ConnectorID, probo.ActionConnectorDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.ConnectorID.TenantID())
|
||||
|
||||
if err := prb.Connectors.Delete(ctx, input.ConnectorID); err != nil {
|
||||
panic(fmt.Errorf("cannot delete connector: %w", err))
|
||||
}
|
||||
|
||||
return &types.DeleteConnectorPayload{
|
||||
DeletedConnectorID: input.ConnectorID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteSlackConnection is the resolver for the deleteSlackConnection field.
|
||||
func (r *mutationResolver) DeleteSlackConnection(ctx context.Context, input types.DeleteSlackConnectionInput) (*types.DeleteSlackConnectionPayload, error) {
|
||||
if err := r.authorize(ctx, input.SlackConnectionID, probo.ActionConnectorDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.SlackConnectionID.TenantID())
|
||||
|
||||
err := prb.Connectors.Delete(ctx, input.SlackConnectionID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot delete slack connection", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DeleteSlackConnectionPayload{
|
||||
DeletedSlackConnectionID: input.SlackConnectionID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SlackConnections is the resolver for the slackConnections field.
|
||||
func (r *organizationResolver) SlackConnections(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.SlackConnectionConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionSlackConnectionList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
slackProvider := coredata.ConnectorProviderSlack
|
||||
filter := coredata.NewConnectorProviderFilter(&slackProvider)
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.ConnectorOrderField]{
|
||||
Field: coredata.ConnectorOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
page, err := prb.Connectors.ListForOrganizationID(ctx, obj.ID, cursor, filter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list organization slack connections", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewSlackConnectionConnection(page), nil
|
||||
}
|
||||
|
||||
// SlackOAuth2Scopes is the resolver for the slackOAuth2Scopes field.
|
||||
func (r *organizationResolver) SlackOAuth2Scopes(ctx context.Context, obj *types.Organization) ([]string, error) {
|
||||
return slack.OAuth2Scopes, nil
|
||||
}
|
||||
|
||||
// Connectors is the resolver for the connectors field.
|
||||
func (r *organizationResolver) Connectors(ctx context.Context, obj *types.Organization, filter *types.ConnectorFilter) ([]*types.Connector, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionConnectorList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
connectors, err := prb.Connectors.ListAllForOrganizationID(ctx, obj.ID)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("cannot list organization connectors: %w", err))
|
||||
}
|
||||
|
||||
if filter != nil && len(filter.Providers) > 0 {
|
||||
allowed := make(map[coredata.ConnectorProvider]struct{}, len(filter.Providers))
|
||||
for _, provider := range filter.Providers {
|
||||
allowed[provider] = struct{}{}
|
||||
}
|
||||
|
||||
filtered := make(coredata.Connectors, 0, len(connectors))
|
||||
for _, cnnctr := range connectors {
|
||||
if _, ok := allowed[cnnctr.Provider]; ok {
|
||||
filtered = append(filtered, cnnctr)
|
||||
}
|
||||
}
|
||||
connectors = filtered
|
||||
}
|
||||
|
||||
return types.NewConnectors(connectors), nil
|
||||
}
|
||||
|
||||
// ConnectorProviderInfos is the resolver for the connectorProviderInfos field.
|
||||
func (r *organizationResolver) ConnectorProviderInfos(ctx context.Context, obj *types.Organization) ([]*types.ConnectorProviderInfo, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionConnectorList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var infos []*types.ConnectorProviderInfo
|
||||
for _, provider := range coredata.ConnectorProviders() {
|
||||
_, oauthErr := r.connectorRegistry.Get(string(provider))
|
||||
scopes := drivers.ProviderOAuth2Scopes(provider)
|
||||
if scopes == nil {
|
||||
scopes = []string{}
|
||||
}
|
||||
info := &types.ConnectorProviderInfo{
|
||||
Provider: provider,
|
||||
DisplayName: providerDisplayName(provider),
|
||||
OauthConfigured: oauthErr == nil,
|
||||
APIKeySupported: providerSupportsAPIKey(provider),
|
||||
ClientCredentialsSupported: providerSupportsClientCredentials(provider),
|
||||
Oauth2Scopes: scopes,
|
||||
ExtraSettings: providerExtraSettings(provider),
|
||||
}
|
||||
infos = append(infos, info)
|
||||
}
|
||||
return infos, nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *slackConnectionResolver) Permission(ctx context.Context, obj *types.SlackConnection, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// Connector returns schema.ConnectorResolver implementation.
|
||||
func (r *Resolver) Connector() schema.ConnectorResolver { return &connectorResolver{r} }
|
||||
|
||||
// SlackConnection returns schema.SlackConnectionResolver implementation.
|
||||
func (r *Resolver) SlackConnection() schema.SlackConnectionResolver {
|
||||
return &slackConnectionResolver{r}
|
||||
}
|
||||
|
||||
type connectorResolver struct{ *Resolver }
|
||||
type slackConnectionResolver struct{ *Resolver }
|
||||
1064
pkg/server/api/console/v1/control.resolvers.go
Normal file
1064
pkg/server/api/console/v1/control.resolvers.go
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,489 @@
|
||||
package console_v1
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver
|
||||
// implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.87
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/vikstrous/dataloadgen"
|
||||
"go.gearno.de/kit/log"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"go.probo.inc/probo/pkg/probo"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/dataloader"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/schema"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/types"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils"
|
||||
"go.probo.inc/probo/pkg/validator"
|
||||
)
|
||||
|
||||
// ProcessingActivity is the resolver for the processingActivity field.
|
||||
func (r *dataProtectionImpactAssessmentResolver) ProcessingActivity(ctx context.Context, obj *types.DataProtectionImpactAssessment) (*types.ProcessingActivity, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionProcessingActivityList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
dpia, err := prb.DataProtectionImpactAssessments.Get(ctx, obj.ID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot get processing activity dpia", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
processingActivity, err := prb.ProcessingActivities.Get(ctx, dpia.ProcessingActivityID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot get processing activity", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewProcessingActivity(processingActivity), nil
|
||||
}
|
||||
|
||||
// Organization is the resolver for the organization field.
|
||||
func (r *dataProtectionImpactAssessmentResolver) Organization(ctx context.Context, obj *types.DataProtectionImpactAssessment) (*types.Organization, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
dpia, err := prb.DataProtectionImpactAssessments.Get(ctx, obj.ID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot get processing activity dpia", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
organization, err := prb.Organizations.Get(ctx, dpia.OrganizationID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot get organization", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewOrganization(organization), nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *dataProtectionImpactAssessmentResolver) Permission(ctx context.Context, obj *types.DataProtectionImpactAssessment, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// TotalCount is the resolver for the totalCount field.
|
||||
func (r *dataProtectionImpactAssessmentConnectionResolver) TotalCount(ctx context.Context, obj *types.DataProtectionImpactAssessmentConnection) (int, error) {
|
||||
if err := r.authorize(ctx, obj.ParentID, probo.ActionDataProtectionImpactAssessmentList); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
||||
|
||||
switch obj.Resolver.(type) {
|
||||
case *organizationResolver:
|
||||
count, err := prb.DataProtectionImpactAssessments.CountForOrganizationID(ctx, obj.ParentID, obj.Filter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count organization data protection impact assessments", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "unsupported resolver")
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
// CreateDataProtectionImpactAssessment is the resolver for the createDataProtectionImpactAssessment field.
|
||||
func (r *mutationResolver) CreateDataProtectionImpactAssessment(ctx context.Context, input types.CreateDataProtectionImpactAssessmentInput) (*types.CreateDataProtectionImpactAssessmentPayload, error) {
|
||||
if err := r.authorize(ctx, input.ProcessingActivityID, probo.ActionDataProtectionImpactAssessmentCreate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.ProcessingActivityID.TenantID())
|
||||
|
||||
req := probo.CreateDataProtectionImpactAssessmentRequest{
|
||||
ProcessingActivityID: input.ProcessingActivityID,
|
||||
Description: input.Description,
|
||||
NecessityAndProportionality: input.NecessityAndProportionality,
|
||||
PotentialRisk: input.PotentialRisk,
|
||||
Mitigations: input.Mitigations,
|
||||
ResidualRisk: input.ResidualRisk,
|
||||
}
|
||||
|
||||
dpia, err := prb.DataProtectionImpactAssessments.Create(ctx, &req)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceAlreadyExists) {
|
||||
return nil, gqlutils.Conflict(ctx, err)
|
||||
}
|
||||
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot create data protection impact assessment", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.CreateDataProtectionImpactAssessmentPayload{
|
||||
DataProtectionImpactAssessment: types.NewDataProtectionImpactAssessment(dpia),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateDataProtectionImpactAssessment is the resolver for the updateDataProtectionImpactAssessment field.
|
||||
func (r *mutationResolver) UpdateDataProtectionImpactAssessment(ctx context.Context, input types.UpdateDataProtectionImpactAssessmentInput) (*types.UpdateDataProtectionImpactAssessmentPayload, error) {
|
||||
if err := r.authorize(ctx, input.ID, probo.ActionDataProtectionImpactAssessmentUpdate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.ID.TenantID())
|
||||
|
||||
req := probo.UpdateDataProtectionImpactAssessmentRequest{
|
||||
ID: input.ID,
|
||||
Description: gqlutils.UnwrapOmittable(input.Description),
|
||||
NecessityAndProportionality: gqlutils.UnwrapOmittable(input.NecessityAndProportionality),
|
||||
PotentialRisk: gqlutils.UnwrapOmittable(input.PotentialRisk),
|
||||
Mitigations: gqlutils.UnwrapOmittable(input.Mitigations),
|
||||
ResidualRisk: input.ResidualRisk,
|
||||
}
|
||||
|
||||
dpia, err := prb.DataProtectionImpactAssessments.Update(ctx, &req)
|
||||
if err != nil {
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot update data protection impact assessment", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.UpdateDataProtectionImpactAssessmentPayload{
|
||||
DataProtectionImpactAssessment: types.NewDataProtectionImpactAssessment(dpia),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteDataProtectionImpactAssessment is the resolver for the deleteDataProtectionImpactAssessment field.
|
||||
func (r *mutationResolver) DeleteDataProtectionImpactAssessment(ctx context.Context, input types.DeleteDataProtectionImpactAssessmentInput) (*types.DeleteDataProtectionImpactAssessmentPayload, error) {
|
||||
if err := r.authorize(ctx, input.DataProtectionImpactAssessmentID, probo.ActionDataProtectionImpactAssessmentDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.DataProtectionImpactAssessmentID.TenantID())
|
||||
|
||||
err := prb.DataProtectionImpactAssessments.Delete(ctx, input.DataProtectionImpactAssessmentID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot delete data protection impact assessment", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DeleteDataProtectionImpactAssessmentPayload{
|
||||
DeletedDataProtectionImpactAssessmentID: input.DataProtectionImpactAssessmentID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreateTransferImpactAssessment is the resolver for the createTransferImpactAssessment field.
|
||||
func (r *mutationResolver) CreateTransferImpactAssessment(ctx context.Context, input types.CreateTransferImpactAssessmentInput) (*types.CreateTransferImpactAssessmentPayload, error) {
|
||||
if err := r.authorize(ctx, input.ProcessingActivityID, probo.ActionTransferImpactAssessmentCreate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.ProcessingActivityID.TenantID())
|
||||
|
||||
req := probo.CreateTransferImpactAssessmentRequest{
|
||||
ProcessingActivityID: input.ProcessingActivityID,
|
||||
DataSubjects: input.DataSubjects,
|
||||
LegalMechanism: input.LegalMechanism,
|
||||
Transfer: input.Transfer,
|
||||
LocalLawRisk: input.LocalLawRisk,
|
||||
SupplementaryMeasures: input.SupplementaryMeasures,
|
||||
}
|
||||
|
||||
tia, err := prb.TransferImpactAssessments.Create(ctx, &req)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceAlreadyExists) {
|
||||
return nil, gqlutils.Conflict(ctx, err)
|
||||
}
|
||||
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot create transfer impact assessment", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.CreateTransferImpactAssessmentPayload{
|
||||
TransferImpactAssessment: types.NewTransferImpactAssessment(tia),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateTransferImpactAssessment is the resolver for the updateTransferImpactAssessment field.
|
||||
func (r *mutationResolver) UpdateTransferImpactAssessment(ctx context.Context, input types.UpdateTransferImpactAssessmentInput) (*types.UpdateTransferImpactAssessmentPayload, error) {
|
||||
if err := r.authorize(ctx, input.ID, probo.ActionTransferImpactAssessmentUpdate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.ID.TenantID())
|
||||
|
||||
req := probo.UpdateTransferImpactAssessmentRequest{
|
||||
ID: input.ID,
|
||||
DataSubjects: gqlutils.UnwrapOmittable(input.DataSubjects),
|
||||
LegalMechanism: gqlutils.UnwrapOmittable(input.LegalMechanism),
|
||||
Transfer: gqlutils.UnwrapOmittable(input.Transfer),
|
||||
LocalLawRisk: gqlutils.UnwrapOmittable(input.LocalLawRisk),
|
||||
SupplementaryMeasures: gqlutils.UnwrapOmittable(input.SupplementaryMeasures),
|
||||
}
|
||||
|
||||
tia, err := prb.TransferImpactAssessments.Update(ctx, &req)
|
||||
if err != nil {
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot update transfer impact assessment", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.UpdateTransferImpactAssessmentPayload{
|
||||
TransferImpactAssessment: types.NewTransferImpactAssessment(tia),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteTransferImpactAssessment is the resolver for the deleteTransferImpactAssessment field.
|
||||
func (r *mutationResolver) DeleteTransferImpactAssessment(ctx context.Context, input types.DeleteTransferImpactAssessmentInput) (*types.DeleteTransferImpactAssessmentPayload, error) {
|
||||
if err := r.authorize(ctx, input.TransferImpactAssessmentID, probo.ActionTransferImpactAssessmentDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.TransferImpactAssessmentID.TenantID())
|
||||
|
||||
err := prb.TransferImpactAssessments.Delete(ctx, input.TransferImpactAssessmentID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot delete transfer impact assessment", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DeleteTransferImpactAssessmentPayload{
|
||||
DeletedTransferImpactAssessmentID: input.TransferImpactAssessmentID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ExportDataProtectionImpactAssessmentsPDF is the resolver for the exportDataProtectionImpactAssessmentsPDF field.
|
||||
func (r *mutationResolver) ExportDataProtectionImpactAssessmentsPDF(ctx context.Context, input types.ExportDataProtectionImpactAssessmentsPDFInput) (*types.ExportDataProtectionImpactAssessmentsPDFPayload, error) {
|
||||
if err := r.authorize(ctx, input.OrganizationID, probo.ActionDataProtectionImpactAssessmentExport); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
||||
|
||||
var snapshotIDPtr *gid.GID
|
||||
if input.Filter != nil {
|
||||
snapshotIDPtr = input.Filter.SnapshotID
|
||||
}
|
||||
dpiaFilter := coredata.NewDataProtectionImpactAssessmentFilter(&snapshotIDPtr)
|
||||
|
||||
pdf, err := prb.DataProtectionImpactAssessments.ExportPDF(ctx, input.OrganizationID, dpiaFilter)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot export data protection impact assessments PDF", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.ExportDataProtectionImpactAssessmentsPDFPayload{
|
||||
Data: fmt.Sprintf("data:application/pdf;base64,%s", base64.StdEncoding.EncodeToString(pdf)),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ExportTransferImpactAssessmentsPDF is the resolver for the exportTransferImpactAssessmentsPDF field.
|
||||
func (r *mutationResolver) ExportTransferImpactAssessmentsPDF(ctx context.Context, input types.ExportTransferImpactAssessmentsPDFInput) (*types.ExportTransferImpactAssessmentsPDFPayload, error) {
|
||||
if err := r.authorize(ctx, input.OrganizationID, probo.ActionTransferImpactAssessmentExport); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
||||
|
||||
var snapshotIDPtr *gid.GID
|
||||
if input.Filter != nil {
|
||||
snapshotIDPtr = input.Filter.SnapshotID
|
||||
}
|
||||
tiaFilter := coredata.NewTransferImpactAssessmentFilter(&snapshotIDPtr)
|
||||
|
||||
pdf, err := prb.TransferImpactAssessments.ExportPDF(ctx, input.OrganizationID, tiaFilter)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot export transfer impact assessments PDF", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.ExportTransferImpactAssessmentsPDFPayload{
|
||||
Data: fmt.Sprintf("data:application/pdf;base64,%s", base64.StdEncoding.EncodeToString(pdf)),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DataProtectionImpactAssessments is the resolver for the dataProtectionImpactAssessments field.
|
||||
func (r *organizationResolver) DataProtectionImpactAssessments(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DataProtectionImpactAssessmentOrderBy, filter *types.DataProtectionImpactAssessmentFilter) (*types.DataProtectionImpactAssessmentConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionDataProtectionImpactAssessmentList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.DataProtectionImpactAssessmentOrderField]{
|
||||
Field: coredata.DataProtectionImpactAssessmentOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.DataProtectionImpactAssessmentOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
dpiaFilter := coredata.NewDataProtectionImpactAssessmentFilter(nil)
|
||||
if filter != nil {
|
||||
dpiaFilter = coredata.NewDataProtectionImpactAssessmentFilter(&filter.SnapshotID)
|
||||
}
|
||||
|
||||
page, err := prb.DataProtectionImpactAssessments.ListForOrganizationID(ctx, obj.ID, cursor, dpiaFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list organization data protection impact assessments", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewDataProtectionImpactAssessmentConnection(page, r, obj.ID, dpiaFilter), nil
|
||||
}
|
||||
|
||||
// TransferImpactAssessments is the resolver for the transferImpactAssessments field.
|
||||
func (r *organizationResolver) TransferImpactAssessments(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.TransferImpactAssessmentOrderBy, filter *types.TransferImpactAssessmentFilter) (*types.TransferImpactAssessmentConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionTransferImpactAssessmentList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.TransferImpactAssessmentOrderField]{
|
||||
Field: coredata.TransferImpactAssessmentOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.TransferImpactAssessmentOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
tiaFilter := coredata.NewTransferImpactAssessmentFilter(nil)
|
||||
if filter != nil {
|
||||
tiaFilter = coredata.NewTransferImpactAssessmentFilter(&filter.SnapshotID)
|
||||
}
|
||||
|
||||
page, err := prb.TransferImpactAssessments.ListForOrganizationID(ctx, obj.ID, cursor, tiaFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list organization transfer impact assessments", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewTransferImpactAssessmentConnection(page, r, obj.ID, tiaFilter), nil
|
||||
}
|
||||
|
||||
// ProcessingActivity is the resolver for the processingActivity field.
|
||||
func (r *transferImpactAssessmentResolver) ProcessingActivity(ctx context.Context, obj *types.TransferImpactAssessment) (*types.ProcessingActivity, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionProcessingActivityGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
processingActivity, err := prb.ProcessingActivities.Get(ctx, obj.ProcessingActivity.ID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot get processing activity", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewProcessingActivity(processingActivity), nil
|
||||
}
|
||||
|
||||
// Organization is the resolver for the organization field.
|
||||
func (r *transferImpactAssessmentResolver) Organization(ctx context.Context, obj *types.TransferImpactAssessment) (*types.Organization, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
loaders := dataloader.FromContext(ctx)
|
||||
|
||||
organization, err := loaders.Organization.Load(ctx, obj.Organization.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get organization", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewOrganization(organization), nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *transferImpactAssessmentResolver) Permission(ctx context.Context, obj *types.TransferImpactAssessment, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// TotalCount is the resolver for the totalCount field.
|
||||
func (r *transferImpactAssessmentConnectionResolver) TotalCount(ctx context.Context, obj *types.TransferImpactAssessmentConnection) (int, error) {
|
||||
if err := r.authorize(ctx, obj.ParentID, probo.ActionTransferImpactAssessmentList); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
||||
|
||||
switch obj.Resolver.(type) {
|
||||
case *organizationResolver:
|
||||
count, err := prb.TransferImpactAssessments.CountForOrganizationID(ctx, obj.ParentID, obj.Filter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count organization transfer impact assessments", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "unsupported resolver")
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
// DataProtectionImpactAssessment returns schema.DataProtectionImpactAssessmentResolver implementation.
|
||||
func (r *Resolver) DataProtectionImpactAssessment() schema.DataProtectionImpactAssessmentResolver {
|
||||
return &dataProtectionImpactAssessmentResolver{r}
|
||||
}
|
||||
|
||||
// DataProtectionImpactAssessmentConnection returns schema.DataProtectionImpactAssessmentConnectionResolver implementation.
|
||||
func (r *Resolver) DataProtectionImpactAssessmentConnection() schema.DataProtectionImpactAssessmentConnectionResolver {
|
||||
return &dataProtectionImpactAssessmentConnectionResolver{r}
|
||||
}
|
||||
|
||||
// TransferImpactAssessment returns schema.TransferImpactAssessmentResolver implementation.
|
||||
func (r *Resolver) TransferImpactAssessment() schema.TransferImpactAssessmentResolver {
|
||||
return &transferImpactAssessmentResolver{r}
|
||||
}
|
||||
|
||||
// TransferImpactAssessmentConnection returns schema.TransferImpactAssessmentConnectionResolver implementation.
|
||||
func (r *Resolver) TransferImpactAssessmentConnection() schema.TransferImpactAssessmentConnectionResolver {
|
||||
return &transferImpactAssessmentConnectionResolver{r}
|
||||
}
|
||||
|
||||
type dataProtectionImpactAssessmentResolver struct{ *Resolver }
|
||||
type dataProtectionImpactAssessmentConnectionResolver struct{ *Resolver }
|
||||
type transferImpactAssessmentResolver struct{ *Resolver }
|
||||
type transferImpactAssessmentConnectionResolver struct{ *Resolver }
|
||||
1901
pkg/server/api/console/v1/document.resolvers.go
Normal file
1901
pkg/server/api/console/v1/document.resolvers.go
Normal file
File diff suppressed because it is too large
Load Diff
56
pkg/server/api/console/v1/electronic_signature.resolvers.go
Normal file
56
pkg/server/api/console/v1/electronic_signature.resolvers.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package console_v1
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver
|
||||
// implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.87
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/schema"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/types"
|
||||
)
|
||||
|
||||
// CertificateFileURL is the resolver for the certificateFileUrl field.
|
||||
func (r *electronicSignatureResolver) CertificateFileURL(ctx context.Context, obj *types.ElectronicSignature) (*string, error) {
|
||||
signature, err := r.esign.GetSignatureByID(ctx, obj.ID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot load signature: %w", err)
|
||||
}
|
||||
|
||||
if signature.CertificateFileID == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
url, err := r.esign.GenerateCertificateFileURL(ctx, *signature.CertificateFileID, 1*time.Hour)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot generate certificate file URL: %w", err)
|
||||
}
|
||||
|
||||
return &url, nil
|
||||
}
|
||||
|
||||
// Events is the resolver for the events field.
|
||||
func (r *electronicSignatureResolver) Events(ctx context.Context, obj *types.ElectronicSignature) ([]*types.ElectronicSignatureEvent, error) {
|
||||
events, err := r.esign.GetEventsBySignatureID(ctx, obj.ID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot load signature events: %w", err)
|
||||
}
|
||||
|
||||
result := make([]*types.ElectronicSignatureEvent, len(events))
|
||||
for i := range events {
|
||||
result[i] = types.NewElectronicSignatureEvent(events[i])
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ElectronicSignature returns schema.ElectronicSignatureResolver implementation.
|
||||
func (r *Resolver) ElectronicSignature() schema.ElectronicSignatureResolver {
|
||||
return &electronicSignatureResolver{r}
|
||||
}
|
||||
|
||||
type electronicSignatureResolver struct{ *Resolver }
|
||||
197
pkg/server/api/console/v1/evidence.resolvers.go
Normal file
197
pkg/server/api/console/v1/evidence.resolvers.go
Normal file
@@ -0,0 +1,197 @@
|
||||
package console_v1
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver
|
||||
// implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.87
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/vikstrous/dataloadgen"
|
||||
"go.gearno.de/kit/log"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"go.probo.inc/probo/pkg/probo"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/dataloader"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/schema"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/types"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils"
|
||||
"go.probo.inc/probo/pkg/validator"
|
||||
)
|
||||
|
||||
// File is the resolver for the file field.
|
||||
func (r *evidenceResolver) File(ctx context.Context, obj *types.Evidence) (*types.File, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionFileGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if obj.File == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
loaders := dataloader.FromContext(ctx)
|
||||
|
||||
file, err := loaders.File.Load(ctx, obj.File.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot load evidence file", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewFile(file), nil
|
||||
}
|
||||
|
||||
// Task is the resolver for the task field.
|
||||
func (r *evidenceResolver) Task(ctx context.Context, obj *types.Evidence) (*types.Task, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionTaskGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if obj.Task == nil {
|
||||
r.logger.ErrorCtx(ctx, "evidence is not associated with a task")
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
loaders := dataloader.FromContext(ctx)
|
||||
|
||||
task, err := loaders.Task.Load(ctx, obj.Task.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot load task", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewTask(task), nil
|
||||
}
|
||||
|
||||
// Measure is the resolver for the measure field.
|
||||
func (r *evidenceResolver) Measure(ctx context.Context, obj *types.Evidence) (*types.Measure, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionMeasureGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
loaders := dataloader.FromContext(ctx)
|
||||
|
||||
measure, err := loaders.Measure.Load(ctx, obj.Measure.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot load measure", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewMeasure(measure), nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *evidenceResolver) Permission(ctx context.Context, obj *types.Evidence, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// TotalCount is the resolver for the totalCount field.
|
||||
func (r *evidenceConnectionResolver) TotalCount(ctx context.Context, obj *types.EvidenceConnection) (int, error) {
|
||||
if err := r.authorize(ctx, obj.ParentID, probo.ActionEvidenceList); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
||||
|
||||
switch obj.Resolver.(type) {
|
||||
case *measureResolver:
|
||||
count, err := prb.Evidences.CountForMeasureID(ctx, obj.ParentID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count measure evidence", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
case *taskResolver:
|
||||
count, err := prb.Evidences.CountForTaskID(ctx, obj.ParentID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count task evidence", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "unsupported resolver")
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
// DeleteEvidence is the resolver for the deleteEvidence field.
|
||||
func (r *mutationResolver) DeleteEvidence(ctx context.Context, input types.DeleteEvidenceInput) (*types.DeleteEvidencePayload, error) {
|
||||
if err := r.authorize(ctx, input.EvidenceID, probo.ActionEvidenceDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.EvidenceID.TenantID())
|
||||
|
||||
err := prb.Evidences.Delete(ctx, input.EvidenceID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot delete evidence", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DeleteEvidencePayload{
|
||||
DeletedEvidenceID: input.EvidenceID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UploadMeasureEvidence is the resolver for the uploadMeasureEvidence field.
|
||||
func (r *mutationResolver) UploadMeasureEvidence(ctx context.Context, input types.UploadMeasureEvidenceInput) (*types.UploadMeasureEvidencePayload, error) {
|
||||
if err := r.authorize(ctx, input.MeasureID, probo.ActionMeasureEvidenceUpload); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.MeasureID.TenantID())
|
||||
|
||||
evidence, err := prb.Evidences.UploadMeasureEvidence(
|
||||
ctx,
|
||||
probo.UploadMeasureEvidenceRequest{
|
||||
MeasureID: input.MeasureID,
|
||||
File: probo.FileUpload{
|
||||
Content: input.File.File,
|
||||
Filename: input.File.Filename,
|
||||
Size: input.File.Size,
|
||||
ContentType: input.File.ContentType,
|
||||
},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot upload measure evidence", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.UploadMeasureEvidencePayload{
|
||||
EvidenceEdge: types.NewEvidenceEdge(evidence, coredata.EvidenceOrderFieldCreatedAt),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Evidences is the resolver for the evidences field.
|
||||
func (r *organizationResolver) Evidences(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.EvidenceOrderBy) (*types.EvidenceConnection, error) {
|
||||
panic(fmt.Errorf("not implemented: Evidences - evidences"))
|
||||
}
|
||||
|
||||
// Evidence returns schema.EvidenceResolver implementation.
|
||||
func (r *Resolver) Evidence() schema.EvidenceResolver { return &evidenceResolver{r} }
|
||||
|
||||
// EvidenceConnection returns schema.EvidenceConnectionResolver implementation.
|
||||
func (r *Resolver) EvidenceConnection() schema.EvidenceConnectionResolver {
|
||||
return &evidenceConnectionResolver{r}
|
||||
}
|
||||
|
||||
type evidenceResolver struct{ *Resolver }
|
||||
type evidenceConnectionResolver struct{ *Resolver }
|
||||
301
pkg/server/api/console/v1/framework.resolvers.go
Normal file
301
pkg/server/api/console/v1/framework.resolvers.go
Normal file
@@ -0,0 +1,301 @@
|
||||
package console_v1
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver
|
||||
// implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.87
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/vikstrous/dataloadgen"
|
||||
"go.gearno.de/kit/log"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"go.probo.inc/probo/pkg/probo"
|
||||
"go.probo.inc/probo/pkg/server/api/authn"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/dataloader"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/schema"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/types"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils"
|
||||
"go.probo.inc/probo/pkg/validator"
|
||||
)
|
||||
|
||||
// Organization is the resolver for the organization field.
|
||||
func (r *frameworkResolver) Organization(ctx context.Context, obj *types.Framework) (*types.Organization, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
loaders := dataloader.FromContext(ctx)
|
||||
|
||||
organization, err := loaders.Organization.Load(ctx, obj.Organization.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot load organization", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewOrganization(organization), nil
|
||||
}
|
||||
|
||||
// Controls is the resolver for the controls field.
|
||||
func (r *frameworkResolver) Controls(ctx context.Context, obj *types.Framework, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ControlOrderBy, filter *types.ControlFilter) (*types.ControlConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionControlList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.ControlOrderField]{
|
||||
Field: coredata.ControlOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.ControlOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
var controlFilter = coredata.NewControlFilter(nil)
|
||||
if filter != nil {
|
||||
controlFilter = coredata.NewControlFilter(filter.Query)
|
||||
}
|
||||
|
||||
page, err := prb.Controls.ListForFrameworkID(ctx, obj.ID, cursor, controlFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list controls", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewControlConnection(page, r, obj.ID, controlFilter), nil
|
||||
}
|
||||
|
||||
// LightLogoURL is the resolver for the lightLogoURL field.
|
||||
func (r *frameworkResolver) LightLogoURL(ctx context.Context, obj *types.Framework) (*string, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionFrameworkGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
return prb.Frameworks.GenerateLightLogoURL(ctx, obj.ID, 1*time.Hour)
|
||||
}
|
||||
|
||||
// DarkLogoURL is the resolver for the darkLogoURL field.
|
||||
func (r *frameworkResolver) DarkLogoURL(ctx context.Context, obj *types.Framework) (*string, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionFrameworkGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
return prb.Frameworks.GenerateDarkLogoURL(ctx, obj.ID, 1*time.Hour)
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *frameworkResolver) Permission(ctx context.Context, obj *types.Framework, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// TotalCount is the resolver for the totalCount field.
|
||||
func (r *frameworkConnectionResolver) TotalCount(ctx context.Context, obj *types.FrameworkConnection) (int, error) {
|
||||
if err := r.authorize(ctx, obj.ParentID, probo.ActionFrameworkList); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
switch obj.Resolver.(type) {
|
||||
case *organizationResolver:
|
||||
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
||||
|
||||
count, err := prb.Frameworks.CountForOrganizationID(ctx, obj.ParentID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count frameworks", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "unsupported resolver")
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
// CreateFramework is the resolver for the createFramework field.
|
||||
func (r *mutationResolver) CreateFramework(ctx context.Context, input types.CreateFrameworkInput) (*types.CreateFrameworkPayload, error) {
|
||||
if err := r.authorize(ctx, input.OrganizationID, probo.ActionFrameworkCreate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
||||
|
||||
framework, err := prb.Frameworks.Create(
|
||||
ctx,
|
||||
probo.CreateFrameworkRequest{
|
||||
OrganizationID: input.OrganizationID,
|
||||
Name: input.Name,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot create framework", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.CreateFrameworkPayload{
|
||||
FrameworkEdge: types.NewFrameworkEdge(framework, coredata.FrameworkOrderFieldCreatedAt),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateFramework is the resolver for the updateFramework field.
|
||||
func (r *mutationResolver) UpdateFramework(ctx context.Context, input types.UpdateFrameworkInput) (*types.UpdateFrameworkPayload, error) {
|
||||
if err := r.authorize(ctx, input.ID, probo.ActionFrameworkUpdate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.ID.TenantID())
|
||||
|
||||
framework, err := prb.Frameworks.Update(
|
||||
ctx,
|
||||
probo.UpdateFrameworkRequest{
|
||||
ID: input.ID,
|
||||
Name: input.Name,
|
||||
Description: gqlutils.UnwrapOmittable(input.Description),
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot update framework", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.UpdateFrameworkPayload{
|
||||
Framework: types.NewFramework(framework),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ImportFramework is the resolver for the importFramework field.
|
||||
func (r *mutationResolver) ImportFramework(ctx context.Context, input types.ImportFrameworkInput) (*types.ImportFrameworkPayload, error) {
|
||||
if err := r.authorize(ctx, input.OrganizationID, probo.ActionFrameworkImport); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
||||
|
||||
req := probo.ImportFrameworkRequest{}
|
||||
if err := json.NewDecoder(input.File.File).Decode(&req.Framework); err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot decode framework", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
framework, err := prb.Frameworks.Import(ctx, input.OrganizationID, req)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceAlreadyExists) {
|
||||
return nil, gqlutils.Conflict(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot import framework", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.ImportFrameworkPayload{
|
||||
FrameworkEdge: types.NewFrameworkEdge(framework, coredata.FrameworkOrderFieldCreatedAt),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteFramework is the resolver for the deleteFramework field.
|
||||
func (r *mutationResolver) DeleteFramework(ctx context.Context, input types.DeleteFrameworkInput) (*types.DeleteFrameworkPayload, error) {
|
||||
if err := r.authorize(ctx, input.FrameworkID, probo.ActionFrameworkDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.FrameworkID.TenantID())
|
||||
|
||||
err := prb.Frameworks.Delete(ctx, input.FrameworkID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot delete framework", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DeleteFrameworkPayload{
|
||||
DeletedFrameworkID: input.FrameworkID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ExportFramework is the resolver for the exportFramework field.
|
||||
func (r *mutationResolver) ExportFramework(ctx context.Context, input types.ExportFrameworkInput) (*types.ExportFrameworkPayload, error) {
|
||||
if err := r.authorize(ctx, input.FrameworkID, probo.ActionFrameworkExport); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.FrameworkID.TenantID())
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
|
||||
exportJob, exportErr := prb.Frameworks.RequestExport(
|
||||
ctx,
|
||||
input.FrameworkID,
|
||||
identity.EmailAddress,
|
||||
identity.FullName,
|
||||
)
|
||||
if exportErr != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot export framework", log.Error(exportErr))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.ExportFrameworkPayload{
|
||||
ExportJobID: exportJob.ID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Frameworks is the resolver for the frameworks field.
|
||||
func (r *organizationResolver) Frameworks(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.FrameworkOrderBy) (*types.FrameworkConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionFrameworkList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.FrameworkOrderField]{
|
||||
Field: coredata.FrameworkOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.FrameworkOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
page, err := prb.Frameworks.ListForOrganizationID(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list organization frameworks", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewFrameworkConnection(page, r, obj.ID), nil
|
||||
}
|
||||
|
||||
// Framework returns schema.FrameworkResolver implementation.
|
||||
func (r *Resolver) Framework() schema.FrameworkResolver { return &frameworkResolver{r} }
|
||||
|
||||
// FrameworkConnection returns schema.FrameworkConnectionResolver implementation.
|
||||
func (r *Resolver) FrameworkConnection() schema.FrameworkConnectionResolver {
|
||||
return &frameworkConnectionResolver{r}
|
||||
}
|
||||
|
||||
type frameworkResolver struct{ *Resolver }
|
||||
type frameworkConnectionResolver struct{ *Resolver }
|
||||
@@ -1,4 +1,5 @@
|
||||
schema: ["schema.graphql"]
|
||||
schema:
|
||||
- "graphql/*.graphql"
|
||||
|
||||
exec:
|
||||
filename: "schema/schema.go"
|
||||
@@ -12,7 +13,7 @@ resolver:
|
||||
layout: "follow-schema"
|
||||
dir: "."
|
||||
package: "console_v1"
|
||||
filename_template: "v1_resolver.go"
|
||||
filename_template: "{name}.resolvers.go"
|
||||
|
||||
autobind: []
|
||||
call_argument_directives_with_null: true
|
||||
|
||||
709
pkg/server/api/console/v1/graphql/access_review_campaign.graphql
Normal file
709
pkg/server/api/console/v1/graphql/access_review_campaign.graphql
Normal file
@@ -0,0 +1,709 @@
|
||||
extend type Organization {
|
||||
accessSources(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: AccessSourceOrder
|
||||
): AccessSourceConnection! @goField(forceResolver: true)
|
||||
|
||||
accessReviewCampaigns(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: AccessReviewCampaignOrder
|
||||
): AccessReviewCampaignConnection! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
enum AccessReviewCampaignStatus
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.AccessReviewCampaignStatus"
|
||||
) {
|
||||
DRAFT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessReviewCampaignStatusDraft"
|
||||
)
|
||||
IN_PROGRESS
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessReviewCampaignStatusInProgress"
|
||||
)
|
||||
PENDING_ACTIONS
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessReviewCampaignStatusPendingActions"
|
||||
)
|
||||
FAILED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessReviewCampaignStatusFailed"
|
||||
)
|
||||
COMPLETED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessReviewCampaignStatusCompleted"
|
||||
)
|
||||
CANCELLED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessReviewCampaignStatusCancelled"
|
||||
)
|
||||
}
|
||||
|
||||
enum AccessSourceCategory
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.AccessSourceCategory"
|
||||
) {
|
||||
SAAS
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessSourceCategorySaaS"
|
||||
)
|
||||
CLOUD_INFRA
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessSourceCategoryCloudInfra"
|
||||
)
|
||||
SOURCE_CODE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessSourceCategorySourceCode"
|
||||
)
|
||||
OTHER
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessSourceCategoryOther"
|
||||
)
|
||||
}
|
||||
|
||||
enum AccessReviewCampaignSourceFetchStatus
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.AccessReviewCampaignSourceFetchStatus"
|
||||
) {
|
||||
QUEUED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessReviewCampaignSourceFetchStatusQueued"
|
||||
)
|
||||
FETCHING
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessReviewCampaignSourceFetchStatusFetching"
|
||||
)
|
||||
SUCCESS
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessReviewCampaignSourceFetchStatusSuccess"
|
||||
)
|
||||
FAILED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessReviewCampaignSourceFetchStatusFailed"
|
||||
)
|
||||
}
|
||||
|
||||
enum AccessEntryFlag
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.AccessEntryFlag") {
|
||||
NONE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessEntryFlagNone"
|
||||
)
|
||||
ORPHANED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessEntryFlagOrphaned"
|
||||
)
|
||||
INACTIVE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessEntryFlagInactive"
|
||||
)
|
||||
EXCESSIVE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessEntryFlagExcessive"
|
||||
)
|
||||
ROLE_MISMATCH
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessEntryFlagRoleMismatch"
|
||||
)
|
||||
NEW
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessEntryFlagNew"
|
||||
)
|
||||
DORMANT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessEntryFlagDormant"
|
||||
)
|
||||
TERMINATED_USER
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessEntryFlagTerminatedUser"
|
||||
)
|
||||
CONTRACTOR_EXPIRED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessEntryFlagContractorExpired"
|
||||
)
|
||||
SOD_CONFLICT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessEntryFlagSoDConflict"
|
||||
)
|
||||
PRIVILEGED_ACCESS
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessEntryFlagPrivilegedAccess"
|
||||
)
|
||||
ROLE_CREEP
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessEntryFlagRoleCreep"
|
||||
)
|
||||
NO_BUSINESS_JUSTIFICATION
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessEntryFlagNoBusinessJustification"
|
||||
)
|
||||
OUT_OF_DEPARTMENT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessEntryFlagOutOfDepartment"
|
||||
)
|
||||
SHARED_ACCOUNT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessEntryFlagSharedAccount"
|
||||
)
|
||||
}
|
||||
|
||||
enum AccessEntryDecision
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.AccessEntryDecision"
|
||||
) {
|
||||
PENDING
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessEntryDecisionPending"
|
||||
)
|
||||
APPROVED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessEntryDecisionApproved"
|
||||
)
|
||||
REVOKE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessEntryDecisionRevoke"
|
||||
)
|
||||
DEFER
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessEntryDecisionDefer"
|
||||
)
|
||||
ESCALATE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessEntryDecisionEscalate"
|
||||
)
|
||||
}
|
||||
|
||||
enum AccessEntryIncrementalTag
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.AccessEntryIncrementalTag") {
|
||||
NEW
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessEntryIncrementalTagNew"
|
||||
)
|
||||
REMOVED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessEntryIncrementalTagRemoved"
|
||||
)
|
||||
UNCHANGED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessEntryIncrementalTagUnchanged"
|
||||
)
|
||||
}
|
||||
|
||||
enum MfaStatus
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.MFAStatus") {
|
||||
ENABLED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.MFAStatusEnabled"
|
||||
)
|
||||
DISABLED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.MFAStatusDisabled"
|
||||
)
|
||||
UNKNOWN
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.MFAStatusUnknown"
|
||||
)
|
||||
}
|
||||
|
||||
enum AccessEntryAuthMethod
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.AccessEntryAuthMethod"
|
||||
) {
|
||||
SSO
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessEntryAuthMethodSSO"
|
||||
)
|
||||
PASSWORD
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessEntryAuthMethodPassword"
|
||||
)
|
||||
API_KEY
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessEntryAuthMethodAPIKey"
|
||||
)
|
||||
SERVICE_ACCOUNT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessEntryAuthMethodServiceAccount"
|
||||
)
|
||||
UNKNOWN
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessEntryAuthMethodUnknown"
|
||||
)
|
||||
}
|
||||
|
||||
enum AccessEntryAccountType
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.AccessEntryAccountType"
|
||||
) {
|
||||
USER
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessEntryAccountTypeUser"
|
||||
)
|
||||
SERVICE_ACCOUNT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AccessEntryAccountTypeServiceAccount"
|
||||
)
|
||||
}
|
||||
|
||||
enum AccessSourceOrderField
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.AccessSourceOrderField"
|
||||
) {
|
||||
CREATED_AT
|
||||
}
|
||||
|
||||
enum AccessReviewCampaignOrderField
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.AccessReviewCampaignOrderField"
|
||||
) {
|
||||
CREATED_AT
|
||||
}
|
||||
|
||||
enum AccessEntryOrderField
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.AccessEntryOrderField"
|
||||
) {
|
||||
CREATED_AT
|
||||
}
|
||||
|
||||
enum AccessSourceConnectionStatus {
|
||||
CONNECTED
|
||||
DISCONNECTED
|
||||
NOT_APPLICABLE
|
||||
}
|
||||
|
||||
input AccessSourceOrder {
|
||||
direction: OrderDirection!
|
||||
field: AccessSourceOrderField!
|
||||
}
|
||||
|
||||
input AccessReviewCampaignOrder {
|
||||
direction: OrderDirection!
|
||||
field: AccessReviewCampaignOrderField!
|
||||
}
|
||||
|
||||
input AccessEntryOrder {
|
||||
direction: OrderDirection!
|
||||
field: AccessEntryOrderField!
|
||||
}
|
||||
|
||||
input AccessEntryFilter
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.AccessEntryFilter"
|
||||
) {
|
||||
decision: AccessEntryDecision
|
||||
flag: AccessEntryFlag
|
||||
incrementalTag: AccessEntryIncrementalTag
|
||||
isAdmin: Boolean
|
||||
authMethod: AccessEntryAuthMethod
|
||||
accountType: AccessEntryAccountType
|
||||
}
|
||||
|
||||
type AccessReview implements Node {
|
||||
id: ID!
|
||||
organization: Organization! @goField(forceResolver: true)
|
||||
identitySource: AccessSource @goField(forceResolver: true)
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
accessSources(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: AccessSourceOrder
|
||||
): AccessSourceConnection! @goField(forceResolver: true)
|
||||
|
||||
campaigns(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: AccessReviewCampaignOrder
|
||||
): AccessReviewCampaignConnection! @goField(forceResolver: true)
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type ProviderOrganization {
|
||||
slug: String!
|
||||
displayName: String!
|
||||
}
|
||||
|
||||
type AccessSource implements Node {
|
||||
id: ID!
|
||||
organization: Organization! @goField(forceResolver: true)
|
||||
connectorId: ID
|
||||
connector: Connector @goField(forceResolver: true)
|
||||
name: String!
|
||||
csvData: String
|
||||
providerOrganizations: [ProviderOrganization!]! @goField(forceResolver: true)
|
||||
needsConfiguration: Boolean! @goField(forceResolver: true)
|
||||
connectionStatus: AccessSourceConnectionStatus! @goField(forceResolver: true)
|
||||
selectedOrganization: String @goField(forceResolver: true)
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type AccessReviewCampaignScopeSource
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.AccessReviewCampaignScopeSource"
|
||||
) {
|
||||
id: ID!
|
||||
source: AccessSource!
|
||||
name: String!
|
||||
fetchStatus: AccessReviewCampaignSourceFetchStatus!
|
||||
fetchedAccountsCount: Int!
|
||||
attemptCount: Int!
|
||||
lastError: String
|
||||
fetchStartedAt: Datetime
|
||||
fetchCompletedAt: Datetime
|
||||
|
||||
entries(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: AccessEntryOrder
|
||||
filter: AccessEntryFilter
|
||||
): AccessEntryConnection! @goField(forceResolver: true)
|
||||
|
||||
statistics: AccessReviewCampaignStatistics! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type AccessReviewCampaign implements Node {
|
||||
id: ID!
|
||||
organization: Organization! @goField(forceResolver: true)
|
||||
name: String!
|
||||
description: String!
|
||||
status: AccessReviewCampaignStatus!
|
||||
startedAt: Datetime
|
||||
completedAt: Datetime
|
||||
frameworkControls: [String!]
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
scopeSources: [AccessReviewCampaignScopeSource!]! @goField(forceResolver: true)
|
||||
|
||||
entries(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: AccessEntryOrder
|
||||
accessSourceId: ID
|
||||
filter: AccessEntryFilter
|
||||
): AccessEntryConnection! @goField(forceResolver: true)
|
||||
|
||||
pendingEntryCount: Int! @goField(forceResolver: true)
|
||||
|
||||
statistics: AccessReviewCampaignStatistics! @goField(forceResolver: true)
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type AccessEntry implements Node {
|
||||
id: ID!
|
||||
campaign: AccessReviewCampaign! @goField(forceResolver: true)
|
||||
accessSource: AccessSource! @goField(forceResolver: true)
|
||||
email: String!
|
||||
fullName: String!
|
||||
role: String!
|
||||
jobTitle: String!
|
||||
isAdmin: Boolean!
|
||||
mfaStatus: MfaStatus!
|
||||
authMethod: AccessEntryAuthMethod!
|
||||
accountType: AccessEntryAccountType!
|
||||
lastLogin: Datetime
|
||||
accountCreatedAt: Datetime
|
||||
externalId: String!
|
||||
incrementalTag: AccessEntryIncrementalTag!
|
||||
flags: [AccessEntryFlag!]!
|
||||
flagReasons: [String!]!
|
||||
decision: AccessEntryDecision!
|
||||
decisionNote: String
|
||||
decidedBy: ID
|
||||
decidedAt: Datetime
|
||||
decisionHistory: [AccessEntryDecisionHistoryEntry!]!
|
||||
@goField(forceResolver: true)
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type AccessEntryDecisionHistoryEntry {
|
||||
id: ID!
|
||||
decision: AccessEntryDecision!
|
||||
decisionNote: String
|
||||
decidedBy: ID
|
||||
decidedAt: Datetime!
|
||||
createdAt: Datetime!
|
||||
}
|
||||
|
||||
type AccessSourceConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.AccessSourceConnection"
|
||||
) {
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
edges: [AccessSourceEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type AccessSourceEdge {
|
||||
cursor: CursorKey!
|
||||
node: AccessSource!
|
||||
}
|
||||
|
||||
type AccessReviewCampaignConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.AccessReviewCampaignConnection"
|
||||
) {
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
edges: [AccessReviewCampaignEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type AccessReviewCampaignEdge {
|
||||
cursor: CursorKey!
|
||||
node: AccessReviewCampaign!
|
||||
}
|
||||
|
||||
type AccessEntryConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.AccessEntryConnection"
|
||||
) {
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
edges: [AccessEntryEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type AccessEntryEdge {
|
||||
cursor: CursorKey!
|
||||
node: AccessEntry!
|
||||
}
|
||||
|
||||
type AccessReviewCampaignStatistics {
|
||||
totalCount: Int!
|
||||
decisionCounts: [AccessEntryDecisionCount!]!
|
||||
flagCounts: [AccessEntryFlagCount!]!
|
||||
incrementalTagCounts: [AccessEntryIncrementalTagCount!]!
|
||||
}
|
||||
|
||||
type AccessEntryDecisionCount {
|
||||
decision: AccessEntryDecision!
|
||||
count: Int!
|
||||
}
|
||||
|
||||
type AccessEntryFlagCount {
|
||||
flag: AccessEntryFlag!
|
||||
count: Int!
|
||||
}
|
||||
|
||||
type AccessEntryIncrementalTagCount {
|
||||
incrementalTag: AccessEntryIncrementalTag!
|
||||
count: Int!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
createAccessSource(
|
||||
input: CreateAccessSourceInput!
|
||||
): CreateAccessSourcePayload!
|
||||
updateAccessSource(
|
||||
input: UpdateAccessSourceInput!
|
||||
): UpdateAccessSourcePayload!
|
||||
deleteAccessSource(
|
||||
input: DeleteAccessSourceInput!
|
||||
): DeleteAccessSourcePayload!
|
||||
configureAccessSource(
|
||||
input: ConfigureAccessSourceInput!
|
||||
): ConfigureAccessSourcePayload!
|
||||
createAccessReviewCampaign(
|
||||
input: CreateAccessReviewCampaignInput!
|
||||
): CreateAccessReviewCampaignPayload!
|
||||
updateAccessReviewCampaign(
|
||||
input: UpdateAccessReviewCampaignInput!
|
||||
): UpdateAccessReviewCampaignPayload!
|
||||
deleteAccessReviewCampaign(
|
||||
input: DeleteAccessReviewCampaignInput!
|
||||
): DeleteAccessReviewCampaignPayload!
|
||||
startAccessReviewCampaign(
|
||||
input: StartAccessReviewCampaignInput!
|
||||
): StartAccessReviewCampaignPayload!
|
||||
closeAccessReviewCampaign(
|
||||
input: CloseAccessReviewCampaignInput!
|
||||
): CloseAccessReviewCampaignPayload!
|
||||
cancelAccessReviewCampaign(
|
||||
input: CancelAccessReviewCampaignInput!
|
||||
): CancelAccessReviewCampaignPayload!
|
||||
addAccessReviewCampaignScopeSource(
|
||||
input: AddAccessReviewCampaignScopeSourceInput!
|
||||
): AddAccessReviewCampaignScopeSourcePayload!
|
||||
removeAccessReviewCampaignScopeSource(
|
||||
input: RemoveAccessReviewCampaignScopeSourceInput!
|
||||
): RemoveAccessReviewCampaignScopeSourcePayload!
|
||||
recordAccessEntryDecision(
|
||||
input: RecordAccessEntryDecisionInput!
|
||||
): RecordAccessEntryDecisionPayload!
|
||||
recordAccessEntryDecisions(
|
||||
input: RecordAccessEntryDecisionsInput!
|
||||
): RecordAccessEntryDecisionsPayload!
|
||||
flagAccessEntry(
|
||||
input: FlagAccessEntryInput!
|
||||
): FlagAccessEntryPayload!
|
||||
}
|
||||
|
||||
input CreateAccessSourceInput {
|
||||
organizationId: ID!
|
||||
connectorId: ID
|
||||
name: String!
|
||||
csvData: String
|
||||
}
|
||||
|
||||
type CreateAccessSourcePayload {
|
||||
accessSourceEdge: AccessSourceEdge!
|
||||
}
|
||||
|
||||
input UpdateAccessSourceInput {
|
||||
accessSourceId: ID!
|
||||
name: String @goField(omittable: true)
|
||||
connectorId: ID @goField(omittable: true)
|
||||
csvData: String @goField(omittable: true)
|
||||
}
|
||||
|
||||
type UpdateAccessSourcePayload {
|
||||
accessSource: AccessSource!
|
||||
}
|
||||
|
||||
input DeleteAccessSourceInput {
|
||||
accessSourceId: ID!
|
||||
}
|
||||
|
||||
type DeleteAccessSourcePayload {
|
||||
deletedAccessSourceId: ID!
|
||||
}
|
||||
|
||||
input ConfigureAccessSourceInput {
|
||||
accessSourceId: ID!
|
||||
organizationSlug: String!
|
||||
}
|
||||
|
||||
type ConfigureAccessSourcePayload {
|
||||
accessSource: AccessSource!
|
||||
}
|
||||
|
||||
input CreateAccessReviewCampaignInput {
|
||||
organizationId: ID!
|
||||
name: String!
|
||||
description: String
|
||||
frameworkControls: [String!]
|
||||
accessSourceIds: [ID!]
|
||||
}
|
||||
|
||||
type CreateAccessReviewCampaignPayload {
|
||||
accessReviewCampaignEdge: AccessReviewCampaignEdge!
|
||||
}
|
||||
|
||||
input UpdateAccessReviewCampaignInput {
|
||||
accessReviewCampaignId: ID!
|
||||
name: String @goField(omittable: true)
|
||||
description: String @goField(omittable: true)
|
||||
frameworkControls: [String!] @goField(omittable: true)
|
||||
}
|
||||
|
||||
type UpdateAccessReviewCampaignPayload {
|
||||
accessReviewCampaign: AccessReviewCampaign!
|
||||
}
|
||||
|
||||
input DeleteAccessReviewCampaignInput {
|
||||
accessReviewCampaignId: ID!
|
||||
}
|
||||
|
||||
type DeleteAccessReviewCampaignPayload {
|
||||
deletedAccessReviewCampaignId: ID!
|
||||
}
|
||||
|
||||
input StartAccessReviewCampaignInput {
|
||||
accessReviewCampaignId: ID!
|
||||
}
|
||||
|
||||
type StartAccessReviewCampaignPayload {
|
||||
accessReviewCampaign: AccessReviewCampaign!
|
||||
}
|
||||
|
||||
input CloseAccessReviewCampaignInput {
|
||||
accessReviewCampaignId: ID!
|
||||
}
|
||||
|
||||
type CloseAccessReviewCampaignPayload {
|
||||
accessReviewCampaign: AccessReviewCampaign!
|
||||
}
|
||||
|
||||
input CancelAccessReviewCampaignInput {
|
||||
accessReviewCampaignId: ID!
|
||||
}
|
||||
|
||||
type CancelAccessReviewCampaignPayload {
|
||||
accessReviewCampaign: AccessReviewCampaign!
|
||||
}
|
||||
|
||||
input AddAccessReviewCampaignScopeSourceInput {
|
||||
accessReviewCampaignId: ID!
|
||||
accessSourceId: ID!
|
||||
}
|
||||
|
||||
type AddAccessReviewCampaignScopeSourcePayload {
|
||||
accessReviewCampaign: AccessReviewCampaign!
|
||||
}
|
||||
|
||||
input RemoveAccessReviewCampaignScopeSourceInput {
|
||||
accessReviewCampaignId: ID!
|
||||
accessSourceId: ID!
|
||||
}
|
||||
|
||||
type RemoveAccessReviewCampaignScopeSourcePayload {
|
||||
accessReviewCampaign: AccessReviewCampaign!
|
||||
}
|
||||
|
||||
input RecordAccessEntryDecisionInput {
|
||||
accessEntryId: ID!
|
||||
decision: AccessEntryDecision!
|
||||
decisionNote: String
|
||||
}
|
||||
|
||||
type RecordAccessEntryDecisionPayload {
|
||||
accessEntry: AccessEntry!
|
||||
}
|
||||
|
||||
input RecordAccessEntryDecisionsInput {
|
||||
decisions: [AccessEntryDecisionInput!]!
|
||||
}
|
||||
|
||||
input AccessEntryDecisionInput {
|
||||
accessEntryId: ID!
|
||||
decision: AccessEntryDecision!
|
||||
decisionNote: String
|
||||
}
|
||||
|
||||
type RecordAccessEntryDecisionsPayload {
|
||||
accessEntries: [AccessEntry!]!
|
||||
}
|
||||
|
||||
input FlagAccessEntryInput {
|
||||
accessEntryId: ID!
|
||||
flags: [AccessEntryFlag!]!
|
||||
flagReasons: [String!]
|
||||
}
|
||||
|
||||
type FlagAccessEntryPayload {
|
||||
accessEntry: AccessEntry!
|
||||
}
|
||||
241
pkg/server/api/console/v1/graphql/asset.graphql
Normal file
241
pkg/server/api/console/v1/graphql/asset.graphql
Normal file
@@ -0,0 +1,241 @@
|
||||
extend type Organization {
|
||||
assets(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: AssetOrder
|
||||
filter: AssetFilter = { snapshotId: null }
|
||||
): AssetConnection! @goField(forceResolver: true)
|
||||
|
||||
data(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: DatumOrder
|
||||
filter: DatumFilter = { snapshotId: null }
|
||||
): DatumConnection! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
enum AssetType @goModel(model: "go.probo.inc/probo/pkg/coredata.AssetType") {
|
||||
PHYSICAL @goEnum(value: "go.probo.inc/probo/pkg/coredata.AssetTypePhysical")
|
||||
VIRTUAL @goEnum(value: "go.probo.inc/probo/pkg/coredata.AssetTypeVirtual")
|
||||
}
|
||||
|
||||
enum AssetOrderField
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.AssetOrderField") {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AssetOrderFieldCreatedAt"
|
||||
)
|
||||
AMOUNT
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.AssetOrderFieldAmount")
|
||||
}
|
||||
|
||||
enum DatumOrderField
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.DatumOrderField") {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DatumOrderFieldCreatedAt"
|
||||
)
|
||||
NAME @goEnum(value: "go.probo.inc/probo/pkg/coredata.DatumOrderFieldName")
|
||||
DATA_CLASSIFICATION
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DatumOrderFieldDataClassification"
|
||||
)
|
||||
}
|
||||
|
||||
enum DataClassification
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.DataClassification") {
|
||||
PUBLIC
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DataClassificationPublic"
|
||||
)
|
||||
INTERNAL
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DataClassificationInternal"
|
||||
)
|
||||
CONFIDENTIAL
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DataClassificationConfidential"
|
||||
)
|
||||
SECRET
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DataClassificationSecret"
|
||||
)
|
||||
}
|
||||
|
||||
input AssetOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.AssetOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: AssetOrderField!
|
||||
}
|
||||
|
||||
input DatumOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.DatumOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: DatumOrderField!
|
||||
}
|
||||
|
||||
input AssetFilter {
|
||||
snapshotId: ID
|
||||
}
|
||||
|
||||
input DatumFilter {
|
||||
snapshotId: ID
|
||||
}
|
||||
|
||||
type Asset implements Node {
|
||||
id: ID!
|
||||
snapshotId: ID
|
||||
name: String!
|
||||
amount: Int!
|
||||
owner: Profile! @goField(forceResolver: true)
|
||||
vendors(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: VendorOrder
|
||||
): VendorConnection! @goField(forceResolver: true)
|
||||
assetType: AssetType!
|
||||
dataTypesStored: String!
|
||||
organization: Organization! @goField(forceResolver: true)
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type Datum implements Node
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.Datum"
|
||||
) {
|
||||
id: ID!
|
||||
snapshotId: ID
|
||||
name: String!
|
||||
dataClassification: DataClassification!
|
||||
owner: Profile! @goField(forceResolver: true)
|
||||
vendors(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: VendorOrder
|
||||
): VendorConnection! @goField(forceResolver: true)
|
||||
organization: Organization! @goField(forceResolver: true)
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type AssetConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.AssetConnection"
|
||||
) {
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
edges: [AssetEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type AssetEdge {
|
||||
cursor: CursorKey!
|
||||
node: Asset!
|
||||
}
|
||||
|
||||
type DatumConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.DatumConnection"
|
||||
) {
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
edges: [DatumEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type DatumEdge {
|
||||
cursor: CursorKey!
|
||||
node: Datum!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
createAsset(input: CreateAssetInput!): CreateAssetPayload!
|
||||
updateAsset(input: UpdateAssetInput!): UpdateAssetPayload!
|
||||
deleteAsset(input: DeleteAssetInput!): DeleteAssetPayload!
|
||||
createDatum(input: CreateDatumInput!): CreateDatumPayload!
|
||||
updateDatum(input: UpdateDatumInput!): UpdateDatumPayload!
|
||||
deleteDatum(input: DeleteDatumInput!): DeleteDatumPayload!
|
||||
}
|
||||
|
||||
input CreateAssetInput {
|
||||
organizationId: ID!
|
||||
name: String!
|
||||
amount: Int!
|
||||
ownerId: ID!
|
||||
assetType: AssetType!
|
||||
dataTypesStored: String!
|
||||
vendorIds: [ID!]
|
||||
}
|
||||
|
||||
input UpdateAssetInput {
|
||||
id: ID!
|
||||
name: String
|
||||
amount: Int
|
||||
ownerId: ID
|
||||
assetType: AssetType
|
||||
dataTypesStored: String
|
||||
vendorIds: [ID!]
|
||||
}
|
||||
|
||||
input DeleteAssetInput {
|
||||
assetId: ID!
|
||||
}
|
||||
|
||||
input CreateDatumInput {
|
||||
organizationId: ID!
|
||||
name: String!
|
||||
dataClassification: DataClassification!
|
||||
ownerId: ID!
|
||||
vendorIds: [ID!]
|
||||
}
|
||||
|
||||
input UpdateDatumInput {
|
||||
id: ID!
|
||||
name: String
|
||||
dataClassification: DataClassification
|
||||
ownerId: ID
|
||||
vendorIds: [ID!]
|
||||
}
|
||||
|
||||
input DeleteDatumInput {
|
||||
datumId: ID!
|
||||
}
|
||||
|
||||
type CreateAssetPayload {
|
||||
assetEdge: AssetEdge!
|
||||
}
|
||||
|
||||
type UpdateAssetPayload {
|
||||
asset: Asset!
|
||||
}
|
||||
|
||||
type DeleteAssetPayload {
|
||||
deletedAssetId: ID!
|
||||
}
|
||||
|
||||
type CreateDatumPayload {
|
||||
datumEdge: DatumEdge!
|
||||
}
|
||||
|
||||
type UpdateDatumPayload {
|
||||
datum: Datum!
|
||||
}
|
||||
|
||||
type DeleteDatumPayload {
|
||||
deletedDatumId: ID!
|
||||
}
|
||||
413
pkg/server/api/console/v1/graphql/audit.graphql
Normal file
413
pkg/server/api/console/v1/graphql/audit.graphql
Normal file
@@ -0,0 +1,413 @@
|
||||
extend type Organization {
|
||||
audits(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: AuditOrder
|
||||
): AuditConnection! @goField(forceResolver: true)
|
||||
|
||||
findings(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: FindingOrder
|
||||
filter: FindingFilter = { snapshotId: null }
|
||||
): FindingConnection @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
enum AuditState @goModel(model: "go.probo.inc/probo/pkg/coredata.AuditState") {
|
||||
NOT_STARTED
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.AuditStateNotStarted")
|
||||
IN_PROGRESS
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.AuditStateInProgress")
|
||||
COMPLETED
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.AuditStateCompleted")
|
||||
REJECTED
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.AuditStateRejected")
|
||||
OUTDATED
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.AuditStateOutdated")
|
||||
}
|
||||
|
||||
enum FindingKind
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.FindingKind") {
|
||||
MINOR_NONCONFORMITY
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingKindMinorNonconformity"
|
||||
)
|
||||
MAJOR_NONCONFORMITY
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingKindMajorNonconformity"
|
||||
)
|
||||
OBSERVATION
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingKindObservation"
|
||||
)
|
||||
EXCEPTION
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingKindException"
|
||||
)
|
||||
}
|
||||
|
||||
enum FindingStatus
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.FindingStatus") {
|
||||
OPEN
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingStatusOpen"
|
||||
)
|
||||
IN_PROGRESS
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingStatusInProgress"
|
||||
)
|
||||
CLOSED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingStatusClosed"
|
||||
)
|
||||
RISK_ACCEPTED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingStatusRiskAccepted"
|
||||
)
|
||||
MITIGATED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingStatusMitigated"
|
||||
)
|
||||
FALSE_POSITIVE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingStatusFalsePositive"
|
||||
)
|
||||
}
|
||||
|
||||
enum FindingPriority
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.FindingPriority") {
|
||||
LOW
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingPriorityLow"
|
||||
)
|
||||
MEDIUM
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingPriorityMedium"
|
||||
)
|
||||
HIGH
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingPriorityHigh"
|
||||
)
|
||||
}
|
||||
|
||||
enum AuditOrderField
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.AuditOrderField") {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AuditOrderFieldCreatedAt"
|
||||
)
|
||||
VALID_FROM
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AuditOrderFieldValidFrom"
|
||||
)
|
||||
VALID_UNTIL
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AuditOrderFieldValidUntil"
|
||||
)
|
||||
STATE @goEnum(value: "go.probo.inc/probo/pkg/coredata.AuditOrderFieldState")
|
||||
}
|
||||
|
||||
enum FindingOrderField
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.FindingOrderField") {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingOrderFieldCreatedAt"
|
||||
)
|
||||
REFERENCE_ID
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingOrderFieldReferenceId"
|
||||
)
|
||||
IDENTIFIED_ON
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingOrderFieldIdentifiedOn"
|
||||
)
|
||||
DUE_DATE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingOrderFieldDueDate"
|
||||
)
|
||||
STATUS
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingOrderFieldStatus"
|
||||
)
|
||||
PRIORITY
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingOrderFieldPriority"
|
||||
)
|
||||
KIND
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingOrderFieldKind"
|
||||
)
|
||||
}
|
||||
|
||||
input AuditOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.AuditOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: AuditOrderField!
|
||||
}
|
||||
|
||||
input FindingOrder {
|
||||
field: FindingOrderField!
|
||||
direction: OrderDirection!
|
||||
}
|
||||
|
||||
input FindingFilter {
|
||||
snapshotId: ID
|
||||
kind: FindingKind
|
||||
status: FindingStatus
|
||||
priority: FindingPriority
|
||||
ownerId: ID
|
||||
}
|
||||
|
||||
type Audit implements Node {
|
||||
id: ID!
|
||||
name: String
|
||||
organization: Organization @goField(forceResolver: true)
|
||||
framework: Framework @goField(forceResolver: true)
|
||||
validFrom: Datetime
|
||||
validUntil: Datetime
|
||||
report: Report @goField(forceResolver: true)
|
||||
reportUrl: String @goField(forceResolver: true)
|
||||
state: AuditState!
|
||||
|
||||
controls(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: ControlOrder
|
||||
filter: ControlFilter
|
||||
): ControlConnection @goField(forceResolver: true)
|
||||
|
||||
findings(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: FindingOrder
|
||||
filter: FindingFilter = { snapshotId: null }
|
||||
): FindingConnection @goField(forceResolver: true)
|
||||
|
||||
trustCenterVisibility: TrustCenterVisibility!
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type Finding implements Node {
|
||||
id: ID!
|
||||
snapshotId: ID
|
||||
organization: Organization @goField(forceResolver: true)
|
||||
kind: FindingKind!
|
||||
referenceId: String!
|
||||
description: String
|
||||
source: String
|
||||
audits(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: AuditOrder
|
||||
): AuditConnection @goField(forceResolver: true)
|
||||
identifiedOn: Datetime
|
||||
rootCause: String
|
||||
correctiveAction: String
|
||||
owner: Profile @goField(forceResolver: true)
|
||||
dueDate: Datetime
|
||||
status: FindingStatus!
|
||||
priority: FindingPriority!
|
||||
risk: Risk @goField(forceResolver: true)
|
||||
effectivenessCheck: String
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type Report implements Node {
|
||||
id: ID!
|
||||
objectKey: String!
|
||||
mimeType: String!
|
||||
filename: String!
|
||||
size: Int!
|
||||
downloadUrl: String @goField(forceResolver: true)
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
audit: Audit @goField(forceResolver: true)
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type AuditConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.AuditConnection"
|
||||
) {
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
edges: [AuditEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type AuditEdge {
|
||||
cursor: CursorKey!
|
||||
node: Audit!
|
||||
}
|
||||
|
||||
type FindingConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.FindingConnection"
|
||||
) {
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
edges: [FindingEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type FindingEdge
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.FindingEdge"
|
||||
) {
|
||||
cursor: CursorKey!
|
||||
node: Finding!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
createAudit(input: CreateAuditInput!): CreateAuditPayload
|
||||
updateAudit(input: UpdateAuditInput!): UpdateAuditPayload
|
||||
deleteAudit(input: DeleteAuditInput!): DeleteAuditPayload
|
||||
uploadAuditReport(input: UploadAuditReportInput!): UploadAuditReportPayload
|
||||
deleteAuditReport(input: DeleteAuditReportInput!): DeleteAuditReportPayload
|
||||
createFinding(input: CreateFindingInput!): CreateFindingPayload
|
||||
updateFinding(input: UpdateFindingInput!): UpdateFindingPayload
|
||||
deleteFinding(input: DeleteFindingInput!): DeleteFindingPayload
|
||||
createFindingAuditMapping(
|
||||
input: CreateFindingAuditMappingInput!
|
||||
): CreateFindingAuditMappingPayload
|
||||
deleteFindingAuditMapping(
|
||||
input: DeleteFindingAuditMappingInput!
|
||||
): DeleteFindingAuditMappingPayload
|
||||
}
|
||||
|
||||
input CreateAuditInput {
|
||||
organizationId: ID!
|
||||
frameworkId: ID!
|
||||
name: String
|
||||
validFrom: Datetime
|
||||
validUntil: Datetime
|
||||
state: AuditState
|
||||
trustCenterVisibility: TrustCenterVisibility
|
||||
file: Upload
|
||||
}
|
||||
|
||||
input UpdateAuditInput {
|
||||
id: ID!
|
||||
name: String @goField(omittable: true)
|
||||
validFrom: Datetime
|
||||
validUntil: Datetime
|
||||
state: AuditState
|
||||
trustCenterVisibility: TrustCenterVisibility
|
||||
}
|
||||
|
||||
input DeleteAuditInput {
|
||||
auditId: ID!
|
||||
}
|
||||
|
||||
input UploadAuditReportInput {
|
||||
auditId: ID!
|
||||
file: Upload!
|
||||
}
|
||||
|
||||
input DeleteAuditReportInput {
|
||||
auditId: ID!
|
||||
}
|
||||
|
||||
input CreateFindingInput {
|
||||
organizationId: ID!
|
||||
kind: FindingKind!
|
||||
description: String
|
||||
source: String
|
||||
identifiedOn: Datetime
|
||||
rootCause: String
|
||||
correctiveAction: String
|
||||
ownerId: ID
|
||||
dueDate: Datetime
|
||||
status: FindingStatus!
|
||||
priority: FindingPriority!
|
||||
riskId: ID
|
||||
effectivenessCheck: String
|
||||
}
|
||||
|
||||
input UpdateFindingInput {
|
||||
id: ID!
|
||||
description: String @goField(omittable: true)
|
||||
source: String @goField(omittable: true)
|
||||
identifiedOn: Datetime @goField(omittable: true)
|
||||
rootCause: String @goField(omittable: true)
|
||||
correctiveAction: String @goField(omittable: true)
|
||||
ownerId: ID
|
||||
dueDate: Datetime @goField(omittable: true)
|
||||
status: FindingStatus
|
||||
priority: FindingPriority
|
||||
riskId: ID @goField(omittable: true)
|
||||
effectivenessCheck: String @goField(omittable: true)
|
||||
}
|
||||
|
||||
input DeleteFindingInput {
|
||||
findingId: ID!
|
||||
}
|
||||
|
||||
input CreateFindingAuditMappingInput {
|
||||
findingId: ID!
|
||||
auditId: ID!
|
||||
referenceId: String!
|
||||
}
|
||||
|
||||
input DeleteFindingAuditMappingInput {
|
||||
findingId: ID!
|
||||
auditId: ID!
|
||||
}
|
||||
|
||||
type CreateAuditPayload {
|
||||
auditEdge: AuditEdge
|
||||
}
|
||||
|
||||
type UpdateAuditPayload {
|
||||
audit: Audit
|
||||
}
|
||||
|
||||
type DeleteAuditPayload {
|
||||
deletedAuditId: ID
|
||||
}
|
||||
|
||||
type UploadAuditReportPayload {
|
||||
audit: Audit
|
||||
}
|
||||
|
||||
type DeleteAuditReportPayload {
|
||||
audit: Audit
|
||||
}
|
||||
|
||||
type CreateFindingPayload {
|
||||
findingEdge: FindingEdge
|
||||
}
|
||||
|
||||
type UpdateFindingPayload {
|
||||
finding: Finding
|
||||
}
|
||||
|
||||
type DeleteFindingPayload {
|
||||
deletedFindingId: ID
|
||||
}
|
||||
|
||||
type CreateFindingAuditMappingPayload {
|
||||
findingEdge: FindingEdge
|
||||
auditEdge: AuditEdge
|
||||
}
|
||||
|
||||
type DeleteFindingAuditMappingPayload {
|
||||
deletedFindingId: ID
|
||||
deletedAuditId: ID
|
||||
}
|
||||
81
pkg/server/api/console/v1/graphql/audit_log.graphql
Normal file
81
pkg/server/api/console/v1/graphql/audit_log.graphql
Normal file
@@ -0,0 +1,81 @@
|
||||
extend type Organization {
|
||||
auditLogEntries(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: AuditLogEntryOrder
|
||||
filter: AuditLogEntryFilter
|
||||
): AuditLogEntryConnection! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
enum AuditLogActorType
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.AuditLogActorType"
|
||||
) {
|
||||
USER
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AuditLogActorTypeUser"
|
||||
)
|
||||
API_KEY
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AuditLogActorTypeAPIKey"
|
||||
)
|
||||
SYSTEM
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AuditLogActorTypeSystem"
|
||||
)
|
||||
}
|
||||
|
||||
enum AuditLogEntryOrderField
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.AuditLogEntryOrderField"
|
||||
) {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.AuditLogEntryOrderFieldCreatedAt"
|
||||
)
|
||||
}
|
||||
|
||||
input AuditLogEntryOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.AuditLogEntryOrderBy"
|
||||
) {
|
||||
field: AuditLogEntryOrderField!
|
||||
direction: OrderDirection!
|
||||
}
|
||||
|
||||
input AuditLogEntryFilter {
|
||||
action: String
|
||||
actorId: ID
|
||||
resourceType: String
|
||||
resourceId: ID
|
||||
}
|
||||
|
||||
type AuditLogEntry implements Node {
|
||||
id: ID!
|
||||
organization: Organization @goField(forceResolver: true)
|
||||
actorId: ID!
|
||||
actorType: AuditLogActorType!
|
||||
action: String!
|
||||
resourceType: String!
|
||||
resourceId: ID!
|
||||
metadata: String
|
||||
createdAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type AuditLogEntryConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.AuditLogEntryConnection"
|
||||
) {
|
||||
edges: [AuditLogEntryEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type AuditLogEntryEdge {
|
||||
cursor: CursorKey!
|
||||
node: AuditLogEntry!
|
||||
}
|
||||
349
pkg/server/api/console/v1/graphql/base.graphql
Normal file
349
pkg/server/api/console/v1/graphql/base.graphql
Normal file
@@ -0,0 +1,349 @@
|
||||
# Directives
|
||||
directive @goField(
|
||||
forceResolver: Boolean
|
||||
name: String
|
||||
omittable: Boolean
|
||||
) on INPUT_FIELD_DEFINITION | FIELD_DEFINITION
|
||||
|
||||
directive @goModel(
|
||||
model: String
|
||||
models: [String!]
|
||||
) on OBJECT | INPUT_OBJECT | SCALAR | ENUM | INTERFACE | UNION
|
||||
|
||||
directive @goEnum(value: String) on ENUM_VALUE
|
||||
|
||||
# Scalars
|
||||
scalar CursorKey
|
||||
scalar Datetime
|
||||
scalar Upload
|
||||
scalar Duration
|
||||
scalar BigInt
|
||||
scalar EmailAddr
|
||||
|
||||
# Interfaces
|
||||
interface Node {
|
||||
id: ID!
|
||||
}
|
||||
|
||||
# Pagination
|
||||
type PageInfo {
|
||||
hasNextPage: Boolean!
|
||||
hasPreviousPage: Boolean!
|
||||
startCursor: CursorKey
|
||||
endCursor: CursorKey
|
||||
}
|
||||
|
||||
# Enums
|
||||
enum OrderDirection
|
||||
@goModel(model: "go.probo.inc/probo/pkg/page.OrderDirection") {
|
||||
ASC @goEnum(value: "go.probo.inc/probo/pkg/page.OrderDirectionAsc")
|
||||
DESC @goEnum(value: "go.probo.inc/probo/pkg/page.OrderDirectionDesc")
|
||||
}
|
||||
|
||||
enum CountryCode
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.CountryCode") {
|
||||
AD @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeAD")
|
||||
AE @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeAE")
|
||||
AF @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeAF")
|
||||
AG @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeAG")
|
||||
AI @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeAI")
|
||||
AL @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeAL")
|
||||
AM @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeAM")
|
||||
AO @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeAO")
|
||||
AQ @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeAQ")
|
||||
AR @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeAR")
|
||||
AS @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeAS")
|
||||
AT @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeAT")
|
||||
AU @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeAU")
|
||||
AW @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeAW")
|
||||
AX @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeAX")
|
||||
AZ @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeAZ")
|
||||
BA @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeBA")
|
||||
BB @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeBB")
|
||||
BD @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeBD")
|
||||
BE @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeBE")
|
||||
BF @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeBF")
|
||||
BG @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeBG")
|
||||
BH @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeBH")
|
||||
BI @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeBI")
|
||||
BJ @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeBJ")
|
||||
BL @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeBL")
|
||||
BM @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeBM")
|
||||
BN @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeBN")
|
||||
BO @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeBO")
|
||||
BQ @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeBQ")
|
||||
BR @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeBR")
|
||||
BS @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeBS")
|
||||
BT @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeBT")
|
||||
BV @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeBV")
|
||||
BW @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeBW")
|
||||
BY @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeBY")
|
||||
BZ @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeBZ")
|
||||
CA @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeCA")
|
||||
CC @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeCC")
|
||||
CD @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeCD")
|
||||
CF @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeCF")
|
||||
CG @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeCG")
|
||||
CH @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeCH")
|
||||
CI @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeCI")
|
||||
CK @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeCK")
|
||||
CL @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeCL")
|
||||
CM @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeCM")
|
||||
CN @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeCN")
|
||||
CO @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeCO")
|
||||
CR @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeCR")
|
||||
CU @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeCU")
|
||||
CV @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeCV")
|
||||
CW @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeCW")
|
||||
CX @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeCX")
|
||||
CY @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeCY")
|
||||
CZ @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeCZ")
|
||||
DE @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeDE")
|
||||
DJ @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeDJ")
|
||||
DK @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeDK")
|
||||
DM @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeDM")
|
||||
DO @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeDO")
|
||||
DZ @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeDZ")
|
||||
EC @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeEC")
|
||||
EE @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeEE")
|
||||
EG @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeEG")
|
||||
EH @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeEH")
|
||||
ER @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeER")
|
||||
ES @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeES")
|
||||
ET @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeET")
|
||||
EU @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeEU")
|
||||
FI @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeFI")
|
||||
FJ @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeFJ")
|
||||
FK @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeFK")
|
||||
FM @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeFM")
|
||||
FO @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeFO")
|
||||
FR @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeFR")
|
||||
GA @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeGA")
|
||||
GB @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeGB")
|
||||
GD @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeGD")
|
||||
GE @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeGE")
|
||||
GF @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeGF")
|
||||
GG @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeGG")
|
||||
GH @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeGH")
|
||||
GI @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeGI")
|
||||
GL @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeGL")
|
||||
GM @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeGM")
|
||||
GN @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeGN")
|
||||
GP @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeGP")
|
||||
GQ @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeGQ")
|
||||
GR @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeGR")
|
||||
GT @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeGT")
|
||||
GU @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeGU")
|
||||
GW @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeGW")
|
||||
GY @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeGY")
|
||||
HK @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeHK")
|
||||
HM @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeHM")
|
||||
HN @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeHN")
|
||||
HR @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeHR")
|
||||
HT @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeHT")
|
||||
HU @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeHU")
|
||||
ID @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeID")
|
||||
IE @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeIE")
|
||||
IL @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeIL")
|
||||
IM @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeIM")
|
||||
IN @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeIN")
|
||||
IO @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeIO")
|
||||
IQ @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeIQ")
|
||||
IR @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeIR")
|
||||
IS @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeIS")
|
||||
IT @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeIT")
|
||||
JE @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeJE")
|
||||
JM @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeJM")
|
||||
JO @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeJO")
|
||||
JP @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeJP")
|
||||
KE @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeKE")
|
||||
KG @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeKG")
|
||||
KH @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeKH")
|
||||
KI @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeKI")
|
||||
KM @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeKM")
|
||||
KN @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeKN")
|
||||
KP @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeKP")
|
||||
KR @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeKR")
|
||||
KW @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeKW")
|
||||
KY @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeKY")
|
||||
KZ @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeKZ")
|
||||
LA @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeLA")
|
||||
LB @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeLB")
|
||||
LC @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeLC")
|
||||
LI @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeLI")
|
||||
LK @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeLK")
|
||||
LR @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeLR")
|
||||
LS @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeLS")
|
||||
LT @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeLT")
|
||||
LU @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeLU")
|
||||
LV @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeLV")
|
||||
LY @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeLY")
|
||||
MA @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeMA")
|
||||
MC @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeMC")
|
||||
MD @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeMD")
|
||||
ME @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeME")
|
||||
MF @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeMF")
|
||||
MG @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeMG")
|
||||
MH @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeMH")
|
||||
MK @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeMK")
|
||||
ML @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeML")
|
||||
MM @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeMM")
|
||||
MN @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeMN")
|
||||
MO @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeMO")
|
||||
MP @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeMP")
|
||||
MQ @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeMQ")
|
||||
MR @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeMR")
|
||||
MS @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeMS")
|
||||
MT @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeMT")
|
||||
MU @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeMU")
|
||||
MV @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeMV")
|
||||
MW @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeMW")
|
||||
MX @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeMX")
|
||||
MY @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeMY")
|
||||
MZ @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeMZ")
|
||||
NA @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeNA")
|
||||
NC @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeNC")
|
||||
NE @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeNE")
|
||||
NF @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeNF")
|
||||
NG @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeNG")
|
||||
NI @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeNI")
|
||||
NL @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeNL")
|
||||
NO @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeNO")
|
||||
NP @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeNP")
|
||||
NR @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeNR")
|
||||
NU @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeNU")
|
||||
NZ @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeNZ")
|
||||
OM @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeOM")
|
||||
PA @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodePA")
|
||||
PE @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodePE")
|
||||
PF @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodePF")
|
||||
PG @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodePG")
|
||||
PH @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodePH")
|
||||
PK @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodePK")
|
||||
PL @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodePL")
|
||||
PM @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodePM")
|
||||
PN @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodePN")
|
||||
PR @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodePR")
|
||||
PS @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodePS")
|
||||
PT @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodePT")
|
||||
PW @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodePW")
|
||||
PY @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodePY")
|
||||
QA @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeQA")
|
||||
RE @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeRE")
|
||||
RO @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeRO")
|
||||
RS @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeRS")
|
||||
RU @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeRU")
|
||||
RW @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeRW")
|
||||
SA @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeSA")
|
||||
SB @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeSB")
|
||||
SC @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeSC")
|
||||
SD @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeSD")
|
||||
SE @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeSE")
|
||||
SG @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeSG")
|
||||
SH @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeSH")
|
||||
SI @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeSI")
|
||||
SJ @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeSJ")
|
||||
SK @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeSK")
|
||||
SL @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeSL")
|
||||
SM @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeSM")
|
||||
SN @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeSN")
|
||||
SO @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeSO")
|
||||
SR @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeSR")
|
||||
SS @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeSS")
|
||||
ST @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeST")
|
||||
SV @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeSV")
|
||||
SX @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeSX")
|
||||
SY @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeSY")
|
||||
SZ @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeSZ")
|
||||
TC @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeTC")
|
||||
TD @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeTD")
|
||||
TF @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeTF")
|
||||
TG @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeTG")
|
||||
TH @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeTH")
|
||||
TJ @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeTJ")
|
||||
TK @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeTK")
|
||||
TL @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeTL")
|
||||
TM @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeTM")
|
||||
TN @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeTN")
|
||||
TO @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeTO")
|
||||
TR @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeTR")
|
||||
TT @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeTT")
|
||||
TV @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeTV")
|
||||
TW @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeTW")
|
||||
TZ @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeTZ")
|
||||
UA @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeUA")
|
||||
UG @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeUG")
|
||||
UM @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeUM")
|
||||
US @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeUS")
|
||||
UY @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeUY")
|
||||
UZ @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeUZ")
|
||||
VA @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeVA")
|
||||
VC @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeVC")
|
||||
VE @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeVE")
|
||||
VG @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeVG")
|
||||
VI @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeVI")
|
||||
VN @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeVN")
|
||||
VU @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeVU")
|
||||
WF @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeWF")
|
||||
WS @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeWS")
|
||||
YE @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeYE")
|
||||
YT @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeYT")
|
||||
ZA @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeZA")
|
||||
ZM @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeZM")
|
||||
ZW @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeZW")
|
||||
}
|
||||
|
||||
type File {
|
||||
id: ID!
|
||||
mimeType: String!
|
||||
fileName: String!
|
||||
size: BigInt!
|
||||
downloadUrl: String! @goField(forceResolver: true)
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
}
|
||||
|
||||
# Root Types
|
||||
type Query {
|
||||
node(id: ID!): Node!
|
||||
viewer: Viewer!
|
||||
}
|
||||
|
||||
type Viewer {
|
||||
id: ID!
|
||||
}
|
||||
|
||||
type Organization implements Node {
|
||||
id: ID!
|
||||
name: String!
|
||||
logoUrl: String @goField(forceResolver: true)
|
||||
horizontalLogoUrl: String @goField(forceResolver: true)
|
||||
|
||||
description: String
|
||||
websiteUrl: String
|
||||
email: String
|
||||
headquarterAddress: String
|
||||
context: OrganizationContext @goField(forceResolver: true)
|
||||
|
||||
profiles(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: ProfileOrder
|
||||
filter: ProfileFilter
|
||||
): ProfileConnection! @goField(forceResolver: true)
|
||||
|
||||
measureCategories: [String!]! @goField(forceResolver: true)
|
||||
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
updateOrganizationContext(
|
||||
input: UpdateOrganizationContextInput!
|
||||
): UpdateOrganizationContextPayload!
|
||||
}
|
||||
148
pkg/server/api/console/v1/graphql/connector.graphql
Normal file
148
pkg/server/api/console/v1/graphql/connector.graphql
Normal file
@@ -0,0 +1,148 @@
|
||||
extend type Organization {
|
||||
slackConnections(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
): SlackConnectionConnection! @goField(forceResolver: true)
|
||||
slackOAuth2Scopes: [String!]! @goField(forceResolver: true)
|
||||
connectors(filter: ConnectorFilter): [Connector!]! @goField(forceResolver: true)
|
||||
connectorProviderInfos: [ConnectorProviderInfo!]! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
enum ConnectorProvider
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.ConnectorProvider") {
|
||||
SLACK @goEnum(value: "go.probo.inc/probo/pkg/coredata.ConnectorProviderSlack")
|
||||
GOOGLE_WORKSPACE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ConnectorProviderGoogleWorkspace"
|
||||
)
|
||||
LINEAR @goEnum(value: "go.probo.inc/probo/pkg/coredata.ConnectorProviderLinear")
|
||||
ONE_PASSWORD
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ConnectorProviderOnePassword"
|
||||
)
|
||||
HUBSPOT
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.ConnectorProviderHubSpot")
|
||||
DOCUSIGN
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.ConnectorProviderDocuSign")
|
||||
NOTION @goEnum(value: "go.probo.inc/probo/pkg/coredata.ConnectorProviderNotion")
|
||||
BREX @goEnum(value: "go.probo.inc/probo/pkg/coredata.ConnectorProviderBrex")
|
||||
TALLY @goEnum(value: "go.probo.inc/probo/pkg/coredata.ConnectorProviderTally")
|
||||
CLOUDFLARE
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.ConnectorProviderCloudflare")
|
||||
OPENAI @goEnum(value: "go.probo.inc/probo/pkg/coredata.ConnectorProviderOpenAI")
|
||||
SENTRY @goEnum(value: "go.probo.inc/probo/pkg/coredata.ConnectorProviderSentry")
|
||||
SUPABASE
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.ConnectorProviderSupabase")
|
||||
GITHUB @goEnum(value: "go.probo.inc/probo/pkg/coredata.ConnectorProviderGitHub")
|
||||
INTERCOM
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.ConnectorProviderIntercom")
|
||||
RESEND @goEnum(value: "go.probo.inc/probo/pkg/coredata.ConnectorProviderResend")
|
||||
}
|
||||
|
||||
type ConnectorProviderInfo {
|
||||
provider: ConnectorProvider!
|
||||
displayName: String!
|
||||
oauthConfigured: Boolean!
|
||||
apiKeySupported: Boolean!
|
||||
clientCredentialsSupported: Boolean!
|
||||
oauth2Scopes: [String!]!
|
||||
extraSettings: [ConnectorProviderSettingInfo!]!
|
||||
}
|
||||
|
||||
type ConnectorProviderSettingInfo {
|
||||
key: String!
|
||||
label: String!
|
||||
required: Boolean!
|
||||
}
|
||||
|
||||
input ConnectorFilter {
|
||||
providers: [ConnectorProvider!]
|
||||
}
|
||||
|
||||
type Connector {
|
||||
id: ID!
|
||||
provider: ConnectorProvider!
|
||||
oauth2Scopes: [String!]! @goField(forceResolver: true)
|
||||
createdAt: Datetime!
|
||||
}
|
||||
|
||||
type SlackConnection implements Node {
|
||||
id: ID!
|
||||
channel: String
|
||||
channelId: String
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type SlackConnectionConnection {
|
||||
edges: [SlackConnectionEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type SlackConnectionEdge {
|
||||
cursor: CursorKey!
|
||||
node: SlackConnection!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
createAPIKeyConnector(
|
||||
input: CreateAPIKeyConnectorInput!
|
||||
): CreateAPIKeyConnectorPayload!
|
||||
createClientCredentialsConnector(
|
||||
input: CreateClientCredentialsConnectorInput!
|
||||
): CreateClientCredentialsConnectorPayload!
|
||||
deleteConnector(input: DeleteConnectorInput!): DeleteConnectorPayload!
|
||||
deleteSlackConnection(
|
||||
input: DeleteSlackConnectionInput!
|
||||
): DeleteSlackConnectionPayload!
|
||||
}
|
||||
|
||||
input CreateAPIKeyConnectorInput {
|
||||
organizationId: ID!
|
||||
provider: ConnectorProvider!
|
||||
apiKey: String!
|
||||
tallyOrganizationId: String
|
||||
sentryOrganizationSlug: String
|
||||
supabaseOrganizationSlug: String
|
||||
githubOrganization: String
|
||||
onePasswordScimBridgeUrl: String
|
||||
}
|
||||
|
||||
type CreateAPIKeyConnectorPayload {
|
||||
connector: Connector!
|
||||
}
|
||||
|
||||
input CreateClientCredentialsConnectorInput {
|
||||
organizationId: ID!
|
||||
provider: ConnectorProvider!
|
||||
clientId: String!
|
||||
clientSecret: String!
|
||||
tokenUrl: String!
|
||||
scope: String
|
||||
onePasswordAccountId: String
|
||||
onePasswordRegion: String
|
||||
}
|
||||
|
||||
type CreateClientCredentialsConnectorPayload {
|
||||
connector: Connector
|
||||
}
|
||||
|
||||
input DeleteConnectorInput {
|
||||
connectorId: ID!
|
||||
}
|
||||
|
||||
type DeleteConnectorPayload {
|
||||
deletedConnectorId: ID!
|
||||
}
|
||||
|
||||
input DeleteSlackConnectionInput {
|
||||
slackConnectionId: ID!
|
||||
}
|
||||
|
||||
type DeleteSlackConnectionPayload {
|
||||
deletedSlackConnectionId: ID!
|
||||
}
|
||||
506
pkg/server/api/console/v1/graphql/control.graphql
Normal file
506
pkg/server/api/console/v1/graphql/control.graphql
Normal file
@@ -0,0 +1,506 @@
|
||||
extend type Organization {
|
||||
controls(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: ControlOrder
|
||||
filter: ControlFilter
|
||||
): ControlConnection! @goField(forceResolver: true)
|
||||
|
||||
statementsOfApplicability(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: StatementOfApplicabilityOrder
|
||||
filter: StatementOfApplicabilityFilter = { snapshotId: null }
|
||||
): StatementOfApplicabilityConnection! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
enum ControlImplementationState
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.ControlImplementationState"
|
||||
) {
|
||||
IMPLEMENTED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ControlImplementationStateImplemented"
|
||||
)
|
||||
NOT_IMPLEMENTED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ControlImplementationStateNotImplemented"
|
||||
)
|
||||
}
|
||||
|
||||
enum ControlOrderField
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.ControlOrderField") {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ControlOrderFieldCreatedAt"
|
||||
)
|
||||
SECTION_TITLE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ControlOrderFieldSectionTitle"
|
||||
)
|
||||
}
|
||||
|
||||
enum ApplicabilityStatementOrderField
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.ApplicabilityStatementOrderField") {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ApplicabilityStatementOrderFieldCreatedAt"
|
||||
)
|
||||
CONTROL_SECTION_TITLE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ApplicabilityStatementOrderFieldControlSectionTitle"
|
||||
)
|
||||
}
|
||||
|
||||
enum StatementOfApplicabilityOrderField
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.StatementOfApplicabilityOrderField"
|
||||
) {
|
||||
NAME
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.StatementOfApplicabilityOrderFieldName"
|
||||
)
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.StatementOfApplicabilityOrderFieldCreatedAt"
|
||||
)
|
||||
}
|
||||
|
||||
input ControlOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.ControlOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: ControlOrderField!
|
||||
}
|
||||
|
||||
input ApplicabilityStatementOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.ApplicabilityStatementOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: ApplicabilityStatementOrderField!
|
||||
}
|
||||
|
||||
input StatementOfApplicabilityOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.StatementOfApplicabilityOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: StatementOfApplicabilityOrderField!
|
||||
}
|
||||
|
||||
input ControlFilter {
|
||||
query: String
|
||||
}
|
||||
|
||||
input StatementOfApplicabilityFilter {
|
||||
snapshotId: ID
|
||||
}
|
||||
|
||||
type Control implements Node {
|
||||
id: ID!
|
||||
organization: Organization @goField(forceResolver: true)
|
||||
sectionTitle: String!
|
||||
name: String!
|
||||
description: String
|
||||
bestPractice: Boolean!
|
||||
implemented: ControlImplementationState!
|
||||
notImplementedJustification: String
|
||||
regulatory: Boolean! @goField(forceResolver: true)
|
||||
contractual: Boolean! @goField(forceResolver: true)
|
||||
riskAssessment: Boolean! @goField(forceResolver: true)
|
||||
|
||||
framework: Framework! @goField(forceResolver: true)
|
||||
|
||||
measures(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: MeasureOrder
|
||||
filter: MeasureFilter
|
||||
): MeasureConnection! @goField(forceResolver: true)
|
||||
|
||||
documents(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: DocumentOrder
|
||||
filter: DocumentFilter
|
||||
): DocumentConnection! @goField(forceResolver: true)
|
||||
|
||||
audits(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: AuditOrder
|
||||
): AuditConnection! @goField(forceResolver: true)
|
||||
|
||||
obligations(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: ObligationOrder
|
||||
filter: ObligationFilter
|
||||
): ObligationConnection! @goField(forceResolver: true)
|
||||
|
||||
snapshots(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: SnapshotOrder
|
||||
): SnapshotConnection! @goField(forceResolver: true)
|
||||
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type ControlConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.ControlConnection"
|
||||
) {
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
edges: [ControlEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type ControlEdge {
|
||||
cursor: CursorKey!
|
||||
node: Control!
|
||||
}
|
||||
|
||||
type StatementOfApplicability implements Node {
|
||||
id: ID!
|
||||
name: String!
|
||||
sourceId: ID
|
||||
snapshotId: ID
|
||||
organization: Organization @goField(forceResolver: true)
|
||||
owner: Profile! @goField(forceResolver: true)
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
applicabilityStatements(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: ApplicabilityStatementOrder
|
||||
): ApplicabilityStatementConnection! @goField(forceResolver: true)
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type ApplicabilityStatementConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.ApplicabilityStatementConnection"
|
||||
) {
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
edges: [ApplicabilityStatementEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type ApplicabilityStatementEdge {
|
||||
cursor: CursorKey!
|
||||
node: ApplicabilityStatement!
|
||||
}
|
||||
|
||||
type ApplicabilityStatement implements Node {
|
||||
id: ID!
|
||||
statementOfApplicability: StatementOfApplicability! @goField(forceResolver: true)
|
||||
control: Control! @goField(forceResolver: true)
|
||||
applicability: Boolean!
|
||||
justification: String!
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type StatementOfApplicabilityConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.StatementOfApplicabilityConnection"
|
||||
) {
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
edges: [StatementOfApplicabilityEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type StatementOfApplicabilityEdge {
|
||||
cursor: CursorKey!
|
||||
node: StatementOfApplicability!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
createControl(input: CreateControlInput!): CreateControlPayload!
|
||||
updateControl(input: UpdateControlInput!): UpdateControlPayload!
|
||||
deleteControl(input: DeleteControlInput!): DeleteControlPayload!
|
||||
createControlMeasureMapping(
|
||||
input: CreateControlMeasureMappingInput!
|
||||
): CreateControlMeasureMappingPayload!
|
||||
createControlDocumentMapping(
|
||||
input: CreateControlDocumentMappingInput!
|
||||
): CreateControlDocumentMappingPayload!
|
||||
deleteControlMeasureMapping(
|
||||
input: DeleteControlMeasureMappingInput!
|
||||
): DeleteControlMeasureMappingPayload!
|
||||
deleteControlDocumentMapping(
|
||||
input: DeleteControlDocumentMappingInput!
|
||||
): DeleteControlDocumentMappingPayload!
|
||||
createApplicabilityStatement(
|
||||
input: CreateApplicabilityStatementInput!
|
||||
): CreateApplicabilityStatementPayload!
|
||||
updateApplicabilityStatement(
|
||||
input: UpdateApplicabilityStatementInput!
|
||||
): UpdateApplicabilityStatementPayload!
|
||||
deleteApplicabilityStatement(
|
||||
input: DeleteApplicabilityStatementInput!
|
||||
): DeleteApplicabilityStatementPayload!
|
||||
createControlAuditMapping(
|
||||
input: CreateControlAuditMappingInput!
|
||||
): CreateControlAuditMappingPayload
|
||||
deleteControlAuditMapping(
|
||||
input: DeleteControlAuditMappingInput!
|
||||
): DeleteControlAuditMappingPayload
|
||||
createControlObligationMapping(
|
||||
input: CreateControlObligationMappingInput!
|
||||
): CreateControlObligationMappingPayload!
|
||||
deleteControlObligationMapping(
|
||||
input: DeleteControlObligationMappingInput!
|
||||
): DeleteControlObligationMappingPayload!
|
||||
createControlSnapshotMapping(
|
||||
input: CreateControlSnapshotMappingInput!
|
||||
): CreateControlSnapshotMappingPayload!
|
||||
deleteControlSnapshotMapping(
|
||||
input: DeleteControlSnapshotMappingInput!
|
||||
): DeleteControlSnapshotMappingPayload!
|
||||
createStatementOfApplicability(
|
||||
input: CreateStatementOfApplicabilityInput!
|
||||
): CreateStatementOfApplicabilityPayload!
|
||||
updateStatementOfApplicability(
|
||||
input: UpdateStatementOfApplicabilityInput!
|
||||
): UpdateStatementOfApplicabilityPayload!
|
||||
deleteStatementOfApplicability(
|
||||
input: DeleteStatementOfApplicabilityInput!
|
||||
): DeleteStatementOfApplicabilityPayload!
|
||||
exportStatementOfApplicabilityPDF(
|
||||
input: ExportStatementOfApplicabilityPDFInput!
|
||||
): ExportStatementOfApplicabilityPDFPayload!
|
||||
}
|
||||
|
||||
input CreateControlInput {
|
||||
frameworkId: ID!
|
||||
sectionTitle: String!
|
||||
name: String!
|
||||
description: String
|
||||
bestPractice: Boolean!
|
||||
implemented: ControlImplementationState!
|
||||
notImplementedJustification: String
|
||||
}
|
||||
|
||||
input UpdateControlInput {
|
||||
id: ID!
|
||||
sectionTitle: String
|
||||
name: String
|
||||
description: String @goField(omittable: true)
|
||||
bestPractice: Boolean
|
||||
implemented: ControlImplementationState
|
||||
notImplementedJustification: String @goField(omittable: true)
|
||||
}
|
||||
|
||||
input DeleteControlInput {
|
||||
controlId: ID!
|
||||
}
|
||||
|
||||
input CreateControlMeasureMappingInput {
|
||||
controlId: ID!
|
||||
measureId: ID!
|
||||
}
|
||||
|
||||
input CreateControlDocumentMappingInput {
|
||||
controlId: ID!
|
||||
documentId: ID!
|
||||
}
|
||||
|
||||
input DeleteControlMeasureMappingInput {
|
||||
controlId: ID!
|
||||
measureId: ID!
|
||||
}
|
||||
|
||||
input DeleteControlDocumentMappingInput {
|
||||
controlId: ID!
|
||||
documentId: ID!
|
||||
}
|
||||
|
||||
input CreateApplicabilityStatementInput {
|
||||
statementOfApplicabilityId: ID!
|
||||
controlId: ID!
|
||||
applicability: Boolean!
|
||||
justification: String
|
||||
}
|
||||
|
||||
input UpdateApplicabilityStatementInput {
|
||||
applicabilityStatementId: ID!
|
||||
applicability: Boolean!
|
||||
justification: String
|
||||
}
|
||||
|
||||
input DeleteApplicabilityStatementInput {
|
||||
applicabilityStatementId: ID!
|
||||
}
|
||||
|
||||
input CreateControlAuditMappingInput {
|
||||
controlId: ID!
|
||||
auditId: ID!
|
||||
}
|
||||
|
||||
input DeleteControlAuditMappingInput {
|
||||
controlId: ID!
|
||||
auditId: ID!
|
||||
}
|
||||
|
||||
input CreateControlObligationMappingInput {
|
||||
controlId: ID!
|
||||
obligationId: ID!
|
||||
}
|
||||
|
||||
input DeleteControlObligationMappingInput {
|
||||
controlId: ID!
|
||||
obligationId: ID!
|
||||
}
|
||||
|
||||
input CreateControlSnapshotMappingInput {
|
||||
controlId: ID!
|
||||
snapshotId: ID!
|
||||
}
|
||||
|
||||
input DeleteControlSnapshotMappingInput {
|
||||
controlId: ID!
|
||||
snapshotId: ID!
|
||||
}
|
||||
|
||||
input CreateStatementOfApplicabilityInput {
|
||||
organizationId: ID!
|
||||
name: String!
|
||||
ownerId: ID!
|
||||
}
|
||||
|
||||
input UpdateStatementOfApplicabilityInput {
|
||||
id: ID!
|
||||
name: String
|
||||
ownerId: ID
|
||||
}
|
||||
|
||||
input ApplicabilityStatementInput {
|
||||
controlId: ID!
|
||||
applicability: Boolean!
|
||||
justification: String
|
||||
}
|
||||
|
||||
input DeleteStatementOfApplicabilityInput {
|
||||
statementOfApplicabilityId: ID!
|
||||
}
|
||||
|
||||
input ExportStatementOfApplicabilityPDFInput {
|
||||
statementOfApplicabilityId: ID!
|
||||
}
|
||||
|
||||
type CreateControlPayload {
|
||||
controlEdge: ControlEdge!
|
||||
}
|
||||
|
||||
type UpdateControlPayload {
|
||||
control: Control!
|
||||
}
|
||||
|
||||
type DeleteControlPayload {
|
||||
deletedControlId: ID!
|
||||
}
|
||||
|
||||
type CreateControlMeasureMappingPayload {
|
||||
controlEdge: ControlEdge!
|
||||
measureEdge: MeasureEdge!
|
||||
}
|
||||
|
||||
type CreateControlDocumentMappingPayload {
|
||||
controlEdge: ControlEdge!
|
||||
documentEdge: DocumentEdge!
|
||||
}
|
||||
|
||||
type DeleteControlMeasureMappingPayload {
|
||||
deletedControlId: ID!
|
||||
deletedMeasureId: ID!
|
||||
}
|
||||
|
||||
type DeleteControlDocumentMappingPayload {
|
||||
deletedControlId: ID!
|
||||
deletedDocumentId: ID!
|
||||
}
|
||||
|
||||
type CreateApplicabilityStatementPayload {
|
||||
applicabilityStatementEdge: ApplicabilityStatementEdge!
|
||||
}
|
||||
|
||||
type UpdateApplicabilityStatementPayload {
|
||||
applicabilityStatement: ApplicabilityStatement!
|
||||
}
|
||||
|
||||
type DeleteApplicabilityStatementPayload {
|
||||
deletedApplicabilityStatementId: ID!
|
||||
}
|
||||
|
||||
type CreateControlAuditMappingPayload {
|
||||
controlEdge: ControlEdge
|
||||
auditEdge: AuditEdge
|
||||
}
|
||||
|
||||
type DeleteControlAuditMappingPayload {
|
||||
deletedControlId: ID
|
||||
deletedAuditId: ID
|
||||
}
|
||||
|
||||
type CreateControlObligationMappingPayload {
|
||||
controlEdge: ControlEdge!
|
||||
obligationEdge: ObligationEdge!
|
||||
}
|
||||
|
||||
type DeleteControlObligationMappingPayload {
|
||||
deletedControlId: ID!
|
||||
deletedObligationId: ID!
|
||||
}
|
||||
|
||||
type CreateControlSnapshotMappingPayload {
|
||||
controlEdge: ControlEdge!
|
||||
snapshotEdge: SnapshotEdge!
|
||||
}
|
||||
|
||||
type DeleteControlSnapshotMappingPayload {
|
||||
deletedControlId: ID!
|
||||
deletedSnapshotId: ID!
|
||||
}
|
||||
|
||||
type CreateStatementOfApplicabilityPayload {
|
||||
statementOfApplicabilityEdge: StatementOfApplicabilityEdge!
|
||||
}
|
||||
|
||||
type UpdateStatementOfApplicabilityPayload {
|
||||
statementOfApplicability: StatementOfApplicability!
|
||||
}
|
||||
|
||||
type DeleteStatementOfApplicabilityPayload {
|
||||
deletedStatementOfApplicabilityId: ID!
|
||||
}
|
||||
|
||||
type ExportStatementOfApplicabilityPDFPayload {
|
||||
data: String!
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
extend type Organization {
|
||||
dataProtectionImpactAssessments(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: DataProtectionImpactAssessmentOrder
|
||||
filter: DataProtectionImpactAssessmentFilter = { snapshotId: null }
|
||||
): DataProtectionImpactAssessmentConnection! @goField(forceResolver: true)
|
||||
|
||||
transferImpactAssessments(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: TransferImpactAssessmentOrder
|
||||
filter: TransferImpactAssessmentFilter = { snapshotId: null }
|
||||
): TransferImpactAssessmentConnection! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
enum DataProtectionImpactAssessmentResidualRisk
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.DataProtectionImpactAssessmentResidualRisk"
|
||||
) {
|
||||
LOW
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DataProtectionImpactAssessmentResidualRiskLow"
|
||||
)
|
||||
MEDIUM
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DataProtectionImpactAssessmentResidualRiskMedium"
|
||||
)
|
||||
HIGH
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DataProtectionImpactAssessmentResidualRiskHigh"
|
||||
)
|
||||
}
|
||||
|
||||
enum DataProtectionImpactAssessmentOrderField
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.DataProtectionImpactAssessmentOrderField"
|
||||
) {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DataProtectionImpactAssessmentOrderFieldCreatedAt"
|
||||
)
|
||||
}
|
||||
|
||||
enum TransferImpactAssessmentOrderField
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.TransferImpactAssessmentOrderField"
|
||||
) {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.TransferImpactAssessmentOrderFieldCreatedAt"
|
||||
)
|
||||
}
|
||||
|
||||
input DataProtectionImpactAssessmentOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.DataProtectionImpactAssessmentOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: DataProtectionImpactAssessmentOrderField!
|
||||
}
|
||||
|
||||
input TransferImpactAssessmentOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.TransferImpactAssessmentOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: TransferImpactAssessmentOrderField!
|
||||
}
|
||||
|
||||
input DataProtectionImpactAssessmentFilter {
|
||||
snapshotId: ID
|
||||
}
|
||||
|
||||
input TransferImpactAssessmentFilter {
|
||||
snapshotId: ID
|
||||
}
|
||||
|
||||
type DataProtectionImpactAssessment implements Node {
|
||||
id: ID!
|
||||
processingActivity: ProcessingActivity! @goField(forceResolver: true)
|
||||
organization: Organization! @goField(forceResolver: true)
|
||||
description: String
|
||||
necessityAndProportionality: String
|
||||
potentialRisk: String
|
||||
mitigations: String
|
||||
residualRisk: DataProtectionImpactAssessmentResidualRisk
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type TransferImpactAssessment implements Node {
|
||||
id: ID!
|
||||
processingActivity: ProcessingActivity! @goField(forceResolver: true)
|
||||
organization: Organization! @goField(forceResolver: true)
|
||||
dataSubjects: String
|
||||
legalMechanism: String
|
||||
transfer: String
|
||||
localLawRisk: String
|
||||
supplementaryMeasures: String
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type DataProtectionImpactAssessmentConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.DataProtectionImpactAssessmentConnection"
|
||||
) {
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
edges: [DataProtectionImpactAssessmentEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type DataProtectionImpactAssessmentEdge {
|
||||
cursor: CursorKey!
|
||||
node: DataProtectionImpactAssessment!
|
||||
}
|
||||
|
||||
type TransferImpactAssessmentConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.TransferImpactAssessmentConnection"
|
||||
) {
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
edges: [TransferImpactAssessmentEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type TransferImpactAssessmentEdge {
|
||||
cursor: CursorKey!
|
||||
node: TransferImpactAssessment!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
createDataProtectionImpactAssessment(
|
||||
input: CreateDataProtectionImpactAssessmentInput!
|
||||
): CreateDataProtectionImpactAssessmentPayload!
|
||||
updateDataProtectionImpactAssessment(
|
||||
input: UpdateDataProtectionImpactAssessmentInput!
|
||||
): UpdateDataProtectionImpactAssessmentPayload!
|
||||
deleteDataProtectionImpactAssessment(
|
||||
input: DeleteDataProtectionImpactAssessmentInput!
|
||||
): DeleteDataProtectionImpactAssessmentPayload!
|
||||
createTransferImpactAssessment(
|
||||
input: CreateTransferImpactAssessmentInput!
|
||||
): CreateTransferImpactAssessmentPayload!
|
||||
updateTransferImpactAssessment(
|
||||
input: UpdateTransferImpactAssessmentInput!
|
||||
): UpdateTransferImpactAssessmentPayload!
|
||||
deleteTransferImpactAssessment(
|
||||
input: DeleteTransferImpactAssessmentInput!
|
||||
): DeleteTransferImpactAssessmentPayload!
|
||||
exportDataProtectionImpactAssessmentsPDF(
|
||||
input: ExportDataProtectionImpactAssessmentsPDFInput!
|
||||
): ExportDataProtectionImpactAssessmentsPDFPayload!
|
||||
exportTransferImpactAssessmentsPDF(
|
||||
input: ExportTransferImpactAssessmentsPDFInput!
|
||||
): ExportTransferImpactAssessmentsPDFPayload!
|
||||
}
|
||||
|
||||
input CreateDataProtectionImpactAssessmentInput {
|
||||
processingActivityId: ID!
|
||||
description: String
|
||||
necessityAndProportionality: String
|
||||
potentialRisk: String
|
||||
mitigations: String
|
||||
residualRisk: DataProtectionImpactAssessmentResidualRisk
|
||||
}
|
||||
|
||||
input UpdateDataProtectionImpactAssessmentInput {
|
||||
id: ID!
|
||||
description: String @goField(omittable: true)
|
||||
necessityAndProportionality: String @goField(omittable: true)
|
||||
potentialRisk: String @goField(omittable: true)
|
||||
mitigations: String @goField(omittable: true)
|
||||
residualRisk: DataProtectionImpactAssessmentResidualRisk
|
||||
}
|
||||
|
||||
input DeleteDataProtectionImpactAssessmentInput {
|
||||
dataProtectionImpactAssessmentId: ID!
|
||||
}
|
||||
|
||||
input CreateTransferImpactAssessmentInput {
|
||||
processingActivityId: ID!
|
||||
dataSubjects: String
|
||||
legalMechanism: String
|
||||
transfer: String
|
||||
localLawRisk: String
|
||||
supplementaryMeasures: String
|
||||
}
|
||||
|
||||
input UpdateTransferImpactAssessmentInput {
|
||||
id: ID!
|
||||
dataSubjects: String @goField(omittable: true)
|
||||
legalMechanism: String @goField(omittable: true)
|
||||
transfer: String @goField(omittable: true)
|
||||
localLawRisk: String @goField(omittable: true)
|
||||
supplementaryMeasures: String @goField(omittable: true)
|
||||
}
|
||||
|
||||
input DeleteTransferImpactAssessmentInput {
|
||||
transferImpactAssessmentId: ID!
|
||||
}
|
||||
|
||||
input ExportDataProtectionImpactAssessmentsPDFInput {
|
||||
organizationId: ID!
|
||||
filter: DataProtectionImpactAssessmentFilter
|
||||
}
|
||||
|
||||
input ExportTransferImpactAssessmentsPDFInput {
|
||||
organizationId: ID!
|
||||
filter: TransferImpactAssessmentFilter
|
||||
}
|
||||
|
||||
type CreateDataProtectionImpactAssessmentPayload {
|
||||
dataProtectionImpactAssessment: DataProtectionImpactAssessment!
|
||||
}
|
||||
|
||||
type UpdateDataProtectionImpactAssessmentPayload {
|
||||
dataProtectionImpactAssessment: DataProtectionImpactAssessment!
|
||||
}
|
||||
|
||||
type DeleteDataProtectionImpactAssessmentPayload {
|
||||
deletedDataProtectionImpactAssessmentId: ID!
|
||||
}
|
||||
|
||||
type CreateTransferImpactAssessmentPayload {
|
||||
transferImpactAssessment: TransferImpactAssessment!
|
||||
}
|
||||
|
||||
type UpdateTransferImpactAssessmentPayload {
|
||||
transferImpactAssessment: TransferImpactAssessment!
|
||||
}
|
||||
|
||||
type DeleteTransferImpactAssessmentPayload {
|
||||
deletedTransferImpactAssessmentId: ID!
|
||||
}
|
||||
|
||||
type ExportDataProtectionImpactAssessmentsPDFPayload {
|
||||
data: String!
|
||||
}
|
||||
|
||||
type ExportTransferImpactAssessmentsPDFPayload {
|
||||
data: String!
|
||||
}
|
||||
826
pkg/server/api/console/v1/graphql/document.graphql
Normal file
826
pkg/server/api/console/v1/graphql/document.graphql
Normal file
@@ -0,0 +1,826 @@
|
||||
extend type Organization {
|
||||
documents(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: DocumentOrder
|
||||
filter: DocumentFilter
|
||||
): DocumentConnection! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
extend type Viewer {
|
||||
signableDocuments(
|
||||
organizationId: ID!
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: DocumentOrder
|
||||
): EmployeeDocumentConnection! @goField(forceResolver: true)
|
||||
|
||||
signableDocument(id: ID!): EmployeeDocument @goField(forceResolver: true)
|
||||
|
||||
approvableDocuments(
|
||||
organizationId: ID!
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: DocumentOrder
|
||||
): EmployeeDocumentConnection! @goField(forceResolver: true)
|
||||
|
||||
approvableDocument(id: ID!): EmployeeDocument @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
enum DocumentVersionStatus
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.DocumentVersionStatus") {
|
||||
DRAFT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DocumentVersionStatusDraft"
|
||||
)
|
||||
PENDING_APPROVAL
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DocumentVersionStatusPendingApproval"
|
||||
)
|
||||
PUBLISHED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DocumentVersionStatusPublished"
|
||||
)
|
||||
}
|
||||
|
||||
enum DocumentStatus
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.DocumentStatus") {
|
||||
ACTIVE
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.DocumentStatusActive")
|
||||
ARCHIVED
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.DocumentStatusArchived")
|
||||
}
|
||||
|
||||
enum DocumentType
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.DocumentType") {
|
||||
OTHER @goEnum(value: "go.probo.inc/probo/pkg/coredata.DocumentTypeOther")
|
||||
GOVERNANCE
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.DocumentTypeGovernance")
|
||||
POLICY @goEnum(value: "go.probo.inc/probo/pkg/coredata.DocumentTypePolicy")
|
||||
PROCEDURE
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.DocumentTypeProcedure")
|
||||
PLAN @goEnum(value: "go.probo.inc/probo/pkg/coredata.DocumentTypePlan")
|
||||
REGISTER
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.DocumentTypeRegister")
|
||||
RECORD @goEnum(value: "go.probo.inc/probo/pkg/coredata.DocumentTypeRecord")
|
||||
REPORT @goEnum(value: "go.probo.inc/probo/pkg/coredata.DocumentTypeReport")
|
||||
TEMPLATE
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.DocumentTypeTemplate")
|
||||
}
|
||||
|
||||
enum DocumentClassification
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.DocumentClassification") {
|
||||
PUBLIC
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DocumentClassificationPublic"
|
||||
)
|
||||
INTERNAL
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DocumentClassificationInternal"
|
||||
)
|
||||
CONFIDENTIAL
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DocumentClassificationConfidential"
|
||||
)
|
||||
SECRET
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DocumentClassificationSecret"
|
||||
)
|
||||
}
|
||||
|
||||
enum DocumentOrderField
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.DocumentOrderField") {
|
||||
TITLE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DocumentOrderFieldTitle"
|
||||
)
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DocumentOrderFieldCreatedAt"
|
||||
)
|
||||
UPDATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DocumentOrderFieldUpdatedAt"
|
||||
)
|
||||
DOCUMENT_TYPE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DocumentOrderFieldDocumentType"
|
||||
)
|
||||
}
|
||||
|
||||
enum DocumentVersionOrderField
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.DocumentVersionOrderField"
|
||||
) {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DocumentVersionOrderFieldCreatedAt"
|
||||
)
|
||||
}
|
||||
|
||||
enum DocumentVersionSignatureState
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.DocumentVersionSignatureState"
|
||||
) {
|
||||
REQUESTED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DocumentVersionSignatureStateRequested"
|
||||
)
|
||||
SIGNED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DocumentVersionSignatureStateSigned"
|
||||
)
|
||||
}
|
||||
|
||||
enum DocumentVersionSignatureOrderField
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.DocumentVersionSignatureOrderField"
|
||||
) {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DocumentVersionSignatureOrderFieldCreatedAt"
|
||||
)
|
||||
SIGNED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DocumentVersionSignatureOrderFieldSignedAt"
|
||||
)
|
||||
}
|
||||
|
||||
enum DocumentVersionApprovalDecisionState
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.DocumentVersionApprovalDecisionState"
|
||||
) {
|
||||
PENDING
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DocumentVersionApprovalDecisionStatePending"
|
||||
)
|
||||
APPROVED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DocumentVersionApprovalDecisionStateApproved"
|
||||
)
|
||||
REJECTED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DocumentVersionApprovalDecisionStateRejected"
|
||||
)
|
||||
VOIDED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DocumentVersionApprovalDecisionStateVoided"
|
||||
)
|
||||
}
|
||||
|
||||
enum DocumentVersionApprovalDecisionOrderField
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.DocumentVersionApprovalDecisionOrderField"
|
||||
) {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DocumentVersionApprovalDecisionOrderFieldCreatedAt"
|
||||
)
|
||||
}
|
||||
|
||||
enum DocumentVersionApprovalQuorumStatus
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.DocumentVersionApprovalQuorumStatus"
|
||||
) {
|
||||
PENDING
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DocumentVersionApprovalQuorumStatusPending"
|
||||
)
|
||||
APPROVED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DocumentVersionApprovalQuorumStatusApproved"
|
||||
)
|
||||
REJECTED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DocumentVersionApprovalQuorumStatusRejected"
|
||||
)
|
||||
VOIDED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DocumentVersionApprovalQuorumStatusVoided"
|
||||
)
|
||||
}
|
||||
|
||||
enum DocumentVersionApprovalQuorumOrderField
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.DocumentVersionApprovalQuorumOrderField"
|
||||
) {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DocumentVersionApprovalQuorumOrderFieldCreatedAt"
|
||||
)
|
||||
}
|
||||
|
||||
input DocumentOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.DocumentOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: DocumentOrderField!
|
||||
}
|
||||
|
||||
input DocumentVersionOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.DocumentVersionOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: DocumentVersionOrderField!
|
||||
}
|
||||
|
||||
input DocumentFilter {
|
||||
query: String
|
||||
documentTypes: [DocumentType!]
|
||||
classifications: [DocumentClassification!]
|
||||
status: [DocumentStatus!]
|
||||
}
|
||||
|
||||
input DocumentVersionFilter {
|
||||
statuses: [DocumentVersionStatus!]
|
||||
}
|
||||
|
||||
input DocumentVersionSignatureOrder {
|
||||
field: DocumentVersionSignatureOrderField!
|
||||
direction: OrderDirection!
|
||||
}
|
||||
|
||||
input DocumentVersionSignatureFilter {
|
||||
states: [DocumentVersionSignatureState!]
|
||||
activeContract: Boolean
|
||||
}
|
||||
|
||||
input DocumentVersionApprovalQuorumOrder {
|
||||
field: DocumentVersionApprovalQuorumOrderField!
|
||||
direction: OrderDirection!
|
||||
}
|
||||
|
||||
input DocumentVersionApprovalDecisionFilter {
|
||||
states: [DocumentVersionApprovalDecisionState!]
|
||||
}
|
||||
|
||||
input DocumentVersionApprovalDecisionOrder {
|
||||
field: DocumentVersionApprovalDecisionOrderField!
|
||||
direction: OrderDirection!
|
||||
}
|
||||
|
||||
type Document implements Node {
|
||||
id: ID!
|
||||
currentPublishedMajor: Int
|
||||
currentPublishedMinor: Int
|
||||
trustCenterVisibility: TrustCenterVisibility!
|
||||
organization: Organization! @goField(forceResolver: true)
|
||||
|
||||
versions(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: DocumentVersionOrder
|
||||
filter: DocumentVersionFilter
|
||||
): DocumentVersionConnection! @goField(forceResolver: true)
|
||||
|
||||
controls(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: ControlOrder
|
||||
filter: ControlFilter
|
||||
): ControlConnection! @goField(forceResolver: true)
|
||||
|
||||
defaultApprovers: [Profile!]! @goField(forceResolver: true)
|
||||
|
||||
status: DocumentStatus!
|
||||
archivedAt: Datetime
|
||||
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type DocumentVersion implements Node {
|
||||
id: ID!
|
||||
document: Document! @goField(forceResolver: true)
|
||||
status: DocumentVersionStatus!
|
||||
major: Int!
|
||||
minor: Int!
|
||||
content: String!
|
||||
changelog: String!
|
||||
title: String!
|
||||
classification: DocumentClassification!
|
||||
documentType: DocumentType!
|
||||
approvers(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: ProfileOrder
|
||||
): ProfileConnection! @goField(forceResolver: true)
|
||||
|
||||
signatures(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: DocumentVersionSignatureOrder
|
||||
filter: DocumentVersionSignatureFilter
|
||||
): DocumentVersionSignatureConnection! @goField(forceResolver: true)
|
||||
|
||||
approvalQuorums(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: DocumentVersionApprovalQuorumOrder
|
||||
): DocumentVersionApprovalQuorumConnection! @goField(forceResolver: true)
|
||||
|
||||
signed: Boolean! @goField(forceResolver: true)
|
||||
|
||||
publishedAt: Datetime
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type DocumentVersionSignature implements Node {
|
||||
id: ID!
|
||||
documentVersion: DocumentVersion! @goField(forceResolver: true)
|
||||
state: DocumentVersionSignatureState!
|
||||
signedBy: Profile! @goField(forceResolver: true)
|
||||
signedAt: Datetime
|
||||
requestedAt: Datetime!
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type DocumentVersionApprovalDecision implements Node {
|
||||
id: ID!
|
||||
quorum: DocumentVersionApprovalQuorum! @goField(forceResolver: true)
|
||||
documentVersion: DocumentVersion! @goField(forceResolver: true)
|
||||
approver: Profile! @goField(forceResolver: true)
|
||||
state: DocumentVersionApprovalDecisionState!
|
||||
comment: String
|
||||
decidedAt: Datetime
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type DocumentVersionApprovalQuorum implements Node {
|
||||
id: ID!
|
||||
documentVersion: DocumentVersion! @goField(forceResolver: true)
|
||||
status: DocumentVersionApprovalQuorumStatus!
|
||||
decisions(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: DocumentVersionApprovalDecisionOrder
|
||||
filter: DocumentVersionApprovalDecisionFilter
|
||||
): DocumentVersionApprovalDecisionConnection! @goField(forceResolver: true)
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type EmployeeDocument
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.EmployeeDocument"
|
||||
) {
|
||||
id: ID!
|
||||
title: String!
|
||||
signed: Boolean @goField(forceResolver: true)
|
||||
approvalState: DocumentVersionApprovalDecisionState @goField(forceResolver: true)
|
||||
|
||||
versions(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: DocumentVersionOrder
|
||||
): EmployeeDocumentVersionConnection! @goField(forceResolver: true)
|
||||
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
}
|
||||
|
||||
type EmployeeDocumentVersion
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.EmployeeDocumentVersion"
|
||||
) {
|
||||
id: ID!
|
||||
major: Int!
|
||||
minor: Int!
|
||||
status: DocumentVersionStatus!
|
||||
classification: DocumentClassification!
|
||||
documentType: DocumentType!
|
||||
signed: Boolean! @goField(forceResolver: true)
|
||||
approvalDecision: DocumentVersionApprovalDecision @goField(forceResolver: true)
|
||||
publishedAt: Datetime
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
}
|
||||
|
||||
type DocumentConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.DocumentConnection"
|
||||
) {
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
edges: [DocumentEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type DocumentEdge {
|
||||
cursor: CursorKey!
|
||||
node: Document!
|
||||
}
|
||||
|
||||
type DocumentVersionConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.DocumentVersionConnection"
|
||||
) {
|
||||
edges: [DocumentVersionEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type DocumentVersionEdge {
|
||||
cursor: CursorKey!
|
||||
node: DocumentVersion!
|
||||
}
|
||||
|
||||
type DocumentVersionSignatureConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.DocumentVersionSignatureConnection"
|
||||
) {
|
||||
edges: [DocumentVersionSignatureEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type DocumentVersionSignatureEdge {
|
||||
cursor: CursorKey!
|
||||
node: DocumentVersionSignature!
|
||||
}
|
||||
|
||||
type DocumentVersionApprovalQuorumConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.DocumentVersionApprovalQuorumConnection"
|
||||
) {
|
||||
edges: [DocumentVersionApprovalQuorumEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type DocumentVersionApprovalQuorumEdge {
|
||||
cursor: CursorKey!
|
||||
node: DocumentVersionApprovalQuorum!
|
||||
}
|
||||
|
||||
type DocumentVersionApprovalDecisionConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.DocumentVersionApprovalDecisionConnection"
|
||||
) {
|
||||
edges: [DocumentVersionApprovalDecisionEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type DocumentVersionApprovalDecisionEdge {
|
||||
cursor: CursorKey!
|
||||
node: DocumentVersionApprovalDecision!
|
||||
}
|
||||
|
||||
type EmployeeDocumentConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.EmployeeDocumentConnection"
|
||||
) {
|
||||
edges: [EmployeeDocumentEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type EmployeeDocumentEdge
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.EmployeeDocumentEdge"
|
||||
) {
|
||||
cursor: CursorKey!
|
||||
node: EmployeeDocument!
|
||||
}
|
||||
|
||||
type EmployeeDocumentVersionConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.EmployeeDocumentVersionConnection"
|
||||
) {
|
||||
edges: [EmployeeDocumentVersionEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type EmployeeDocumentVersionEdge
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.EmployeeDocumentVersionEdge"
|
||||
) {
|
||||
cursor: CursorKey!
|
||||
node: EmployeeDocumentVersion!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
createDocument(input: CreateDocumentInput!): CreateDocumentPayload!
|
||||
updateDocument(input: UpdateDocumentInput!): UpdateDocumentPayload!
|
||||
deleteDocumentDraft(input: DeleteDocumentDraftInput!): DeleteDocumentDraftPayload!
|
||||
archiveDocument(input: ArchiveDocumentInput!): ArchiveDocumentPayload!
|
||||
unarchiveDocument(input: UnarchiveDocumentInput!): UnarchiveDocumentPayload!
|
||||
deleteDocument(input: DeleteDocumentInput!): DeleteDocumentPayload!
|
||||
publishMajorDocumentVersion(
|
||||
input: PublishMajorDocumentVersionInput!
|
||||
): PublishDocumentVersionPayload!
|
||||
publishMinorDocumentVersion(
|
||||
input: PublishMinorDocumentVersionInput!
|
||||
): PublishDocumentVersionPayload!
|
||||
bulkPublishMajorDocumentVersions(
|
||||
input: BulkPublishDocumentVersionsInput!
|
||||
): BulkPublishDocumentVersionsPayload!
|
||||
bulkPublishMinorDocumentVersions(
|
||||
input: BulkPublishDocumentVersionsInput!
|
||||
): BulkPublishDocumentVersionsPayload!
|
||||
requestDocumentVersionApproval(
|
||||
input: RequestDocumentVersionApprovalInput!
|
||||
): RequestDocumentVersionApprovalPayload!
|
||||
voidDocumentVersionApproval(
|
||||
input: VoidDocumentVersionApprovalInput!
|
||||
): VoidDocumentVersionApprovalPayload!
|
||||
bulkDeleteDocuments(
|
||||
input: BulkDeleteDocumentsInput!
|
||||
): BulkDeleteDocumentsPayload!
|
||||
bulkArchiveDocuments(
|
||||
input: BulkArchiveDocumentsInput!
|
||||
): BulkArchiveDocumentsPayload!
|
||||
bulkUnarchiveDocuments(
|
||||
input: BulkUnarchiveDocumentsInput!
|
||||
): BulkUnarchiveDocumentsPayload!
|
||||
bulkExportDocuments(
|
||||
input: BulkExportDocumentsInput!
|
||||
): BulkExportDocumentsPayload!
|
||||
generateDocumentChangelog(
|
||||
input: GenerateDocumentChangelogInput!
|
||||
): GenerateDocumentChangelogPayload!
|
||||
requestSignature(input: RequestSignatureInput!): RequestSignaturePayload!
|
||||
bulkRequestSignatures(
|
||||
input: BulkRequestSignaturesInput!
|
||||
): BulkRequestSignaturesPayload!
|
||||
sendSigningNotifications(
|
||||
input: SendSigningNotificationsInput!
|
||||
): SendSigningNotificationsPayload!
|
||||
cancelSignatureRequest(
|
||||
input: CancelSignatureRequestInput!
|
||||
): CancelSignatureRequestPayload!
|
||||
signDocument(input: SignDocumentInput!): SignDocumentPayload!
|
||||
approveDocumentVersion(
|
||||
input: ApproveDocumentVersionInput!
|
||||
): ApproveDocumentVersionPayload!
|
||||
rejectDocumentVersion(
|
||||
input: RejectDocumentVersionInput!
|
||||
): RejectDocumentVersionPayload!
|
||||
exportDocumentVersionPDF(
|
||||
input: ExportDocumentVersionPDFInput!
|
||||
): ExportDocumentVersionPDFPayload!
|
||||
exportEmployeeDocumentVersionPDF(
|
||||
input: ExportEmployeeDocumentVersionPDFInput!
|
||||
): ExportEmployeeDocumentVersionPDFPayload!
|
||||
}
|
||||
|
||||
input CreateDocumentInput {
|
||||
organizationId: ID!
|
||||
title: String!
|
||||
content: String
|
||||
documentType: DocumentType!
|
||||
classification: DocumentClassification!
|
||||
trustCenterVisibility: TrustCenterVisibility
|
||||
defaultApproverIds: [ID!]
|
||||
}
|
||||
|
||||
input UpdateDocumentInput {
|
||||
id: ID!
|
||||
title: String
|
||||
content: String
|
||||
classification: DocumentClassification
|
||||
documentType: DocumentType
|
||||
trustCenterVisibility: TrustCenterVisibility
|
||||
defaultApproverIds: [ID!]
|
||||
}
|
||||
|
||||
input DeleteDocumentDraftInput {
|
||||
documentId: ID!
|
||||
}
|
||||
|
||||
input ArchiveDocumentInput {
|
||||
documentId: ID!
|
||||
}
|
||||
|
||||
input UnarchiveDocumentInput {
|
||||
documentId: ID!
|
||||
}
|
||||
|
||||
input DeleteDocumentInput {
|
||||
documentId: ID!
|
||||
}
|
||||
|
||||
input ExportDocumentVersionPDFInput {
|
||||
documentVersionId: ID!
|
||||
withWatermark: Boolean!
|
||||
watermarkEmail: EmailAddr
|
||||
withSignatures: Boolean!
|
||||
}
|
||||
|
||||
input ExportEmployeeDocumentVersionPDFInput {
|
||||
documentVersionId: ID!
|
||||
}
|
||||
|
||||
input PublishMajorDocumentVersionInput {
|
||||
documentId: ID!
|
||||
changelog: String
|
||||
}
|
||||
|
||||
input PublishMinorDocumentVersionInput {
|
||||
documentId: ID!
|
||||
changelog: String
|
||||
}
|
||||
|
||||
input BulkPublishDocumentVersionsInput {
|
||||
documentIds: [ID!]!
|
||||
changelog: String!
|
||||
}
|
||||
|
||||
input RequestDocumentVersionApprovalInput {
|
||||
documentId: ID!
|
||||
approverIds: [ID!]!
|
||||
changelog: String
|
||||
}
|
||||
|
||||
input VoidDocumentVersionApprovalInput {
|
||||
documentVersionId: ID!
|
||||
}
|
||||
|
||||
input BulkDeleteDocumentsInput {
|
||||
documentIds: [ID!]!
|
||||
}
|
||||
|
||||
input BulkArchiveDocumentsInput {
|
||||
documentIds: [ID!]!
|
||||
}
|
||||
|
||||
input BulkUnarchiveDocumentsInput {
|
||||
documentIds: [ID!]!
|
||||
}
|
||||
|
||||
input BulkExportDocumentsInput {
|
||||
documentIds: [ID!]!
|
||||
withWatermark: Boolean!
|
||||
watermarkEmail: EmailAddr
|
||||
withSignatures: Boolean!
|
||||
}
|
||||
|
||||
input GenerateDocumentChangelogInput {
|
||||
documentId: ID!
|
||||
}
|
||||
|
||||
input RequestSignatureInput {
|
||||
documentVersionId: ID!
|
||||
signatoryId: ID!
|
||||
}
|
||||
|
||||
input BulkRequestSignaturesInput {
|
||||
documentIds: [ID!]!
|
||||
signatoryIds: [ID!]!
|
||||
}
|
||||
|
||||
input SendSigningNotificationsInput {
|
||||
organizationId: ID!
|
||||
}
|
||||
|
||||
input CancelSignatureRequestInput {
|
||||
documentVersionSignatureId: ID!
|
||||
}
|
||||
|
||||
input SignDocumentInput {
|
||||
documentVersionId: ID!
|
||||
}
|
||||
|
||||
input ApproveDocumentVersionInput {
|
||||
documentVersionId: ID!
|
||||
comment: String
|
||||
}
|
||||
|
||||
input RejectDocumentVersionInput {
|
||||
documentVersionId: ID!
|
||||
comment: String
|
||||
}
|
||||
|
||||
type CreateDocumentPayload {
|
||||
documentEdge: DocumentEdge!
|
||||
documentVersionEdge: DocumentVersionEdge!
|
||||
}
|
||||
|
||||
type UpdateDocumentPayload {
|
||||
document: Document!
|
||||
documentVersion: DocumentVersion
|
||||
documentVersionEdge: DocumentVersionEdge
|
||||
}
|
||||
|
||||
type DeleteDocumentDraftPayload {
|
||||
document: Document!
|
||||
}
|
||||
|
||||
type ArchiveDocumentPayload {
|
||||
document: Document!
|
||||
}
|
||||
|
||||
type UnarchiveDocumentPayload {
|
||||
document: Document!
|
||||
}
|
||||
|
||||
type DeleteDocumentPayload {
|
||||
deletedDocumentId: ID!
|
||||
}
|
||||
|
||||
type ExportDocumentVersionPDFPayload {
|
||||
data: String!
|
||||
}
|
||||
|
||||
type ExportEmployeeDocumentVersionPDFPayload {
|
||||
data: String!
|
||||
}
|
||||
|
||||
type PublishDocumentVersionPayload {
|
||||
document: Document!
|
||||
documentVersion: DocumentVersion!
|
||||
}
|
||||
|
||||
type BulkPublishDocumentVersionsPayload {
|
||||
documentVersions: [DocumentVersion!]!
|
||||
documents: [Document!]!
|
||||
}
|
||||
|
||||
type RequestDocumentVersionApprovalPayload {
|
||||
approvalQuorum: DocumentVersionApprovalQuorum!
|
||||
}
|
||||
|
||||
type VoidDocumentVersionApprovalPayload {
|
||||
approvalQuorum: DocumentVersionApprovalQuorum!
|
||||
documentVersion: DocumentVersion!
|
||||
}
|
||||
|
||||
type BulkDeleteDocumentsPayload {
|
||||
deletedDocumentIds: [ID!]!
|
||||
}
|
||||
|
||||
type BulkArchiveDocumentsPayload {
|
||||
documents: [Document!]!
|
||||
}
|
||||
|
||||
type BulkUnarchiveDocumentsPayload {
|
||||
documents: [Document!]!
|
||||
}
|
||||
|
||||
type BulkExportDocumentsPayload {
|
||||
exportJobId: ID!
|
||||
}
|
||||
|
||||
type RequestSignaturePayload {
|
||||
documentVersionSignatureEdge: DocumentVersionSignatureEdge!
|
||||
}
|
||||
|
||||
type BulkRequestSignaturesPayload {
|
||||
documentVersionSignatureEdges: [DocumentVersionSignatureEdge!]!
|
||||
}
|
||||
|
||||
type SendSigningNotificationsPayload {
|
||||
success: Boolean!
|
||||
}
|
||||
|
||||
type CancelSignatureRequestPayload {
|
||||
deletedDocumentVersionSignatureId: ID!
|
||||
}
|
||||
|
||||
type SignDocumentPayload {
|
||||
documentVersionSignature: DocumentVersionSignature!
|
||||
}
|
||||
|
||||
type ApproveDocumentVersionPayload {
|
||||
approvalDecision: DocumentVersionApprovalDecision!
|
||||
}
|
||||
|
||||
type RejectDocumentVersionPayload {
|
||||
approvalDecision: DocumentVersionApprovalDecision!
|
||||
}
|
||||
|
||||
type GenerateDocumentChangelogPayload {
|
||||
changelog: String!
|
||||
}
|
||||
143
pkg/server/api/console/v1/graphql/electronic_signature.graphql
Normal file
143
pkg/server/api/console/v1/graphql/electronic_signature.graphql
Normal file
@@ -0,0 +1,143 @@
|
||||
enum ElectronicSignatureStatus
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureStatus"
|
||||
) {
|
||||
PENDING
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureStatusPending"
|
||||
)
|
||||
ACCEPTED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureStatusAccepted"
|
||||
)
|
||||
PROCESSING
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureStatusProcessing"
|
||||
)
|
||||
COMPLETED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureStatusCompleted"
|
||||
)
|
||||
FAILED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureStatusFailed"
|
||||
)
|
||||
}
|
||||
|
||||
enum ElectronicSignatureDocumentType
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureDocumentType"
|
||||
) {
|
||||
NDA
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureDocumentTypeNDA"
|
||||
)
|
||||
DPA
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureDocumentTypeDPA"
|
||||
)
|
||||
MSA
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureDocumentTypeMSA"
|
||||
)
|
||||
SOW
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureDocumentTypeSOW"
|
||||
)
|
||||
SLA
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureDocumentTypeSLA"
|
||||
)
|
||||
TOS
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureDocumentTypeTOS"
|
||||
)
|
||||
PRIVACY_POLICY
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureDocumentTypePrivacyPolicy"
|
||||
)
|
||||
OTHER
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureDocumentTypeOther"
|
||||
)
|
||||
}
|
||||
|
||||
enum ElectronicSignatureEventType
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureEventType"
|
||||
) {
|
||||
DOCUMENT_VIEWED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureEventTypeDocumentViewed"
|
||||
)
|
||||
CONSENT_GIVEN
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureEventTypeConsentGiven"
|
||||
)
|
||||
FULL_NAME_TYPED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureEventTypeFullNameTyped"
|
||||
)
|
||||
SIGNATURE_ACCEPTED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureEventTypeSignatureAccepted"
|
||||
)
|
||||
SIGNATURE_COMPLETED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureEventTypeSignatureCompleted"
|
||||
)
|
||||
SEAL_COMPUTED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureEventTypeSealComputed"
|
||||
)
|
||||
TIMESTAMP_REQUESTED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureEventTypeTimestampRequested"
|
||||
)
|
||||
CERTIFICATE_GENERATED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureEventTypeCertificateGenerated"
|
||||
)
|
||||
PROCESSING_ERROR
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureEventTypeProcessingError"
|
||||
)
|
||||
}
|
||||
|
||||
enum ElectronicSignatureEventSource
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureEventSource"
|
||||
) {
|
||||
CLIENT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureEventSourceClient"
|
||||
)
|
||||
SERVER
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureEventSourceServer"
|
||||
)
|
||||
}
|
||||
|
||||
type ElectronicSignature implements Node {
|
||||
id: ID!
|
||||
status: ElectronicSignatureStatus!
|
||||
documentType: ElectronicSignatureDocumentType!
|
||||
consentText: String!
|
||||
lastError: String
|
||||
signedAt: Datetime
|
||||
certificateFileUrl: String @goField(forceResolver: true)
|
||||
events: [ElectronicSignatureEvent!]! @goField(forceResolver: true)
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
}
|
||||
|
||||
type ElectronicSignatureEvent {
|
||||
id: ID!
|
||||
eventType: ElectronicSignatureEventType!
|
||||
eventSource: ElectronicSignatureEventSource!
|
||||
actorEmail: String!
|
||||
actorIpAddress: String!
|
||||
actorUserAgent: String!
|
||||
occurredAt: Datetime!
|
||||
createdAt: Datetime!
|
||||
}
|
||||
92
pkg/server/api/console/v1/graphql/evidence.graphql
Normal file
92
pkg/server/api/console/v1/graphql/evidence.graphql
Normal file
@@ -0,0 +1,92 @@
|
||||
extend type Organization {
|
||||
evidences(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: EvidenceOrder
|
||||
): EvidenceConnection! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
enum EvidenceState
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.EvidenceState") {
|
||||
FULFILLED
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.EvidenceStateFulfilled")
|
||||
REQUESTED
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.EvidenceStateRequested")
|
||||
}
|
||||
|
||||
enum EvidenceType
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.EvidenceType") {
|
||||
FILE @goEnum(value: "go.probo.inc/probo/pkg/coredata.EvidenceTypeFile")
|
||||
LINK @goEnum(value: "go.probo.inc/probo/pkg/coredata.EvidenceTypeLink")
|
||||
}
|
||||
|
||||
enum EvidenceOrderField
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.EvidenceOrderField") {
|
||||
CREATED_AT
|
||||
}
|
||||
|
||||
input EvidenceOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.EvidenceOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: EvidenceOrderField!
|
||||
}
|
||||
|
||||
type Evidence implements Node {
|
||||
id: ID!
|
||||
size: Int!
|
||||
state: EvidenceState!
|
||||
type: EvidenceType!
|
||||
file: File @goField(forceResolver: true)
|
||||
url: String
|
||||
description: String
|
||||
|
||||
task: Task @goField(forceResolver: true)
|
||||
measure: Measure! @goField(forceResolver: true)
|
||||
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type EvidenceConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.EvidenceConnection"
|
||||
) {
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
edges: [EvidenceEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type EvidenceEdge {
|
||||
cursor: CursorKey!
|
||||
node: Evidence!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
deleteEvidence(input: DeleteEvidenceInput!): DeleteEvidencePayload!
|
||||
uploadMeasureEvidence(
|
||||
input: UploadMeasureEvidenceInput!
|
||||
): UploadMeasureEvidencePayload!
|
||||
}
|
||||
|
||||
input DeleteEvidenceInput {
|
||||
evidenceId: ID!
|
||||
}
|
||||
|
||||
input UploadMeasureEvidenceInput {
|
||||
measureId: ID!
|
||||
file: Upload!
|
||||
}
|
||||
|
||||
type DeleteEvidencePayload {
|
||||
deletedEvidenceId: ID!
|
||||
}
|
||||
|
||||
type UploadMeasureEvidencePayload {
|
||||
evidenceEdge: EvidenceEdge!
|
||||
}
|
||||
116
pkg/server/api/console/v1/graphql/framework.graphql
Normal file
116
pkg/server/api/console/v1/graphql/framework.graphql
Normal file
@@ -0,0 +1,116 @@
|
||||
extend type Organization {
|
||||
frameworks(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: FrameworkOrder
|
||||
): FrameworkConnection! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
enum FrameworkOrderField
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.FrameworkOrderField") {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.FrameworkOrderFieldCreatedAt"
|
||||
)
|
||||
}
|
||||
|
||||
input FrameworkOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.FrameworkOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: FrameworkOrderField!
|
||||
}
|
||||
|
||||
type Framework implements Node {
|
||||
id: ID!
|
||||
name: String!
|
||||
description: String
|
||||
|
||||
organization: Organization! @goField(forceResolver: true)
|
||||
|
||||
controls(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: ControlOrder
|
||||
filter: ControlFilter
|
||||
): ControlConnection! @goField(forceResolver: true)
|
||||
lightLogoURL: String @goField(forceResolver: true)
|
||||
darkLogoURL: String @goField(forceResolver: true)
|
||||
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type FrameworkConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.FrameworkConnection"
|
||||
) {
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
edges: [FrameworkEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type FrameworkEdge {
|
||||
cursor: CursorKey!
|
||||
node: Framework!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
createFramework(input: CreateFrameworkInput!): CreateFrameworkPayload!
|
||||
updateFramework(input: UpdateFrameworkInput!): UpdateFrameworkPayload!
|
||||
importFramework(input: ImportFrameworkInput!): ImportFrameworkPayload!
|
||||
deleteFramework(input: DeleteFrameworkInput!): DeleteFrameworkPayload!
|
||||
exportFramework(input: ExportFrameworkInput!): ExportFrameworkPayload!
|
||||
}
|
||||
|
||||
input CreateFrameworkInput {
|
||||
organizationId: ID!
|
||||
name: String!
|
||||
description: String
|
||||
}
|
||||
|
||||
input UpdateFrameworkInput {
|
||||
id: ID!
|
||||
name: String
|
||||
description: String @goField(omittable: true)
|
||||
}
|
||||
|
||||
input ImportFrameworkInput {
|
||||
organizationId: ID!
|
||||
file: Upload!
|
||||
}
|
||||
|
||||
input DeleteFrameworkInput {
|
||||
frameworkId: ID!
|
||||
}
|
||||
|
||||
input ExportFrameworkInput {
|
||||
frameworkId: ID!
|
||||
}
|
||||
|
||||
type CreateFrameworkPayload {
|
||||
frameworkEdge: FrameworkEdge!
|
||||
}
|
||||
|
||||
type UpdateFrameworkPayload {
|
||||
framework: Framework!
|
||||
}
|
||||
|
||||
type ImportFrameworkPayload {
|
||||
frameworkEdge: FrameworkEdge!
|
||||
}
|
||||
|
||||
type DeleteFrameworkPayload {
|
||||
deletedFrameworkId: ID!
|
||||
}
|
||||
|
||||
type ExportFrameworkPayload {
|
||||
exportJobId: ID!
|
||||
}
|
||||
188
pkg/server/api/console/v1/graphql/mailing_list.graphql
Normal file
188
pkg/server/api/console/v1/graphql/mailing_list.graphql
Normal file
@@ -0,0 +1,188 @@
|
||||
enum MailingListSubscriberStatus
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.MailingListSubscriberStatus"
|
||||
) {
|
||||
PENDING
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.MailingListSubscriberStatusPending"
|
||||
)
|
||||
CONFIRMED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.MailingListSubscriberStatusConfirmed"
|
||||
)
|
||||
}
|
||||
|
||||
enum MailingListUpdateStatus
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.MailingListUpdateStatus"
|
||||
) {
|
||||
DRAFT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.MailingListUpdateStatusDraft"
|
||||
)
|
||||
ENQUEUED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.MailingListUpdateStatusEnqueued"
|
||||
)
|
||||
PROCESSING
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.MailingListUpdateStatusProcessing"
|
||||
)
|
||||
SENT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.MailingListUpdateStatusSent"
|
||||
)
|
||||
}
|
||||
|
||||
type MailingList implements Node {
|
||||
id: ID!
|
||||
replyTo: EmailAddr
|
||||
|
||||
subscribers(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
): MailingListSubscriberConnection! @goField(forceResolver: true)
|
||||
|
||||
updates(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
): MailingListUpdateConnection! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type MailingListSubscriber implements Node {
|
||||
id: ID!
|
||||
fullName: String!
|
||||
email: EmailAddr!
|
||||
status: MailingListSubscriberStatus!
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
}
|
||||
|
||||
type MailingListSubscriberConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.MailingListSubscriberConnection"
|
||||
) {
|
||||
edges: [MailingListSubscriberEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type MailingListSubscriberEdge {
|
||||
cursor: CursorKey!
|
||||
node: MailingListSubscriber!
|
||||
}
|
||||
|
||||
type MailingListUpdate implements Node {
|
||||
id: ID!
|
||||
title: String!
|
||||
body: String!
|
||||
status: MailingListUpdateStatus!
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
}
|
||||
|
||||
type MailingListUpdateConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.MailingListUpdateConnection"
|
||||
) {
|
||||
edges: [MailingListUpdateEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type MailingListUpdateEdge {
|
||||
cursor: CursorKey!
|
||||
node: MailingListUpdate!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
createMailingListUpdate(
|
||||
input: CreateMailingListUpdateInput!
|
||||
): CreateMailingListUpdatePayload!
|
||||
updateMailingListUpdate(
|
||||
input: UpdateMailingListUpdateInput!
|
||||
): UpdateMailingListUpdatePayload!
|
||||
sendMailingListUpdate(
|
||||
input: SendMailingListUpdateInput!
|
||||
): SendMailingListUpdatePayload!
|
||||
deleteMailingListUpdate(
|
||||
input: DeleteMailingListUpdateInput!
|
||||
): DeleteMailingListUpdatePayload!
|
||||
updateMailingList(
|
||||
input: UpdateMailingListInput!
|
||||
): UpdateMailingListPayload!
|
||||
createMailingListSubscriber(
|
||||
input: CreateMailingListSubscriberInput!
|
||||
): CreateMailingListSubscriberPayload!
|
||||
deleteMailingListSubscriber(
|
||||
input: DeleteMailingListSubscriberInput!
|
||||
): DeleteMailingListSubscriberPayload!
|
||||
}
|
||||
|
||||
input UpdateMailingListInput {
|
||||
id: ID!
|
||||
replyTo: EmailAddr
|
||||
}
|
||||
|
||||
type UpdateMailingListPayload {
|
||||
mailingList: MailingList!
|
||||
}
|
||||
|
||||
input CreateMailingListUpdateInput {
|
||||
mailingListId: ID!
|
||||
title: String!
|
||||
body: String!
|
||||
}
|
||||
|
||||
input UpdateMailingListUpdateInput {
|
||||
id: ID!
|
||||
title: String
|
||||
body: String
|
||||
}
|
||||
|
||||
input SendMailingListUpdateInput {
|
||||
id: ID!
|
||||
}
|
||||
|
||||
input DeleteMailingListUpdateInput {
|
||||
id: ID!
|
||||
}
|
||||
|
||||
input CreateMailingListSubscriberInput {
|
||||
mailingListId: ID!
|
||||
fullName: String!
|
||||
email: EmailAddr!
|
||||
confirmed: Boolean
|
||||
}
|
||||
|
||||
input DeleteMailingListSubscriberInput {
|
||||
id: ID!
|
||||
}
|
||||
|
||||
type CreateMailingListUpdatePayload {
|
||||
mailingListUpdate: MailingListUpdate!
|
||||
}
|
||||
|
||||
type UpdateMailingListUpdatePayload {
|
||||
mailingListUpdate: MailingListUpdate!
|
||||
}
|
||||
|
||||
type SendMailingListUpdatePayload {
|
||||
mailingListUpdate: MailingListUpdate!
|
||||
}
|
||||
|
||||
type DeleteMailingListUpdatePayload {
|
||||
deletedMailingListUpdateId: ID!
|
||||
}
|
||||
|
||||
type CreateMailingListSubscriberPayload {
|
||||
mailingListSubscriberEdge: MailingListSubscriberEdge!
|
||||
}
|
||||
|
||||
type DeleteMailingListSubscriberPayload {
|
||||
deletedMailingListSubscriberId: ID!
|
||||
}
|
||||
200
pkg/server/api/console/v1/graphql/measure.graphql
Normal file
200
pkg/server/api/console/v1/graphql/measure.graphql
Normal file
@@ -0,0 +1,200 @@
|
||||
extend type Organization {
|
||||
measures(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: MeasureOrder
|
||||
filter: MeasureFilter
|
||||
): MeasureConnection! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
enum MeasureState
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.MeasureState") {
|
||||
NOT_STARTED
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.MeasureStateNotStarted")
|
||||
IN_PROGRESS
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.MeasureStateInProgress")
|
||||
NOT_APPLICABLE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.MeasureStateNotApplicable"
|
||||
)
|
||||
IMPLEMENTED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.MeasureStateImplemented"
|
||||
)
|
||||
UNKNOWN
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.MeasureStateUnknown"
|
||||
)
|
||||
NOT_IMPLEMENTED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.MeasureStateNotImplemented"
|
||||
)
|
||||
}
|
||||
|
||||
enum MeasureOrderField
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.MeasureOrderField") {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.MeasureOrderFieldCreatedAt"
|
||||
)
|
||||
NAME @goEnum(value: "go.probo.inc/probo/pkg/coredata.MeasureOrderFieldName")
|
||||
}
|
||||
|
||||
input MeasureOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.MeasureOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: MeasureOrderField!
|
||||
}
|
||||
|
||||
input MeasureFilter {
|
||||
query: String
|
||||
state: MeasureState
|
||||
category: String
|
||||
}
|
||||
|
||||
type Measure implements Node {
|
||||
id: ID!
|
||||
category: String!
|
||||
name: String!
|
||||
description: String
|
||||
state: MeasureState!
|
||||
|
||||
evidences(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: EvidenceOrder
|
||||
): EvidenceConnection! @goField(forceResolver: true)
|
||||
|
||||
tasks(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: TaskOrder
|
||||
): TaskConnection! @goField(forceResolver: true)
|
||||
|
||||
risks(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: RiskOrder
|
||||
filter: RiskFilter
|
||||
): RiskConnection! @goField(forceResolver: true)
|
||||
|
||||
controls(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: ControlOrder
|
||||
filter: ControlFilter
|
||||
): ControlConnection! @goField(forceResolver: true)
|
||||
|
||||
documents(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: DocumentOrder
|
||||
filter: DocumentFilter
|
||||
): DocumentConnection! @goField(forceResolver: true)
|
||||
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type MeasureConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.MeasureConnection"
|
||||
) {
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
edges: [MeasureEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type MeasureEdge {
|
||||
cursor: CursorKey!
|
||||
node: Measure!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
createMeasure(input: CreateMeasureInput!): CreateMeasurePayload!
|
||||
updateMeasure(input: UpdateMeasureInput!): UpdateMeasurePayload!
|
||||
importMeasure(input: ImportMeasureInput!): ImportMeasurePayload!
|
||||
deleteMeasure(input: DeleteMeasureInput!): DeleteMeasurePayload!
|
||||
createMeasureDocumentMapping(
|
||||
input: CreateMeasureDocumentMappingInput!
|
||||
): CreateMeasureDocumentMappingPayload!
|
||||
deleteMeasureDocumentMapping(
|
||||
input: DeleteMeasureDocumentMappingInput!
|
||||
): DeleteMeasureDocumentMappingPayload!
|
||||
}
|
||||
|
||||
input CreateMeasureInput {
|
||||
organizationId: ID!
|
||||
name: String!
|
||||
description: String
|
||||
category: String!
|
||||
}
|
||||
|
||||
input UpdateMeasureInput {
|
||||
id: ID!
|
||||
name: String
|
||||
description: String @goField(omittable: true)
|
||||
category: String
|
||||
state: MeasureState
|
||||
}
|
||||
|
||||
input ImportMeasureInput {
|
||||
organizationId: ID!
|
||||
file: Upload!
|
||||
}
|
||||
|
||||
input DeleteMeasureInput {
|
||||
measureId: ID!
|
||||
}
|
||||
|
||||
input CreateMeasureDocumentMappingInput {
|
||||
measureId: ID!
|
||||
documentId: ID!
|
||||
}
|
||||
|
||||
input DeleteMeasureDocumentMappingInput {
|
||||
measureId: ID!
|
||||
documentId: ID!
|
||||
}
|
||||
|
||||
type CreateMeasurePayload {
|
||||
measureEdge: MeasureEdge!
|
||||
}
|
||||
|
||||
type UpdateMeasurePayload {
|
||||
measure: Measure!
|
||||
}
|
||||
|
||||
type ImportMeasurePayload {
|
||||
measureEdges: [MeasureEdge!]!
|
||||
}
|
||||
|
||||
type DeleteMeasurePayload {
|
||||
deletedMeasureId: ID!
|
||||
}
|
||||
|
||||
type CreateMeasureDocumentMappingPayload {
|
||||
measureEdge: MeasureEdge!
|
||||
documentEdge: DocumentEdge!
|
||||
}
|
||||
|
||||
type DeleteMeasureDocumentMappingPayload {
|
||||
deletedMeasureId: ID!
|
||||
deletedDocumentId: ID!
|
||||
}
|
||||
92
pkg/server/api/console/v1/graphql/meeting.graphql
Normal file
92
pkg/server/api/console/v1/graphql/meeting.graphql
Normal file
@@ -0,0 +1,92 @@
|
||||
extend type Organization {
|
||||
meetings(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: MeetingOrder
|
||||
): MeetingConnection! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
enum MeetingOrderField
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.MeetingOrderField") {
|
||||
DATE @goEnum(value: "go.probo.inc/probo/pkg/coredata.MeetingOrderFieldDate")
|
||||
NAME @goEnum(value: "go.probo.inc/probo/pkg/coredata.MeetingOrderFieldName")
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.MeetingOrderFieldCreatedAt"
|
||||
)
|
||||
}
|
||||
|
||||
input MeetingOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.MeetingOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: MeetingOrderField!
|
||||
}
|
||||
|
||||
type Meeting implements Node {
|
||||
id: ID!
|
||||
name: String!
|
||||
date: Datetime!
|
||||
minutes: String
|
||||
attendees: [Profile!]! @goField(forceResolver: true)
|
||||
organization: Organization! @goField(forceResolver: true)
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type MeetingConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.MeetingConnection"
|
||||
) {
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
edges: [MeetingEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type MeetingEdge {
|
||||
cursor: CursorKey!
|
||||
node: Meeting!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
createMeeting(input: CreateMeetingInput!): CreateMeetingPayload!
|
||||
updateMeeting(input: UpdateMeetingInput!): UpdateMeetingPayload!
|
||||
deleteMeeting(input: DeleteMeetingInput!): DeleteMeetingPayload!
|
||||
}
|
||||
|
||||
input CreateMeetingInput {
|
||||
organizationId: ID!
|
||||
name: String!
|
||||
date: Datetime!
|
||||
attendeeIds: [ID!]
|
||||
minutes: String
|
||||
}
|
||||
|
||||
input UpdateMeetingInput {
|
||||
meetingId: ID!
|
||||
name: String
|
||||
date: Datetime
|
||||
attendeeIds: [ID!]
|
||||
minutes: String @goField(omittable: true)
|
||||
}
|
||||
|
||||
input DeleteMeetingInput {
|
||||
meetingId: ID!
|
||||
}
|
||||
|
||||
type CreateMeetingPayload {
|
||||
meetingEdge: MeetingEdge!
|
||||
}
|
||||
|
||||
type UpdateMeetingPayload {
|
||||
meeting: Meeting!
|
||||
}
|
||||
|
||||
type DeleteMeetingPayload {
|
||||
deletedMeetingId: ID!
|
||||
}
|
||||
152
pkg/server/api/console/v1/graphql/obligation.graphql
Normal file
152
pkg/server/api/console/v1/graphql/obligation.graphql
Normal file
@@ -0,0 +1,152 @@
|
||||
extend type Organization {
|
||||
obligations(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: ObligationOrder
|
||||
filter: ObligationFilter = { snapshotId: null }
|
||||
): ObligationConnection! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
enum ObligationStatus
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.ObligationStatus") {
|
||||
NON_COMPLIANT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ObligationStatusNonCompliant"
|
||||
)
|
||||
PARTIALLY_COMPLIANT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ObligationStatusPartiallyCompliant"
|
||||
)
|
||||
COMPLIANT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ObligationStatusCompliant"
|
||||
)
|
||||
}
|
||||
|
||||
enum ObligationType
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.ObligationType") {
|
||||
LEGAL @goEnum(value: "go.probo.inc/probo/pkg/coredata.ObligationTypeLegal")
|
||||
CONTRACTUAL
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ObligationTypeContractual"
|
||||
)
|
||||
}
|
||||
|
||||
enum ObligationOrderField
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.ObligationOrderField") {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ObligationOrderFieldCreatedAt"
|
||||
)
|
||||
LAST_REVIEW_DATE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ObligationOrderFieldLastReviewDate"
|
||||
)
|
||||
DUE_DATE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ObligationOrderFieldDueDate"
|
||||
)
|
||||
STATUS
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ObligationOrderFieldStatus"
|
||||
)
|
||||
}
|
||||
|
||||
input ObligationOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.ObligationOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: ObligationOrderField!
|
||||
}
|
||||
|
||||
input ObligationFilter {
|
||||
snapshotId: ID
|
||||
}
|
||||
|
||||
type Obligation implements Node {
|
||||
id: ID!
|
||||
snapshotId: ID
|
||||
sourceId: ID
|
||||
organization: Organization! @goField(forceResolver: true)
|
||||
area: String
|
||||
source: String
|
||||
requirement: String
|
||||
actionsToBeImplemented: String
|
||||
regulator: String
|
||||
owner: Profile! @goField(forceResolver: true)
|
||||
lastReviewDate: Datetime
|
||||
dueDate: Datetime
|
||||
status: ObligationStatus!
|
||||
type: ObligationType!
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type ObligationConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.ObligationConnection"
|
||||
) {
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
edges: [ObligationEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type ObligationEdge {
|
||||
cursor: CursorKey!
|
||||
node: Obligation!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
createObligation(input: CreateObligationInput!): CreateObligationPayload!
|
||||
updateObligation(input: UpdateObligationInput!): UpdateObligationPayload!
|
||||
deleteObligation(input: DeleteObligationInput!): DeleteObligationPayload!
|
||||
}
|
||||
|
||||
input CreateObligationInput {
|
||||
organizationId: ID!
|
||||
area: String
|
||||
source: String
|
||||
requirement: String
|
||||
actionsToBeImplemented: String
|
||||
regulator: String
|
||||
ownerId: ID!
|
||||
lastReviewDate: Datetime
|
||||
dueDate: Datetime
|
||||
status: ObligationStatus!
|
||||
type: ObligationType!
|
||||
}
|
||||
|
||||
input UpdateObligationInput {
|
||||
id: ID!
|
||||
area: String @goField(omittable: true)
|
||||
source: String @goField(omittable: true)
|
||||
requirement: String @goField(omittable: true)
|
||||
actionsToBeImplemented: String @goField(omittable: true)
|
||||
regulator: String @goField(omittable: true)
|
||||
ownerId: ID
|
||||
lastReviewDate: Datetime @goField(omittable: true)
|
||||
dueDate: Datetime @goField(omittable: true)
|
||||
status: ObligationStatus
|
||||
type: ObligationType
|
||||
}
|
||||
|
||||
input DeleteObligationInput {
|
||||
obligationId: ID!
|
||||
}
|
||||
|
||||
type CreateObligationPayload {
|
||||
obligationEdge: ObligationEdge!
|
||||
}
|
||||
|
||||
type UpdateObligationPayload {
|
||||
obligation: Obligation!
|
||||
}
|
||||
|
||||
type DeleteObligationPayload {
|
||||
deletedObligationId: ID!
|
||||
}
|
||||
83
pkg/server/api/console/v1/graphql/organization.graphql
Normal file
83
pkg/server/api/console/v1/graphql/organization.graphql
Normal file
@@ -0,0 +1,83 @@
|
||||
type OrganizationContext {
|
||||
organizationId: ID!
|
||||
product: String
|
||||
architecture: String
|
||||
team: String
|
||||
processes: String
|
||||
customers: String
|
||||
}
|
||||
|
||||
enum ProfileState
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.ProfileState") {
|
||||
ACTIVE @goEnum(value: "go.probo.inc/probo/pkg/coredata.ProfileStateActive")
|
||||
INACTIVE
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.ProfileStateInactive")
|
||||
}
|
||||
|
||||
type Profile implements Node {
|
||||
id: ID!
|
||||
fullName: String!
|
||||
emailAddress: EmailAddr!
|
||||
state: ProfileState!
|
||||
additionalEmailAddresses: [EmailAddr!]!
|
||||
kind: String
|
||||
position: String
|
||||
contractStartDate: Datetime
|
||||
contractEndDate: Datetime
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
enum ProfileOrderField
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.MembershipProfileOrderField") {
|
||||
FULL_NAME
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.MembershipProfileOrderFieldFullName"
|
||||
)
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.MembershipProfileOrderFieldCreatedAt"
|
||||
)
|
||||
KIND @goEnum(value: "go.probo.inc/probo/pkg/coredata.MembershipProfileOrderFieldKind")
|
||||
}
|
||||
|
||||
input ProfileOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.ProfileOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: ProfileOrderField!
|
||||
}
|
||||
|
||||
input ProfileFilter {
|
||||
excludeContractEnded: Boolean
|
||||
}
|
||||
|
||||
type ProfileConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.ProfileConnection"
|
||||
) {
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
edges: [ProfileEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type ProfileEdge {
|
||||
cursor: CursorKey!
|
||||
node: Profile!
|
||||
}
|
||||
|
||||
input UpdateOrganizationContextInput {
|
||||
organizationId: ID!
|
||||
product: String @goField(omittable: true)
|
||||
architecture: String @goField(omittable: true)
|
||||
team: String @goField(omittable: true)
|
||||
processes: String @goField(omittable: true)
|
||||
customers: String @goField(omittable: true)
|
||||
}
|
||||
|
||||
type UpdateOrganizationContextPayload {
|
||||
context: OrganizationContext!
|
||||
}
|
||||
298
pkg/server/api/console/v1/graphql/processing_activity.graphql
Normal file
298
pkg/server/api/console/v1/graphql/processing_activity.graphql
Normal file
@@ -0,0 +1,298 @@
|
||||
extend type Organization {
|
||||
processingActivities(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: ProcessingActivityOrder
|
||||
filter: ProcessingActivityFilter = { snapshotId: null }
|
||||
): ProcessingActivityConnection! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
enum ProcessingActivitySpecialOrCriminalDatum
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.ProcessingActivitySpecialOrCriminalDatum"
|
||||
) {
|
||||
YES
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ProcessingActivitySpecialOrCriminalDatumYes"
|
||||
)
|
||||
NO
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ProcessingActivitySpecialOrCriminalDatumNo"
|
||||
)
|
||||
POSSIBLE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ProcessingActivitySpecialOrCriminalDatumPossible"
|
||||
)
|
||||
}
|
||||
|
||||
enum ProcessingActivityLawfulBasis
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.ProcessingActivityLawfulBasis"
|
||||
) {
|
||||
LEGITIMATE_INTEREST
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ProcessingActivityLawfulBasisLegitimateInterest"
|
||||
)
|
||||
CONSENT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ProcessingActivityLawfulBasisConsent"
|
||||
)
|
||||
CONTRACTUAL_NECESSITY
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ProcessingActivityLawfulBasisContractualNecessity"
|
||||
)
|
||||
LEGAL_OBLIGATION
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ProcessingActivityLawfulBasisLegalObligation"
|
||||
)
|
||||
VITAL_INTERESTS
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ProcessingActivityLawfulBasisVitalInterests"
|
||||
)
|
||||
PUBLIC_TASK
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ProcessingActivityLawfulBasisPublicTask"
|
||||
)
|
||||
}
|
||||
|
||||
enum ProcessingActivityTransferSafeguard
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.ProcessingActivityTransferSafeguard"
|
||||
) {
|
||||
STANDARD_CONTRACTUAL_CLAUSES
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ProcessingActivityTransferSafeguardStandardContractualClauses"
|
||||
)
|
||||
BINDING_CORPORATE_RULES
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ProcessingActivityTransferSafeguardBindingCorporateRules"
|
||||
)
|
||||
ADEQUACY_DECISION
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ProcessingActivityTransferSafeguardAdequacyDecision"
|
||||
)
|
||||
DEROGATIONS
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ProcessingActivityTransferSafeguardDerogations"
|
||||
)
|
||||
CODES_OF_CONDUCT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ProcessingActivityTransferSafeguardCodesOfConduct"
|
||||
)
|
||||
CERTIFICATION_MECHANISMS
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ProcessingActivityTransferSafeguardCertificationMechanisms"
|
||||
)
|
||||
}
|
||||
|
||||
enum ProcessingActivityDataProtectionImpactAssessment
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.ProcessingActivityDataProtectionImpactAssessment"
|
||||
) {
|
||||
NEEDED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ProcessingActivityDataProtectionImpactAssessmentNeeded"
|
||||
)
|
||||
NOT_NEEDED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ProcessingActivityDataProtectionImpactAssessmentNotNeeded"
|
||||
)
|
||||
}
|
||||
|
||||
enum ProcessingActivityTransferImpactAssessment
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.ProcessingActivityTransferImpactAssessment"
|
||||
) {
|
||||
NEEDED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ProcessingActivityTransferImpactAssessmentNeeded"
|
||||
)
|
||||
NOT_NEEDED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ProcessingActivityTransferImpactAssessmentNotNeeded"
|
||||
)
|
||||
}
|
||||
|
||||
enum ProcessingActivityRole
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.ProcessingActivityRole") {
|
||||
CONTROLLER
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ProcessingActivityRoleController"
|
||||
)
|
||||
PROCESSOR
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ProcessingActivityRoleProcessor"
|
||||
)
|
||||
}
|
||||
|
||||
enum ProcessingActivityOrderField
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.ProcessingActivityOrderField"
|
||||
) {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ProcessingActivityOrderFieldCreatedAt"
|
||||
)
|
||||
NAME
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ProcessingActivityOrderFieldName"
|
||||
)
|
||||
}
|
||||
|
||||
input ProcessingActivityOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.ProcessingActivityOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: ProcessingActivityOrderField!
|
||||
}
|
||||
|
||||
input ProcessingActivityFilter {
|
||||
snapshotId: ID
|
||||
}
|
||||
|
||||
type ProcessingActivity implements Node {
|
||||
id: ID!
|
||||
snapshotId: ID
|
||||
sourceId: ID
|
||||
organization: Organization! @goField(forceResolver: true)
|
||||
name: String!
|
||||
purpose: String
|
||||
dataSubjectCategory: String
|
||||
personalDataCategory: String
|
||||
specialOrCriminalData: ProcessingActivitySpecialOrCriminalDatum!
|
||||
consentEvidenceLink: String
|
||||
lawfulBasis: ProcessingActivityLawfulBasis!
|
||||
recipients: String
|
||||
location: String
|
||||
internationalTransfers: Boolean!
|
||||
transferSafeguards: ProcessingActivityTransferSafeguard
|
||||
retentionPeriod: String
|
||||
securityMeasures: String
|
||||
dataProtectionImpactAssessmentNeeded: ProcessingActivityDataProtectionImpactAssessment!
|
||||
transferImpactAssessmentNeeded: ProcessingActivityTransferImpactAssessment!
|
||||
lastReviewDate: Datetime
|
||||
nextReviewDate: Datetime
|
||||
role: ProcessingActivityRole!
|
||||
dataProtectionOfficer: Profile @goField(forceResolver: true)
|
||||
vendors(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: VendorOrder
|
||||
): VendorConnection! @goField(forceResolver: true)
|
||||
dataProtectionImpactAssessment: DataProtectionImpactAssessment
|
||||
@goField(forceResolver: true)
|
||||
transferImpactAssessment: TransferImpactAssessment
|
||||
@goField(forceResolver: true)
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type ProcessingActivityConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.ProcessingActivityConnection"
|
||||
) {
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
edges: [ProcessingActivityEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type ProcessingActivityEdge {
|
||||
cursor: CursorKey!
|
||||
node: ProcessingActivity!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
createProcessingActivity(
|
||||
input: CreateProcessingActivityInput!
|
||||
): CreateProcessingActivityPayload!
|
||||
updateProcessingActivity(
|
||||
input: UpdateProcessingActivityInput!
|
||||
): UpdateProcessingActivityPayload!
|
||||
deleteProcessingActivity(
|
||||
input: DeleteProcessingActivityInput!
|
||||
): DeleteProcessingActivityPayload!
|
||||
exportProcessingActivitiesPDF(
|
||||
input: ExportProcessingActivitiesPDFInput!
|
||||
): ExportProcessingActivitiesPDFPayload!
|
||||
}
|
||||
|
||||
input CreateProcessingActivityInput {
|
||||
organizationId: ID!
|
||||
name: String!
|
||||
purpose: String
|
||||
dataSubjectCategory: String
|
||||
personalDataCategory: String
|
||||
specialOrCriminalData: ProcessingActivitySpecialOrCriminalDatum!
|
||||
consentEvidenceLink: String
|
||||
lawfulBasis: ProcessingActivityLawfulBasis!
|
||||
recipients: String
|
||||
location: String
|
||||
internationalTransfers: Boolean!
|
||||
transferSafeguards: ProcessingActivityTransferSafeguard
|
||||
retentionPeriod: String
|
||||
securityMeasures: String
|
||||
dataProtectionImpactAssessmentNeeded: ProcessingActivityDataProtectionImpactAssessment!
|
||||
transferImpactAssessmentNeeded: ProcessingActivityTransferImpactAssessment!
|
||||
lastReviewDate: Datetime
|
||||
nextReviewDate: Datetime
|
||||
role: ProcessingActivityRole!
|
||||
dataProtectionOfficerId: ID
|
||||
vendorIds: [ID!]
|
||||
}
|
||||
|
||||
input UpdateProcessingActivityInput {
|
||||
id: ID!
|
||||
name: String
|
||||
purpose: String @goField(omittable: true)
|
||||
dataSubjectCategory: String @goField(omittable: true)
|
||||
personalDataCategory: String @goField(omittable: true)
|
||||
specialOrCriminalData: ProcessingActivitySpecialOrCriminalDatum
|
||||
consentEvidenceLink: String
|
||||
lawfulBasis: ProcessingActivityLawfulBasis
|
||||
recipients: String @goField(omittable: true)
|
||||
location: String @goField(omittable: true)
|
||||
internationalTransfers: Boolean
|
||||
transferSafeguards: ProcessingActivityTransferSafeguard
|
||||
@goField(omittable: true)
|
||||
retentionPeriod: String @goField(omittable: true)
|
||||
securityMeasures: String @goField(omittable: true)
|
||||
dataProtectionImpactAssessmentNeeded: ProcessingActivityDataProtectionImpactAssessment
|
||||
transferImpactAssessmentNeeded: ProcessingActivityTransferImpactAssessment
|
||||
lastReviewDate: Datetime @goField(omittable: true)
|
||||
nextReviewDate: Datetime @goField(omittable: true)
|
||||
role: ProcessingActivityRole
|
||||
dataProtectionOfficerId: ID @goField(omittable: true)
|
||||
vendorIds: [ID!]
|
||||
}
|
||||
|
||||
input DeleteProcessingActivityInput {
|
||||
processingActivityId: ID!
|
||||
}
|
||||
|
||||
input ExportProcessingActivitiesPDFInput {
|
||||
organizationId: ID!
|
||||
filter: ProcessingActivityFilter
|
||||
}
|
||||
|
||||
type CreateProcessingActivityPayload {
|
||||
processingActivityEdge: ProcessingActivityEdge!
|
||||
}
|
||||
|
||||
type UpdateProcessingActivityPayload {
|
||||
processingActivity: ProcessingActivity!
|
||||
}
|
||||
|
||||
type DeleteProcessingActivityPayload {
|
||||
deletedProcessingActivityId: ID!
|
||||
}
|
||||
|
||||
type ExportProcessingActivitiesPDFPayload {
|
||||
data: String!
|
||||
}
|
||||
145
pkg/server/api/console/v1/graphql/rights_request.graphql
Normal file
145
pkg/server/api/console/v1/graphql/rights_request.graphql
Normal file
@@ -0,0 +1,145 @@
|
||||
extend type Organization {
|
||||
rightsRequests(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: RightsRequestOrder
|
||||
): RightsRequestConnection! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
enum RightsRequestType
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.RightsRequestType") {
|
||||
ACCESS
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.RightsRequestTypeAccess"
|
||||
)
|
||||
DELETION
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.RightsRequestTypeDeletion"
|
||||
)
|
||||
PORTABILITY
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.RightsRequestTypePortability"
|
||||
)
|
||||
}
|
||||
|
||||
enum RightsRequestState
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.RightsRequestState") {
|
||||
TODO
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.RightsRequestStateTodo")
|
||||
IN_PROGRESS
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.RightsRequestStateInProgress"
|
||||
)
|
||||
DONE
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.RightsRequestStateDone")
|
||||
}
|
||||
|
||||
enum RightsRequestOrderField
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.RightsRequestOrderField") {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.RightsRequestOrderFieldCreatedAt"
|
||||
)
|
||||
DEADLINE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.RightsRequestOrderFieldDeadline"
|
||||
)
|
||||
STATE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.RightsRequestOrderFieldState"
|
||||
)
|
||||
TYPE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.RightsRequestOrderFieldType"
|
||||
)
|
||||
}
|
||||
|
||||
input RightsRequestOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.RightsRequestOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: RightsRequestOrderField!
|
||||
}
|
||||
|
||||
type RightsRequest implements Node {
|
||||
id: ID!
|
||||
organization: Organization! @goField(forceResolver: true)
|
||||
requestType: RightsRequestType!
|
||||
requestState: RightsRequestState!
|
||||
dataSubject: String
|
||||
contact: String
|
||||
details: String
|
||||
deadline: Datetime
|
||||
actionTaken: String
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type RightsRequestConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.RightsRequestConnection"
|
||||
) {
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
edges: [RightsRequestEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type RightsRequestEdge {
|
||||
cursor: CursorKey!
|
||||
node: RightsRequest!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
createRightsRequest(
|
||||
input: CreateRightsRequestInput!
|
||||
): CreateRightsRequestPayload!
|
||||
updateRightsRequest(
|
||||
input: UpdateRightsRequestInput!
|
||||
): UpdateRightsRequestPayload!
|
||||
deleteRightsRequest(
|
||||
input: DeleteRightsRequestInput!
|
||||
): DeleteRightsRequestPayload!
|
||||
}
|
||||
|
||||
input CreateRightsRequestInput {
|
||||
organizationId: ID!
|
||||
requestType: RightsRequestType!
|
||||
requestState: RightsRequestState!
|
||||
dataSubject: String
|
||||
contact: String
|
||||
details: String
|
||||
deadline: Datetime
|
||||
actionTaken: String
|
||||
}
|
||||
|
||||
input UpdateRightsRequestInput {
|
||||
id: ID!
|
||||
requestType: RightsRequestType
|
||||
requestState: RightsRequestState
|
||||
dataSubject: String @goField(omittable: true)
|
||||
contact: String @goField(omittable: true)
|
||||
details: String @goField(omittable: true)
|
||||
deadline: Datetime @goField(omittable: true)
|
||||
actionTaken: String @goField(omittable: true)
|
||||
}
|
||||
|
||||
input DeleteRightsRequestInput {
|
||||
rightsRequestId: ID!
|
||||
}
|
||||
|
||||
type CreateRightsRequestPayload {
|
||||
rightsRequestEdge: RightsRequestEdge!
|
||||
}
|
||||
|
||||
type UpdateRightsRequestPayload {
|
||||
rightsRequest: RightsRequest!
|
||||
}
|
||||
|
||||
type DeleteRightsRequestPayload {
|
||||
deletedRightsRequestId: ID!
|
||||
}
|
||||
270
pkg/server/api/console/v1/graphql/risk.graphql
Normal file
270
pkg/server/api/console/v1/graphql/risk.graphql
Normal file
@@ -0,0 +1,270 @@
|
||||
extend type Organization {
|
||||
risks(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: RiskOrder
|
||||
filter: RiskFilter = { snapshotId: null }
|
||||
): RiskConnection! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
enum RiskTreatment
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.RiskTreatment") {
|
||||
MITIGATED
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.RiskTreatmentMitigated")
|
||||
ACCEPTED
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.RiskTreatmentAccepted")
|
||||
AVOIDED
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.RiskTreatmentAvoided")
|
||||
TRANSFERRED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.RiskTreatmentTransferred"
|
||||
)
|
||||
}
|
||||
|
||||
enum RiskOrderField
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.RiskOrderField") {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.RiskOrderFieldCreatedAt"
|
||||
)
|
||||
UPDATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.RiskOrderFieldUpdatedAt"
|
||||
)
|
||||
NAME @goEnum(value: "go.probo.inc/probo/pkg/coredata.RiskOrderFieldName")
|
||||
CATEGORY
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.RiskOrderFieldCategory")
|
||||
TREATMENT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.RiskOrderFieldTreatment"
|
||||
)
|
||||
INHERENT_RISK_SCORE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.RiskOrderFieldInherentRiskScore"
|
||||
)
|
||||
RESIDUAL_RISK_SCORE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.RiskOrderFieldResidualRiskScore"
|
||||
)
|
||||
OWNER_FULL_NAME
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.RiskOrderFieldOwnerFullName"
|
||||
)
|
||||
}
|
||||
|
||||
input RiskOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.RiskOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: RiskOrderField!
|
||||
}
|
||||
|
||||
input RiskFilter {
|
||||
query: String
|
||||
snapshotId: ID
|
||||
}
|
||||
|
||||
type Risk implements Node {
|
||||
id: ID!
|
||||
snapshotId: ID
|
||||
name: String!
|
||||
description: String
|
||||
category: String!
|
||||
treatment: RiskTreatment!
|
||||
inherentLikelihood: Int!
|
||||
inherentImpact: Int!
|
||||
inherentRiskScore: Int!
|
||||
residualLikelihood: Int!
|
||||
residualImpact: Int!
|
||||
residualRiskScore: Int!
|
||||
note: String!
|
||||
|
||||
owner: Profile @goField(forceResolver: true)
|
||||
organization: Organization! @goField(forceResolver: true)
|
||||
|
||||
measures(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: MeasureOrder
|
||||
filter: MeasureFilter
|
||||
): MeasureConnection! @goField(forceResolver: true)
|
||||
|
||||
documents(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: DocumentOrder
|
||||
filter: DocumentFilter
|
||||
): DocumentConnection! @goField(forceResolver: true)
|
||||
|
||||
controls(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: ControlOrder
|
||||
filter: ControlFilter
|
||||
): ControlConnection! @goField(forceResolver: true)
|
||||
|
||||
obligations(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: ObligationOrder
|
||||
filter: ObligationFilter
|
||||
): ObligationConnection! @goField(forceResolver: true)
|
||||
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type RiskConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.RiskConnection"
|
||||
) {
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
edges: [RiskEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type RiskEdge {
|
||||
cursor: CursorKey!
|
||||
node: Risk!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
createRisk(input: CreateRiskInput!): CreateRiskPayload!
|
||||
updateRisk(input: UpdateRiskInput!): UpdateRiskPayload!
|
||||
deleteRisk(input: DeleteRiskInput!): DeleteRiskPayload!
|
||||
createRiskMeasureMapping(
|
||||
input: CreateRiskMeasureMappingInput!
|
||||
): CreateRiskMeasureMappingPayload!
|
||||
deleteRiskMeasureMapping(
|
||||
input: DeleteRiskMeasureMappingInput!
|
||||
): DeleteRiskMeasureMappingPayload!
|
||||
createRiskDocumentMapping(
|
||||
input: CreateRiskDocumentMappingInput!
|
||||
): CreateRiskDocumentMappingPayload!
|
||||
deleteRiskDocumentMapping(
|
||||
input: DeleteRiskDocumentMappingInput!
|
||||
): DeleteRiskDocumentMappingPayload!
|
||||
createRiskObligationMapping(
|
||||
input: CreateRiskObligationMappingInput!
|
||||
): CreateRiskObligationMappingPayload!
|
||||
deleteRiskObligationMapping(
|
||||
input: DeleteRiskObligationMappingInput!
|
||||
): DeleteRiskObligationMappingPayload!
|
||||
}
|
||||
|
||||
input CreateRiskInput {
|
||||
organizationId: ID!
|
||||
name: String!
|
||||
description: String
|
||||
category: String!
|
||||
ownerId: ID
|
||||
treatment: RiskTreatment!
|
||||
inherentLikelihood: Int!
|
||||
inherentImpact: Int!
|
||||
residualLikelihood: Int
|
||||
residualImpact: Int
|
||||
note: String
|
||||
}
|
||||
|
||||
input UpdateRiskInput {
|
||||
id: ID!
|
||||
name: String
|
||||
description: String @goField(omittable: true)
|
||||
category: String
|
||||
ownerId: ID @goField(omittable: true)
|
||||
treatment: RiskTreatment
|
||||
inherentLikelihood: Int
|
||||
inherentImpact: Int
|
||||
residualLikelihood: Int
|
||||
residualImpact: Int
|
||||
note: String
|
||||
}
|
||||
|
||||
input DeleteRiskInput {
|
||||
riskId: ID!
|
||||
}
|
||||
|
||||
input CreateRiskMeasureMappingInput {
|
||||
riskId: ID!
|
||||
measureId: ID!
|
||||
}
|
||||
|
||||
input DeleteRiskMeasureMappingInput {
|
||||
riskId: ID!
|
||||
measureId: ID!
|
||||
}
|
||||
|
||||
input CreateRiskDocumentMappingInput {
|
||||
riskId: ID!
|
||||
documentId: ID!
|
||||
}
|
||||
|
||||
input DeleteRiskDocumentMappingInput {
|
||||
riskId: ID!
|
||||
documentId: ID!
|
||||
}
|
||||
|
||||
input CreateRiskObligationMappingInput {
|
||||
riskId: ID!
|
||||
obligationId: ID!
|
||||
}
|
||||
|
||||
input DeleteRiskObligationMappingInput {
|
||||
riskId: ID!
|
||||
obligationId: ID!
|
||||
}
|
||||
|
||||
type CreateRiskPayload {
|
||||
riskEdge: RiskEdge!
|
||||
}
|
||||
|
||||
type UpdateRiskPayload {
|
||||
risk: Risk!
|
||||
}
|
||||
|
||||
type DeleteRiskPayload {
|
||||
deletedRiskId: ID!
|
||||
}
|
||||
|
||||
type CreateRiskMeasureMappingPayload {
|
||||
riskEdge: RiskEdge!
|
||||
measureEdge: MeasureEdge!
|
||||
}
|
||||
|
||||
type DeleteRiskMeasureMappingPayload {
|
||||
deletedMeasureId: ID!
|
||||
deletedRiskId: ID!
|
||||
}
|
||||
|
||||
type CreateRiskDocumentMappingPayload {
|
||||
riskEdge: RiskEdge!
|
||||
documentEdge: DocumentEdge!
|
||||
}
|
||||
|
||||
type DeleteRiskDocumentMappingPayload {
|
||||
deletedRiskId: ID!
|
||||
deletedDocumentId: ID!
|
||||
}
|
||||
|
||||
type CreateRiskObligationMappingPayload {
|
||||
riskEdge: RiskEdge!
|
||||
obligationEdge: ObligationEdge!
|
||||
}
|
||||
|
||||
type DeleteRiskObligationMappingPayload {
|
||||
deletedRiskId: ID!
|
||||
deletedObligationId: ID!
|
||||
}
|
||||
113
pkg/server/api/console/v1/graphql/snapshot.graphql
Normal file
113
pkg/server/api/console/v1/graphql/snapshot.graphql
Normal file
@@ -0,0 +1,113 @@
|
||||
extend type Organization {
|
||||
snapshots(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: SnapshotOrder
|
||||
): SnapshotConnection! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
enum SnapshotsType
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.SnapshotsType") {
|
||||
RISKS @goEnum(value: "go.probo.inc/probo/pkg/coredata.SnapshotsTypeRisks")
|
||||
VENDORS
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.SnapshotsTypeVendors")
|
||||
ASSETS @goEnum(value: "go.probo.inc/probo/pkg/coredata.SnapshotsTypeAssets")
|
||||
DATA @goEnum(value: "go.probo.inc/probo/pkg/coredata.SnapshotsTypeData")
|
||||
FINDINGS
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.SnapshotsTypeFindings"
|
||||
)
|
||||
OBLIGATIONS
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.SnapshotsTypeObligations"
|
||||
)
|
||||
PROCESSING_ACTIVITIES
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.SnapshotsTypeProcessingActivities"
|
||||
)
|
||||
STATEMENTS_OF_APPLICABILITY
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.SnapshotsTypeStatementsOfApplicability"
|
||||
)
|
||||
}
|
||||
|
||||
enum SnapshotOrderField
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.SnapshotOrderField") {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.SnapshotOrderFieldCreatedAt"
|
||||
)
|
||||
NAME
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.SnapshotOrderFieldName")
|
||||
TYPE
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.SnapshotOrderFieldType")
|
||||
}
|
||||
|
||||
input SnapshotOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.SnapshotOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: SnapshotOrderField!
|
||||
}
|
||||
|
||||
type Snapshot implements Node {
|
||||
id: ID!
|
||||
organization: Organization! @goField(forceResolver: true)
|
||||
name: String!
|
||||
description: String
|
||||
type: SnapshotsType!
|
||||
|
||||
controls(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: ControlOrder
|
||||
filter: ControlFilter
|
||||
): ControlConnection! @goField(forceResolver: true)
|
||||
|
||||
createdAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type SnapshotConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.SnapshotConnection"
|
||||
) {
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
edges: [SnapshotEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type SnapshotEdge {
|
||||
cursor: CursorKey!
|
||||
node: Snapshot!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
createSnapshot(input: CreateSnapshotInput!): CreateSnapshotPayload!
|
||||
deleteSnapshot(input: DeleteSnapshotInput!): DeleteSnapshotPayload!
|
||||
}
|
||||
|
||||
input CreateSnapshotInput {
|
||||
organizationId: ID!
|
||||
name: String!
|
||||
description: String
|
||||
type: SnapshotsType!
|
||||
}
|
||||
|
||||
input DeleteSnapshotInput {
|
||||
snapshotId: ID!
|
||||
}
|
||||
|
||||
type CreateSnapshotPayload {
|
||||
snapshotEdge: SnapshotEdge!
|
||||
}
|
||||
|
||||
type DeleteSnapshotPayload {
|
||||
deletedSnapshotId: ID!
|
||||
}
|
||||
137
pkg/server/api/console/v1/graphql/task.graphql
Normal file
137
pkg/server/api/console/v1/graphql/task.graphql
Normal file
@@ -0,0 +1,137 @@
|
||||
extend type Organization {
|
||||
tasks(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: TaskOrder
|
||||
): TaskConnection! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
enum TaskState @goModel(model: "go.probo.inc/probo/pkg/coredata.TaskState") {
|
||||
TODO @goEnum(value: "go.probo.inc/probo/pkg/coredata.TaskStateTodo")
|
||||
IN_PROGRESS @goEnum(value: "go.probo.inc/probo/pkg/coredata.TaskStateInProgress")
|
||||
DONE @goEnum(value: "go.probo.inc/probo/pkg/coredata.TaskStateDone")
|
||||
}
|
||||
|
||||
enum TaskPriority
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.TaskPriority") {
|
||||
URGENT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.TaskPriorityUrgent"
|
||||
)
|
||||
HIGH
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.TaskPriorityHigh"
|
||||
)
|
||||
MEDIUM
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.TaskPriorityMedium"
|
||||
)
|
||||
LOW
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.TaskPriorityLow"
|
||||
)
|
||||
}
|
||||
|
||||
enum TaskOrderField
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.TaskOrderField") {
|
||||
PRIORITY_RANK
|
||||
CREATED_AT
|
||||
}
|
||||
|
||||
input TaskOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.TaskOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: TaskOrderField!
|
||||
}
|
||||
|
||||
type Task implements Node {
|
||||
id: ID!
|
||||
name: String!
|
||||
description: String
|
||||
state: TaskState!
|
||||
priority: TaskPriority!
|
||||
rank: Int!
|
||||
timeEstimate: Duration
|
||||
deadline: Datetime
|
||||
assignedTo: Profile @goField(forceResolver: true)
|
||||
|
||||
organization: Organization! @goField(forceResolver: true)
|
||||
measure: Measure @goField(forceResolver: true)
|
||||
|
||||
evidences(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: EvidenceOrder
|
||||
): EvidenceConnection! @goField(forceResolver: true)
|
||||
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type TaskConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.TaskConnection"
|
||||
) {
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
edges: [TaskEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type TaskEdge {
|
||||
cursor: CursorKey!
|
||||
node: Task!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
createTask(input: CreateTaskInput!): CreateTaskPayload!
|
||||
updateTask(input: UpdateTaskInput!): UpdateTaskPayload!
|
||||
deleteTask(input: DeleteTaskInput!): DeleteTaskPayload!
|
||||
}
|
||||
|
||||
input CreateTaskInput {
|
||||
organizationId: ID!
|
||||
measureId: ID
|
||||
name: String!
|
||||
description: String
|
||||
priority: TaskPriority!
|
||||
timeEstimate: Duration
|
||||
assignedToId: ID
|
||||
deadline: Datetime
|
||||
}
|
||||
|
||||
input UpdateTaskInput {
|
||||
taskId: ID!
|
||||
name: String
|
||||
description: String @goField(omittable: true)
|
||||
state: TaskState
|
||||
priority: TaskPriority
|
||||
rank: Int
|
||||
timeEstimate: Duration @goField(omittable: true)
|
||||
deadline: Datetime @goField(omittable: true)
|
||||
assignedToId: ID @goField(omittable: true)
|
||||
measureId: ID @goField(omittable: true)
|
||||
}
|
||||
|
||||
input DeleteTaskInput {
|
||||
taskId: ID!
|
||||
}
|
||||
|
||||
type CreateTaskPayload {
|
||||
taskEdge: TaskEdge!
|
||||
}
|
||||
|
||||
type UpdateTaskPayload {
|
||||
task: Task!
|
||||
}
|
||||
|
||||
type DeleteTaskPayload {
|
||||
deletedTaskId: ID!
|
||||
}
|
||||
771
pkg/server/api/console/v1/graphql/trust_center.graphql
Normal file
771
pkg/server/api/console/v1/graphql/trust_center.graphql
Normal file
@@ -0,0 +1,771 @@
|
||||
extend type Organization {
|
||||
trustCenter: TrustCenter @goField(forceResolver: true)
|
||||
customDomain: CustomDomain @goField(forceResolver: true)
|
||||
trustCenterFiles(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: TrustCenterFileOrder
|
||||
): TrustCenterFileConnection! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
enum TrustCenterVisibility
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.TrustCenterVisibility") {
|
||||
NONE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.TrustCenterVisibilityNone"
|
||||
)
|
||||
PRIVATE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.TrustCenterVisibilityPrivate"
|
||||
)
|
||||
PUBLIC
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.TrustCenterVisibilityPublic"
|
||||
)
|
||||
}
|
||||
|
||||
enum SearchEngineIndexing
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.SearchEngineIndexing"
|
||||
) {
|
||||
INDEXABLE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.SearchEngineIndexingIndexable"
|
||||
)
|
||||
NOT_INDEXABLE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.SearchEngineIndexingNotIndexable"
|
||||
)
|
||||
}
|
||||
|
||||
enum TrustCenterDocumentAccessStatus
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.TrustCenterDocumentAccessStatus"
|
||||
) {
|
||||
REQUESTED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.TrustCenterDocumentAccessStatusRequested"
|
||||
)
|
||||
GRANTED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.TrustCenterDocumentAccessStatusGranted"
|
||||
)
|
||||
REJECTED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.TrustCenterDocumentAccessStatusRejected"
|
||||
)
|
||||
REVOKED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.TrustCenterDocumentAccessStatusRevoked"
|
||||
)
|
||||
}
|
||||
|
||||
enum TrustCenterAccessOrderField
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.TrustCenterAccessOrderField"
|
||||
) {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.TrustCenterAccessOrderFieldCreatedAt"
|
||||
)
|
||||
}
|
||||
|
||||
enum TrustCenterAccessState
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.TrustCenterAccessState"
|
||||
) {
|
||||
ACTIVE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.TrustCenterAccessStateActive"
|
||||
)
|
||||
INACTIVE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.TrustCenterAccessStateInactive"
|
||||
)
|
||||
}
|
||||
|
||||
enum TrustCenterDocumentAccessOrderField
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.TrustCenterDocumentAccessOrderField"
|
||||
) {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.TrustCenterDocumentAccessOrderFieldCreatedAt"
|
||||
)
|
||||
}
|
||||
|
||||
enum TrustCenterReferenceOrderField
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.TrustCenterReferenceOrderField"
|
||||
) {
|
||||
RANK
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.TrustCenterReferenceOrderFieldRank"
|
||||
)
|
||||
NAME
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.TrustCenterReferenceOrderFieldName"
|
||||
)
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.TrustCenterReferenceOrderFieldCreatedAt"
|
||||
)
|
||||
UPDATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.TrustCenterReferenceOrderFieldUpdatedAt"
|
||||
)
|
||||
}
|
||||
|
||||
enum ComplianceExternalURLOrderField
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.ComplianceExternalURLOrderField"
|
||||
) {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ComplianceExternalURLOrderFieldCreatedAt"
|
||||
)
|
||||
RANK
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ComplianceExternalURLOrderFieldRank"
|
||||
)
|
||||
}
|
||||
|
||||
enum ComplianceFrameworkOrderField
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.ComplianceFrameworkOrderField"
|
||||
) {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ComplianceFrameworkOrderFieldCreatedAt"
|
||||
)
|
||||
RANK
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ComplianceFrameworkOrderFieldRank"
|
||||
)
|
||||
}
|
||||
|
||||
enum ComplianceFrameworkVisibility
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.ComplianceFrameworkVisibility"
|
||||
) {
|
||||
NONE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ComplianceFrameworkVisibilityNone"
|
||||
)
|
||||
PUBLIC
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ComplianceFrameworkVisibilityPublic"
|
||||
)
|
||||
}
|
||||
|
||||
enum TrustCenterFileOrderField
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.TrustCenterFileOrderField"
|
||||
) {
|
||||
NAME
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.TrustCenterFileOrderFieldName"
|
||||
)
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.TrustCenterFileOrderFieldCreatedAt"
|
||||
)
|
||||
UPDATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.TrustCenterFileOrderFieldUpdatedAt"
|
||||
)
|
||||
}
|
||||
|
||||
enum SSLStatus
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.CustomDomainSSLStatus") {
|
||||
PENDING
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.CustomDomainSSLStatusPending"
|
||||
)
|
||||
PROVISIONING
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.CustomDomainSSLStatusProvisioning"
|
||||
)
|
||||
ACTIVE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.CustomDomainSSLStatusActive"
|
||||
)
|
||||
RENEWING
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.CustomDomainSSLStatusRenewing"
|
||||
)
|
||||
EXPIRED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.CustomDomainSSLStatusExpired"
|
||||
)
|
||||
FAILED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.CustomDomainSSLStatusFailed"
|
||||
)
|
||||
}
|
||||
|
||||
input TrustCenterAccessOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.TrustCenterAccessOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: TrustCenterAccessOrderField!
|
||||
}
|
||||
|
||||
input TrustCenterDocumentAccessOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.TrustCenterDocumentAccessOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: TrustCenterDocumentAccessOrderField!
|
||||
}
|
||||
|
||||
input TrustCenterReferenceOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.TrustCenterReferenceOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: TrustCenterReferenceOrderField!
|
||||
}
|
||||
|
||||
input TrustCenterFileOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.TrustCenterFileOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: TrustCenterFileOrderField!
|
||||
}
|
||||
|
||||
input ComplianceExternalURLOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.ComplianceExternalURLOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: ComplianceExternalURLOrderField!
|
||||
}
|
||||
|
||||
input ComplianceFrameworkOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.ComplianceFrameworkOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: ComplianceFrameworkOrderField!
|
||||
}
|
||||
|
||||
type TrustCenter implements Node
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.TrustCenter"
|
||||
) {
|
||||
id: ID!
|
||||
active: Boolean!
|
||||
searchEngineIndexing: SearchEngineIndexing!
|
||||
logoFileUrl: String @goField(forceResolver: true)
|
||||
darkLogoFileUrl: String @goField(forceResolver: true)
|
||||
ndaFileName: String
|
||||
ndaFileUrl: String @goField(forceResolver: true)
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
organization: Organization! @goField(forceResolver: true)
|
||||
|
||||
accesses(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: TrustCenterAccessOrder
|
||||
): TrustCenterAccessConnection! @goField(forceResolver: true)
|
||||
|
||||
references(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: TrustCenterReferenceOrder
|
||||
): TrustCenterReferenceConnection! @goField(forceResolver: true)
|
||||
|
||||
complianceFrameworks(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: ComplianceFrameworkOrder
|
||||
): ComplianceFrameworkConnection! @goField(forceResolver: true)
|
||||
|
||||
externalUrls(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: ComplianceExternalURLOrder
|
||||
): ComplianceExternalURLConnection! @goField(forceResolver: true)
|
||||
|
||||
mailingList: MailingList @goField(forceResolver: true)
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type TrustCenterConnection {
|
||||
edges: [TrustCenterEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type TrustCenterEdge {
|
||||
cursor: CursorKey!
|
||||
node: TrustCenter!
|
||||
}
|
||||
|
||||
type TrustCenterAccess implements Node {
|
||||
id: ID!
|
||||
ndaSignature: ElectronicSignature @goField(forceResolver: true)
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
pendingRequestCount: Int! @goField(forceResolver: true)
|
||||
activeCount: Int! @goField(forceResolver: true)
|
||||
organizationId: ID!
|
||||
identityID: ID!
|
||||
|
||||
profile: Profile! @goField(forceResolver: true)
|
||||
|
||||
availableDocumentAccesses(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: TrustCenterDocumentAccessOrder
|
||||
): TrustCenterDocumentAccessConnection! @goField(forceResolver: true)
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type TrustCenterDocumentAccess
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.TrustCenterDocumentAccess"
|
||||
) {
|
||||
id: ID!
|
||||
status: TrustCenterDocumentAccessStatus!
|
||||
document: Document @goField(forceResolver: true)
|
||||
report: Report @goField(forceResolver: true)
|
||||
trustCenterFile: TrustCenterFile @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type TrustCenterDocumentAccessConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.TrustCenterDocumentAccessConnection"
|
||||
) {
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
edges: [TrustCenterDocumentAccessEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type TrustCenterDocumentAccessEdge {
|
||||
cursor: CursorKey!
|
||||
node: TrustCenterDocumentAccess!
|
||||
}
|
||||
|
||||
type TrustCenterAccessConnection {
|
||||
edges: [TrustCenterAccessEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type TrustCenterAccessEdge {
|
||||
cursor: CursorKey!
|
||||
node: TrustCenterAccess!
|
||||
}
|
||||
|
||||
type TrustCenterReference implements Node {
|
||||
id: ID!
|
||||
name: String!
|
||||
description: String
|
||||
websiteUrl: String!
|
||||
logoUrl: String! @goField(forceResolver: true)
|
||||
rank: Int!
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type TrustCenterReferenceConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.TrustCenterReferenceConnection"
|
||||
) {
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
edges: [TrustCenterReferenceEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type TrustCenterReferenceEdge {
|
||||
cursor: CursorKey!
|
||||
node: TrustCenterReference!
|
||||
}
|
||||
|
||||
type ComplianceFramework implements Node
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.ComplianceFramework"
|
||||
) {
|
||||
id: ID!
|
||||
framework: Framework! @goField(forceResolver: true)
|
||||
rank: Int!
|
||||
visibility: ComplianceFrameworkVisibility!
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
}
|
||||
|
||||
type ComplianceFrameworkConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.ComplianceFrameworkConnection"
|
||||
) {
|
||||
edges: [ComplianceFrameworkEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type ComplianceFrameworkEdge {
|
||||
cursor: CursorKey!
|
||||
node: ComplianceFramework!
|
||||
}
|
||||
|
||||
type ComplianceExternalURL implements Node {
|
||||
id: ID!
|
||||
name: String!
|
||||
url: String!
|
||||
rank: Int!
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type ComplianceExternalURLConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.ComplianceExternalURLConnection"
|
||||
) {
|
||||
edges: [ComplianceExternalURLEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type ComplianceExternalURLEdge {
|
||||
cursor: CursorKey!
|
||||
node: ComplianceExternalURL!
|
||||
}
|
||||
|
||||
type TrustCenterFile implements Node {
|
||||
id: ID!
|
||||
name: String!
|
||||
category: String!
|
||||
fileUrl: String! @goField(forceResolver: true)
|
||||
trustCenterVisibility: TrustCenterVisibility!
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
organization: Organization! @goField(forceResolver: true)
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type TrustCenterFileConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.TrustCenterFileConnection"
|
||||
) {
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
edges: [TrustCenterFileEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type TrustCenterFileEdge {
|
||||
cursor: CursorKey!
|
||||
node: TrustCenterFile!
|
||||
}
|
||||
|
||||
type CustomDomain implements Node {
|
||||
id: ID!
|
||||
organization: Organization!
|
||||
domain: String!
|
||||
sslStatus: SSLStatus!
|
||||
sslExpiresAt: Datetime
|
||||
dnsRecords: [DNSRecordInstruction!]!
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type DNSRecordInstruction {
|
||||
type: String!
|
||||
name: String!
|
||||
value: String!
|
||||
ttl: Int!
|
||||
purpose: String!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
updateTrustCenter(input: UpdateTrustCenterInput!): UpdateTrustCenterPayload!
|
||||
uploadTrustCenterNDA(
|
||||
input: UploadTrustCenterNDAInput!
|
||||
): UploadTrustCenterNDAPayload!
|
||||
deleteTrustCenterNDA(
|
||||
input: DeleteTrustCenterNDAInput!
|
||||
): DeleteTrustCenterNDAPayload!
|
||||
updateTrustCenterBrand(
|
||||
input: UpdateTrustCenterBrandInput!
|
||||
): UpdateTrustCenterBrandPayload!
|
||||
updateTrustCenterAccess(
|
||||
input: UpdateTrustCenterAccessInput!
|
||||
): UpdateTrustCenterAccessPayload!
|
||||
deleteTrustCenterAccess(
|
||||
input: DeleteTrustCenterAccessInput!
|
||||
): DeleteTrustCenterAccessPayload!
|
||||
createTrustCenterReference(
|
||||
input: CreateTrustCenterReferenceInput!
|
||||
): CreateTrustCenterReferencePayload!
|
||||
updateTrustCenterReference(
|
||||
input: UpdateTrustCenterReferenceInput!
|
||||
): UpdateTrustCenterReferencePayload!
|
||||
deleteTrustCenterReference(
|
||||
input: DeleteTrustCenterReferenceInput!
|
||||
): DeleteTrustCenterReferencePayload!
|
||||
createComplianceFramework(
|
||||
input: CreateComplianceFrameworkInput!
|
||||
): CreateComplianceFrameworkPayload!
|
||||
updateComplianceFramework(
|
||||
input: UpdateComplianceFrameworkInput!
|
||||
): UpdateComplianceFrameworkPayload!
|
||||
deleteComplianceFramework(
|
||||
input: DeleteComplianceFrameworkInput!
|
||||
): DeleteComplianceFrameworkPayload!
|
||||
createComplianceExternalURL(
|
||||
input: CreateComplianceExternalURLInput!
|
||||
): CreateComplianceExternalURLPayload!
|
||||
updateComplianceExternalURL(
|
||||
input: UpdateComplianceExternalURLInput!
|
||||
): UpdateComplianceExternalURLPayload!
|
||||
deleteComplianceExternalURL(
|
||||
input: DeleteComplianceExternalURLInput!
|
||||
): DeleteComplianceExternalURLPayload!
|
||||
createTrustCenterFile(
|
||||
input: CreateTrustCenterFileInput!
|
||||
): CreateTrustCenterFilePayload!
|
||||
updateTrustCenterFile(
|
||||
input: UpdateTrustCenterFileInput!
|
||||
): UpdateTrustCenterFilePayload!
|
||||
getTrustCenterFile(
|
||||
input: GetTrustCenterFileInput!
|
||||
): GetTrustCenterFilePayload!
|
||||
deleteTrustCenterFile(
|
||||
input: DeleteTrustCenterFileInput!
|
||||
): DeleteTrustCenterFilePayload!
|
||||
createCustomDomain(
|
||||
input: CreateCustomDomainInput!
|
||||
): CreateCustomDomainPayload!
|
||||
deleteCustomDomain(
|
||||
input: DeleteCustomDomainInput!
|
||||
): DeleteCustomDomainPayload!
|
||||
}
|
||||
|
||||
input UpdateTrustCenterInput {
|
||||
trustCenterId: ID!
|
||||
active: Boolean
|
||||
searchEngineIndexing: SearchEngineIndexing
|
||||
}
|
||||
|
||||
input UploadTrustCenterNDAInput {
|
||||
trustCenterId: ID!
|
||||
fileName: String!
|
||||
file: Upload!
|
||||
}
|
||||
|
||||
input DeleteTrustCenterNDAInput {
|
||||
trustCenterId: ID!
|
||||
}
|
||||
|
||||
input UpdateTrustCenterBrandInput {
|
||||
trustCenterId: ID!
|
||||
logoFile: Upload @goField(omittable: true)
|
||||
darkLogoFile: Upload @goField(omittable: true)
|
||||
}
|
||||
|
||||
input TrustCenterDocumentAccessInput {
|
||||
id: ID!
|
||||
status: TrustCenterDocumentAccessStatus!
|
||||
}
|
||||
|
||||
input UpdateTrustCenterAccessInput {
|
||||
id: ID!
|
||||
name: String
|
||||
state: TrustCenterAccessState
|
||||
documents: [TrustCenterDocumentAccessInput!]
|
||||
reports: [TrustCenterDocumentAccessInput!]
|
||||
trustCenterFiles: [TrustCenterDocumentAccessInput!]
|
||||
}
|
||||
|
||||
input DeleteTrustCenterAccessInput {
|
||||
id: ID!
|
||||
}
|
||||
|
||||
input CreateTrustCenterReferenceInput {
|
||||
trustCenterId: ID!
|
||||
name: String!
|
||||
description: String
|
||||
websiteUrl: String!
|
||||
logoFile: Upload!
|
||||
}
|
||||
|
||||
input UpdateTrustCenterReferenceInput {
|
||||
id: ID!
|
||||
name: String
|
||||
description: String @goField(omittable: true)
|
||||
websiteUrl: String
|
||||
logoFile: Upload
|
||||
rank: Int
|
||||
}
|
||||
|
||||
input DeleteTrustCenterReferenceInput {
|
||||
id: ID!
|
||||
}
|
||||
|
||||
input CreateComplianceFrameworkInput {
|
||||
trustCenterId: ID!
|
||||
frameworkId: ID!
|
||||
}
|
||||
|
||||
input UpdateComplianceFrameworkInput {
|
||||
id: ID!
|
||||
rank: Int!
|
||||
}
|
||||
|
||||
input DeleteComplianceFrameworkInput {
|
||||
id: ID!
|
||||
}
|
||||
|
||||
input CreateComplianceExternalURLInput {
|
||||
trustCenterId: ID!
|
||||
name: String!
|
||||
url: String!
|
||||
}
|
||||
|
||||
input UpdateComplianceExternalURLInput {
|
||||
id: ID!
|
||||
name: String!
|
||||
url: String!
|
||||
rank: Int
|
||||
}
|
||||
|
||||
input DeleteComplianceExternalURLInput {
|
||||
id: ID!
|
||||
}
|
||||
|
||||
input CreateTrustCenterFileInput {
|
||||
organizationId: ID!
|
||||
name: String!
|
||||
category: String!
|
||||
file: Upload!
|
||||
trustCenterVisibility: TrustCenterVisibility!
|
||||
}
|
||||
|
||||
input UpdateTrustCenterFileInput {
|
||||
id: ID!
|
||||
name: String
|
||||
category: String
|
||||
trustCenterVisibility: TrustCenterVisibility
|
||||
}
|
||||
|
||||
input GetTrustCenterFileInput {
|
||||
id: ID!
|
||||
}
|
||||
|
||||
input DeleteTrustCenterFileInput {
|
||||
id: ID!
|
||||
}
|
||||
|
||||
input CreateCustomDomainInput {
|
||||
organizationId: ID!
|
||||
domain: String!
|
||||
}
|
||||
|
||||
input DeleteCustomDomainInput {
|
||||
organizationId: ID!
|
||||
}
|
||||
|
||||
type UpdateTrustCenterPayload {
|
||||
trustCenter: TrustCenter!
|
||||
}
|
||||
|
||||
type UploadTrustCenterNDAPayload {
|
||||
trustCenter: TrustCenter!
|
||||
}
|
||||
|
||||
type DeleteTrustCenterNDAPayload {
|
||||
trustCenter: TrustCenter!
|
||||
}
|
||||
|
||||
type UpdateTrustCenterBrandPayload {
|
||||
trustCenter: TrustCenter!
|
||||
}
|
||||
|
||||
type UpdateTrustCenterAccessPayload {
|
||||
trustCenterAccess: TrustCenterAccess!
|
||||
}
|
||||
|
||||
type DeleteTrustCenterAccessPayload {
|
||||
deletedTrustCenterAccessId: ID!
|
||||
}
|
||||
|
||||
type CreateTrustCenterReferencePayload {
|
||||
trustCenterReferenceEdge: TrustCenterReferenceEdge!
|
||||
}
|
||||
|
||||
type UpdateTrustCenterReferencePayload {
|
||||
trustCenterReference: TrustCenterReference!
|
||||
}
|
||||
|
||||
type DeleteTrustCenterReferencePayload {
|
||||
deletedTrustCenterReferenceId: ID!
|
||||
}
|
||||
|
||||
type CreateComplianceFrameworkPayload {
|
||||
complianceFrameworkEdge: ComplianceFrameworkEdge!
|
||||
}
|
||||
|
||||
type UpdateComplianceFrameworkPayload {
|
||||
complianceFramework: ComplianceFramework!
|
||||
}
|
||||
|
||||
type DeleteComplianceFrameworkPayload {
|
||||
deletedComplianceFrameworkId: ID!
|
||||
}
|
||||
|
||||
type CreateComplianceExternalURLPayload {
|
||||
complianceExternalUrlEdge: ComplianceExternalURLEdge!
|
||||
}
|
||||
|
||||
type UpdateComplianceExternalURLPayload {
|
||||
complianceExternalUrl: ComplianceExternalURL!
|
||||
}
|
||||
|
||||
type DeleteComplianceExternalURLPayload {
|
||||
deletedComplianceExternalUrlId: ID!
|
||||
}
|
||||
|
||||
type CreateTrustCenterFilePayload {
|
||||
trustCenterFileEdge: TrustCenterFileEdge!
|
||||
}
|
||||
|
||||
type UpdateTrustCenterFilePayload {
|
||||
trustCenterFile: TrustCenterFile!
|
||||
}
|
||||
|
||||
type GetTrustCenterFilePayload {
|
||||
trustCenterFile: TrustCenterFile!
|
||||
}
|
||||
|
||||
type DeleteTrustCenterFilePayload {
|
||||
deletedTrustCenterFileId: ID!
|
||||
}
|
||||
|
||||
type CreateCustomDomainPayload {
|
||||
customDomain: CustomDomain!
|
||||
}
|
||||
|
||||
type DeleteCustomDomainPayload {
|
||||
deletedCustomDomainId: ID!
|
||||
}
|
||||
704
pkg/server/api/console/v1/graphql/vendor.graphql
Normal file
704
pkg/server/api/console/v1/graphql/vendor.graphql
Normal file
@@ -0,0 +1,704 @@
|
||||
extend type Organization {
|
||||
vendors(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: VendorOrder
|
||||
filter: VendorFilter = { snapshotId: null }
|
||||
): VendorConnection! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
enum VendorCategory
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.VendorCategory") {
|
||||
ANALYTICS
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryAnalytics"
|
||||
)
|
||||
CLOUD_MONITORING
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryCloudMonitoring"
|
||||
)
|
||||
CLOUD_PROVIDER
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryCloudProvider"
|
||||
)
|
||||
COLLABORATION
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryCollaboration"
|
||||
)
|
||||
CUSTOMER_SUPPORT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryCustomerSupport"
|
||||
)
|
||||
DATA_STORAGE_AND_PROCESSING
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryDataStorageAndProcessing"
|
||||
)
|
||||
DOCUMENT_MANAGEMENT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryDocumentManagement"
|
||||
)
|
||||
EMPLOYEE_MANAGEMENT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryEmployeeManagement"
|
||||
)
|
||||
ENGINEERING
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryEngineering"
|
||||
)
|
||||
FINANCE
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.VendorCategoryFinance")
|
||||
IDENTITY_PROVIDER
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryIdentityProvider"
|
||||
)
|
||||
IT @goEnum(value: "go.probo.inc/probo/pkg/coredata.VendorCategoryIT")
|
||||
MARKETING
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryMarketing"
|
||||
)
|
||||
OFFICE_OPERATIONS
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryOfficeOperations"
|
||||
)
|
||||
OTHER @goEnum(value: "go.probo.inc/probo/pkg/coredata.VendorCategoryOther")
|
||||
PASSWORD_MANAGEMENT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryPasswordManagement"
|
||||
)
|
||||
PRODUCT_AND_DESIGN
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryProductAndDesign"
|
||||
)
|
||||
PROFESSIONAL_SERVICES
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryProfessionalServices"
|
||||
)
|
||||
RECRUITING
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryRecruiting"
|
||||
)
|
||||
SALES @goEnum(value: "go.probo.inc/probo/pkg/coredata.VendorCategorySales")
|
||||
SECURITY
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.VendorCategorySecurity")
|
||||
VERSION_CONTROL
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryVersionControl"
|
||||
)
|
||||
}
|
||||
|
||||
enum DataSensitivity
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.DataSensitivity") {
|
||||
NONE @goEnum(value: "go.probo.inc/probo/pkg/coredata.DataSensitivityNone")
|
||||
LOW @goEnum(value: "go.probo.inc/probo/pkg/coredata.DataSensitivityLow")
|
||||
MEDIUM
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.DataSensitivityMedium")
|
||||
HIGH @goEnum(value: "go.probo.inc/probo/pkg/coredata.DataSensitivityHigh")
|
||||
CRITICAL
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DataSensitivityCritical"
|
||||
)
|
||||
}
|
||||
|
||||
enum BusinessImpact
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.BusinessImpact") {
|
||||
LOW @goEnum(value: "go.probo.inc/probo/pkg/coredata.BusinessImpactLow")
|
||||
MEDIUM
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.BusinessImpactMedium")
|
||||
HIGH @goEnum(value: "go.probo.inc/probo/pkg/coredata.BusinessImpactHigh")
|
||||
CRITICAL
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.BusinessImpactCritical")
|
||||
}
|
||||
|
||||
enum VendorOrderField
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.VendorOrderField") {
|
||||
NAME @goEnum(value: "go.probo.inc/probo/pkg/coredata.VendorOrderFieldName")
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorOrderFieldCreatedAt"
|
||||
)
|
||||
UPDATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorOrderFieldUpdatedAt"
|
||||
)
|
||||
}
|
||||
|
||||
enum VendorComplianceReportOrderField
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.VendorComplianceReportOrderField"
|
||||
) {
|
||||
REPORT_DATE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorComplianceReportOrderFieldReportDate"
|
||||
)
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorComplianceReportOrderFieldCreatedAt"
|
||||
)
|
||||
}
|
||||
|
||||
enum VendorContactOrderField
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.VendorContactOrderField") {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorContactOrderFieldCreatedAt"
|
||||
)
|
||||
FULL_NAME
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorContactOrderFieldFullName"
|
||||
)
|
||||
EMAIL
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorContactOrderFieldEmail"
|
||||
)
|
||||
}
|
||||
|
||||
enum VendorServiceOrderField
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.VendorServiceOrderField") {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorServiceOrderFieldCreatedAt"
|
||||
)
|
||||
NAME
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorServiceOrderFieldName"
|
||||
)
|
||||
}
|
||||
|
||||
enum VendorRiskAssessmentOrderField
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.VendorRiskAssessmentOrderField"
|
||||
) {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorRiskAssessmentOrderFieldCreatedAt"
|
||||
)
|
||||
EXPIRES_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorRiskAssessmentOrderFieldExpiresAt"
|
||||
)
|
||||
}
|
||||
|
||||
input VendorOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.VendorOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: VendorOrderField!
|
||||
}
|
||||
|
||||
input VendorComplianceReportOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.VendorComplianceReportOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: VendorComplianceReportOrderField!
|
||||
}
|
||||
|
||||
input VendorContactOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.VendorContactOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: VendorContactOrderField!
|
||||
}
|
||||
|
||||
input VendorServiceOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.VendorServiceOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: VendorServiceOrderField!
|
||||
}
|
||||
|
||||
input VendorRiskAssessmentOrder {
|
||||
field: VendorRiskAssessmentOrderField!
|
||||
direction: OrderDirection!
|
||||
}
|
||||
|
||||
input VendorFilter {
|
||||
snapshotId: ID
|
||||
}
|
||||
|
||||
type Vendor implements Node {
|
||||
id: ID!
|
||||
snapshotId: ID
|
||||
name: String!
|
||||
category: VendorCategory!
|
||||
description: String
|
||||
|
||||
organization: Organization! @goField(forceResolver: true)
|
||||
|
||||
complianceReports(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: VendorComplianceReportOrder
|
||||
): VendorComplianceReportConnection! @goField(forceResolver: true)
|
||||
|
||||
businessAssociateAgreement: VendorBusinessAssociateAgreement
|
||||
@goField(forceResolver: true)
|
||||
dataPrivacyAgreement: VendorDataPrivacyAgreement
|
||||
@goField(forceResolver: true)
|
||||
|
||||
contacts(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: VendorContactOrder
|
||||
): VendorContactConnection! @goField(forceResolver: true)
|
||||
|
||||
services(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: VendorServiceOrder
|
||||
): VendorServiceConnection! @goField(forceResolver: true)
|
||||
|
||||
riskAssessments(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: VendorRiskAssessmentOrder
|
||||
): VendorRiskAssessmentConnection! @goField(forceResolver: true)
|
||||
|
||||
businessOwner: Profile @goField(forceResolver: true)
|
||||
securityOwner: Profile @goField(forceResolver: true)
|
||||
|
||||
statusPageUrl: String
|
||||
termsOfServiceUrl: String
|
||||
privacyPolicyUrl: String
|
||||
serviceLevelAgreementUrl: String
|
||||
dataProcessingAgreementUrl: String
|
||||
businessAssociateAgreementUrl: String
|
||||
subprocessorsListUrl: String
|
||||
certifications: [String!]!
|
||||
countries: [CountryCode!]!
|
||||
securityPageUrl: String
|
||||
trustPageUrl: String
|
||||
headquarterAddress: String
|
||||
legalName: String
|
||||
websiteUrl: String
|
||||
showOnTrustCenter: Boolean!
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type VendorComplianceReport implements Node {
|
||||
id: ID!
|
||||
vendor: Vendor! @goField(forceResolver: true)
|
||||
reportDate: Datetime!
|
||||
validUntil: Datetime
|
||||
reportName: String!
|
||||
file: File @goField(forceResolver: true)
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type VendorBusinessAssociateAgreement implements Node {
|
||||
id: ID!
|
||||
vendor: Vendor! @goField(forceResolver: true)
|
||||
validFrom: Datetime
|
||||
validUntil: Datetime
|
||||
fileName: String!
|
||||
fileUrl: String! @goField(forceResolver: true)
|
||||
fileSize: BigInt!
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type VendorContact implements Node {
|
||||
id: ID!
|
||||
vendor: Vendor! @goField(forceResolver: true)
|
||||
fullName: String
|
||||
email: EmailAddr
|
||||
phone: String
|
||||
role: String
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type VendorService implements Node {
|
||||
id: ID!
|
||||
vendor: Vendor! @goField(forceResolver: true)
|
||||
name: String!
|
||||
description: String
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type VendorDataPrivacyAgreement implements Node {
|
||||
id: ID!
|
||||
vendor: Vendor! @goField(forceResolver: true)
|
||||
validFrom: Datetime
|
||||
validUntil: Datetime
|
||||
fileName: String!
|
||||
fileUrl: String! @goField(forceResolver: true)
|
||||
fileSize: BigInt!
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type VendorRiskAssessment implements Node {
|
||||
id: ID!
|
||||
vendor: Vendor! @goField(forceResolver: true)
|
||||
expiresAt: Datetime!
|
||||
dataSensitivity: DataSensitivity!
|
||||
businessImpact: BusinessImpact!
|
||||
notes: String
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type VendorConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.VendorConnection"
|
||||
) {
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
edges: [VendorEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type VendorEdge {
|
||||
cursor: CursorKey!
|
||||
node: Vendor!
|
||||
}
|
||||
|
||||
type VendorComplianceReportConnection {
|
||||
edges: [VendorComplianceReportEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type VendorComplianceReportEdge {
|
||||
cursor: CursorKey!
|
||||
node: VendorComplianceReport!
|
||||
}
|
||||
|
||||
type VendorContactConnection {
|
||||
edges: [VendorContactEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type VendorContactEdge {
|
||||
cursor: CursorKey!
|
||||
node: VendorContact!
|
||||
}
|
||||
|
||||
type VendorServiceConnection {
|
||||
edges: [VendorServiceEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type VendorServiceEdge {
|
||||
cursor: CursorKey!
|
||||
node: VendorService!
|
||||
}
|
||||
|
||||
type VendorRiskAssessmentConnection {
|
||||
edges: [VendorRiskAssessmentEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type VendorRiskAssessmentEdge {
|
||||
cursor: CursorKey!
|
||||
node: VendorRiskAssessment!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
createVendor(input: CreateVendorInput!): CreateVendorPayload!
|
||||
updateVendor(input: UpdateVendorInput!): UpdateVendorPayload!
|
||||
deleteVendor(input: DeleteVendorInput!): DeleteVendorPayload!
|
||||
createVendorContact(
|
||||
input: CreateVendorContactInput!
|
||||
): CreateVendorContactPayload!
|
||||
updateVendorContact(
|
||||
input: UpdateVendorContactInput!
|
||||
): UpdateVendorContactPayload!
|
||||
deleteVendorContact(
|
||||
input: DeleteVendorContactInput!
|
||||
): DeleteVendorContactPayload!
|
||||
createVendorService(
|
||||
input: CreateVendorServiceInput!
|
||||
): CreateVendorServicePayload!
|
||||
updateVendorService(
|
||||
input: UpdateVendorServiceInput!
|
||||
): UpdateVendorServicePayload!
|
||||
deleteVendorService(
|
||||
input: DeleteVendorServiceInput!
|
||||
): DeleteVendorServicePayload!
|
||||
uploadVendorComplianceReport(
|
||||
input: UploadVendorComplianceReportInput!
|
||||
): UploadVendorComplianceReportPayload!
|
||||
deleteVendorComplianceReport(
|
||||
input: DeleteVendorComplianceReportInput!
|
||||
): DeleteVendorComplianceReportPayload!
|
||||
uploadVendorBusinessAssociateAgreement(
|
||||
input: UploadVendorBusinessAssociateAgreementInput!
|
||||
): UploadVendorBusinessAssociateAgreementPayload!
|
||||
updateVendorBusinessAssociateAgreement(
|
||||
input: UpdateVendorBusinessAssociateAgreementInput!
|
||||
): UpdateVendorBusinessAssociateAgreementPayload!
|
||||
deleteVendorBusinessAssociateAgreement(
|
||||
input: DeleteVendorBusinessAssociateAgreementInput!
|
||||
): DeleteVendorBusinessAssociateAgreementPayload!
|
||||
uploadVendorDataPrivacyAgreement(
|
||||
input: UploadVendorDataPrivacyAgreementInput!
|
||||
): UploadVendorDataPrivacyAgreementPayload!
|
||||
updateVendorDataPrivacyAgreement(
|
||||
input: UpdateVendorDataPrivacyAgreementInput!
|
||||
): UpdateVendorDataPrivacyAgreementPayload!
|
||||
deleteVendorDataPrivacyAgreement(
|
||||
input: DeleteVendorDataPrivacyAgreementInput!
|
||||
): DeleteVendorDataPrivacyAgreementPayload!
|
||||
createVendorRiskAssessment(
|
||||
input: CreateVendorRiskAssessmentInput!
|
||||
): CreateVendorRiskAssessmentPayload!
|
||||
assessVendor(input: AssessVendorInput!): AssessVendorPayload!
|
||||
}
|
||||
|
||||
input CreateVendorInput {
|
||||
organizationId: ID!
|
||||
name: String!
|
||||
description: String
|
||||
headquarterAddress: String
|
||||
legalName: String
|
||||
websiteUrl: String
|
||||
privacyPolicyUrl: String
|
||||
category: VendorCategory
|
||||
serviceLevelAgreementUrl: String
|
||||
dataProcessingAgreementUrl: String
|
||||
businessAssociateAgreementUrl: String
|
||||
subprocessorsListUrl: String
|
||||
certifications: [String!]
|
||||
countries: [CountryCode!]
|
||||
securityPageUrl: String
|
||||
trustPageUrl: String
|
||||
statusPageUrl: String
|
||||
termsOfServiceUrl: String
|
||||
businessOwnerId: ID
|
||||
securityOwnerId: ID
|
||||
}
|
||||
|
||||
input UpdateVendorInput {
|
||||
id: ID!
|
||||
name: String
|
||||
description: String @goField(omittable: true)
|
||||
statusPageUrl: String @goField(omittable: true)
|
||||
termsOfServiceUrl: String @goField(omittable: true)
|
||||
privacyPolicyUrl: String @goField(omittable: true)
|
||||
serviceLevelAgreementUrl: String @goField(omittable: true)
|
||||
dataProcessingAgreementUrl: String @goField(omittable: true)
|
||||
businessAssociateAgreementUrl: String @goField(omittable: true)
|
||||
subprocessorsListUrl: String @goField(omittable: true)
|
||||
websiteUrl: String @goField(omittable: true)
|
||||
legalName: String @goField(omittable: true)
|
||||
headquarterAddress: String @goField(omittable: true)
|
||||
category: VendorCategory
|
||||
certifications: [String!]
|
||||
countries: [CountryCode!]
|
||||
securityPageUrl: String @goField(omittable: true)
|
||||
trustPageUrl: String @goField(omittable: true)
|
||||
businessOwnerId: ID @goField(omittable: true)
|
||||
securityOwnerId: ID @goField(omittable: true)
|
||||
showOnTrustCenter: Boolean
|
||||
}
|
||||
|
||||
input DeleteVendorInput {
|
||||
vendorId: ID!
|
||||
}
|
||||
|
||||
input CreateVendorContactInput {
|
||||
vendorId: ID!
|
||||
fullName: String
|
||||
email: EmailAddr
|
||||
phone: String
|
||||
role: String
|
||||
}
|
||||
|
||||
input UpdateVendorContactInput {
|
||||
id: ID!
|
||||
fullName: String @goField(omittable: true)
|
||||
email: EmailAddr @goField(omittable: true)
|
||||
phone: String @goField(omittable: true)
|
||||
role: String @goField(omittable: true)
|
||||
}
|
||||
|
||||
input DeleteVendorContactInput {
|
||||
vendorContactId: ID!
|
||||
}
|
||||
|
||||
input CreateVendorServiceInput {
|
||||
vendorId: ID!
|
||||
name: String!
|
||||
description: String
|
||||
url: String
|
||||
type: String
|
||||
}
|
||||
|
||||
input UpdateVendorServiceInput {
|
||||
id: ID!
|
||||
name: String
|
||||
description: String @goField(omittable: true)
|
||||
url: String
|
||||
type: String
|
||||
}
|
||||
|
||||
input DeleteVendorServiceInput {
|
||||
vendorServiceId: ID!
|
||||
}
|
||||
|
||||
input UploadVendorComplianceReportInput {
|
||||
vendorId: ID!
|
||||
reportDate: Datetime!
|
||||
validUntil: Datetime
|
||||
reportName: String!
|
||||
file: Upload!
|
||||
}
|
||||
|
||||
input DeleteVendorComplianceReportInput {
|
||||
reportId: ID!
|
||||
}
|
||||
|
||||
input UploadVendorBusinessAssociateAgreementInput {
|
||||
vendorId: ID!
|
||||
validFrom: Datetime
|
||||
validUntil: Datetime
|
||||
fileName: String!
|
||||
file: Upload!
|
||||
}
|
||||
|
||||
input UpdateVendorBusinessAssociateAgreementInput {
|
||||
vendorId: ID!
|
||||
validFrom: Datetime @goField(omittable: true)
|
||||
validUntil: Datetime @goField(omittable: true)
|
||||
}
|
||||
|
||||
input DeleteVendorBusinessAssociateAgreementInput {
|
||||
vendorId: ID!
|
||||
}
|
||||
|
||||
input UploadVendorDataPrivacyAgreementInput {
|
||||
vendorId: ID!
|
||||
validFrom: Datetime
|
||||
validUntil: Datetime
|
||||
fileName: String!
|
||||
file: Upload!
|
||||
}
|
||||
|
||||
input UpdateVendorDataPrivacyAgreementInput {
|
||||
vendorId: ID!
|
||||
validFrom: Datetime @goField(omittable: true)
|
||||
validUntil: Datetime @goField(omittable: true)
|
||||
}
|
||||
|
||||
input DeleteVendorDataPrivacyAgreementInput {
|
||||
vendorId: ID!
|
||||
}
|
||||
|
||||
input CreateVendorRiskAssessmentInput {
|
||||
vendorId: ID!
|
||||
expiresAt: Datetime!
|
||||
dataSensitivity: DataSensitivity!
|
||||
businessImpact: BusinessImpact!
|
||||
notes: String
|
||||
}
|
||||
|
||||
input AssessVendorInput {
|
||||
id: ID!
|
||||
websiteUrl: String!
|
||||
}
|
||||
|
||||
type CreateVendorPayload {
|
||||
vendorEdge: VendorEdge!
|
||||
}
|
||||
|
||||
type UpdateVendorPayload {
|
||||
vendor: Vendor!
|
||||
}
|
||||
|
||||
type DeleteVendorPayload {
|
||||
deletedVendorId: ID!
|
||||
}
|
||||
|
||||
type CreateVendorContactPayload {
|
||||
vendorContactEdge: VendorContactEdge!
|
||||
}
|
||||
|
||||
type UpdateVendorContactPayload {
|
||||
vendorContact: VendorContact!
|
||||
}
|
||||
|
||||
type DeleteVendorContactPayload {
|
||||
deletedVendorContactId: ID!
|
||||
}
|
||||
|
||||
type CreateVendorServicePayload {
|
||||
vendorServiceEdge: VendorServiceEdge!
|
||||
}
|
||||
|
||||
type UpdateVendorServicePayload {
|
||||
vendorService: VendorService!
|
||||
}
|
||||
|
||||
type DeleteVendorServicePayload {
|
||||
deletedVendorServiceId: ID!
|
||||
}
|
||||
|
||||
type UploadVendorComplianceReportPayload {
|
||||
vendorComplianceReportEdge: VendorComplianceReportEdge!
|
||||
}
|
||||
|
||||
type DeleteVendorComplianceReportPayload {
|
||||
deletedVendorComplianceReportId: ID!
|
||||
}
|
||||
|
||||
type UploadVendorBusinessAssociateAgreementPayload {
|
||||
vendorBusinessAssociateAgreement: VendorBusinessAssociateAgreement!
|
||||
}
|
||||
|
||||
type UpdateVendorBusinessAssociateAgreementPayload {
|
||||
vendorBusinessAssociateAgreement: VendorBusinessAssociateAgreement!
|
||||
}
|
||||
|
||||
type DeleteVendorBusinessAssociateAgreementPayload {
|
||||
deletedVendorId: ID!
|
||||
}
|
||||
|
||||
type UploadVendorDataPrivacyAgreementPayload {
|
||||
vendorDataPrivacyAgreement: VendorDataPrivacyAgreement!
|
||||
}
|
||||
|
||||
type UpdateVendorDataPrivacyAgreementPayload {
|
||||
vendorDataPrivacyAgreement: VendorDataPrivacyAgreement!
|
||||
}
|
||||
|
||||
type DeleteVendorDataPrivacyAgreementPayload {
|
||||
deletedVendorId: ID!
|
||||
}
|
||||
|
||||
type CreateVendorRiskAssessmentPayload {
|
||||
vendorRiskAssessmentEdge: VendorRiskAssessmentEdge!
|
||||
}
|
||||
|
||||
type AssessVendorPayload {
|
||||
vendor: Vendor!
|
||||
}
|
||||
179
pkg/server/api/console/v1/graphql/webhook.graphql
Normal file
179
pkg/server/api/console/v1/graphql/webhook.graphql
Normal file
@@ -0,0 +1,179 @@
|
||||
extend type Organization {
|
||||
webhookSubscriptions(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: WebhookSubscriptionOrder
|
||||
): WebhookSubscriptionConnection! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
enum WebhookEventType
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.WebhookEventType") {
|
||||
MEETING_CREATED
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeMeetingCreated")
|
||||
MEETING_UPDATED
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeMeetingUpdated")
|
||||
MEETING_DELETED
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeMeetingDeleted")
|
||||
VENDOR_CREATED
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeVendorCreated")
|
||||
VENDOR_UPDATED
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeVendorUpdated")
|
||||
VENDOR_DELETED
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeVendorDeleted")
|
||||
USER_CREATED
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeUserCreated")
|
||||
USER_UPDATED
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeUserUpdated")
|
||||
USER_DELETED
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeUserDeleted")
|
||||
OBLIGATION_CREATED
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeObligationCreated")
|
||||
OBLIGATION_UPDATED
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeObligationUpdated")
|
||||
OBLIGATION_DELETED
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeObligationDeleted")
|
||||
}
|
||||
|
||||
enum WebhookEventStatus
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.WebhookEventStatus") {
|
||||
PENDING
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventStatusPending")
|
||||
SUCCEEDED
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventStatusSucceeded")
|
||||
FAILED
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventStatusFailed")
|
||||
}
|
||||
|
||||
enum WebhookSubscriptionOrderField
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.WebhookSubscriptionOrderField"
|
||||
) {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.WebhookSubscriptionOrderFieldCreatedAt"
|
||||
)
|
||||
}
|
||||
|
||||
enum WebhookEventOrderField
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.WebhookEventOrderField"
|
||||
) {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.WebhookEventOrderFieldCreatedAt"
|
||||
)
|
||||
}
|
||||
|
||||
input WebhookSubscriptionOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.WebhookSubscriptionOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: WebhookSubscriptionOrderField!
|
||||
}
|
||||
|
||||
input WebhookEventOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.WebhookEventOrderBy"
|
||||
) {
|
||||
field: WebhookEventOrderField!
|
||||
direction: OrderDirection!
|
||||
}
|
||||
|
||||
type WebhookSubscription implements Node {
|
||||
id: ID!
|
||||
organization: Organization @goField(forceResolver: true)
|
||||
endpointUrl: String!
|
||||
signingSecret: String! @goField(forceResolver: true)
|
||||
selectedEvents: [WebhookEventType!]!
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
events(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: WebhookEventOrder
|
||||
): WebhookEventConnection! @goField(forceResolver: true)
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type WebhookEvent implements Node {
|
||||
id: ID!
|
||||
webhookSubscriptionId: ID!
|
||||
status: WebhookEventStatus!
|
||||
response: String
|
||||
createdAt: Datetime!
|
||||
}
|
||||
|
||||
type WebhookSubscriptionConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.WebhookSubscriptionConnection"
|
||||
) {
|
||||
edges: [WebhookSubscriptionEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type WebhookSubscriptionEdge {
|
||||
cursor: CursorKey!
|
||||
node: WebhookSubscription!
|
||||
}
|
||||
|
||||
type WebhookEventConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.WebhookEventConnection"
|
||||
) {
|
||||
edges: [WebhookEventEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type WebhookEventEdge {
|
||||
cursor: CursorKey!
|
||||
node: WebhookEvent!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
createWebhookSubscription(
|
||||
input: CreateWebhookSubscriptionInput!
|
||||
): CreateWebhookSubscriptionPayload!
|
||||
updateWebhookSubscription(
|
||||
input: UpdateWebhookSubscriptionInput!
|
||||
): UpdateWebhookSubscriptionPayload!
|
||||
deleteWebhookSubscription(
|
||||
input: DeleteWebhookSubscriptionInput!
|
||||
): DeleteWebhookSubscriptionPayload!
|
||||
}
|
||||
|
||||
input CreateWebhookSubscriptionInput {
|
||||
organizationId: ID!
|
||||
endpointUrl: String!
|
||||
selectedEvents: [WebhookEventType!]!
|
||||
}
|
||||
|
||||
input UpdateWebhookSubscriptionInput {
|
||||
id: ID!
|
||||
endpointUrl: String
|
||||
selectedEvents: [WebhookEventType!]
|
||||
}
|
||||
|
||||
input DeleteWebhookSubscriptionInput {
|
||||
webhookSubscriptionId: ID!
|
||||
}
|
||||
|
||||
type CreateWebhookSubscriptionPayload {
|
||||
webhookSubscriptionEdge: WebhookSubscriptionEdge!
|
||||
}
|
||||
|
||||
type UpdateWebhookSubscriptionPayload {
|
||||
webhookSubscription: WebhookSubscription!
|
||||
}
|
||||
|
||||
type DeleteWebhookSubscriptionPayload {
|
||||
deletedWebhookSubscriptionId: ID!
|
||||
}
|
||||
287
pkg/server/api/console/v1/mailing_list.resolvers.go
Normal file
287
pkg/server/api/console/v1/mailing_list.resolvers.go
Normal file
@@ -0,0 +1,287 @@
|
||||
package console_v1
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver
|
||||
// implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.87
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"go.gearno.de/kit/log"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/mailman"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"go.probo.inc/probo/pkg/probo"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/schema"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/types"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils"
|
||||
"go.probo.inc/probo/pkg/validator"
|
||||
)
|
||||
|
||||
// Subscribers is the resolver for the subscribers field on MailingList.
|
||||
func (r *mailingListResolver) Subscribers(ctx context.Context, obj *types.MailingList, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.MailingListSubscriberConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionMailingListSubscriberList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.MailingListSubscriberOrderField]{
|
||||
Field: coredata.MailingListSubscriberOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
result, err := r.mailman.ListSubscribers(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list mailing list subscribers", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewMailingListSubscriberConnection(result, r, obj.ID), nil
|
||||
}
|
||||
|
||||
// Updates is the resolver for the updates field on MailingList.
|
||||
func (r *mailingListResolver) Updates(ctx context.Context, obj *types.MailingList, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.MailingListUpdateConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionMailingListUpdateList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.MailingListUpdateOrderField]{
|
||||
Field: coredata.MailingListUpdateOrderFieldUpdatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
result, err := r.mailman.ListMailingListUpdates(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list mailing list updates", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewMailingListUpdateConnection(result, r, obj.ID), nil
|
||||
}
|
||||
|
||||
// TotalCount is the resolver for the totalCount field.
|
||||
func (r *mailingListSubscriberConnectionResolver) TotalCount(ctx context.Context, obj *types.MailingListSubscriberConnection) (int, error) {
|
||||
if err := r.authorize(ctx, obj.ParentID, probo.ActionMailingListSubscriberList); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
switch obj.Resolver.(type) {
|
||||
case *mailingListResolver:
|
||||
count, err := r.mailman.CountSubscribers(ctx, obj.ParentID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count mailing list subscribers", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "unsupported resolver for mailing list subscriber connection", log.String("resolver", fmt.Sprintf("%T", obj.Resolver)))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
// TotalCount is the resolver for the totalCount field on MailingListUpdateConnection.
|
||||
func (r *mailingListUpdateConnectionResolver) TotalCount(ctx context.Context, obj *types.MailingListUpdateConnection) (int, error) {
|
||||
if err := r.authorize(ctx, obj.ParentID, probo.ActionMailingListUpdateList); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
count, err := r.mailman.CountMailingListUpdates(ctx, obj.ParentID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count mailing list updates", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// CreateMailingListUpdate is the resolver for the createMailingListUpdate field.
|
||||
func (r *mutationResolver) CreateMailingListUpdate(ctx context.Context, input types.CreateMailingListUpdateInput) (*types.CreateMailingListUpdatePayload, error) {
|
||||
if err := r.authorize(ctx, input.MailingListID, probo.ActionMailingListUpdateCreate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mlu, err := r.mailman.CreateMailingListUpdate(
|
||||
ctx,
|
||||
&mailman.CreateMailingListUpdateRequest{
|
||||
MailingListID: input.MailingListID,
|
||||
Title: input.Title,
|
||||
Body: input.Body,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot create mailing list update", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.CreateMailingListUpdatePayload{
|
||||
MailingListUpdate: types.NewMailingListUpdate(mlu),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateMailingListUpdate is the resolver for the updateMailingListUpdate field.
|
||||
func (r *mutationResolver) UpdateMailingListUpdate(ctx context.Context, input types.UpdateMailingListUpdateInput) (*types.UpdateMailingListUpdatePayload, error) {
|
||||
if err := r.authorize(ctx, input.ID, probo.ActionMailingListUpdateUpdate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mlu, err := r.mailman.UpdateMailingListUpdate(
|
||||
ctx,
|
||||
&mailman.UpdateMailingListUpdateRequest{
|
||||
ID: input.ID,
|
||||
Title: input.Title,
|
||||
Body: input.Body,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
if errors.Is(err, mailman.ErrMailingListUpdateAlreadySent) {
|
||||
return nil, gqlutils.Conflictf(ctx, "mailing list update can only be edited when in draft")
|
||||
}
|
||||
if errors.Is(err, mailman.ErrMailingListUpdateNotFound) {
|
||||
return nil, gqlutils.NotFoundf(ctx, "mailing list update not found")
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot update mailing list update", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.UpdateMailingListUpdatePayload{
|
||||
MailingListUpdate: types.NewMailingListUpdate(mlu),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SendMailingListUpdate is the resolver for the sendMailingListUpdate field.
|
||||
func (r *mutationResolver) SendMailingListUpdate(ctx context.Context, input types.SendMailingListUpdateInput) (*types.SendMailingListUpdatePayload, error) {
|
||||
if err := r.authorize(ctx, input.ID, probo.ActionMailingListUpdateUpdate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mlu, err := r.mailman.SendMailingListUpdate(ctx, input.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, mailman.ErrMailingListUpdateAlreadySent) {
|
||||
return nil, gqlutils.Conflictf(ctx, "mailing list update has already been queued for sending")
|
||||
}
|
||||
if errors.Is(err, mailman.ErrMailingListUpdateNotFound) {
|
||||
return nil, gqlutils.NotFoundf(ctx, "mailing list update not found")
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot queue mailing list update for sending", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.SendMailingListUpdatePayload{
|
||||
MailingListUpdate: types.NewMailingListUpdate(mlu),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteMailingListUpdate is the resolver for the deleteMailingListUpdate field.
|
||||
func (r *mutationResolver) DeleteMailingListUpdate(ctx context.Context, input types.DeleteMailingListUpdateInput) (*types.DeleteMailingListUpdatePayload, error) {
|
||||
if err := r.authorize(ctx, input.ID, probo.ActionMailingListUpdateDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := r.mailman.DeleteMailingListUpdate(ctx, input.ID); err != nil {
|
||||
if errors.Is(err, mailman.ErrMailingListUpdateNotFound) {
|
||||
return nil, gqlutils.NotFoundf(ctx, "mailing list update not found")
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot delete mailing list update", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DeleteMailingListUpdatePayload{
|
||||
DeletedMailingListUpdateID: input.ID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateMailingList is the resolver for the updateMailingList field.
|
||||
func (r *mutationResolver) UpdateMailingList(ctx context.Context, input types.UpdateMailingListInput) (*types.UpdateMailingListPayload, error) {
|
||||
if err := r.authorize(ctx, input.ID, probo.ActionMailingListUpdate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ml, err := r.mailman.UpdateMailingList(ctx, input.ID, input.ReplyTo)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot update mailing list", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.UpdateMailingListPayload{
|
||||
MailingList: types.NewMailingList(ml),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreateMailingListSubscriber is the resolver for the createMailingListSubscriber field.
|
||||
func (r *mutationResolver) CreateMailingListSubscriber(ctx context.Context, input types.CreateMailingListSubscriberInput) (*types.CreateMailingListSubscriberPayload, error) {
|
||||
if err := r.authorize(ctx, input.MailingListID, probo.ActionMailingListSubscriberCreate); err != nil {
|
||||
return nil, 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 {
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
if errors.Is(err, mailman.ErrSubscriberAlreadyExist) {
|
||||
return nil, gqlutils.Conflictf(ctx, "subscriber already exists in this mailing list")
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot create mailing list subscriber", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.CreateMailingListSubscriberPayload{
|
||||
MailingListSubscriberEdge: types.NewMailingListSubscriberEdge(subscriber, coredata.MailingListSubscriberOrderFieldCreatedAt),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteMailingListSubscriber is the resolver for the deleteMailingListSubscriber field.
|
||||
func (r *mutationResolver) DeleteMailingListSubscriber(ctx context.Context, input types.DeleteMailingListSubscriberInput) (*types.DeleteMailingListSubscriberPayload, error) {
|
||||
if err := r.authorize(ctx, input.ID, probo.ActionMailingListSubscriberDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := r.mailman.DeleteSubscriber(ctx, input.ID); err != nil {
|
||||
if errors.Is(err, mailman.ErrSubscriberNotFound) {
|
||||
return nil, gqlutils.NotFoundf(ctx, "mailing list subscriber not found")
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot delete mailing list subscriber", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DeleteMailingListSubscriberPayload{
|
||||
DeletedMailingListSubscriberID: input.ID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// MailingList returns schema.MailingListResolver implementation.
|
||||
func (r *Resolver) MailingList() schema.MailingListResolver { return &mailingListResolver{r} }
|
||||
|
||||
// MailingListSubscriberConnection returns schema.MailingListSubscriberConnectionResolver implementation.
|
||||
func (r *Resolver) MailingListSubscriberConnection() schema.MailingListSubscriberConnectionResolver {
|
||||
return &mailingListSubscriberConnectionResolver{r}
|
||||
}
|
||||
|
||||
// MailingListUpdateConnection returns schema.MailingListUpdateConnectionResolver implementation.
|
||||
func (r *Resolver) MailingListUpdateConnection() schema.MailingListUpdateConnectionResolver {
|
||||
return &mailingListUpdateConnectionResolver{r}
|
||||
}
|
||||
|
||||
type mailingListResolver struct{ *Resolver }
|
||||
type mailingListSubscriberConnectionResolver struct{ *Resolver }
|
||||
type mailingListUpdateConnectionResolver struct{ *Resolver }
|
||||
433
pkg/server/api/console/v1/measure.resolvers.go
Normal file
433
pkg/server/api/console/v1/measure.resolvers.go
Normal file
@@ -0,0 +1,433 @@
|
||||
package console_v1
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver
|
||||
// implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.87
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"go.gearno.de/kit/log"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"go.probo.inc/probo/pkg/probo"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/schema"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/types"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils"
|
||||
"go.probo.inc/probo/pkg/validator"
|
||||
)
|
||||
|
||||
// Evidences is the resolver for the evidences field.
|
||||
func (r *measureResolver) Evidences(ctx context.Context, obj *types.Measure, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.EvidenceOrderBy) (*types.EvidenceConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionEvidenceList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.EvidenceOrderField]{
|
||||
Field: coredata.EvidenceOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.EvidenceOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
page, err := prb.Evidences.ListForMeasureID(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list measure evidences", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewEvidenceConnection(page, r, obj.ID), nil
|
||||
}
|
||||
|
||||
// Tasks is the resolver for the tasks field.
|
||||
func (r *measureResolver) Tasks(ctx context.Context, obj *types.Measure, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.TaskOrderBy) (*types.TaskConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionTaskList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.TaskOrderField]{
|
||||
Field: coredata.TaskOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.TaskOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
page, err := prb.Tasks.ListForMeasureID(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list measure tasks", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewTaskConnection(page, r, obj.ID), nil
|
||||
}
|
||||
|
||||
// Risks is the resolver for the risks field.
|
||||
func (r *measureResolver) Risks(ctx context.Context, obj *types.Measure, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.RiskOrderBy, filter *types.RiskFilter) (*types.RiskConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionRiskList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.RiskOrderField]{
|
||||
Field: coredata.RiskOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.RiskOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
var riskFilter = coredata.NewRiskFilter(nil, nil)
|
||||
if filter != nil {
|
||||
riskFilter = coredata.NewRiskFilter(filter.Query, &filter.SnapshotID)
|
||||
}
|
||||
|
||||
page, err := prb.Risks.ListForMeasureID(ctx, obj.ID, cursor, riskFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list measure risks", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewRiskConnection(page, r, obj.ID, riskFilter), nil
|
||||
}
|
||||
|
||||
// Controls is the resolver for the controls field.
|
||||
func (r *measureResolver) Controls(ctx context.Context, obj *types.Measure, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ControlOrderBy, filter *types.ControlFilter) (*types.ControlConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionControlList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.ControlOrderField]{
|
||||
Field: coredata.ControlOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.ControlOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
var controlFilter = coredata.NewControlFilter(nil)
|
||||
if filter != nil {
|
||||
controlFilter = coredata.NewControlFilter(filter.Query)
|
||||
}
|
||||
|
||||
page, err := prb.Controls.ListForMeasureID(ctx, obj.ID, cursor, controlFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list measure controls", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewControlConnection(page, r, obj.ID, controlFilter), nil
|
||||
}
|
||||
|
||||
// Documents is the resolver for the documents field.
|
||||
func (r *measureResolver) Documents(ctx context.Context, obj *types.Measure, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentOrderBy, filter *types.DocumentFilter) (*types.DocumentConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionDocumentList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.DocumentOrderField]{
|
||||
Field: coredata.DocumentOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.DocumentOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
var documentFilter = coredata.NewDocumentFilter(nil)
|
||||
if filter != nil {
|
||||
documentFilter = coredata.NewDocumentFilter(filter.Query).
|
||||
WithDocumentTypes(filter.DocumentTypes).
|
||||
WithClassifications(filter.Classifications)
|
||||
}
|
||||
|
||||
pg, err := prb.Documents.ListForMeasureID(ctx, obj.ID, cursor, documentFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list documents", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewDocumentConnection(pg, r, obj.ID, documentFilter), nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *measureResolver) Permission(ctx context.Context, obj *types.Measure, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// TotalCount is the resolver for the totalCount field.
|
||||
func (r *measureConnectionResolver) TotalCount(ctx context.Context, obj *types.MeasureConnection) (int, error) {
|
||||
if err := r.authorize(ctx, obj.ParentID, probo.ActionMeasureList); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
||||
|
||||
switch obj.Resolver.(type) {
|
||||
case *organizationResolver:
|
||||
count, err := prb.Measures.CountForOrganizationID(ctx, obj.ParentID, obj.Filters)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count measures", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
case *controlResolver:
|
||||
count, err := prb.Measures.CountForControlID(ctx, obj.ParentID, obj.Filters)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count measures", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
case *riskResolver:
|
||||
count, err := prb.Measures.CountForRiskID(ctx, obj.ParentID, obj.Filters)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count measures", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "unsupported resolver")
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
// // CreateMeasure is the resolver for the createMeasure field.
|
||||
func (r *mutationResolver) CreateMeasure(ctx context.Context, input types.CreateMeasureInput) (*types.CreateMeasurePayload, error) {
|
||||
if err := r.authorize(ctx, input.OrganizationID, probo.ActionMeasureCreate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
||||
|
||||
measure, err := prb.Measures.Create(
|
||||
ctx,
|
||||
probo.CreateMeasureRequest{
|
||||
OrganizationID: input.OrganizationID,
|
||||
Name: input.Name,
|
||||
Description: input.Description,
|
||||
Category: input.Category,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceAlreadyExists) {
|
||||
return nil, gqlutils.Conflict(ctx, err)
|
||||
}
|
||||
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot create measure", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.CreateMeasurePayload{
|
||||
MeasureEdge: types.NewMeasureEdge(measure, coredata.MeasureOrderFieldCreatedAt),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateMeasure is the resolver for the updateMeasure field.
|
||||
func (r *mutationResolver) UpdateMeasure(ctx context.Context, input types.UpdateMeasureInput) (*types.UpdateMeasurePayload, error) {
|
||||
if err := r.authorize(ctx, input.ID, probo.ActionMeasureUpdate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.ID.TenantID())
|
||||
|
||||
measure, err := prb.Measures.Update(
|
||||
ctx,
|
||||
probo.UpdateMeasureRequest{
|
||||
ID: input.ID,
|
||||
Name: input.Name,
|
||||
Description: gqlutils.UnwrapOmittable(input.Description),
|
||||
Category: input.Category,
|
||||
State: input.State,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot update measure", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.UpdateMeasurePayload{
|
||||
Measure: types.NewMeasure(measure),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ImportMeasure is the resolver for the importMeasure field.
|
||||
func (r *mutationResolver) ImportMeasure(ctx context.Context, input types.ImportMeasureInput) (*types.ImportMeasurePayload, error) {
|
||||
if err := r.authorize(ctx, input.OrganizationID, probo.ActionMeasureImport); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
||||
|
||||
var req probo.ImportMeasureRequest
|
||||
if err := json.NewDecoder(input.File.File).Decode(&req.Measures); err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot unmarshal measure", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
measures, err := prb.Measures.Import(ctx, input.OrganizationID, req)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot import measure", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
measureEdges := make([]*types.MeasureEdge, len(measures.Data))
|
||||
for i, measure := range measures.Data {
|
||||
measureEdges[i] = types.NewMeasureEdge(measure, coredata.MeasureOrderFieldCreatedAt)
|
||||
}
|
||||
|
||||
return &types.ImportMeasurePayload{
|
||||
MeasureEdges: measureEdges,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteMeasure is the resolver for the deleteMeasure field.
|
||||
func (r *mutationResolver) DeleteMeasure(ctx context.Context, input types.DeleteMeasureInput) (*types.DeleteMeasurePayload, error) {
|
||||
if err := r.authorize(ctx, input.MeasureID, probo.ActionMeasureDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.MeasureID.TenantID())
|
||||
|
||||
err := prb.Measures.Delete(ctx, input.MeasureID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot delete measure", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DeleteMeasurePayload{
|
||||
DeletedMeasureID: input.MeasureID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreateMeasureDocumentMapping is the resolver for the createMeasureDocumentMapping field.
|
||||
func (r *mutationResolver) CreateMeasureDocumentMapping(ctx context.Context, input types.CreateMeasureDocumentMappingInput) (*types.CreateMeasureDocumentMappingPayload, error) {
|
||||
if err := r.authorize(ctx, input.MeasureID, probo.ActionMeasureDocumentMappingCreate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.MeasureID.TenantID())
|
||||
|
||||
measure, document, err := prb.Measures.CreateDocumentMapping(ctx, input.MeasureID, input.DocumentID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceAlreadyExists) {
|
||||
return nil, gqlutils.Conflict(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot create measure document mapping", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.CreateMeasureDocumentMappingPayload{
|
||||
MeasureEdge: types.NewMeasureEdge(measure, coredata.MeasureOrderFieldCreatedAt),
|
||||
DocumentEdge: types.NewDocumentEdge(document, coredata.DocumentOrderFieldTitle),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteMeasureDocumentMapping is the resolver for the deleteMeasureDocumentMapping field.
|
||||
func (r *mutationResolver) DeleteMeasureDocumentMapping(ctx context.Context, input types.DeleteMeasureDocumentMappingInput) (*types.DeleteMeasureDocumentMappingPayload, error) {
|
||||
if err := r.authorize(ctx, input.MeasureID, probo.ActionMeasureDocumentMappingDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.MeasureID.TenantID())
|
||||
|
||||
measure, document, err := prb.Measures.DeleteDocumentMapping(ctx, input.MeasureID, input.DocumentID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot delete measure document mapping", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DeleteMeasureDocumentMappingPayload{
|
||||
DeletedMeasureID: measure.ID,
|
||||
DeletedDocumentID: document.ID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Measures is the resolver for the measures field.
|
||||
func (r *organizationResolver) Measures(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.MeasureOrderBy, filter *types.MeasureFilter) (*types.MeasureConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionMeasureList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.MeasureOrderField]{
|
||||
Field: coredata.MeasureOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.MeasureOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
var measureFilter = coredata.NewMeasureFilter(nil, nil, nil)
|
||||
if filter != nil {
|
||||
measureFilter = coredata.NewMeasureFilter(filter.Query, filter.State, filter.Category)
|
||||
}
|
||||
|
||||
page, err := prb.Measures.ListForOrganizationID(ctx, obj.ID, cursor, measureFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list organization measures", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewMeasureConnection(page, r, obj.ID, measureFilter), nil
|
||||
}
|
||||
|
||||
// Measure returns schema.MeasureResolver implementation.
|
||||
func (r *Resolver) Measure() schema.MeasureResolver { return &measureResolver{r} }
|
||||
|
||||
// MeasureConnection returns schema.MeasureConnectionResolver implementation.
|
||||
func (r *Resolver) MeasureConnection() schema.MeasureConnectionResolver {
|
||||
return &measureConnectionResolver{r}
|
||||
}
|
||||
|
||||
type measureResolver struct{ *Resolver }
|
||||
type measureConnectionResolver struct{ *Resolver }
|
||||
227
pkg/server/api/console/v1/meeting.resolvers.go
Normal file
227
pkg/server/api/console/v1/meeting.resolvers.go
Normal file
@@ -0,0 +1,227 @@
|
||||
package console_v1
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver
|
||||
// implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.87
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/vikstrous/dataloadgen"
|
||||
"go.gearno.de/kit/log"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/iam"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"go.probo.inc/probo/pkg/probo"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/dataloader"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/schema"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/types"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils"
|
||||
"go.probo.inc/probo/pkg/validator"
|
||||
)
|
||||
|
||||
// Attendees is the resolver for the attendees field.
|
||||
func (r *meetingResolver) Attendees(ctx context.Context, obj *types.Meeting) ([]*types.Profile, error) {
|
||||
// TODO bug must be paginated
|
||||
|
||||
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
attendees, err := prb.Meetings.GetAttendees(ctx, obj.ID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot load meeting attendees", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
if len(attendees) == 0 {
|
||||
return []*types.Profile{}, nil
|
||||
}
|
||||
|
||||
people := make([]*types.Profile, len(attendees))
|
||||
for i, attendee := range attendees {
|
||||
people[i] = types.NewProfile(attendee)
|
||||
}
|
||||
|
||||
return people, nil
|
||||
}
|
||||
|
||||
// Organization is the resolver for the organization field.
|
||||
func (r *meetingResolver) Organization(ctx context.Context, obj *types.Meeting) (*types.Organization, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
loaders := dataloader.FromContext(ctx)
|
||||
|
||||
organization, err := loaders.Organization.Load(ctx, obj.Organization.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot load organization", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewOrganization(organization), nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *meetingResolver) Permission(ctx context.Context, obj *types.Meeting, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// TotalCount is the resolver for the totalCount field.
|
||||
func (r *meetingConnectionResolver) TotalCount(ctx context.Context, obj *types.MeetingConnection) (int, error) {
|
||||
if err := r.authorize(ctx, obj.ParentID, probo.ActionMeetingList); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
||||
|
||||
switch obj.Resolver.(type) {
|
||||
case *organizationResolver:
|
||||
count, err := prb.Meetings.CountForOrganizationID(ctx, obj.ParentID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count meetings", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "unsupported resolver")
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
// CreateMeeting is the resolver for the createMeeting field.
|
||||
func (r *mutationResolver) CreateMeeting(ctx context.Context, input types.CreateMeetingInput) (*types.CreateMeetingPayload, error) {
|
||||
if err := r.authorize(ctx, input.OrganizationID, probo.ActionMeetingCreate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
||||
|
||||
meeting, err := prb.Meetings.Create(
|
||||
ctx,
|
||||
probo.CreateMeetingRequest{
|
||||
OrganizationID: input.OrganizationID,
|
||||
Name: input.Name,
|
||||
Date: input.Date,
|
||||
AttendeeIDs: input.AttendeeIds,
|
||||
Minutes: input.Minutes,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot create meeting", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.CreateMeetingPayload{
|
||||
MeetingEdge: types.NewMeetingEdge(meeting, coredata.MeetingOrderFieldCreatedAt),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateMeeting is the resolver for the updateMeeting field.
|
||||
func (r *mutationResolver) UpdateMeeting(ctx context.Context, input types.UpdateMeetingInput) (*types.UpdateMeetingPayload, error) {
|
||||
if err := r.authorize(ctx, input.MeetingID, probo.ActionMeetingUpdate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.MeetingID.TenantID())
|
||||
|
||||
var attendeeIDs []gid.GID
|
||||
if input.AttendeeIds != nil {
|
||||
attendeeIDs = input.AttendeeIds
|
||||
}
|
||||
|
||||
meeting, err := prb.Meetings.Update(
|
||||
ctx,
|
||||
probo.UpdateMeetingRequest{
|
||||
MeetingID: input.MeetingID,
|
||||
Name: input.Name,
|
||||
Date: input.Date,
|
||||
AttendeeIDs: attendeeIDs,
|
||||
Minutes: gqlutils.UnwrapOmittable(input.Minutes),
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot update meeting", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.UpdateMeetingPayload{
|
||||
Meeting: types.NewMeeting(meeting),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteMeeting is the resolver for the deleteMeeting field.
|
||||
func (r *mutationResolver) DeleteMeeting(ctx context.Context, input types.DeleteMeetingInput) (*types.DeleteMeetingPayload, error) {
|
||||
if err := r.authorize(ctx, input.MeetingID, probo.ActionMeetingDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.MeetingID.TenantID())
|
||||
|
||||
err := prb.Meetings.Delete(ctx, input.MeetingID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot delete meeting", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DeleteMeetingPayload{
|
||||
DeletedMeetingID: input.MeetingID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Meetings is the resolver for the meetings field.
|
||||
func (r *organizationResolver) Meetings(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.MeetingOrderBy) (*types.MeetingConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionMeetingList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.MeetingOrderField]{
|
||||
Field: coredata.MeetingOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.MeetingOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
page, err := prb.Meetings.ListForOrganizationID(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list organization meetings", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewMeetingConnection(page, r, obj.ID), nil
|
||||
}
|
||||
|
||||
// Meeting returns schema.MeetingResolver implementation.
|
||||
func (r *Resolver) Meeting() schema.MeetingResolver { return &meetingResolver{r} }
|
||||
|
||||
// MeetingConnection returns schema.MeetingConnectionResolver implementation.
|
||||
func (r *Resolver) MeetingConnection() schema.MeetingConnectionResolver {
|
||||
return &meetingConnectionResolver{r}
|
||||
}
|
||||
|
||||
type meetingResolver struct{ *Resolver }
|
||||
type meetingConnectionResolver struct{ *Resolver }
|
||||
247
pkg/server/api/console/v1/obligation.resolvers.go
Normal file
247
pkg/server/api/console/v1/obligation.resolvers.go
Normal file
@@ -0,0 +1,247 @@
|
||||
package console_v1
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver
|
||||
// implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.87
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/vikstrous/dataloadgen"
|
||||
"go.gearno.de/kit/log"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/iam"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"go.probo.inc/probo/pkg/probo"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/dataloader"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/schema"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/types"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils"
|
||||
"go.probo.inc/probo/pkg/validator"
|
||||
)
|
||||
|
||||
// CreateObligation is the resolver for the createObligation field.
|
||||
func (r *mutationResolver) CreateObligation(ctx context.Context, input types.CreateObligationInput) (*types.CreateObligationPayload, error) {
|
||||
if err := r.authorize(ctx, input.OrganizationID, probo.ActionObligationCreate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
||||
|
||||
req := probo.CreateObligationRequest{
|
||||
OrganizationID: input.OrganizationID,
|
||||
Area: input.Area,
|
||||
Source: input.Source,
|
||||
Requirement: input.Requirement,
|
||||
ActionsToBeImplemented: input.ActionsToBeImplemented,
|
||||
Regulator: input.Regulator,
|
||||
OwnerID: input.OwnerID,
|
||||
LastReviewDate: input.LastReviewDate,
|
||||
DueDate: input.DueDate,
|
||||
Status: input.Status,
|
||||
Type: input.Type,
|
||||
}
|
||||
|
||||
obligation, err := prb.Obligations.Create(ctx, &req)
|
||||
if err != nil {
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot create obligation", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.CreateObligationPayload{
|
||||
ObligationEdge: types.NewObligationEdge(obligation, coredata.ObligationOrderFieldCreatedAt),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateObligation is the resolver for the updateObligation field.
|
||||
func (r *mutationResolver) UpdateObligation(ctx context.Context, input types.UpdateObligationInput) (*types.UpdateObligationPayload, error) {
|
||||
if err := r.authorize(ctx, input.ID, probo.ActionObligationUpdate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.ID.TenantID())
|
||||
|
||||
req := probo.UpdateObligationRequest{
|
||||
ID: input.ID,
|
||||
Area: gqlutils.UnwrapOmittable(input.Area),
|
||||
Source: gqlutils.UnwrapOmittable(input.Source),
|
||||
Requirement: gqlutils.UnwrapOmittable(input.Requirement),
|
||||
ActionsToBeImplemented: gqlutils.UnwrapOmittable(input.ActionsToBeImplemented),
|
||||
Regulator: gqlutils.UnwrapOmittable(input.Regulator),
|
||||
OwnerID: input.OwnerID,
|
||||
LastReviewDate: gqlutils.UnwrapOmittable(input.LastReviewDate),
|
||||
DueDate: gqlutils.UnwrapOmittable(input.DueDate),
|
||||
Status: input.Status,
|
||||
Type: input.Type,
|
||||
}
|
||||
|
||||
obligation, err := prb.Obligations.Update(ctx, &req)
|
||||
if err != nil {
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot update obligation", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.UpdateObligationPayload{
|
||||
Obligation: types.NewObligation(obligation),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteObligation is the resolver for the deleteObligation field.
|
||||
func (r *mutationResolver) DeleteObligation(ctx context.Context, input types.DeleteObligationInput) (*types.DeleteObligationPayload, error) {
|
||||
if err := r.authorize(ctx, input.ObligationID, probo.ActionObligationDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.ObligationID.TenantID())
|
||||
|
||||
err := prb.Obligations.Delete(ctx, input.ObligationID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot delete obligation", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DeleteObligationPayload{
|
||||
DeletedObligationID: input.ObligationID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Organization is the resolver for the organization field.
|
||||
func (r *obligationResolver) Organization(ctx context.Context, obj *types.Obligation) (*types.Organization, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
loaders := dataloader.FromContext(ctx)
|
||||
|
||||
organization, err := loaders.Organization.Load(ctx, obj.Organization.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get obligation organization", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewOrganization(organization), nil
|
||||
}
|
||||
|
||||
// Owner is the resolver for the owner field.
|
||||
func (r *obligationResolver) Owner(ctx context.Context, obj *types.Obligation) (*types.Profile, error) {
|
||||
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
loaders := dataloader.FromContext(ctx)
|
||||
|
||||
owner, err := loaders.Profile.Load(ctx, obj.Owner.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get obligation owner", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewProfile(owner), nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *obligationResolver) Permission(ctx context.Context, obj *types.Obligation, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// TotalCount is the resolver for the totalCount field.
|
||||
func (r *obligationConnectionResolver) TotalCount(ctx context.Context, obj *types.ObligationConnection) (int, error) {
|
||||
if err := r.authorize(ctx, obj.ParentID, probo.ActionObligationList); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
||||
|
||||
switch obj.Resolver.(type) {
|
||||
case *organizationResolver:
|
||||
obligationFilter := coredata.NewObligationFilter(nil)
|
||||
if obj.Filter != nil {
|
||||
obligationFilter = coredata.NewObligationFilter(&obj.Filter.SnapshotID)
|
||||
}
|
||||
|
||||
count, err := prb.Obligations.CountForOrganizationID(ctx, obj.ParentID, obligationFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count obligations", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
case *riskResolver:
|
||||
obligationFilter := coredata.NewObligationFilter(nil)
|
||||
if obj.Filter != nil {
|
||||
obligationFilter = coredata.NewObligationFilter(&obj.Filter.SnapshotID)
|
||||
}
|
||||
|
||||
count, err := prb.Obligations.CountForRiskID(ctx, obj.ParentID, obligationFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count risk obligations", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "unsupported resolver")
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
// Obligations is the resolver for the obligations field.
|
||||
func (r *organizationResolver) Obligations(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ObligationOrderBy, filter *types.ObligationFilter) (*types.ObligationConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionObligationList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.ObligationOrderField]{
|
||||
Field: coredata.ObligationOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.ObligationOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
obligationFilter := coredata.NewObligationFilter(nil)
|
||||
if filter != nil {
|
||||
obligationFilter = coredata.NewObligationFilter(&filter.SnapshotID)
|
||||
}
|
||||
|
||||
page, err := prb.Obligations.ListForOrganizationID(ctx, obj.ID, cursor, obligationFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list organization obligations", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewObligationConnection(page, r, obj.ID, filter), nil
|
||||
}
|
||||
|
||||
// Obligation returns schema.ObligationResolver implementation.
|
||||
func (r *Resolver) Obligation() schema.ObligationResolver { return &obligationResolver{r} }
|
||||
|
||||
// ObligationConnection returns schema.ObligationConnectionResolver implementation.
|
||||
func (r *Resolver) ObligationConnection() schema.ObligationConnectionResolver {
|
||||
return &obligationConnectionResolver{r}
|
||||
}
|
||||
|
||||
type obligationResolver struct{ *Resolver }
|
||||
type obligationConnectionResolver struct{ *Resolver }
|
||||
61
pkg/server/api/console/v1/organization.resolvers.go
Normal file
61
pkg/server/api/console/v1/organization.resolvers.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package console_v1
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver
|
||||
// implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.87
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"go.gearno.de/kit/log"
|
||||
"go.probo.inc/probo/pkg/iam"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/schema"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/types"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils"
|
||||
)
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *profileResolver) Permission(ctx context.Context, obj *types.Profile, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// TotalCount is the resolver for the totalCount field.
|
||||
func (r *profileConnectionResolver) TotalCount(ctx context.Context, obj *types.ProfileConnection) (int, error) {
|
||||
if err := r.authorize(ctx, obj.ParentID, iam.ActionMembershipProfileList); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
switch obj.Resolver.(type) {
|
||||
case *organizationResolver:
|
||||
count, err := r.iam.OrganizationService.CountProfiles(ctx, obj.ParentID, obj.Filters)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count profiles", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
case *documentVersionResolver:
|
||||
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
||||
count, err := prb.Documents.CountVersionApprovers(ctx, obj.ParentID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count document version approvers", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "unsupported resolver for profile connection", log.String("resolver", fmt.Sprintf("%T", obj.Resolver)))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
// Profile returns schema.ProfileResolver implementation.
|
||||
func (r *Resolver) Profile() schema.ProfileResolver { return &profileResolver{r} }
|
||||
|
||||
// ProfileConnection returns schema.ProfileConnectionResolver implementation.
|
||||
func (r *Resolver) ProfileConnection() schema.ProfileConnectionResolver {
|
||||
return &profileConnectionResolver{r}
|
||||
}
|
||||
|
||||
type profileResolver struct{ *Resolver }
|
||||
type profileConnectionResolver struct{ *Resolver }
|
||||
353
pkg/server/api/console/v1/processing_activity.resolvers.go
Normal file
353
pkg/server/api/console/v1/processing_activity.resolvers.go
Normal file
@@ -0,0 +1,353 @@
|
||||
package console_v1
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver
|
||||
// implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.87
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/vikstrous/dataloadgen"
|
||||
"go.gearno.de/kit/log"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/iam"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"go.probo.inc/probo/pkg/probo"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/dataloader"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/schema"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/types"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils"
|
||||
)
|
||||
|
||||
// CreateProcessingActivity is the resolver for the createProcessingActivity field.
|
||||
func (r *mutationResolver) CreateProcessingActivity(ctx context.Context, input types.CreateProcessingActivityInput) (*types.CreateProcessingActivityPayload, error) {
|
||||
if err := r.authorize(ctx, input.OrganizationID, probo.ActionProcessingActivityCreate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
||||
|
||||
req := probo.CreateProcessingActivityRequest{
|
||||
OrganizationID: input.OrganizationID,
|
||||
Name: input.Name,
|
||||
Purpose: input.Purpose,
|
||||
DataSubjectCategory: input.DataSubjectCategory,
|
||||
PersonalDataCategory: input.PersonalDataCategory,
|
||||
SpecialOrCriminalData: input.SpecialOrCriminalData,
|
||||
LawfulBasis: input.LawfulBasis,
|
||||
Recipients: input.Recipients,
|
||||
Location: input.Location,
|
||||
InternationalTransfers: input.InternationalTransfers,
|
||||
TransferSafeguard: input.TransferSafeguards,
|
||||
RetentionPeriod: input.RetentionPeriod,
|
||||
SecurityMeasures: input.SecurityMeasures,
|
||||
DataProtectionImpactAssessmentNeeded: input.DataProtectionImpactAssessmentNeeded,
|
||||
TransferImpactAssessmentNeeded: input.TransferImpactAssessmentNeeded,
|
||||
LastReviewDate: input.LastReviewDate,
|
||||
NextReviewDate: input.NextReviewDate,
|
||||
Role: input.Role,
|
||||
DataProtectionOfficerID: input.DataProtectionOfficerID,
|
||||
VendorIDs: input.VendorIds,
|
||||
}
|
||||
|
||||
activity, err := prb.ProcessingActivities.Create(ctx, &req)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot create processing activity", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.CreateProcessingActivityPayload{
|
||||
ProcessingActivityEdge: types.NewProcessingActivityEdge(activity, coredata.ProcessingActivityOrderFieldCreatedAt),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateProcessingActivity is the resolver for the updateProcessingActivity field.
|
||||
func (r *mutationResolver) UpdateProcessingActivity(ctx context.Context, input types.UpdateProcessingActivityInput) (*types.UpdateProcessingActivityPayload, error) {
|
||||
if err := r.authorize(ctx, input.ID, probo.ActionProcessingActivityUpdate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.ID.TenantID())
|
||||
|
||||
req := probo.UpdateProcessingActivityRequest{
|
||||
ID: input.ID,
|
||||
Name: input.Name,
|
||||
Purpose: gqlutils.UnwrapOmittable(input.Purpose),
|
||||
DataSubjectCategory: gqlutils.UnwrapOmittable(input.DataSubjectCategory),
|
||||
PersonalDataCategory: gqlutils.UnwrapOmittable(input.PersonalDataCategory),
|
||||
SpecialOrCriminalData: input.SpecialOrCriminalData,
|
||||
LawfulBasis: input.LawfulBasis,
|
||||
Recipients: gqlutils.UnwrapOmittable(input.Recipients),
|
||||
Location: gqlutils.UnwrapOmittable(input.Location),
|
||||
InternationalTransfers: input.InternationalTransfers,
|
||||
TransferSafeguard: gqlutils.UnwrapOmittable(input.TransferSafeguards),
|
||||
RetentionPeriod: gqlutils.UnwrapOmittable(input.RetentionPeriod),
|
||||
SecurityMeasures: gqlutils.UnwrapOmittable(input.SecurityMeasures),
|
||||
DataProtectionImpactAssessmentNeeded: input.DataProtectionImpactAssessmentNeeded,
|
||||
TransferImpactAssessmentNeeded: input.TransferImpactAssessmentNeeded,
|
||||
LastReviewDate: gqlutils.UnwrapOmittable(input.LastReviewDate),
|
||||
NextReviewDate: gqlutils.UnwrapOmittable(input.NextReviewDate),
|
||||
Role: input.Role,
|
||||
DataProtectionOfficerID: gqlutils.UnwrapOmittable(input.DataProtectionOfficerID),
|
||||
VendorIDs: &input.VendorIds,
|
||||
}
|
||||
|
||||
activity, err := prb.ProcessingActivities.Update(ctx, &req)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot update processing activity", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.UpdateProcessingActivityPayload{
|
||||
ProcessingActivity: types.NewProcessingActivity(activity),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteProcessingActivity is the resolver for the deleteProcessingActivity field.
|
||||
func (r *mutationResolver) DeleteProcessingActivity(ctx context.Context, input types.DeleteProcessingActivityInput) (*types.DeleteProcessingActivityPayload, error) {
|
||||
if err := r.authorize(ctx, input.ProcessingActivityID, probo.ActionProcessingActivityDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.ProcessingActivityID.TenantID())
|
||||
|
||||
err := prb.ProcessingActivities.Delete(ctx, input.ProcessingActivityID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot delete processing activity", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DeleteProcessingActivityPayload{
|
||||
DeletedProcessingActivityID: input.ProcessingActivityID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ExportProcessingActivitiesPDF is the resolver for the exportProcessingActivitiesPDF field.
|
||||
func (r *mutationResolver) ExportProcessingActivitiesPDF(ctx context.Context, input types.ExportProcessingActivitiesPDFInput) (*types.ExportProcessingActivitiesPDFPayload, error) {
|
||||
if err := r.authorize(ctx, input.OrganizationID, probo.ActionProcessingActivityExport); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
||||
|
||||
var snapshotIDPtr *gid.GID
|
||||
if input.Filter != nil {
|
||||
snapshotIDPtr = input.Filter.SnapshotID
|
||||
}
|
||||
processingActivityFilter := coredata.NewProcessingActivityFilter(&snapshotIDPtr)
|
||||
|
||||
pdf, err := prb.ProcessingActivities.ExportPDF(ctx, input.OrganizationID, processingActivityFilter)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot export processing activities PDF", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.ExportProcessingActivitiesPDFPayload{
|
||||
Data: fmt.Sprintf("data:application/pdf;base64,%s", base64.StdEncoding.EncodeToString(pdf)),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ProcessingActivities is the resolver for the processingActivities field.
|
||||
func (r *organizationResolver) ProcessingActivities(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ProcessingActivityOrderBy, filter *types.ProcessingActivityFilter) (*types.ProcessingActivityConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionProcessingActivityList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.ProcessingActivityOrderField]{
|
||||
Field: coredata.ProcessingActivityOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.ProcessingActivityOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
processingActivityFilter := coredata.NewProcessingActivityFilter(nil)
|
||||
if filter != nil {
|
||||
processingActivityFilter = coredata.NewProcessingActivityFilter(&filter.SnapshotID)
|
||||
}
|
||||
|
||||
page, err := prb.ProcessingActivities.ListForOrganizationID(ctx, obj.ID, cursor, processingActivityFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list organization processing activities", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewProcessingActivityConnection(page, r, obj.ID, filter), nil
|
||||
}
|
||||
|
||||
// Organization is the resolver for the organization field.
|
||||
func (r *processingActivityResolver) Organization(ctx context.Context, obj *types.ProcessingActivity) (*types.Organization, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
loaders := dataloader.FromContext(ctx)
|
||||
|
||||
organization, err := loaders.Organization.Load(ctx, obj.Organization.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get organization", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewOrganization(organization), nil
|
||||
}
|
||||
|
||||
// DataProtectionOfficer is the resolver for the dataProtectionOfficer field.
|
||||
func (r *processingActivityResolver) DataProtectionOfficer(ctx context.Context, obj *types.ProcessingActivity) (*types.Profile, error) {
|
||||
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if obj.DataProtectionOfficer == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
loaders := dataloader.FromContext(ctx)
|
||||
|
||||
dpo, err := loaders.Profile.Load(ctx, obj.DataProtectionOfficer.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, dataloadgen.ErrNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get data protection officer", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewProfile(dpo), nil
|
||||
}
|
||||
|
||||
// Vendors is the resolver for the vendors field.
|
||||
func (r *processingActivityResolver) Vendors(ctx context.Context, obj *types.ProcessingActivity, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorOrderBy) (*types.VendorConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionVendorList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.VendorOrderField]{
|
||||
Field: coredata.VendorOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.VendorOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
page, err := prb.Vendors.ListForProcessingActivityID(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list processing activity vendors", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewVendorConnection(page, r, obj.ID), nil
|
||||
}
|
||||
|
||||
// DataProtectionImpactAssessment is the resolver for the dataProtectionImpactAssessment field.
|
||||
func (r *processingActivityResolver) DataProtectionImpactAssessment(ctx context.Context, obj *types.ProcessingActivity) (*types.DataProtectionImpactAssessment, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionDataProtectionImpactAssessmentGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
dpia, err := prb.DataProtectionImpactAssessments.GetByProcessingActivityID(ctx, obj.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) {
|
||||
return nil, nil
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot get processing activity dpia", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewDataProtectionImpactAssessment(dpia), nil
|
||||
}
|
||||
|
||||
// TransferImpactAssessment is the resolver for the transferImpactAssessment field.
|
||||
func (r *processingActivityResolver) TransferImpactAssessment(ctx context.Context, obj *types.ProcessingActivity) (*types.TransferImpactAssessment, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionTransferImpactAssessmentGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
tia, err := prb.TransferImpactAssessments.GetByProcessingActivityID(ctx, obj.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) {
|
||||
return nil, nil
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot get processing activity tia", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewTransferImpactAssessment(tia), nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *processingActivityResolver) Permission(ctx context.Context, obj *types.ProcessingActivity, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// TotalCount is the resolver for the totalCount field.
|
||||
func (r *processingActivityConnectionResolver) TotalCount(ctx context.Context, obj *types.ProcessingActivityConnection) (int, error) {
|
||||
if err := r.authorize(ctx, obj.ParentID, probo.ActionProcessingActivityList); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
||||
|
||||
switch obj.Resolver.(type) {
|
||||
case *organizationResolver:
|
||||
processingActivityFilter := coredata.NewProcessingActivityFilter(nil)
|
||||
if obj.Filter != nil {
|
||||
processingActivityFilter = coredata.NewProcessingActivityFilter(&obj.Filter.SnapshotID)
|
||||
}
|
||||
|
||||
count, err := prb.ProcessingActivities.CountForOrganizationID(ctx, obj.ParentID, processingActivityFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count organization processing activities", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "unsupported resolver")
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
// ProcessingActivity returns schema.ProcessingActivityResolver implementation.
|
||||
func (r *Resolver) ProcessingActivity() schema.ProcessingActivityResolver {
|
||||
return &processingActivityResolver{r}
|
||||
}
|
||||
|
||||
// ProcessingActivityConnection returns schema.ProcessingActivityConnectionResolver implementation.
|
||||
func (r *Resolver) ProcessingActivityConnection() schema.ProcessingActivityConnectionResolver {
|
||||
return &processingActivityConnectionResolver{r}
|
||||
}
|
||||
|
||||
type processingActivityResolver struct{ *Resolver }
|
||||
type processingActivityConnectionResolver struct{ *Resolver }
|
||||
202
pkg/server/api/console/v1/rights_request.resolvers.go
Normal file
202
pkg/server/api/console/v1/rights_request.resolvers.go
Normal file
@@ -0,0 +1,202 @@
|
||||
package console_v1
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver
|
||||
// implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.87
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"go.gearno.de/kit/log"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/iam"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"go.probo.inc/probo/pkg/probo"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/schema"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/types"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils"
|
||||
"go.probo.inc/probo/pkg/validator"
|
||||
)
|
||||
|
||||
// CreateRightsRequest is the resolver for the createRightsRequest field.
|
||||
func (r *mutationResolver) CreateRightsRequest(ctx context.Context, input types.CreateRightsRequestInput) (*types.CreateRightsRequestPayload, error) {
|
||||
if err := r.authorize(ctx, input.OrganizationID, probo.ActionRightsRequestCreate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
||||
|
||||
req := probo.CreateRightsRequestRequest{
|
||||
OrganizationID: input.OrganizationID,
|
||||
RequestType: &input.RequestType,
|
||||
RequestState: &input.RequestState,
|
||||
DataSubject: input.DataSubject,
|
||||
Contact: input.Contact,
|
||||
Details: input.Details,
|
||||
Deadline: input.Deadline,
|
||||
ActionTaken: input.ActionTaken,
|
||||
}
|
||||
|
||||
rightsRequest, err := prb.RightsRequests.Create(ctx, &req)
|
||||
if err != nil {
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot create rights request", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.CreateRightsRequestPayload{
|
||||
RightsRequestEdge: types.NewRightsRequestEdge(rightsRequest, coredata.RightsRequestOrderFieldCreatedAt),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateRightsRequest is the resolver for the updateRightsRequest field.
|
||||
func (r *mutationResolver) UpdateRightsRequest(ctx context.Context, input types.UpdateRightsRequestInput) (*types.UpdateRightsRequestPayload, error) {
|
||||
if err := r.authorize(ctx, input.ID, probo.ActionRightsRequestUpdate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.ID.TenantID())
|
||||
|
||||
req := probo.UpdateRightsRequestRequest{
|
||||
ID: input.ID,
|
||||
RequestType: input.RequestType,
|
||||
RequestState: input.RequestState,
|
||||
DataSubject: gqlutils.UnwrapOmittable(input.DataSubject),
|
||||
Contact: gqlutils.UnwrapOmittable(input.Contact),
|
||||
Details: gqlutils.UnwrapOmittable(input.Details),
|
||||
Deadline: gqlutils.UnwrapOmittable(input.Deadline),
|
||||
ActionTaken: gqlutils.UnwrapOmittable(input.ActionTaken),
|
||||
}
|
||||
|
||||
rightsRequest, err := prb.RightsRequests.Update(ctx, &req)
|
||||
if err != nil {
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot update rights request", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.UpdateRightsRequestPayload{
|
||||
RightsRequest: types.NewRightsRequest(rightsRequest),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteRightsRequest is the resolver for the deleteRightsRequest field.
|
||||
func (r *mutationResolver) DeleteRightsRequest(ctx context.Context, input types.DeleteRightsRequestInput) (*types.DeleteRightsRequestPayload, error) {
|
||||
if err := r.authorize(ctx, input.RightsRequestID, probo.ActionRightsRequestDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.RightsRequestID.TenantID())
|
||||
|
||||
err := prb.RightsRequests.Delete(ctx, input.RightsRequestID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot delete rights request", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DeleteRightsRequestPayload{
|
||||
DeletedRightsRequestID: input.RightsRequestID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// RightsRequests is the resolver for the rightsRequests field.
|
||||
func (r *organizationResolver) RightsRequests(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.RightsRequestOrderBy) (*types.RightsRequestConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionRightsRequestList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.RightsRequestOrderField]{
|
||||
Field: coredata.RightsRequestOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.RightsRequestOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
page, err := prb.RightsRequests.ListForOrganizationID(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list organization rights requests", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewRightsRequestConnection(page, r, obj.ID), nil
|
||||
}
|
||||
|
||||
// Organization is the resolver for the organization field.
|
||||
func (r *rightsRequestResolver) Organization(ctx context.Context, obj *types.RightsRequest) (*types.Organization, error) {
|
||||
if err := r.authorize(ctx, obj.ID, iam.ActionOrganizationGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
rightsRequest, err := prb.RightsRequests.Get(ctx, obj.ID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot get rights request", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
organization, err := prb.Organizations.Get(ctx, rightsRequest.OrganizationID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot get organization", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewOrganization(organization), nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *rightsRequestResolver) Permission(ctx context.Context, obj *types.RightsRequest, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// TotalCount is the resolver for the totalCount field.
|
||||
func (r *rightsRequestConnectionResolver) TotalCount(ctx context.Context, obj *types.RightsRequestConnection) (int, error) {
|
||||
if err := r.authorize(ctx, obj.ParentID, probo.ActionRightsRequestList); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
||||
|
||||
switch obj.Resolver.(type) {
|
||||
case *organizationResolver:
|
||||
count, err := prb.RightsRequests.CountByOrganizationID(ctx, obj.ParentID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count rights requests", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return count, nil
|
||||
default:
|
||||
r.logger.ErrorCtx(ctx, "unsupported resolver type for RightsRequestConnection")
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
// RightsRequest returns schema.RightsRequestResolver implementation.
|
||||
func (r *Resolver) RightsRequest() schema.RightsRequestResolver { return &rightsRequestResolver{r} }
|
||||
|
||||
// RightsRequestConnection returns schema.RightsRequestConnectionResolver implementation.
|
||||
func (r *Resolver) RightsRequestConnection() schema.RightsRequestConnectionResolver {
|
||||
return &rightsRequestConnectionResolver{r}
|
||||
}
|
||||
|
||||
type rightsRequestResolver struct{ *Resolver }
|
||||
type rightsRequestConnectionResolver struct{ *Resolver }
|
||||
505
pkg/server/api/console/v1/risk.resolvers.go
Normal file
505
pkg/server/api/console/v1/risk.resolvers.go
Normal file
@@ -0,0 +1,505 @@
|
||||
package console_v1
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver
|
||||
// implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.87
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/vikstrous/dataloadgen"
|
||||
"go.gearno.de/kit/log"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/iam"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"go.probo.inc/probo/pkg/probo"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/dataloader"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/schema"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/types"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils"
|
||||
"go.probo.inc/probo/pkg/validator"
|
||||
)
|
||||
|
||||
// CreateRisk is the resolver for the createRisk field.
|
||||
func (r *mutationResolver) CreateRisk(ctx context.Context, input types.CreateRiskInput) (*types.CreateRiskPayload, error) {
|
||||
if err := r.authorize(ctx, input.OrganizationID, probo.ActionRiskCreate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
||||
|
||||
risk, err := prb.Risks.Create(
|
||||
ctx,
|
||||
probo.CreateRiskRequest{
|
||||
OrganizationID: input.OrganizationID,
|
||||
Name: input.Name,
|
||||
Description: input.Description,
|
||||
Category: input.Category,
|
||||
Treatment: input.Treatment,
|
||||
OwnerID: input.OwnerID,
|
||||
InherentLikelihood: input.InherentLikelihood,
|
||||
InherentImpact: input.InherentImpact,
|
||||
ResidualLikelihood: input.ResidualLikelihood,
|
||||
ResidualImpact: input.ResidualImpact,
|
||||
Note: input.Note,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceAlreadyExists) {
|
||||
return nil, gqlutils.Conflict(ctx, err)
|
||||
}
|
||||
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot create risk", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.CreateRiskPayload{
|
||||
RiskEdge: types.NewRiskEdge(risk, coredata.RiskOrderFieldCreatedAt),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateRisk is the resolver for the updateRisk field.
|
||||
func (r *mutationResolver) UpdateRisk(ctx context.Context, input types.UpdateRiskInput) (*types.UpdateRiskPayload, error) {
|
||||
if err := r.authorize(ctx, input.ID, probo.ActionRiskUpdate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.ID.TenantID())
|
||||
|
||||
risk, err := prb.Risks.Update(
|
||||
ctx,
|
||||
probo.UpdateRiskRequest{
|
||||
ID: input.ID,
|
||||
Name: input.Name,
|
||||
Description: gqlutils.UnwrapOmittable(input.Description),
|
||||
Category: input.Category,
|
||||
Treatment: input.Treatment,
|
||||
OwnerID: gqlutils.UnwrapOmittable(input.OwnerID),
|
||||
InherentLikelihood: input.InherentLikelihood,
|
||||
InherentImpact: input.InherentImpact,
|
||||
ResidualLikelihood: input.ResidualLikelihood,
|
||||
ResidualImpact: input.ResidualImpact,
|
||||
Note: input.Note,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot update risk", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.UpdateRiskPayload{
|
||||
Risk: types.NewRisk(risk),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteRisk is the resolver for the deleteRisk field.
|
||||
func (r *mutationResolver) DeleteRisk(ctx context.Context, input types.DeleteRiskInput) (*types.DeleteRiskPayload, error) {
|
||||
if err := r.authorize(ctx, input.RiskID, probo.ActionRiskDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.RiskID.TenantID())
|
||||
|
||||
err := prb.Risks.Delete(ctx, input.RiskID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot delete risk", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DeleteRiskPayload{
|
||||
DeletedRiskID: input.RiskID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreateRiskMeasureMapping is the resolver for the createRiskMeasureMapping field.
|
||||
func (r *mutationResolver) CreateRiskMeasureMapping(ctx context.Context, input types.CreateRiskMeasureMappingInput) (*types.CreateRiskMeasureMappingPayload, error) {
|
||||
if err := r.authorize(ctx, input.RiskID, probo.ActionRiskMeasureMappingCreate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.RiskID.TenantID())
|
||||
|
||||
risk, measure, err := prb.Risks.CreateMeasureMapping(ctx, input.RiskID, input.MeasureID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot create risk measure mapping", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.CreateRiskMeasureMappingPayload{
|
||||
RiskEdge: types.NewRiskEdge(risk, coredata.RiskOrderFieldCreatedAt),
|
||||
MeasureEdge: types.NewMeasureEdge(measure, coredata.MeasureOrderFieldCreatedAt),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteRiskMeasureMapping is the resolver for the deleteRiskMeasureMapping field.
|
||||
func (r *mutationResolver) DeleteRiskMeasureMapping(ctx context.Context, input types.DeleteRiskMeasureMappingInput) (*types.DeleteRiskMeasureMappingPayload, error) {
|
||||
if err := r.authorize(ctx, input.RiskID, probo.ActionRiskMeasureMappingDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.RiskID.TenantID())
|
||||
|
||||
risk, measure, err := prb.Risks.DeleteMeasureMapping(ctx, input.RiskID, input.MeasureID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot delete risk measure mapping", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DeleteRiskMeasureMappingPayload{
|
||||
DeletedRiskID: risk.ID,
|
||||
DeletedMeasureID: measure.ID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreateRiskDocumentMapping is the resolver for the createRiskDocumentMapping field.
|
||||
func (r *mutationResolver) CreateRiskDocumentMapping(ctx context.Context, input types.CreateRiskDocumentMappingInput) (*types.CreateRiskDocumentMappingPayload, error) {
|
||||
if err := r.authorize(ctx, input.RiskID, probo.ActionRiskDocumentMappingCreate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.RiskID.TenantID())
|
||||
|
||||
risk, document, err := prb.Risks.CreateDocumentMapping(ctx, input.RiskID, input.DocumentID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot create risk document mapping", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.CreateRiskDocumentMappingPayload{
|
||||
RiskEdge: types.NewRiskEdge(risk, coredata.RiskOrderFieldCreatedAt),
|
||||
DocumentEdge: types.NewDocumentEdge(document, coredata.DocumentOrderFieldTitle),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteRiskDocumentMapping is the resolver for the deleteRiskDocumentMapping field.
|
||||
func (r *mutationResolver) DeleteRiskDocumentMapping(ctx context.Context, input types.DeleteRiskDocumentMappingInput) (*types.DeleteRiskDocumentMappingPayload, error) {
|
||||
if err := r.authorize(ctx, input.RiskID, probo.ActionRiskDocumentMappingDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.RiskID.TenantID())
|
||||
|
||||
risk, document, err := prb.Risks.DeleteDocumentMapping(ctx, input.RiskID, input.DocumentID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot delete risk document mapping", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DeleteRiskDocumentMappingPayload{
|
||||
DeletedRiskID: risk.ID,
|
||||
DeletedDocumentID: document.ID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreateRiskObligationMapping is the resolver for the createRiskObligationMapping field.
|
||||
func (r *mutationResolver) CreateRiskObligationMapping(ctx context.Context, input types.CreateRiskObligationMappingInput) (*types.CreateRiskObligationMappingPayload, error) {
|
||||
if err := r.authorize(ctx, input.RiskID, probo.ActionRiskObligationMappingCreate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.RiskID.TenantID())
|
||||
|
||||
risk, obligation, err := prb.Risks.CreateObligationMapping(ctx, input.RiskID, input.ObligationID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot create risk obligation mapping", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.CreateRiskObligationMappingPayload{
|
||||
RiskEdge: types.NewRiskEdge(risk, coredata.RiskOrderFieldCreatedAt),
|
||||
ObligationEdge: types.NewObligationEdge(obligation, coredata.ObligationOrderFieldCreatedAt),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteRiskObligationMapping is the resolver for the deleteRiskObligationMapping field.
|
||||
func (r *mutationResolver) DeleteRiskObligationMapping(ctx context.Context, input types.DeleteRiskObligationMappingInput) (*types.DeleteRiskObligationMappingPayload, error) {
|
||||
if err := r.authorize(ctx, input.RiskID, probo.ActionRiskObligationMappingDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.RiskID.TenantID())
|
||||
|
||||
risk, obligation, err := prb.Risks.DeleteObligationMapping(ctx, input.RiskID, input.ObligationID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot delete risk obligation mapping", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DeleteRiskObligationMappingPayload{
|
||||
DeletedRiskID: risk.ID,
|
||||
DeletedObligationID: obligation.ID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Risks is the resolver for the risks field.
|
||||
func (r *organizationResolver) Risks(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.RiskOrderBy, filter *types.RiskFilter) (*types.RiskConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionRiskList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.RiskOrderField]{
|
||||
Field: coredata.RiskOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.RiskOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
var riskFilter = coredata.NewRiskFilter(nil, nil)
|
||||
if filter != nil {
|
||||
riskFilter = coredata.NewRiskFilter(filter.Query, &filter.SnapshotID)
|
||||
}
|
||||
|
||||
page, err := prb.Risks.ListForOrganizationID(ctx, obj.ID, cursor, riskFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list organization risks", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewRiskConnection(page, r, obj.ID, riskFilter), nil
|
||||
}
|
||||
|
||||
// Owner is the resolver for the owner field.
|
||||
func (r *riskResolver) Owner(ctx context.Context, obj *types.Risk) (*types.Profile, error) {
|
||||
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if obj.Owner == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
loaders := dataloader.FromContext(ctx)
|
||||
|
||||
owner, err := loaders.Profile.Load(ctx, obj.Owner.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get owner", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewProfile(owner), nil
|
||||
}
|
||||
|
||||
// Organization is the resolver for the organization field.
|
||||
func (r *riskResolver) Organization(ctx context.Context, obj *types.Risk) (*types.Organization, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
loaders := dataloader.FromContext(ctx)
|
||||
|
||||
organization, err := loaders.Organization.Load(ctx, obj.Organization.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get organization", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewOrganization(organization), nil
|
||||
}
|
||||
|
||||
// Measures is the resolver for the measures field.
|
||||
func (r *riskResolver) Measures(ctx context.Context, obj *types.Risk, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.MeasureOrderBy, filter *types.MeasureFilter) (*types.MeasureConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionMeasureList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.MeasureOrderField]{
|
||||
Field: coredata.MeasureOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.MeasureOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
var measureFilter = coredata.NewMeasureFilter(nil, nil, nil)
|
||||
if filter != nil {
|
||||
measureFilter = coredata.NewMeasureFilter(filter.Query, filter.State, filter.Category)
|
||||
}
|
||||
|
||||
page, err := prb.Measures.ListForRiskID(ctx, obj.ID, cursor, measureFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list risk measures", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewMeasureConnection(page, r, obj.ID, measureFilter), nil
|
||||
}
|
||||
|
||||
// Documents is the resolver for the documents field.
|
||||
func (r *riskResolver) Documents(ctx context.Context, obj *types.Risk, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentOrderBy, filter *types.DocumentFilter) (*types.DocumentConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionDocumentList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.DocumentOrderField]{
|
||||
Field: coredata.DocumentOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.DocumentOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
var documentFilter = coredata.NewDocumentFilter(nil)
|
||||
if filter != nil {
|
||||
documentFilter = coredata.NewDocumentFilter(filter.Query).
|
||||
WithDocumentTypes(filter.DocumentTypes).
|
||||
WithClassifications(filter.Classifications)
|
||||
}
|
||||
|
||||
page, err := prb.Documents.ListForRiskID(ctx, obj.ID, cursor, documentFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list risk documents", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewDocumentConnection(page, r, obj.ID, documentFilter), nil
|
||||
}
|
||||
|
||||
// Controls is the resolver for the controls field.
|
||||
func (r *riskResolver) Controls(ctx context.Context, obj *types.Risk, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ControlOrderBy, filter *types.ControlFilter) (*types.ControlConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionControlList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.ControlOrderField]{
|
||||
Field: coredata.ControlOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.ControlOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
var filters = coredata.NewControlFilter(nil)
|
||||
if filter != nil {
|
||||
filters = coredata.NewControlFilter(filter.Query)
|
||||
}
|
||||
|
||||
page, err := prb.Controls.ListForRiskID(ctx, obj.ID, cursor, filters)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list risk controls", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewControlConnection(page, r, obj.ID, filters), nil
|
||||
}
|
||||
|
||||
// Obligations is the resolver for the obligations field.
|
||||
func (r *riskResolver) Obligations(ctx context.Context, obj *types.Risk, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ObligationOrderBy, filter *types.ObligationFilter) (*types.ObligationConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionObligationList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.ObligationOrderField]{
|
||||
Field: coredata.ObligationOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.ObligationOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
var obligationFilter = coredata.NewObligationFilter(nil)
|
||||
if filter != nil {
|
||||
obligationFilter = coredata.NewObligationFilter(&filter.SnapshotID)
|
||||
}
|
||||
|
||||
page, err := prb.Obligations.ListForRiskID(ctx, obj.ID, cursor, obligationFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list risk obligations", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewObligationConnection(page, r, obj.ID, filter), nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *riskResolver) Permission(ctx context.Context, obj *types.Risk, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// TotalCount is the resolver for the totalCount field.
|
||||
func (r *riskConnectionResolver) TotalCount(ctx context.Context, obj *types.RiskConnection) (int, error) {
|
||||
if err := r.authorize(ctx, obj.ParentID, probo.ActionRiskList); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
||||
|
||||
switch obj.Resolver.(type) {
|
||||
case *measureResolver:
|
||||
count, err := prb.Risks.CountForMeasureID(ctx, obj.ParentID, obj.Filters)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count risks", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
case *organizationResolver:
|
||||
count, err := prb.Risks.CountForOrganizationID(ctx, obj.ParentID, obj.Filters)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count risks", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "unsupported resolver")
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
// Risk returns schema.RiskResolver implementation.
|
||||
func (r *Resolver) Risk() schema.RiskResolver { return &riskResolver{r} }
|
||||
|
||||
// RiskConnection returns schema.RiskConnectionResolver implementation.
|
||||
func (r *Resolver) RiskConnection() schema.RiskConnectionResolver { return &riskConnectionResolver{r} }
|
||||
|
||||
type riskResolver struct{ *Resolver }
|
||||
type riskConnectionResolver struct{ *Resolver }
|
||||
File diff suppressed because it is too large
Load Diff
195
pkg/server/api/console/v1/snapshot.resolvers.go
Normal file
195
pkg/server/api/console/v1/snapshot.resolvers.go
Normal file
@@ -0,0 +1,195 @@
|
||||
package console_v1
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver
|
||||
// implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.87
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"go.gearno.de/kit/log"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"go.probo.inc/probo/pkg/probo"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/schema"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/types"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils"
|
||||
)
|
||||
|
||||
// CreateSnapshot is the resolver for the createSnapshot field.
|
||||
func (r *mutationResolver) CreateSnapshot(ctx context.Context, input types.CreateSnapshotInput) (*types.CreateSnapshotPayload, error) {
|
||||
if err := r.authorize(ctx, input.OrganizationID, probo.ActionSnapshotCreate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
||||
|
||||
snapshot, err := prb.Snapshots.Create(
|
||||
ctx,
|
||||
&probo.CreateSnapshotRequest{
|
||||
OrganizationID: input.OrganizationID,
|
||||
Name: input.Name,
|
||||
Description: input.Description,
|
||||
Type: input.Type,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot create snapshot", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.CreateSnapshotPayload{
|
||||
SnapshotEdge: types.NewSnapshotEdge(snapshot, coredata.SnapshotOrderFieldCreatedAt),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteSnapshot is the resolver for the deleteSnapshot field.
|
||||
func (r *mutationResolver) DeleteSnapshot(ctx context.Context, input types.DeleteSnapshotInput) (*types.DeleteSnapshotPayload, error) {
|
||||
if err := r.authorize(ctx, input.SnapshotID, probo.ActionSnapshotDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.SnapshotID.TenantID())
|
||||
|
||||
err := prb.Snapshots.Delete(ctx, input.SnapshotID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot delete snapshot", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DeleteSnapshotPayload{
|
||||
DeletedSnapshotID: input.SnapshotID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Snapshots is the resolver for the snapshots field.
|
||||
func (r *organizationResolver) Snapshots(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.SnapshotOrderBy) (*types.SnapshotConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionSnapshotList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.SnapshotOrderField]{
|
||||
Field: coredata.SnapshotOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.SnapshotOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
page, err := prb.Snapshots.ListForOrganizationID(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list organization snapshots", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewSnapshotConnection(page, r, obj.ID), nil
|
||||
}
|
||||
|
||||
// Organization is the resolver for the organization field.
|
||||
func (r *snapshotResolver) Organization(ctx context.Context, obj *types.Snapshot) (*types.Organization, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
snapshot, err := prb.Snapshots.Get(ctx, obj.ID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot get snapshot", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
organization, err := prb.Organizations.Get(ctx, snapshot.OrganizationID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get organization", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewOrganization(organization), nil
|
||||
}
|
||||
|
||||
// Controls is the resolver for the controls field.
|
||||
func (r *snapshotResolver) Controls(ctx context.Context, obj *types.Snapshot, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ControlOrderBy, filter *types.ControlFilter) (*types.ControlConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionControlList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.ControlOrderField]{
|
||||
Field: coredata.ControlOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.ControlOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
var controlFilter = coredata.NewControlFilter(nil)
|
||||
if filter != nil {
|
||||
controlFilter = coredata.NewControlFilter(filter.Query)
|
||||
}
|
||||
|
||||
page, err := prb.Controls.ListForSnapshotID(ctx, obj.ID, cursor, controlFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list snapshot controls", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewControlConnection(page, r, obj.ID, controlFilter), nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *snapshotResolver) Permission(ctx context.Context, obj *types.Snapshot, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// TotalCount is the resolver for the totalCount field.
|
||||
func (r *snapshotConnectionResolver) TotalCount(ctx context.Context, obj *types.SnapshotConnection) (int, error) {
|
||||
if err := r.authorize(ctx, obj.ParentID, probo.ActionSnapshotList); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
||||
|
||||
switch obj.Resolver.(type) {
|
||||
case *organizationResolver:
|
||||
count, err := prb.Snapshots.CountForOrganizationID(ctx, obj.ParentID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count snapshots", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "unsupported resolver")
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
// Snapshot returns schema.SnapshotResolver implementation.
|
||||
func (r *Resolver) Snapshot() schema.SnapshotResolver { return &snapshotResolver{r} }
|
||||
|
||||
// SnapshotConnection returns schema.SnapshotConnectionResolver implementation.
|
||||
func (r *Resolver) SnapshotConnection() schema.SnapshotConnectionResolver {
|
||||
return &snapshotConnectionResolver{r}
|
||||
}
|
||||
|
||||
type snapshotResolver struct{ *Resolver }
|
||||
type snapshotConnectionResolver struct{ *Resolver }
|
||||
289
pkg/server/api/console/v1/task.resolvers.go
Normal file
289
pkg/server/api/console/v1/task.resolvers.go
Normal file
@@ -0,0 +1,289 @@
|
||||
package console_v1
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver
|
||||
// implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.87
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/vikstrous/dataloadgen"
|
||||
"go.gearno.de/kit/log"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/iam"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"go.probo.inc/probo/pkg/probo"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/dataloader"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/schema"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/types"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils"
|
||||
"go.probo.inc/probo/pkg/validator"
|
||||
)
|
||||
|
||||
// CreateTask is the resolver for the createTask field.
|
||||
func (r *mutationResolver) CreateTask(ctx context.Context, input types.CreateTaskInput) (*types.CreateTaskPayload, error) {
|
||||
if err := r.authorize(ctx, input.OrganizationID, probo.ActionTaskCreate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
||||
|
||||
task, err := prb.Tasks.Create(
|
||||
ctx,
|
||||
probo.CreateTaskRequest{
|
||||
MeasureID: input.MeasureID,
|
||||
OrganizationID: input.OrganizationID,
|
||||
Name: input.Name,
|
||||
Description: input.Description,
|
||||
Priority: input.Priority,
|
||||
TimeEstimate: input.TimeEstimate,
|
||||
AssignedToID: input.AssignedToID,
|
||||
Deadline: input.Deadline,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceAlreadyExists) {
|
||||
return nil, gqlutils.Conflict(ctx, err)
|
||||
}
|
||||
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot create task", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.CreateTaskPayload{
|
||||
TaskEdge: types.NewTaskEdge(task, coredata.TaskOrderFieldCreatedAt),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateTask is the resolver for the updateTask field.
|
||||
func (r *mutationResolver) UpdateTask(ctx context.Context, input types.UpdateTaskInput) (*types.UpdateTaskPayload, error) {
|
||||
if err := r.authorize(ctx, input.TaskID, probo.ActionTaskUpdate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.TaskID.TenantID())
|
||||
|
||||
task, err := prb.Tasks.Update(
|
||||
ctx,
|
||||
probo.UpdateTaskRequest{
|
||||
TaskID: input.TaskID,
|
||||
Name: input.Name,
|
||||
Description: gqlutils.UnwrapOmittable(input.Description),
|
||||
State: input.State,
|
||||
Priority: input.Priority,
|
||||
Rank: input.Rank,
|
||||
TimeEstimate: gqlutils.UnwrapOmittable(input.TimeEstimate),
|
||||
Deadline: gqlutils.UnwrapOmittable(input.Deadline),
|
||||
AssignedToID: gqlutils.UnwrapOmittable(input.AssignedToID),
|
||||
MeasureID: gqlutils.UnwrapOmittable(input.MeasureID),
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot update task", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.UpdateTaskPayload{
|
||||
Task: types.NewTask(task),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteTask is the resolver for the deleteTask field.
|
||||
func (r *mutationResolver) DeleteTask(ctx context.Context, input types.DeleteTaskInput) (*types.DeleteTaskPayload, error) {
|
||||
if err := r.authorize(ctx, input.TaskID, probo.ActionTaskDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.TaskID.TenantID())
|
||||
|
||||
err := prb.Tasks.Delete(ctx, input.TaskID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot delete task", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DeleteTaskPayload{
|
||||
DeletedTaskID: input.TaskID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Tasks is the resolver for the tasks field.
|
||||
func (r *organizationResolver) Tasks(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.TaskOrderBy) (*types.TaskConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionTaskList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.TaskOrderField]{
|
||||
Field: coredata.TaskOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.TaskOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
page, err := prb.Tasks.ListForOrganizationID(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list organization tasks", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewTaskConnection(page, r, obj.ID), nil
|
||||
}
|
||||
|
||||
// AssignedTo is the resolver for the assignedTo field.
|
||||
func (r *taskResolver) AssignedTo(ctx context.Context, obj *types.Task) (*types.Profile, error) {
|
||||
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if obj.AssignedTo == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
loaders := dataloader.FromContext(ctx)
|
||||
|
||||
assignee, err := loaders.Profile.Load(ctx, obj.AssignedTo.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get assigned to", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewProfile(assignee), nil
|
||||
}
|
||||
|
||||
// Organization is the resolver for the organization field.
|
||||
func (r *taskResolver) Organization(ctx context.Context, obj *types.Task) (*types.Organization, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
loaders := dataloader.FromContext(ctx)
|
||||
|
||||
organization, err := loaders.Organization.Load(ctx, obj.Organization.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get organization", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewOrganization(organization), nil
|
||||
}
|
||||
|
||||
// Measure is the resolver for the measure field.
|
||||
func (r *taskResolver) Measure(ctx context.Context, obj *types.Task) (*types.Measure, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionMeasureGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if obj.Measure == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
loaders := dataloader.FromContext(ctx)
|
||||
|
||||
measure, err := loaders.Measure.Load(ctx, obj.Measure.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get measure", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewMeasure(measure), nil
|
||||
}
|
||||
|
||||
// Evidences is the resolver for the evidences field.
|
||||
func (r *taskResolver) Evidences(ctx context.Context, obj *types.Task, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.EvidenceOrderBy) (*types.EvidenceConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionEvidenceList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.EvidenceOrderField]{
|
||||
Field: coredata.EvidenceOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.EvidenceOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
page, err := prb.Evidences.ListForTaskID(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list task evidences", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewEvidenceConnection(page, r, obj.ID), nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *taskResolver) Permission(ctx context.Context, obj *types.Task, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// TotalCount is the resolver for the totalCount field.
|
||||
func (r *taskConnectionResolver) TotalCount(ctx context.Context, obj *types.TaskConnection) (int, error) {
|
||||
if err := r.authorize(ctx, obj.ParentID, probo.ActionTaskList); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
||||
|
||||
switch obj.Resolver.(type) {
|
||||
case *measureResolver:
|
||||
count, err := prb.Tasks.CountForMeasureID(ctx, obj.ParentID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count tasks", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
case *organizationResolver:
|
||||
count, err := prb.Tasks.CountForOrganizationID(ctx, obj.ParentID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count tasks", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "unsupported resolver")
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
// Task returns schema.TaskResolver implementation.
|
||||
func (r *Resolver) Task() schema.TaskResolver { return &taskResolver{r} }
|
||||
|
||||
// TaskConnection returns schema.TaskConnectionResolver implementation.
|
||||
func (r *Resolver) TaskConnection() schema.TaskConnectionResolver { return &taskConnectionResolver{r} }
|
||||
|
||||
type taskResolver struct{ *Resolver }
|
||||
type taskConnectionResolver struct{ *Resolver }
|
||||
1350
pkg/server/api/console/v1/trust_center.resolvers.go
Normal file
1350
pkg/server/api/console/v1/trust_center.resolvers.go
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1138
pkg/server/api/console/v1/vendor.resolvers.go
Normal file
1138
pkg/server/api/console/v1/vendor.resolvers.go
Normal file
File diff suppressed because it is too large
Load Diff
261
pkg/server/api/console/v1/webhook.resolvers.go
Normal file
261
pkg/server/api/console/v1/webhook.resolvers.go
Normal file
@@ -0,0 +1,261 @@
|
||||
package console_v1
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver
|
||||
// implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.87
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/vikstrous/dataloadgen"
|
||||
"go.gearno.de/kit/log"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"go.probo.inc/probo/pkg/probo"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/dataloader"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/schema"
|
||||
"go.probo.inc/probo/pkg/server/api/console/v1/types"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils"
|
||||
"go.probo.inc/probo/pkg/validator"
|
||||
)
|
||||
|
||||
// CreateWebhookSubscription is the resolver for the createWebhookSubscription field.
|
||||
func (r *mutationResolver) CreateWebhookSubscription(ctx context.Context, input types.CreateWebhookSubscriptionInput) (*types.CreateWebhookSubscriptionPayload, error) {
|
||||
if err := r.authorize(ctx, input.OrganizationID, probo.ActionWebhookSubscriptionCreate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
||||
|
||||
wc, err := prb.WebhookSubscriptions.Create(
|
||||
ctx,
|
||||
probo.CreateWebhookSubscriptionRequest{
|
||||
OrganizationID: input.OrganizationID,
|
||||
EndpointURL: input.EndpointURL,
|
||||
SelectedEvents: input.SelectedEvents,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot create webhook subscription", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.CreateWebhookSubscriptionPayload{
|
||||
WebhookSubscriptionEdge: types.NewWebhookSubscriptionEdge(wc, coredata.WebhookSubscriptionOrderFieldCreatedAt),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateWebhookSubscription is the resolver for the updateWebhookSubscription field.
|
||||
func (r *mutationResolver) UpdateWebhookSubscription(ctx context.Context, input types.UpdateWebhookSubscriptionInput) (*types.UpdateWebhookSubscriptionPayload, error) {
|
||||
if err := r.authorize(ctx, input.ID, probo.ActionWebhookSubscriptionUpdate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.ID.TenantID())
|
||||
|
||||
wc, err := prb.WebhookSubscriptions.Update(
|
||||
ctx,
|
||||
probo.UpdateWebhookSubscriptionRequest{
|
||||
WebhookSubscriptionID: input.ID,
|
||||
EndpointURL: input.EndpointURL,
|
||||
SelectedEvents: input.SelectedEvents,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot update webhook subscription", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.UpdateWebhookSubscriptionPayload{
|
||||
WebhookSubscription: types.NewWebhookSubscription(wc),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteWebhookSubscription is the resolver for the deleteWebhookSubscription field.
|
||||
func (r *mutationResolver) DeleteWebhookSubscription(ctx context.Context, input types.DeleteWebhookSubscriptionInput) (*types.DeleteWebhookSubscriptionPayload, error) {
|
||||
if err := r.authorize(ctx, input.WebhookSubscriptionID, probo.ActionWebhookSubscriptionDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.WebhookSubscriptionID.TenantID())
|
||||
|
||||
err := prb.WebhookSubscriptions.Delete(ctx, input.WebhookSubscriptionID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot delete webhook subscription", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DeleteWebhookSubscriptionPayload{
|
||||
DeletedWebhookSubscriptionID: input.WebhookSubscriptionID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// WebhookSubscriptions is the resolver for the webhookSubscriptions field.
|
||||
func (r *organizationResolver) WebhookSubscriptions(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.WebhookSubscriptionOrderBy) (*types.WebhookSubscriptionConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionWebhookSubscriptionList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.WebhookSubscriptionOrderField]{
|
||||
Field: coredata.WebhookSubscriptionOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.WebhookSubscriptionOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
page, err := prb.WebhookSubscriptions.ListForOrganizationID(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list organization webhook subscriptions", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewWebhookSubscriptionConnection(page, r, obj.ID), nil
|
||||
}
|
||||
|
||||
// TotalCount is the resolver for the totalCount field.
|
||||
func (r *webhookEventConnectionResolver) TotalCount(ctx context.Context, obj *types.WebhookEventConnection) (int, error) {
|
||||
if err := r.authorize(ctx, obj.ParentID, probo.ActionWebhookSubscriptionGet); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
||||
|
||||
count, err := prb.WebhookSubscriptions.CountEventsForSubscriptionID(ctx, obj.ParentID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count webhook events", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// Organization is the resolver for the organization field.
|
||||
func (r *webhookSubscriptionResolver) Organization(ctx context.Context, obj *types.WebhookSubscription) (*types.Organization, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
loaders := dataloader.FromContext(ctx)
|
||||
|
||||
organization, err := loaders.Organization.Load(ctx, obj.Organization.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot load organization", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewOrganization(organization), nil
|
||||
}
|
||||
|
||||
// SigningSecret is the resolver for the signingSecret field.
|
||||
func (r *webhookSubscriptionResolver) SigningSecret(ctx context.Context, obj *types.WebhookSubscription) (string, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionWebhookSubscriptionUpdate); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
signingSecret, err := prb.WebhookSubscriptions.GetSigningSecret(ctx, obj.ID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot get signing secret", log.Error(err))
|
||||
return "", gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return signingSecret, nil
|
||||
}
|
||||
|
||||
// Events is the resolver for the events field.
|
||||
func (r *webhookSubscriptionResolver) Events(ctx context.Context, obj *types.WebhookSubscription, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.WebhookEventOrderBy) (*types.WebhookEventConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionWebhookSubscriptionGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.WebhookEventOrderField]{
|
||||
Field: coredata.WebhookEventOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.WebhookEventOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
page, err := prb.WebhookSubscriptions.ListEventsForSubscriptionID(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list webhook events", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewWebhookEventConnection(page, r, obj.ID), nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *webhookSubscriptionResolver) Permission(ctx context.Context, obj *types.WebhookSubscription, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// TotalCount is the resolver for the totalCount field.
|
||||
func (r *webhookSubscriptionConnectionResolver) TotalCount(ctx context.Context, obj *types.WebhookSubscriptionConnection) (int, error) {
|
||||
if err := r.authorize(ctx, obj.ParentID, probo.ActionWebhookSubscriptionList); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
||||
|
||||
switch obj.Resolver.(type) {
|
||||
case *organizationResolver:
|
||||
count, err := prb.WebhookSubscriptions.CountForOrganizationID(ctx, obj.ParentID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count webhook subscriptions", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "unsupported resolver for webhook subscription connection", log.String("resolver", fmt.Sprintf("%T", obj.Resolver)))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
// WebhookEventConnection returns schema.WebhookEventConnectionResolver implementation.
|
||||
func (r *Resolver) WebhookEventConnection() schema.WebhookEventConnectionResolver {
|
||||
return &webhookEventConnectionResolver{r}
|
||||
}
|
||||
|
||||
// WebhookSubscription returns schema.WebhookSubscriptionResolver implementation.
|
||||
func (r *Resolver) WebhookSubscription() schema.WebhookSubscriptionResolver {
|
||||
return &webhookSubscriptionResolver{r}
|
||||
}
|
||||
|
||||
// WebhookSubscriptionConnection returns schema.WebhookSubscriptionConnectionResolver implementation.
|
||||
func (r *Resolver) WebhookSubscriptionConnection() schema.WebhookSubscriptionConnectionResolver {
|
||||
return &webhookSubscriptionConnectionResolver{r}
|
||||
}
|
||||
|
||||
type webhookEventConnectionResolver struct{ *Resolver }
|
||||
type webhookSubscriptionResolver struct{ *Resolver }
|
||||
type webhookSubscriptionConnectionResolver struct{ *Resolver }
|
||||
526
pkg/server/api/trust/v1/base.resolvers.go
Normal file
526
pkg/server/api/trust/v1/base.resolvers.go
Normal file
@@ -0,0 +1,526 @@
|
||||
package trust_v1
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver
|
||||
// implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.87
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go.gearno.de/kit/log"
|
||||
"go.probo.inc/probo/pkg/baseurl"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/iam"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"go.probo.inc/probo/pkg/saferedirect"
|
||||
"go.probo.inc/probo/pkg/server/api/authn"
|
||||
"go.probo.inc/probo/pkg/server/api/compliancepage"
|
||||
"go.probo.inc/probo/pkg/server/api/trust/v1/schema"
|
||||
"go.probo.inc/probo/pkg/server/api/trust/v1/types"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils"
|
||||
"go.probo.inc/probo/pkg/trust"
|
||||
)
|
||||
|
||||
// SendMagicLink is the resolver for the sendMagicLink field.
|
||||
func (r *mutationResolver) SendMagicLink(ctx context.Context, input types.SendMagicLinkInput) (*types.SendMagicLinkPayload, error) {
|
||||
trustCenter := compliancepage.CompliancePageFromContext(ctx)
|
||||
|
||||
baseURL := compliancepage.CompliancePageBaseURLFromContext(ctx)
|
||||
|
||||
safeRedirect := saferedirect.New(saferedirect.StaticHosts(baseurl.MustParse(*baseURL).Host()))
|
||||
|
||||
if input.Continue != nil {
|
||||
_, ok := safeRedirect.Validate(ctx, *input.Continue)
|
||||
if !ok {
|
||||
return nil, gqlutils.Invalidf(ctx, "invalid continue URL")
|
||||
}
|
||||
}
|
||||
|
||||
req := &iam.SendMagicLinkRequest{
|
||||
Email: input.Email,
|
||||
CompliancePageID: &trustCenter.ID,
|
||||
OrganizationID: trustCenter.OrganizationID,
|
||||
URLPath: "verify-magic-link",
|
||||
Continue: input.Continue,
|
||||
}
|
||||
|
||||
if err := r.iam.AuthService.SendMagicLink(ctx, req); err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot send magic link", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// VerifyMagicLink is the resolver for the verifyMagicLink field.
|
||||
func (r *mutationResolver) VerifyMagicLink(ctx context.Context, input types.VerifyMagicLinkInput) (*types.VerifyMagicLinkPayload, error) {
|
||||
session := authn.SessionFromContext(ctx)
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
|
||||
email, err := r.iam.AuthService.GetMagicLinkEmail(ctx, input.Token)
|
||||
if err != nil {
|
||||
var errExpiredToken *iam.ErrExpiredToken
|
||||
if errors.As(err, &errExpiredToken) {
|
||||
return nil, gqlutils.Invalid(ctx, err)
|
||||
}
|
||||
|
||||
var errInvalidToken *iam.ErrInvalidToken
|
||||
if errors.As(err, &errInvalidToken) {
|
||||
return nil, gqlutils.Invalid(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get magic link email", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
var continueURL *string
|
||||
|
||||
switch {
|
||||
case session == nil:
|
||||
var err error
|
||||
identity, session, continueURL, err = r.iam.AuthService.OpenSessionWithMagicLink(ctx, input.Token)
|
||||
if err != nil {
|
||||
var errExpiredToken *iam.ErrExpiredToken
|
||||
if errors.As(err, &errExpiredToken) {
|
||||
return nil, gqlutils.Invalid(ctx, err)
|
||||
}
|
||||
|
||||
var errInvalidToken *iam.ErrInvalidToken
|
||||
if errors.As(err, &errInvalidToken) {
|
||||
return nil, gqlutils.Invalid(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot open session with magic link", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
case identity.EmailAddress != email:
|
||||
if err := r.iam.SessionService.CloseSession(ctx, session.ID); err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot close session", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
var err error
|
||||
identity, session, continueURL, err = r.iam.AuthService.OpenSessionWithMagicLink(ctx, input.Token)
|
||||
if err != nil {
|
||||
var errExpiredToken *iam.ErrExpiredToken
|
||||
if errors.As(err, &errExpiredToken) {
|
||||
return nil, gqlutils.Invalid(ctx, err)
|
||||
}
|
||||
|
||||
var errInvalidToken *iam.ErrInvalidToken
|
||||
if errors.As(err, &errInvalidToken) {
|
||||
return nil, gqlutils.Invalid(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot open session with magic link", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
trustCenter := compliancepage.CompliancePageFromContext(ctx)
|
||||
|
||||
if _, err := r.trust.ProvisionMember(ctx, trustCenter.ID, identity.ID); err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot provision member", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
w := gqlutils.HTTPResponseWriterFromContext(ctx)
|
||||
r.sessionCookie.Set(w, session)
|
||||
|
||||
return &types.VerifyMagicLinkPayload{
|
||||
Continue: continueURL,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateFullName is the resolver for the updateFullName field.
|
||||
func (r *mutationResolver) UpdateFullName(ctx context.Context, input types.UpdateFullNameInput) (*types.UpdateFullNamePayload, error) {
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
if identity == nil {
|
||||
return nil, gqlutils.Unauthenticatedf(ctx, "authentication is required to request access")
|
||||
}
|
||||
|
||||
identity, err := r.iam.AccountService.UpdateIdentity(
|
||||
ctx,
|
||||
identity.ID,
|
||||
&iam.UpdateIdentityRequest{
|
||||
FullName: input.FullName,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot update identity", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
compliancePage := compliancepage.CompliancePageFromContext(ctx)
|
||||
|
||||
profile, err := r.iam.OrganizationService.GetProfileForIdentityAndOrganization(ctx, identity.ID, compliancePage.OrganizationID)
|
||||
if err != nil {
|
||||
if _, ok := errors.AsType[*iam.ErrProfileNotFound](err); !ok {
|
||||
r.logger.ErrorCtx(ctx, "cannot get profile", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
if profile.Source == coredata.ProfileSourceManual {
|
||||
if _, err := r.iam.OrganizationService.UpdateUser(ctx, &iam.UpdateUserRequest{
|
||||
ID: profile.ID,
|
||||
FullName: identity.FullName,
|
||||
AdditionalEmailAddresses: profile.AdditionalEmailAddresses,
|
||||
Kind: profile.Kind,
|
||||
Position: profile.Position,
|
||||
ContractStartDate: &profile.ContractStartDate,
|
||||
ContractEndDate: &profile.ContractEndDate,
|
||||
}); err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot update profile", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
return &types.UpdateFullNamePayload{Success: true}, nil
|
||||
}
|
||||
|
||||
// LogoURL is the resolver for the logoUrl field.
|
||||
func (r *organizationResolver) LogoURL(ctx context.Context, obj *types.Organization) (*string, error) {
|
||||
trustService := r.TrustService(ctx, obj.ID.TenantID())
|
||||
|
||||
return trustService.Organizations.GenerateLogoURL(ctx, obj.ID, 1*time.Hour)
|
||||
}
|
||||
|
||||
// Viewer is the resolver for the viewer field.
|
||||
func (r *queryResolver) Viewer(ctx context.Context) (*types.Identity, error) {
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
|
||||
if identity == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &types.Identity{
|
||||
ID: identity.ID,
|
||||
Email: identity.EmailAddress,
|
||||
FullName: identity.FullName,
|
||||
EmailVerified: identity.EmailAddressVerified,
|
||||
CreatedAt: identity.CreatedAt,
|
||||
UpdatedAt: identity.UpdatedAt,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Node is the resolver for the node field.
|
||||
func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
trustService := r.TrustService(ctx, id.TenantID())
|
||||
|
||||
switch id.EntityType() {
|
||||
case coredata.OrganizationEntityType:
|
||||
organization, err := trustService.Organizations.Get(ctx, id)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot get organization", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
return types.NewOrganization(organization), nil
|
||||
|
||||
case coredata.DocumentEntityType:
|
||||
trustCenter := compliancepage.CompliancePageFromContext(ctx)
|
||||
|
||||
document, err := trustService.Documents.Get(ctx, trustCenter.OrganizationID, id)
|
||||
if err != nil {
|
||||
if errors.Is(err, trust.ErrDocumentNotFound) || errors.Is(err, trust.ErrDocumentNotVisible) || errors.Is(err, coredata.ErrResourceNotFound) {
|
||||
return nil, gqlutils.NotFoundf(ctx, "node %q not found", id)
|
||||
}
|
||||
if _, ok := errors.AsType[*trust.ErrDocumentArchived](err); ok {
|
||||
return nil, gqlutils.NotFoundf(ctx, "node %q not found", id)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot get document", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
return types.NewDocument(document), nil
|
||||
|
||||
case coredata.FrameworkEntityType:
|
||||
framework, err := trustService.Frameworks.Get(ctx, id)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot get framework", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
return types.NewFramework(framework), nil
|
||||
|
||||
case coredata.ReportEntityType:
|
||||
trustCenter := compliancepage.CompliancePageFromContext(ctx)
|
||||
|
||||
report, err := trustService.Reports.Get(ctx, trustCenter.OrganizationID, id)
|
||||
if err != nil {
|
||||
if errors.Is(err, trust.ErrReportNotFound) || errors.Is(err, coredata.ErrResourceNotFound) {
|
||||
return nil, gqlutils.NotFoundf(ctx, "node %q not found", id)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot get report", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
return types.NewReport(report), nil
|
||||
|
||||
case coredata.AuditEntityType:
|
||||
audit, err := trustService.Audits.Get(ctx, id)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot get audit", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
return types.NewAudit(audit), nil
|
||||
|
||||
case coredata.VendorEntityType:
|
||||
vendor, err := trustService.Vendors.Get(ctx, id)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot get vendor", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
return types.NewSubprocessor(vendor), nil
|
||||
|
||||
case coredata.TrustCenterEntityType:
|
||||
trustCenter, err := trustService.TrustCenters.Get(ctx, id)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot get trust center", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
return types.NewTrustCenter(trustCenter), nil
|
||||
|
||||
case coredata.TrustCenterReferenceEntityType:
|
||||
reference, err := trustService.TrustCenterReferences.Get(ctx, id)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot get trust center reference", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
return types.NewTrustCenterReference(reference), nil
|
||||
|
||||
case coredata.TrustCenterFileEntityType:
|
||||
trustCenter := compliancepage.CompliancePageFromContext(ctx)
|
||||
|
||||
trustCenterFile, err := trustService.TrustCenterFiles.Get(ctx, trustCenter.OrganizationID, id)
|
||||
if err != nil {
|
||||
if errors.Is(err, trust.ErrTrustCenterFileNotFound) || errors.Is(err, trust.ErrTrustCenterFileNotVisible) {
|
||||
return nil, gqlutils.NotFoundf(ctx, "node %q not found", id)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot get trust center file", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewTrustCenterFile(trustCenterFile), nil
|
||||
|
||||
default:
|
||||
return nil, gqlutils.NotFoundf(ctx, "node %q not found", id)
|
||||
}
|
||||
}
|
||||
|
||||
// CurrentTrustCenter is the resolver for the currentTrustCenter field.
|
||||
func (r *queryResolver) CurrentTrustCenter(ctx context.Context) (*types.TrustCenter, error) {
|
||||
trustCenter := compliancepage.CompliancePageFromContext(ctx)
|
||||
|
||||
trustService := r.TrustService(ctx, trustCenter.ID.TenantID())
|
||||
|
||||
org, err := trustService.Organizations.Get(ctx, trustCenter.OrganizationID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot get organization", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
trustCenter, err = trustService.TrustCenters.Get(ctx, trustCenter.ID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot get trust center", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
response := types.NewTrustCenter(trustCenter)
|
||||
response.Organization = types.NewOrganization(org)
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// OidcProviders is the resolver for the oidcProviders field.
|
||||
func (r *queryResolver) OidcProviders(ctx context.Context) ([]*types.OIDCProviderInfo, error) {
|
||||
providers := r.iam.OIDCService.EnabledProviders()
|
||||
result := make([]*types.OIDCProviderInfo, 0, len(providers))
|
||||
|
||||
for _, p := range providers {
|
||||
name := strings.ToLower(p.String())
|
||||
result = append(result, &types.OIDCProviderInfo{
|
||||
Name: name,
|
||||
LoginURL: r.baseURL.WithPath("/api/connect/v1/oidc/" + name + "/login").MustString(),
|
||||
})
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// LogoFileURL is the resolver for the logoFileUrl field.
|
||||
func (r *trustCenterResolver) LogoFileURL(ctx context.Context, obj *types.TrustCenter) (*string, error) {
|
||||
trustService := r.TrustService(ctx, obj.ID.TenantID())
|
||||
|
||||
return trustService.TrustCenters.GenerateLogoURL(ctx, obj.ID, 1*time.Hour)
|
||||
}
|
||||
|
||||
// DarkLogoFileURL is the resolver for the darkLogoFileUrl field.
|
||||
func (r *trustCenterResolver) DarkLogoFileURL(ctx context.Context, obj *types.TrustCenter) (*string, error) {
|
||||
trustService := r.TrustService(ctx, obj.ID.TenantID())
|
||||
|
||||
return trustService.TrustCenters.GenerateDarkLogoURL(ctx, obj.ID, 1*time.Hour)
|
||||
}
|
||||
|
||||
// Organization is the resolver for the organization field.
|
||||
func (r *trustCenterResolver) Organization(ctx context.Context, obj *types.TrustCenter) (*types.Organization, error) {
|
||||
return obj.Organization, nil
|
||||
}
|
||||
|
||||
// Documents is the resolver for the documents field.
|
||||
func (r *trustCenterResolver) Documents(ctx context.Context, obj *types.TrustCenter, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.DocumentConnection, error) {
|
||||
trustService := r.TrustService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.DocumentOrderField]{
|
||||
Field: coredata.DocumentOrderFieldTitle,
|
||||
Direction: page.OrderDirectionAsc,
|
||||
}
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
documentPage, err := trustService.Documents.ListForOrganizationId(ctx, obj.Organization.ID, cursor)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list public documents", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewDocumentConnection(documentPage), nil
|
||||
}
|
||||
|
||||
// Audits is the resolver for the audits field.
|
||||
func (r *trustCenterResolver) Audits(ctx context.Context, obj *types.TrustCenter, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.AuditConnection, error) {
|
||||
trustService := r.TrustService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.AuditOrderField]{
|
||||
Field: coredata.AuditOrderFieldValidFrom,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
auditPage, err := trustService.Audits.ListForOrganizationId(ctx, obj.Organization.ID, cursor)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list public audits", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewAuditConnection(auditPage), nil
|
||||
}
|
||||
|
||||
// Subprocessors is the resolver for the subprocessors field.
|
||||
func (r *trustCenterResolver) Subprocessors(ctx context.Context, obj *types.TrustCenter, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.SubprocessorConnection, error) {
|
||||
trustService := r.TrustService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.VendorOrderField]{
|
||||
Field: coredata.VendorOrderFieldName,
|
||||
Direction: page.OrderDirectionAsc,
|
||||
}
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
vendorPage, err := trustService.Vendors.ListForOrganizationId(ctx, obj.Organization.ID, cursor)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list subprocessors", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewSubprocessorConnection(vendorPage, r, obj.ID), nil
|
||||
}
|
||||
|
||||
// References is the resolver for the references field.
|
||||
func (r *trustCenterResolver) References(ctx context.Context, obj *types.TrustCenter, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.TrustCenterReferenceConnection, error) {
|
||||
trustService := r.TrustService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.TrustCenterReferenceOrderField]{
|
||||
Field: coredata.TrustCenterReferenceOrderFieldRank,
|
||||
Direction: page.OrderDirectionAsc,
|
||||
}
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
referencePage, err := trustService.TrustCenterReferences.ListForTrustCenterID(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list public trust center references", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewTrustCenterReferenceConnection(referencePage), nil
|
||||
}
|
||||
|
||||
// TrustCenterFiles is the resolver for the trustCenterFiles field.
|
||||
func (r *trustCenterResolver) TrustCenterFiles(ctx context.Context, obj *types.TrustCenter, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.TrustCenterFileConnection, error) {
|
||||
trustService := r.TrustService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.TrustCenterFileOrderField]{
|
||||
Field: coredata.TrustCenterFileOrderFieldName,
|
||||
Direction: page.OrderDirectionAsc,
|
||||
}
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
filter := coredata.NewTrustCenterFileFilter(
|
||||
coredata.WithTrustCenterFileVisibilities(
|
||||
coredata.TrustCenterVisibilityPublic,
|
||||
coredata.TrustCenterVisibilityPrivate,
|
||||
),
|
||||
)
|
||||
trustCenterFilePage, err := trustService.TrustCenterFiles.ListForOrganizationId(ctx, obj.Organization.ID, cursor, filter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list public trust center files", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewTrustCenterFileConnection(trustCenterFilePage), nil
|
||||
}
|
||||
|
||||
// ComplianceFrameworks is the resolver for the complianceFrameworks field.
|
||||
func (r *trustCenterResolver) ComplianceFrameworks(ctx context.Context, obj *types.TrustCenter, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.ComplianceFrameworkConnection, error) {
|
||||
trustService := r.TrustService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.ComplianceFrameworkOrderField]{
|
||||
Field: coredata.ComplianceFrameworkOrderFieldRank,
|
||||
Direction: page.OrderDirectionAsc,
|
||||
}
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
cfPage, err := trustService.ComplianceFrameworks.ListByTrustCenterID(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list compliance frameworks", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewComplianceFrameworkConnection(cfPage), nil
|
||||
}
|
||||
|
||||
// ExternalUrls is the resolver for the externalUrls field.
|
||||
func (r *trustCenterResolver) ExternalUrls(ctx context.Context, obj *types.TrustCenter, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.ComplianceExternalURLConnection, error) {
|
||||
trustService := r.TrustService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.ComplianceExternalURLOrderField]{
|
||||
Field: coredata.ComplianceExternalURLOrderFieldRank,
|
||||
Direction: page.OrderDirectionAsc,
|
||||
}
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
result, err := trustService.ComplianceExternalURLs.ListForTrustCenterID(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list compliance external URLs", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewComplianceExternalURLConnection(result), nil
|
||||
}
|
||||
|
||||
// Mutation returns schema.MutationResolver implementation.
|
||||
func (r *Resolver) Mutation() schema.MutationResolver { return &mutationResolver{r} }
|
||||
|
||||
// Organization returns schema.OrganizationResolver implementation.
|
||||
func (r *Resolver) Organization() schema.OrganizationResolver { return &organizationResolver{r} }
|
||||
|
||||
// Query returns schema.QueryResolver implementation.
|
||||
func (r *Resolver) Query() schema.QueryResolver { return &queryResolver{r} }
|
||||
|
||||
// TrustCenter returns schema.TrustCenterResolver implementation.
|
||||
func (r *Resolver) TrustCenter() schema.TrustCenterResolver { return &trustCenterResolver{r} }
|
||||
|
||||
type mutationResolver struct{ *Resolver }
|
||||
type organizationResolver struct{ *Resolver }
|
||||
type queryResolver struct{ *Resolver }
|
||||
type trustCenterResolver struct{ *Resolver }
|
||||
@@ -1,5 +1,5 @@
|
||||
schema:
|
||||
- "schema.graphql"
|
||||
- "graphql/*.graphql"
|
||||
- "../../../gqlutils/directives/session/schema.graphql"
|
||||
|
||||
exec:
|
||||
@@ -14,7 +14,7 @@ resolver:
|
||||
layout: "follow-schema"
|
||||
dir: "."
|
||||
package: "trust_v1"
|
||||
filename_template: "v1_resolver.go"
|
||||
filename_template: "{name}.resolvers.go"
|
||||
|
||||
autobind: []
|
||||
call_argument_directives_with_null: true
|
||||
|
||||
24
pkg/server/api/trust/v1/graphql/auth.graphql
Normal file
24
pkg/server/api/trust/v1/graphql/auth.graphql
Normal file
@@ -0,0 +1,24 @@
|
||||
input SendMagicLinkInput {
|
||||
email: EmailAddr!
|
||||
continue: String
|
||||
}
|
||||
|
||||
type SendMagicLinkPayload {
|
||||
success: Boolean!
|
||||
}
|
||||
|
||||
input VerifyMagicLinkInput {
|
||||
token: String!
|
||||
}
|
||||
|
||||
type VerifyMagicLinkPayload {
|
||||
continue: String
|
||||
}
|
||||
|
||||
input UpdateFullNameInput {
|
||||
fullName: String!
|
||||
}
|
||||
|
||||
type UpdateFullNamePayload {
|
||||
success: Boolean!
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
# Directives
|
||||
directive @goField(
|
||||
forceResolver: Boolean
|
||||
name: String
|
||||
@@ -49,111 +48,9 @@ type Organization implements Node {
|
||||
headquarterAddress: String
|
||||
}
|
||||
|
||||
enum DocumentType
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.DocumentType") {
|
||||
OTHER @goEnum(value: "go.probo.inc/probo/pkg/coredata.DocumentTypeOther")
|
||||
GOVERNANCE
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.DocumentTypeGovernance")
|
||||
POLICY @goEnum(value: "go.probo.inc/probo/pkg/coredata.DocumentTypePolicy")
|
||||
PROCEDURE
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.DocumentTypeProcedure")
|
||||
PLAN @goEnum(value: "go.probo.inc/probo/pkg/coredata.DocumentTypePlan")
|
||||
REGISTER
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.DocumentTypeRegister")
|
||||
RECORD @goEnum(value: "go.probo.inc/probo/pkg/coredata.DocumentTypeRecord")
|
||||
REPORT @goEnum(value: "go.probo.inc/probo/pkg/coredata.DocumentTypeReport")
|
||||
TEMPLATE
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.DocumentTypeTemplate")
|
||||
}
|
||||
|
||||
type Document implements Node @nda {
|
||||
id: ID!
|
||||
title: String!
|
||||
documentType: DocumentType!
|
||||
isUserAuthorized: Boolean! @goField(forceResolver: true)
|
||||
access: DocumentAccess @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type DocumentConnection @nda {
|
||||
edges: [DocumentEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type DocumentEdge @nda {
|
||||
cursor: CursorKey!
|
||||
node: Document!
|
||||
}
|
||||
|
||||
type Framework implements Node @nda {
|
||||
id: ID!
|
||||
type OIDCProviderInfo {
|
||||
name: String!
|
||||
lightLogoURL: String @goField(forceResolver: true)
|
||||
darkLogoURL: String @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type Report implements Node @nda {
|
||||
id: ID!
|
||||
filename: String!
|
||||
isUserAuthorized: Boolean! @goField(forceResolver: true)
|
||||
access: DocumentAccess @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type Audit implements Node @nda {
|
||||
id: ID!
|
||||
name: String
|
||||
framework: Framework! @goField(forceResolver: true)
|
||||
report: Report @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type AuditConnection @nda {
|
||||
edges: [AuditEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type AuditEdge @nda {
|
||||
cursor: CursorKey!
|
||||
node: Audit!
|
||||
}
|
||||
|
||||
type ComplianceFramework implements Node
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/trust/v1/types.ComplianceFramework"
|
||||
) {
|
||||
id: ID!
|
||||
framework: Framework! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type ComplianceFrameworkConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/trust/v1/types.ComplianceFrameworkConnection"
|
||||
) {
|
||||
edges: [ComplianceFrameworkEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type ComplianceFrameworkEdge
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/trust/v1/types.ComplianceFrameworkEdge"
|
||||
) {
|
||||
cursor: CursorKey!
|
||||
node: ComplianceFramework!
|
||||
}
|
||||
|
||||
type MailingListUpdate implements Node {
|
||||
id: ID!
|
||||
title: String!
|
||||
body: String!
|
||||
updatedAt: Datetime!
|
||||
}
|
||||
|
||||
type MailingListUpdateConnection {
|
||||
edges: [MailingListUpdateEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type MailingListUpdateEdge {
|
||||
cursor: CursorKey!
|
||||
node: MailingListUpdate!
|
||||
loginURL: String!
|
||||
}
|
||||
|
||||
enum CountryCode
|
||||
@@ -409,141 +306,13 @@ enum CountryCode
|
||||
ZW @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeZW")
|
||||
}
|
||||
|
||||
enum SubprocessorCategory
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.VendorCategory") {
|
||||
ANALYTICS
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.VendorCategoryAnalytics")
|
||||
CLOUD_MONITORING
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryCloudMonitoring"
|
||||
)
|
||||
CLOUD_PROVIDER
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryCloudProvider"
|
||||
)
|
||||
COLLABORATION
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryCollaboration"
|
||||
)
|
||||
CUSTOMER_SUPPORT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryCustomerSupport"
|
||||
)
|
||||
DATA_STORAGE_AND_PROCESSING
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryDataStorageAndProcessing"
|
||||
)
|
||||
DOCUMENT_MANAGEMENT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryDocumentManagement"
|
||||
)
|
||||
EMPLOYEE_MANAGEMENT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryEmployeeManagement"
|
||||
)
|
||||
ENGINEERING
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.VendorCategoryEngineering")
|
||||
FINANCE
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.VendorCategoryFinance")
|
||||
IDENTITY_PROVIDER
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryIdentityProvider"
|
||||
)
|
||||
IT @goEnum(value: "go.probo.inc/probo/pkg/coredata.VendorCategoryIT")
|
||||
MARKETING
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.VendorCategoryMarketing")
|
||||
OFFICE_OPERATIONS
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryOfficeOperations"
|
||||
)
|
||||
OTHER @goEnum(value: "go.probo.inc/probo/pkg/coredata.VendorCategoryOther")
|
||||
PASSWORD_MANAGEMENT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryPasswordManagement"
|
||||
)
|
||||
PRODUCT_AND_DESIGN
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryProductAndDesign"
|
||||
)
|
||||
PROFESSIONAL_SERVICES
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryProfessionalServices"
|
||||
)
|
||||
RECRUITING
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.VendorCategoryRecruiting")
|
||||
SALES @goEnum(value: "go.probo.inc/probo/pkg/coredata.VendorCategorySales")
|
||||
SECURITY
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.VendorCategorySecurity")
|
||||
VERSION_CONTROL
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryVersionControl"
|
||||
)
|
||||
}
|
||||
|
||||
type Subprocessor implements Node @nda {
|
||||
id: ID!
|
||||
name: String!
|
||||
description: String
|
||||
category: SubprocessorCategory!
|
||||
websiteUrl: String
|
||||
privacyPolicyUrl: String
|
||||
countries: [CountryCode!]!
|
||||
}
|
||||
|
||||
type SubprocessorConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/trust/v1/types.SubprocessorConnection"
|
||||
) @nda {
|
||||
edges: [SubprocessorEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type SubprocessorEdge @nda {
|
||||
cursor: CursorKey!
|
||||
node: Subprocessor!
|
||||
}
|
||||
|
||||
type TrustCenterReference implements Node @nda {
|
||||
id: ID!
|
||||
name: String!
|
||||
description: String
|
||||
websiteUrl: String!
|
||||
logoUrl: String! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type TrustCenterReferenceConnection @nda {
|
||||
edges: [TrustCenterReferenceEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type TrustCenterReferenceEdge @nda {
|
||||
cursor: CursorKey!
|
||||
node: TrustCenterReference!
|
||||
}
|
||||
|
||||
type TrustCenterFile implements Node @nda {
|
||||
id: ID!
|
||||
name: String!
|
||||
category: String!
|
||||
isUserAuthorized: Boolean! @goField(forceResolver: true)
|
||||
access: DocumentAccess @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type TrustCenterFileConnection @nda {
|
||||
edges: [TrustCenterFileEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type TrustCenterFileEdge @nda {
|
||||
cursor: CursorKey!
|
||||
node: TrustCenterFile!
|
||||
}
|
||||
|
||||
type NonDisclosureAgreement {
|
||||
fileName: String!
|
||||
fileUrl: String! @goField(forceResolver: true)
|
||||
viewerSignature: ElectronicSignature @goField(forceResolver: true)
|
||||
type Query {
|
||||
viewer: Identity
|
||||
node(id: ID!): Node
|
||||
currentTrustCenter: TrustCenter
|
||||
oidcProviders: [OIDCProviderInfo!]!
|
||||
@goField(forceResolver: true)
|
||||
@session(required: OPTIONAL)
|
||||
}
|
||||
|
||||
type TrustCenter implements Node {
|
||||
@@ -553,9 +322,6 @@ type TrustCenter implements Node {
|
||||
logoFileUrl: String @goField(forceResolver: true)
|
||||
darkLogoFileUrl: String @goField(forceResolver: true)
|
||||
|
||||
nonDisclosureAgreement: NonDisclosureAgreement @goField(forceResolver: true)
|
||||
|
||||
viewerSubscription: MailingListSubscriber @goField(forceResolver: true)
|
||||
organization: Organization! @goField(forceResolver: true)
|
||||
|
||||
documents(
|
||||
@@ -606,292 +372,6 @@ type TrustCenter implements Node {
|
||||
last: Int
|
||||
before: CursorKey
|
||||
): ComplianceExternalURLConnection! @goField(forceResolver: true)
|
||||
|
||||
updates(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
): MailingListUpdateConnection! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type ComplianceExternalURL implements Node {
|
||||
id: ID!
|
||||
name: String!
|
||||
url: String!
|
||||
rank: Int!
|
||||
}
|
||||
|
||||
type ComplianceExternalURLConnection {
|
||||
edges: [ComplianceExternalURLEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type ComplianceExternalURLEdge {
|
||||
cursor: CursorKey!
|
||||
node: ComplianceExternalURL!
|
||||
}
|
||||
|
||||
type TrustCenterAccess implements Node {
|
||||
id: ID!
|
||||
email: EmailAddr!
|
||||
name: String!
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
}
|
||||
|
||||
enum DocumentAccessStatus
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.TrustCenterDocumentAccessStatus"
|
||||
) {
|
||||
REQUESTED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.TrustCenterDocumentAccessStatusRequested"
|
||||
)
|
||||
GRANTED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.TrustCenterDocumentAccessStatusGranted"
|
||||
)
|
||||
REJECTED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.TrustCenterDocumentAccessStatusRejected"
|
||||
)
|
||||
REVOKED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.TrustCenterDocumentAccessStatusRevoked"
|
||||
)
|
||||
}
|
||||
|
||||
type DocumentAccess implements Node {
|
||||
id: ID!
|
||||
status: DocumentAccessStatus!
|
||||
}
|
||||
|
||||
input SendMagicLinkInput {
|
||||
email: EmailAddr!
|
||||
continue: String
|
||||
}
|
||||
|
||||
type SendMagicLinkPayload {
|
||||
success: Boolean!
|
||||
}
|
||||
|
||||
input VerifyMagicLinkInput {
|
||||
token: String!
|
||||
}
|
||||
|
||||
type VerifyMagicLinkPayload {
|
||||
continue: String
|
||||
}
|
||||
|
||||
input UpdateFullNameInput {
|
||||
fullName: String!
|
||||
}
|
||||
|
||||
type UpdateFullNamePayload {
|
||||
success: Boolean!
|
||||
}
|
||||
|
||||
type RequestDocumentAccessPayload {
|
||||
document: Document
|
||||
}
|
||||
|
||||
type RequestReportAccessPayload {
|
||||
audit: Audit
|
||||
}
|
||||
|
||||
type RequestFileAccessPayload {
|
||||
file: TrustCenterFile
|
||||
}
|
||||
|
||||
type RequestAccessesPayload {
|
||||
trustCenterAccess: TrustCenterAccess!
|
||||
}
|
||||
|
||||
input ExportDocumentPDFInput {
|
||||
documentId: ID!
|
||||
}
|
||||
|
||||
input ExportReportPDFInput {
|
||||
reportId: ID!
|
||||
}
|
||||
|
||||
input RequestDocumentAccessInput {
|
||||
documentId: ID!
|
||||
}
|
||||
|
||||
input RequestReportAccessInput {
|
||||
reportId: ID!
|
||||
}
|
||||
|
||||
input RequestTrustCenterFileAccessInput {
|
||||
trustCenterFileId: ID!
|
||||
}
|
||||
|
||||
input ExportTrustCenterFileInput {
|
||||
trustCenterFileId: ID!
|
||||
}
|
||||
|
||||
type ExportDocumentPDFPayload {
|
||||
data: String!
|
||||
}
|
||||
|
||||
type ExportReportPDFPayload {
|
||||
data: String!
|
||||
}
|
||||
|
||||
type ExportTrustCenterFilePayload {
|
||||
data: String!
|
||||
}
|
||||
|
||||
# Electronic Signature
|
||||
|
||||
enum ElectronicSignatureStatus
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureStatus"
|
||||
) {
|
||||
PENDING
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureStatusPending"
|
||||
)
|
||||
ACCEPTED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureStatusAccepted"
|
||||
)
|
||||
PROCESSING
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureStatusProcessing"
|
||||
)
|
||||
COMPLETED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureStatusCompleted"
|
||||
)
|
||||
FAILED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureStatusFailed"
|
||||
)
|
||||
}
|
||||
|
||||
enum ElectronicSignatureDocumentType
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureDocumentType"
|
||||
) {
|
||||
NDA
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureDocumentTypeNDA"
|
||||
)
|
||||
DPA
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureDocumentTypeDPA"
|
||||
)
|
||||
MSA
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureDocumentTypeMSA"
|
||||
)
|
||||
SOW
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureDocumentTypeSOW"
|
||||
)
|
||||
SLA
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureDocumentTypeSLA"
|
||||
)
|
||||
TOS
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureDocumentTypeTOS"
|
||||
)
|
||||
PRIVACY_POLICY
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureDocumentTypePrivacyPolicy"
|
||||
)
|
||||
OTHER
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureDocumentTypeOther"
|
||||
)
|
||||
}
|
||||
|
||||
enum ElectronicSignatureEventType
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureEventType"
|
||||
) {
|
||||
DOCUMENT_VIEWED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureEventTypeDocumentViewed"
|
||||
)
|
||||
CONSENT_GIVEN
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureEventTypeConsentGiven"
|
||||
)
|
||||
FULL_NAME_TYPED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureEventTypeFullNameTyped"
|
||||
)
|
||||
SIGNATURE_ACCEPTED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureEventTypeSignatureAccepted"
|
||||
)
|
||||
SIGNATURE_COMPLETED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureEventTypeSignatureCompleted"
|
||||
)
|
||||
SEAL_COMPUTED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureEventTypeSealComputed"
|
||||
)
|
||||
TIMESTAMP_REQUESTED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureEventTypeTimestampRequested"
|
||||
)
|
||||
CERTIFICATE_GENERATED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureEventTypeCertificateGenerated"
|
||||
)
|
||||
PROCESSING_ERROR
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureEventTypeProcessingError"
|
||||
)
|
||||
}
|
||||
|
||||
type ElectronicSignature implements Node {
|
||||
id: ID!
|
||||
status: ElectronicSignatureStatus!
|
||||
documentType: ElectronicSignatureDocumentType!
|
||||
consentText: String!
|
||||
lastError: String
|
||||
signedAt: Datetime
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
}
|
||||
|
||||
input AcceptElectronicSignatureInput {
|
||||
signatureId: ID!
|
||||
}
|
||||
|
||||
type AcceptElectronicSignaturePayload {
|
||||
signature: ElectronicSignature!
|
||||
}
|
||||
|
||||
input RecordSigningEventInput {
|
||||
signatureId: ID!
|
||||
eventType: ElectronicSignatureEventType!
|
||||
}
|
||||
|
||||
type RecordSigningEventPayload {
|
||||
success: Boolean!
|
||||
}
|
||||
|
||||
type OIDCProviderInfo {
|
||||
name: String!
|
||||
loginURL: String!
|
||||
}
|
||||
|
||||
type Query {
|
||||
viewer: Identity
|
||||
node(id: ID!): Node
|
||||
currentTrustCenter: TrustCenter
|
||||
oidcProviders: [OIDCProviderInfo!]!
|
||||
@goField(forceResolver: true)
|
||||
@session(required: OPTIONAL)
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
@@ -901,74 +381,4 @@ type Mutation {
|
||||
@session(required: OPTIONAL)
|
||||
updateFullName(input: UpdateFullNameInput!): UpdateFullNamePayload
|
||||
@session(required: PRESENT)
|
||||
|
||||
requestAllAccesses: RequestAccessesPayload! @session(required: PRESENT) @nda
|
||||
|
||||
exportDocumentPDF(input: ExportDocumentPDFInput!): ExportDocumentPDFPayload!
|
||||
@session(required: OPTIONAL) @nda
|
||||
|
||||
exportReportPDF(input: ExportReportPDFInput!): ExportReportPDFPayload!
|
||||
@session(required: OPTIONAL) @nda
|
||||
|
||||
exportTrustCenterFile(
|
||||
input: ExportTrustCenterFileInput!
|
||||
): ExportTrustCenterFilePayload! @session(required: OPTIONAL) @nda
|
||||
|
||||
requestDocumentAccess(
|
||||
input: RequestDocumentAccessInput!
|
||||
): RequestDocumentAccessPayload! @session(required: PRESENT) @nda
|
||||
|
||||
requestReportAccess(
|
||||
input: RequestReportAccessInput!
|
||||
): RequestReportAccessPayload! @session(required: PRESENT) @nda
|
||||
|
||||
requestTrustCenterFileAccess(
|
||||
input: RequestTrustCenterFileAccessInput!
|
||||
): RequestFileAccessPayload! @session(required: PRESENT) @nda
|
||||
|
||||
acceptElectronicSignature(
|
||||
input: AcceptElectronicSignatureInput!
|
||||
): AcceptElectronicSignaturePayload @session(required: PRESENT)
|
||||
|
||||
recordSigningEvent(
|
||||
input: RecordSigningEventInput!
|
||||
): RecordSigningEventPayload @session(required: PRESENT)
|
||||
|
||||
subscribeToMailingList: SubscribeToMailingListPayload! @session(required: PRESENT)
|
||||
|
||||
unsubscribeFromMailingList: UnsubscribeFromMailingListPayload! @session(required: PRESENT)
|
||||
}
|
||||
|
||||
type SubscribeToMailingListPayload {
|
||||
subscription: MailingListSubscriber!
|
||||
}
|
||||
|
||||
type UnsubscribeFromMailingListPayload {
|
||||
deletedMailingListSubscriberId: ID
|
||||
}
|
||||
|
||||
enum MailingListSubscriberStatus
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.MailingListSubscriberStatus"
|
||||
) {
|
||||
PENDING
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.MailingListSubscriberStatusPending"
|
||||
)
|
||||
CONFIRMED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.MailingListSubscriberStatusConfirmed"
|
||||
)
|
||||
}
|
||||
|
||||
type MailingListSubscriber implements Node
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/trust/v1/types.MailingListSubscriber"
|
||||
) {
|
||||
id: ID!
|
||||
fullName: String!
|
||||
email: EmailAddr!
|
||||
status: MailingListSubscriberStatus!
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
}
|
||||
67
pkg/server/api/trust/v1/graphql/mailing_list.graphql
Normal file
67
pkg/server/api/trust/v1/graphql/mailing_list.graphql
Normal file
@@ -0,0 +1,67 @@
|
||||
extend type TrustCenter {
|
||||
viewerSubscription: MailingListSubscriber @goField(forceResolver: true)
|
||||
|
||||
updates(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
): MailingListUpdateConnection! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type MailingListUpdate implements Node {
|
||||
id: ID!
|
||||
title: String!
|
||||
body: String!
|
||||
updatedAt: Datetime!
|
||||
}
|
||||
|
||||
type MailingListUpdateConnection {
|
||||
edges: [MailingListUpdateEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type MailingListUpdateEdge {
|
||||
cursor: CursorKey!
|
||||
node: MailingListUpdate!
|
||||
}
|
||||
|
||||
enum MailingListSubscriberStatus
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.MailingListSubscriberStatus"
|
||||
) {
|
||||
PENDING
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.MailingListSubscriberStatusPending"
|
||||
)
|
||||
CONFIRMED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.MailingListSubscriberStatusConfirmed"
|
||||
)
|
||||
}
|
||||
|
||||
type MailingListSubscriber implements Node
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/trust/v1/types.MailingListSubscriber"
|
||||
) {
|
||||
id: ID!
|
||||
fullName: String!
|
||||
email: EmailAddr!
|
||||
status: MailingListSubscriberStatus!
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
subscribeToMailingList: SubscribeToMailingListPayload! @session(required: PRESENT)
|
||||
|
||||
unsubscribeFromMailingList: UnsubscribeFromMailingListPayload! @session(required: PRESENT)
|
||||
}
|
||||
|
||||
type SubscribeToMailingListPayload {
|
||||
subscription: MailingListSubscriber!
|
||||
}
|
||||
|
||||
type UnsubscribeFromMailingListPayload {
|
||||
deletedMailingListSubscriberId: ID
|
||||
}
|
||||
153
pkg/server/api/trust/v1/graphql/nda.graphql
Normal file
153
pkg/server/api/trust/v1/graphql/nda.graphql
Normal file
@@ -0,0 +1,153 @@
|
||||
extend type TrustCenter {
|
||||
nonDisclosureAgreement: NonDisclosureAgreement @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type NonDisclosureAgreement {
|
||||
fileName: String!
|
||||
fileUrl: String! @goField(forceResolver: true)
|
||||
viewerSignature: ElectronicSignature @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
enum ElectronicSignatureStatus
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureStatus"
|
||||
) {
|
||||
PENDING
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureStatusPending"
|
||||
)
|
||||
ACCEPTED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureStatusAccepted"
|
||||
)
|
||||
PROCESSING
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureStatusProcessing"
|
||||
)
|
||||
COMPLETED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureStatusCompleted"
|
||||
)
|
||||
FAILED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureStatusFailed"
|
||||
)
|
||||
}
|
||||
|
||||
enum ElectronicSignatureDocumentType
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureDocumentType"
|
||||
) {
|
||||
NDA
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureDocumentTypeNDA"
|
||||
)
|
||||
DPA
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureDocumentTypeDPA"
|
||||
)
|
||||
MSA
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureDocumentTypeMSA"
|
||||
)
|
||||
SOW
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureDocumentTypeSOW"
|
||||
)
|
||||
SLA
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureDocumentTypeSLA"
|
||||
)
|
||||
TOS
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureDocumentTypeTOS"
|
||||
)
|
||||
PRIVACY_POLICY
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureDocumentTypePrivacyPolicy"
|
||||
)
|
||||
OTHER
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureDocumentTypeOther"
|
||||
)
|
||||
}
|
||||
|
||||
enum ElectronicSignatureEventType
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureEventType"
|
||||
) {
|
||||
DOCUMENT_VIEWED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureEventTypeDocumentViewed"
|
||||
)
|
||||
CONSENT_GIVEN
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureEventTypeConsentGiven"
|
||||
)
|
||||
FULL_NAME_TYPED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureEventTypeFullNameTyped"
|
||||
)
|
||||
SIGNATURE_ACCEPTED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureEventTypeSignatureAccepted"
|
||||
)
|
||||
SIGNATURE_COMPLETED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureEventTypeSignatureCompleted"
|
||||
)
|
||||
SEAL_COMPUTED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureEventTypeSealComputed"
|
||||
)
|
||||
TIMESTAMP_REQUESTED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureEventTypeTimestampRequested"
|
||||
)
|
||||
CERTIFICATE_GENERATED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureEventTypeCertificateGenerated"
|
||||
)
|
||||
PROCESSING_ERROR
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ElectronicSignatureEventTypeProcessingError"
|
||||
)
|
||||
}
|
||||
|
||||
type ElectronicSignature implements Node {
|
||||
id: ID!
|
||||
status: ElectronicSignatureStatus!
|
||||
documentType: ElectronicSignatureDocumentType!
|
||||
consentText: String!
|
||||
lastError: String
|
||||
signedAt: Datetime
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
acceptElectronicSignature(
|
||||
input: AcceptElectronicSignatureInput!
|
||||
): AcceptElectronicSignaturePayload @session(required: PRESENT)
|
||||
|
||||
recordSigningEvent(
|
||||
input: RecordSigningEventInput!
|
||||
): RecordSigningEventPayload @session(required: PRESENT)
|
||||
}
|
||||
|
||||
input AcceptElectronicSignatureInput {
|
||||
signatureId: ID!
|
||||
}
|
||||
|
||||
type AcceptElectronicSignaturePayload {
|
||||
signature: ElectronicSignature!
|
||||
}
|
||||
|
||||
input RecordSigningEventInput {
|
||||
signatureId: ID!
|
||||
eventType: ElectronicSignatureEventType!
|
||||
}
|
||||
|
||||
type RecordSigningEventPayload {
|
||||
success: Boolean!
|
||||
}
|
||||
350
pkg/server/api/trust/v1/graphql/trust_center.graphql
Normal file
350
pkg/server/api/trust/v1/graphql/trust_center.graphql
Normal file
@@ -0,0 +1,350 @@
|
||||
enum DocumentType
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.DocumentType") {
|
||||
OTHER @goEnum(value: "go.probo.inc/probo/pkg/coredata.DocumentTypeOther")
|
||||
GOVERNANCE
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.DocumentTypeGovernance")
|
||||
POLICY @goEnum(value: "go.probo.inc/probo/pkg/coredata.DocumentTypePolicy")
|
||||
PROCEDURE
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.DocumentTypeProcedure")
|
||||
PLAN @goEnum(value: "go.probo.inc/probo/pkg/coredata.DocumentTypePlan")
|
||||
REGISTER
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.DocumentTypeRegister")
|
||||
RECORD @goEnum(value: "go.probo.inc/probo/pkg/coredata.DocumentTypeRecord")
|
||||
REPORT @goEnum(value: "go.probo.inc/probo/pkg/coredata.DocumentTypeReport")
|
||||
TEMPLATE
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.DocumentTypeTemplate")
|
||||
}
|
||||
|
||||
type Document implements Node @nda {
|
||||
id: ID!
|
||||
title: String!
|
||||
documentType: DocumentType!
|
||||
isUserAuthorized: Boolean! @goField(forceResolver: true)
|
||||
access: DocumentAccess @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type DocumentConnection @nda {
|
||||
edges: [DocumentEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type DocumentEdge @nda {
|
||||
cursor: CursorKey!
|
||||
node: Document!
|
||||
}
|
||||
|
||||
type Framework implements Node @nda {
|
||||
id: ID!
|
||||
name: String!
|
||||
lightLogoURL: String @goField(forceResolver: true)
|
||||
darkLogoURL: String @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type Report implements Node @nda {
|
||||
id: ID!
|
||||
filename: String!
|
||||
isUserAuthorized: Boolean! @goField(forceResolver: true)
|
||||
access: DocumentAccess @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type Audit implements Node @nda {
|
||||
id: ID!
|
||||
name: String
|
||||
framework: Framework! @goField(forceResolver: true)
|
||||
report: Report @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type AuditConnection @nda {
|
||||
edges: [AuditEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type AuditEdge @nda {
|
||||
cursor: CursorKey!
|
||||
node: Audit!
|
||||
}
|
||||
|
||||
type ComplianceFramework implements Node
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/trust/v1/types.ComplianceFramework"
|
||||
) {
|
||||
id: ID!
|
||||
framework: Framework! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type ComplianceFrameworkConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/trust/v1/types.ComplianceFrameworkConnection"
|
||||
) {
|
||||
edges: [ComplianceFrameworkEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type ComplianceFrameworkEdge
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/trust/v1/types.ComplianceFrameworkEdge"
|
||||
) {
|
||||
cursor: CursorKey!
|
||||
node: ComplianceFramework!
|
||||
}
|
||||
|
||||
enum SubprocessorCategory
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.VendorCategory") {
|
||||
ANALYTICS
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.VendorCategoryAnalytics")
|
||||
CLOUD_MONITORING
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryCloudMonitoring"
|
||||
)
|
||||
CLOUD_PROVIDER
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryCloudProvider"
|
||||
)
|
||||
COLLABORATION
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryCollaboration"
|
||||
)
|
||||
CUSTOMER_SUPPORT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryCustomerSupport"
|
||||
)
|
||||
DATA_STORAGE_AND_PROCESSING
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryDataStorageAndProcessing"
|
||||
)
|
||||
DOCUMENT_MANAGEMENT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryDocumentManagement"
|
||||
)
|
||||
EMPLOYEE_MANAGEMENT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryEmployeeManagement"
|
||||
)
|
||||
ENGINEERING
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.VendorCategoryEngineering")
|
||||
FINANCE
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.VendorCategoryFinance")
|
||||
IDENTITY_PROVIDER
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryIdentityProvider"
|
||||
)
|
||||
IT @goEnum(value: "go.probo.inc/probo/pkg/coredata.VendorCategoryIT")
|
||||
MARKETING
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.VendorCategoryMarketing")
|
||||
OFFICE_OPERATIONS
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryOfficeOperations"
|
||||
)
|
||||
OTHER @goEnum(value: "go.probo.inc/probo/pkg/coredata.VendorCategoryOther")
|
||||
PASSWORD_MANAGEMENT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryPasswordManagement"
|
||||
)
|
||||
PRODUCT_AND_DESIGN
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryProductAndDesign"
|
||||
)
|
||||
PROFESSIONAL_SERVICES
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryProfessionalServices"
|
||||
)
|
||||
RECRUITING
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.VendorCategoryRecruiting")
|
||||
SALES @goEnum(value: "go.probo.inc/probo/pkg/coredata.VendorCategorySales")
|
||||
SECURITY
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.VendorCategorySecurity")
|
||||
VERSION_CONTROL
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryVersionControl"
|
||||
)
|
||||
}
|
||||
|
||||
type Subprocessor implements Node @nda {
|
||||
id: ID!
|
||||
name: String!
|
||||
description: String
|
||||
category: SubprocessorCategory!
|
||||
websiteUrl: String
|
||||
privacyPolicyUrl: String
|
||||
countries: [CountryCode!]!
|
||||
}
|
||||
|
||||
type SubprocessorConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/trust/v1/types.SubprocessorConnection"
|
||||
) @nda {
|
||||
edges: [SubprocessorEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type SubprocessorEdge @nda {
|
||||
cursor: CursorKey!
|
||||
node: Subprocessor!
|
||||
}
|
||||
|
||||
type TrustCenterReference implements Node @nda {
|
||||
id: ID!
|
||||
name: String!
|
||||
description: String
|
||||
websiteUrl: String!
|
||||
logoUrl: String! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type TrustCenterReferenceConnection @nda {
|
||||
edges: [TrustCenterReferenceEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type TrustCenterReferenceEdge @nda {
|
||||
cursor: CursorKey!
|
||||
node: TrustCenterReference!
|
||||
}
|
||||
|
||||
type TrustCenterFile implements Node @nda {
|
||||
id: ID!
|
||||
name: String!
|
||||
category: String!
|
||||
isUserAuthorized: Boolean! @goField(forceResolver: true)
|
||||
access: DocumentAccess @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type TrustCenterFileConnection @nda {
|
||||
edges: [TrustCenterFileEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type TrustCenterFileEdge @nda {
|
||||
cursor: CursorKey!
|
||||
node: TrustCenterFile!
|
||||
}
|
||||
|
||||
type ComplianceExternalURL implements Node {
|
||||
id: ID!
|
||||
name: String!
|
||||
url: String!
|
||||
rank: Int!
|
||||
}
|
||||
|
||||
type ComplianceExternalURLConnection {
|
||||
edges: [ComplianceExternalURLEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type ComplianceExternalURLEdge {
|
||||
cursor: CursorKey!
|
||||
node: ComplianceExternalURL!
|
||||
}
|
||||
|
||||
type TrustCenterAccess implements Node {
|
||||
id: ID!
|
||||
email: EmailAddr!
|
||||
name: String!
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
}
|
||||
|
||||
enum DocumentAccessStatus
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.TrustCenterDocumentAccessStatus"
|
||||
) {
|
||||
REQUESTED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.TrustCenterDocumentAccessStatusRequested"
|
||||
)
|
||||
GRANTED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.TrustCenterDocumentAccessStatusGranted"
|
||||
)
|
||||
REJECTED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.TrustCenterDocumentAccessStatusRejected"
|
||||
)
|
||||
REVOKED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.TrustCenterDocumentAccessStatusRevoked"
|
||||
)
|
||||
}
|
||||
|
||||
type DocumentAccess implements Node {
|
||||
id: ID!
|
||||
status: DocumentAccessStatus!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
requestAllAccesses: RequestAccessesPayload! @session(required: PRESENT) @nda
|
||||
|
||||
exportDocumentPDF(input: ExportDocumentPDFInput!): ExportDocumentPDFPayload!
|
||||
@session(required: OPTIONAL) @nda
|
||||
|
||||
exportReportPDF(input: ExportReportPDFInput!): ExportReportPDFPayload!
|
||||
@session(required: OPTIONAL) @nda
|
||||
|
||||
exportTrustCenterFile(
|
||||
input: ExportTrustCenterFileInput!
|
||||
): ExportTrustCenterFilePayload! @session(required: OPTIONAL) @nda
|
||||
|
||||
requestDocumentAccess(
|
||||
input: RequestDocumentAccessInput!
|
||||
): RequestDocumentAccessPayload! @session(required: PRESENT) @nda
|
||||
|
||||
requestReportAccess(
|
||||
input: RequestReportAccessInput!
|
||||
): RequestReportAccessPayload! @session(required: PRESENT) @nda
|
||||
|
||||
requestTrustCenterFileAccess(
|
||||
input: RequestTrustCenterFileAccessInput!
|
||||
): RequestFileAccessPayload! @session(required: PRESENT) @nda
|
||||
}
|
||||
|
||||
type RequestDocumentAccessPayload {
|
||||
document: Document
|
||||
}
|
||||
|
||||
type RequestReportAccessPayload {
|
||||
audit: Audit
|
||||
}
|
||||
|
||||
type RequestFileAccessPayload {
|
||||
file: TrustCenterFile
|
||||
}
|
||||
|
||||
type RequestAccessesPayload {
|
||||
trustCenterAccess: TrustCenterAccess!
|
||||
}
|
||||
|
||||
input ExportDocumentPDFInput {
|
||||
documentId: ID!
|
||||
}
|
||||
|
||||
input ExportReportPDFInput {
|
||||
reportId: ID!
|
||||
}
|
||||
|
||||
input RequestDocumentAccessInput {
|
||||
documentId: ID!
|
||||
}
|
||||
|
||||
input RequestReportAccessInput {
|
||||
reportId: ID!
|
||||
}
|
||||
|
||||
input RequestTrustCenterFileAccessInput {
|
||||
trustCenterFileId: ID!
|
||||
}
|
||||
|
||||
input ExportTrustCenterFileInput {
|
||||
trustCenterFileId: ID!
|
||||
}
|
||||
|
||||
type ExportDocumentPDFPayload {
|
||||
data: String!
|
||||
}
|
||||
|
||||
type ExportReportPDFPayload {
|
||||
data: String!
|
||||
}
|
||||
|
||||
type ExportTrustCenterFilePayload {
|
||||
data: String!
|
||||
}
|
||||
137
pkg/server/api/trust/v1/mailing_list.resolvers.go
Normal file
137
pkg/server/api/trust/v1/mailing_list.resolvers.go
Normal file
@@ -0,0 +1,137 @@
|
||||
package trust_v1
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver
|
||||
// implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.87
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"go.gearno.de/kit/log"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/mailman"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"go.probo.inc/probo/pkg/server/api/authn"
|
||||
"go.probo.inc/probo/pkg/server/api/compliancepage"
|
||||
"go.probo.inc/probo/pkg/server/api/trust/v1/types"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils"
|
||||
"go.probo.inc/probo/pkg/validator"
|
||||
)
|
||||
|
||||
// SubscribeToMailingList is the resolver for the subscribeToMailingList field.
|
||||
func (r *mutationResolver) SubscribeToMailingList(ctx context.Context) (*types.SubscribeToMailingListPayload, error) {
|
||||
trustCenter := compliancepage.CompliancePageFromContext(ctx)
|
||||
if trustCenter.MailingListID == nil {
|
||||
return nil, gqlutils.NotFoundf(ctx, "mailing list not found")
|
||||
}
|
||||
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
|
||||
subscriber, err := r.mailman.CreateSubscriber(
|
||||
ctx,
|
||||
&mailman.CreateSubscriberRequest{
|
||||
MailingListID: *trustCenter.MailingListID,
|
||||
Email: identity.EmailAddress,
|
||||
FullName: identity.FullName,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||
}
|
||||
if errors.Is(err, mailman.ErrSubscriberAlreadyExist) {
|
||||
return nil, gqlutils.Conflictf(ctx, "already subscribed to this mailing list")
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot subscribe to mailing list", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.SubscribeToMailingListPayload{
|
||||
Subscription: types.NewMailingListSubscriber(subscriber),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UnsubscribeFromMailingList is the resolver for the unsubscribeFromMailingList field.
|
||||
func (r *mutationResolver) UnsubscribeFromMailingList(ctx context.Context) (*types.UnsubscribeFromMailingListPayload, error) {
|
||||
trustCenter := compliancepage.CompliancePageFromContext(ctx)
|
||||
if trustCenter.MailingListID == nil {
|
||||
return nil, gqlutils.NotFoundf(ctx, "mailing list not found")
|
||||
}
|
||||
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
|
||||
subscriber, err := r.mailman.GetSubscriber(ctx, *trustCenter.MailingListID, identity.EmailAddress)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot get mailing list subscription", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
if subscriber == nil {
|
||||
return nil, gqlutils.NotFoundf(ctx, "not subscribed to this mailing list")
|
||||
}
|
||||
|
||||
if err := r.mailman.DeleteSubscriber(ctx, subscriber.ID); err != nil {
|
||||
if errors.Is(err, mailman.ErrSubscriberNotFound) {
|
||||
return nil, gqlutils.NotFoundf(ctx, "not subscribed to this mailing list")
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot unsubscribe from mailing list", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.UnsubscribeFromMailingListPayload{DeletedMailingListSubscriberID: &subscriber.ID}, nil
|
||||
}
|
||||
|
||||
// ViewerSubscription is the resolver for the viewerSubscription field.
|
||||
func (r *trustCenterResolver) ViewerSubscription(ctx context.Context, obj *types.TrustCenter) (*types.MailingListSubscriber, error) {
|
||||
trustCenter := compliancepage.CompliancePageFromContext(ctx)
|
||||
if trustCenter.MailingListID == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
if identity == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
subscriber, err := r.mailman.GetSubscriber(ctx, *trustCenter.MailingListID, identity.EmailAddress)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot get mailing list subscription", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
if subscriber == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return types.NewMailingListSubscriber(subscriber), nil
|
||||
}
|
||||
|
||||
// Updates is the resolver for the updates field.
|
||||
func (r *trustCenterResolver) Updates(ctx context.Context, obj *types.TrustCenter, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.MailingListUpdateConnection, error) {
|
||||
trustService := r.TrustService(ctx, obj.ID.TenantID())
|
||||
|
||||
tc, err := trustService.TrustCenters.Get(ctx, obj.ID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot load trust center", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
if tc.MailingListID == nil {
|
||||
return &types.MailingListUpdateConnection{Edges: []*types.MailingListUpdateEdge{}, PageInfo: &types.PageInfo{}}, nil
|
||||
}
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.MailingListUpdateOrderField]{
|
||||
Field: coredata.MailingListUpdateOrderFieldUpdatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
result, err := r.mailman.ListSentMailingListUpdates(ctx, *tc.MailingListID, cursor)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list mailing list updates", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewMailingListUpdateConnection(result), nil
|
||||
}
|
||||
166
pkg/server/api/trust/v1/nda.resolvers.go
Normal file
166
pkg/server/api/trust/v1/nda.resolvers.go
Normal file
@@ -0,0 +1,166 @@
|
||||
package trust_v1
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver
|
||||
// implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.87
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"go.gearno.de/kit/log"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/esign"
|
||||
"go.probo.inc/probo/pkg/server/api/authn"
|
||||
"go.probo.inc/probo/pkg/server/api/compliancepage"
|
||||
"go.probo.inc/probo/pkg/server/api/trust/v1/schema"
|
||||
"go.probo.inc/probo/pkg/server/api/trust/v1/types"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils"
|
||||
)
|
||||
|
||||
// AcceptElectronicSignature is the resolver for the acceptElectronicSignature field.
|
||||
func (r *mutationResolver) AcceptElectronicSignature(ctx context.Context, input types.AcceptElectronicSignatureInput) (*types.AcceptElectronicSignaturePayload, error) {
|
||||
var (
|
||||
identity = authn.IdentityFromContext(ctx)
|
||||
httpReq = gqlutils.HTTPRequestFromContext(ctx)
|
||||
)
|
||||
|
||||
signerIP, _, _ := net.SplitHostPort(httpReq.RemoteAddr)
|
||||
if signerIP == "" {
|
||||
signerIP = httpReq.RemoteAddr
|
||||
}
|
||||
|
||||
signature, err := r.esign.AcceptSignature(
|
||||
ctx,
|
||||
&esign.AcceptSignatureRequest{
|
||||
SignatureID: input.SignatureID,
|
||||
SignerFullName: identity.FullName,
|
||||
SignerEmail: identity.EmailAddress,
|
||||
SignerIPAddr: signerIP,
|
||||
SignerUA: httpReq.UserAgent(),
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot accept electronic signature", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.AcceptElectronicSignaturePayload{
|
||||
Signature: types.NewElectronicSignature(signature),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// RecordSigningEvent is the resolver for the recordSigningEvent field.
|
||||
func (r *mutationResolver) RecordSigningEvent(ctx context.Context, input types.RecordSigningEventInput) (*types.RecordSigningEventPayload, error) {
|
||||
var (
|
||||
identity = authn.IdentityFromContext(ctx)
|
||||
httpReq = gqlutils.HTTPRequestFromContext(ctx)
|
||||
)
|
||||
|
||||
actorIP, _, _ := net.SplitHostPort(httpReq.RemoteAddr)
|
||||
if actorIP == "" {
|
||||
actorIP = httpReq.RemoteAddr
|
||||
}
|
||||
|
||||
if err := r.esign.RecordEvent(
|
||||
ctx,
|
||||
&esign.RecordEventRequest{
|
||||
SignatureID: input.SignatureID,
|
||||
EventType: input.EventType,
|
||||
EventSource: coredata.ElectronicSignatureEventSourceClient,
|
||||
ActorEmail: identity.EmailAddress,
|
||||
ActorIPAddr: actorIP,
|
||||
ActorUA: httpReq.UserAgent(),
|
||||
},
|
||||
); err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot record signing event", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.RecordSigningEventPayload{Success: true}, nil
|
||||
}
|
||||
|
||||
// FileURL is the resolver for the fileUrl field.
|
||||
func (r *nonDisclosureAgreementResolver) FileURL(ctx context.Context, obj *types.NonDisclosureAgreement) (string, error) {
|
||||
trustCenter := compliancepage.CompliancePageFromContext(ctx)
|
||||
|
||||
if identity := authn.IdentityFromContext(ctx); identity != nil && r.esign != nil {
|
||||
trustService := r.TrustService(ctx, trustCenter.ID.TenantID())
|
||||
|
||||
access, err := trustService.TrustCenterAccesses.GetAccess(ctx, trustCenter.ID, identity.ID)
|
||||
if err == nil && access.ElectronicSignatureID != nil {
|
||||
fileURL, err := r.esign.GenerateSignatureFileURL(ctx, *access.ElectronicSignatureID, 15*time.Minute)
|
||||
if err == nil {
|
||||
return fileURL, nil
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot generate signature file URL, falling back to original NDA", log.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
trustService := r.TrustService(ctx, trustCenter.ID.TenantID())
|
||||
|
||||
fileURL, err := trustService.TrustCenters.GenerateNDAFileURL(ctx, trustCenter.ID, 15*time.Minute)
|
||||
if err != nil {
|
||||
return "", gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return fileURL, nil
|
||||
}
|
||||
|
||||
// ViewerSignature is the resolver for the viewerSignature field.
|
||||
func (r *nonDisclosureAgreementResolver) ViewerSignature(ctx context.Context, obj *types.NonDisclosureAgreement) (*types.ElectronicSignature, error) {
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
if identity == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
trustCenter := compliancepage.CompliancePageFromContext(ctx)
|
||||
trustService := r.TrustService(ctx, trustCenter.ID.TenantID())
|
||||
|
||||
access, err := trustService.TrustCenterAccesses.GetAccess(ctx, trustCenter.ID, identity.ID)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if access.ElectronicSignatureID == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
sig, err := r.esign.GetSignatureByID(ctx, *access.ElectronicSignatureID)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return types.NewElectronicSignature(sig), nil
|
||||
}
|
||||
|
||||
// NonDisclosureAgreement is the resolver for the nonDisclosureAgreement field.
|
||||
func (r *trustCenterResolver) NonDisclosureAgreement(ctx context.Context, obj *types.TrustCenter) (*types.NonDisclosureAgreement, error) {
|
||||
trustCenter := compliancepage.CompliancePageFromContext(ctx)
|
||||
if trustCenter.NonDisclosureAgreementFileID == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
trustService := r.TrustService(ctx, obj.ID.TenantID())
|
||||
|
||||
file, err := trustService.TrustCenters.GetNDAFile(ctx, obj.ID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot load NDA file", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
if file == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return types.NewNonDisclosureAgreement(file), nil
|
||||
}
|
||||
|
||||
// NonDisclosureAgreement returns schema.NonDisclosureAgreementResolver implementation.
|
||||
func (r *Resolver) NonDisclosureAgreement() schema.NonDisclosureAgreementResolver {
|
||||
return &nonDisclosureAgreementResolver{r}
|
||||
}
|
||||
|
||||
type nonDisclosureAgreementResolver struct{ *Resolver }
|
||||
745
pkg/server/api/trust/v1/trust_center.resolvers.go
Normal file
745
pkg/server/api/trust/v1/trust_center.resolvers.go
Normal file
@@ -0,0 +1,745 @@
|
||||
package trust_v1
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver
|
||||
// implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.87
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"go.gearno.de/kit/log"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/server/api/authn"
|
||||
"go.probo.inc/probo/pkg/server/api/compliancepage"
|
||||
"go.probo.inc/probo/pkg/server/api/trust/v1/schema"
|
||||
"go.probo.inc/probo/pkg/server/api/trust/v1/types"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils"
|
||||
"go.probo.inc/probo/pkg/trust"
|
||||
)
|
||||
|
||||
// Framework is the resolver for the framework field.
|
||||
func (r *auditResolver) Framework(ctx context.Context, obj *types.Audit) (*types.Framework, error) {
|
||||
trustService := r.TrustService(ctx, obj.ID.TenantID())
|
||||
|
||||
audit, err := trustService.Audits.Get(ctx, obj.ID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot load audit", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
framework, err := trustService.Frameworks.Get(ctx, audit.FrameworkID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot load framework", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewFramework(framework), nil
|
||||
}
|
||||
|
||||
// Report is the resolver for the report field.
|
||||
func (r *auditResolver) Report(ctx context.Context, obj *types.Audit) (*types.Report, error) {
|
||||
trustService := r.TrustService(ctx, obj.ID.TenantID())
|
||||
|
||||
audit, err := trustService.Audits.Get(ctx, obj.ID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot load audit", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
if audit.ReportID == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
trustCenter := compliancepage.CompliancePageFromContext(ctx)
|
||||
|
||||
report, err := trustService.Reports.Get(ctx, trustCenter.OrganizationID, *audit.ReportID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot load report", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewReport(report), nil
|
||||
}
|
||||
|
||||
// Framework is the resolver for the framework field on ComplianceFramework.
|
||||
func (r *complianceFrameworkResolver) Framework(ctx context.Context, obj *types.ComplianceFramework) (*types.Framework, error) {
|
||||
trustService := r.TrustService(ctx, obj.ID.TenantID())
|
||||
|
||||
framework, err := trustService.Frameworks.Get(ctx, obj.FrameworkID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot load framework", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewFramework(framework), nil
|
||||
}
|
||||
|
||||
// IsUserAuthorized is the resolver for the isUserAuthorized field.
|
||||
func (r *documentResolver) IsUserAuthorized(ctx context.Context, obj *types.Document) (bool, error) {
|
||||
trustService := r.TrustService(ctx, obj.ID.TenantID())
|
||||
trustCenter := compliancepage.CompliancePageFromContext(ctx)
|
||||
|
||||
document, err := trustService.Documents.Get(ctx, trustCenter.OrganizationID, obj.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, trust.ErrDocumentNotFound) || errors.Is(err, trust.ErrDocumentNotVisible) || errors.Is(err, coredata.ErrResourceNotFound) {
|
||||
return false, gqlutils.NotFoundf(ctx, "document %q not found", obj.ID)
|
||||
}
|
||||
if _, ok := errors.AsType[*trust.ErrDocumentArchived](err); ok {
|
||||
return false, gqlutils.NotFoundf(ctx, "document %q not found", obj.ID)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot load document", log.Error(err))
|
||||
return false, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
if document.TrustCenterVisibility == coredata.TrustCenterVisibilityPublic {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
if identity == nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
documentAccess, err := trustService.TrustCenterAccesses.GetDocumentAccess(
|
||||
ctx,
|
||||
trustCenter.ID,
|
||||
identity.ID,
|
||||
obj.ID,
|
||||
)
|
||||
if err != nil {
|
||||
if errors.Is(err, trust.ErrMembershipNotFound) ||
|
||||
errors.Is(err, trust.ErrUserNotFound) ||
|
||||
errors.Is(err, trust.ErrUserInactive) ||
|
||||
errors.Is(err, trust.ErrDocumentAccessNotFound) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot check document access", log.Error(err))
|
||||
return false, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return documentAccess.Status == coredata.TrustCenterDocumentAccessStatusGranted, nil
|
||||
}
|
||||
|
||||
// Access is the resolver for the access field.
|
||||
func (r *documentResolver) Access(ctx context.Context, obj *types.Document) (*types.DocumentAccess, error) {
|
||||
trustService := r.TrustService(ctx, obj.ID.TenantID())
|
||||
trustCenter := compliancepage.CompliancePageFromContext(ctx)
|
||||
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
if identity == nil {
|
||||
return nil, nil // User is not authenticated, so no access requested
|
||||
}
|
||||
|
||||
access, err := trustService.TrustCenterAccesses.GetDocumentAccess(
|
||||
ctx,
|
||||
trustCenter.ID,
|
||||
identity.ID,
|
||||
obj.ID,
|
||||
)
|
||||
if err != nil {
|
||||
if errors.Is(err, trust.ErrMembershipNotFound) ||
|
||||
errors.Is(err, trust.ErrUserNotFound) ||
|
||||
errors.Is(err, trust.ErrDocumentAccessNotFound) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if errors.Is(err, trust.ErrUserInactive) {
|
||||
return nil, gqlutils.Forbidden(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get document access", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DocumentAccess{
|
||||
ID: access.ID,
|
||||
Status: access.Status,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// LightLogoURL is the resolver for the lightLogoURL field.
|
||||
func (r *frameworkResolver) LightLogoURL(ctx context.Context, obj *types.Framework) (*string, error) {
|
||||
trustService := r.TrustService(ctx, obj.ID.TenantID())
|
||||
|
||||
return trustService.Frameworks.GenerateLightLogoURL(ctx, obj.ID, 1*time.Hour)
|
||||
}
|
||||
|
||||
// DarkLogoURL is the resolver for the darkLogoURL field.
|
||||
func (r *frameworkResolver) DarkLogoURL(ctx context.Context, obj *types.Framework) (*string, error) {
|
||||
trustService := r.TrustService(ctx, obj.ID.TenantID())
|
||||
|
||||
return trustService.Frameworks.GenerateDarkLogoURL(ctx, obj.ID, 1*time.Hour)
|
||||
}
|
||||
|
||||
// RequestAllAccesses is the resolver for the requestAllAccesses field.
|
||||
func (r *mutationResolver) RequestAllAccesses(ctx context.Context) (*types.RequestAccessesPayload, error) {
|
||||
trustCenter := compliancepage.CompliancePageFromContext(ctx)
|
||||
trustService := r.TrustService(ctx, trustCenter.ID.TenantID())
|
||||
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
if identity == nil {
|
||||
return nil, gqlutils.Unauthenticatedf(ctx, "authentication is required to request access")
|
||||
}
|
||||
|
||||
access, err := trustService.TrustCenterAccesses.Request(
|
||||
ctx,
|
||||
&trust.TrustCenterAccessRequest{
|
||||
TrustCenterID: trustCenter.ID,
|
||||
IdentityID: identity.ID,
|
||||
DocumentIDs: nil,
|
||||
ReportIDs: nil,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot create trust center access", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.RequestAccessesPayload{
|
||||
TrustCenterAccess: &types.TrustCenterAccess{
|
||||
ID: access.ID,
|
||||
CreatedAt: access.CreatedAt,
|
||||
UpdatedAt: access.UpdatedAt,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ExportDocumentPDF is the resolver for the exportDocumentPDF field.
|
||||
func (r *mutationResolver) ExportDocumentPDF(ctx context.Context, input types.ExportDocumentPDFInput) (*types.ExportDocumentPDFPayload, error) {
|
||||
trustService := r.TrustService(ctx, input.DocumentID.TenantID())
|
||||
trustCenter := compliancepage.CompliancePageFromContext(ctx)
|
||||
|
||||
document, err := trustService.Documents.Get(ctx, trustCenter.OrganizationID, input.DocumentID)
|
||||
if err != nil {
|
||||
if errors.Is(err, trust.ErrDocumentNotFound) || errors.Is(err, trust.ErrDocumentNotVisible) || errors.Is(err, coredata.ErrResourceNotFound) {
|
||||
return nil, gqlutils.NotFoundf(ctx, "document %q not found", input.DocumentID)
|
||||
}
|
||||
if _, ok := errors.AsType[*trust.ErrDocumentArchived](err); ok {
|
||||
return nil, gqlutils.NotFoundf(ctx, "document %q not found", input.DocumentID)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot load document", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
if document.TrustCenterVisibility == coredata.TrustCenterVisibilityPublic {
|
||||
pdf, err := trustService.Documents.ExportPDFWithoutWatermark(ctx, input.DocumentID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot export document PDF", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.ExportDocumentPDFPayload{
|
||||
Data: fmt.Sprintf("data:application/pdf;base64,%s", base64.StdEncoding.EncodeToString(pdf)),
|
||||
}, nil
|
||||
}
|
||||
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
if identity == nil {
|
||||
return nil, gqlutils.Unauthenticated(ctx, errors.New("unauthenticated"))
|
||||
}
|
||||
|
||||
documentAccess, err := trustService.TrustCenterAccesses.GetDocumentAccess(
|
||||
ctx,
|
||||
trustCenter.ID,
|
||||
identity.ID,
|
||||
input.DocumentID,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if documentAccess.Status != coredata.TrustCenterDocumentAccessStatusGranted {
|
||||
return nil, gqlutils.Forbiddenf(ctx, "access denied: no permission to access this document")
|
||||
}
|
||||
|
||||
pdf, err := trustService.Documents.ExportPDF(ctx, input.DocumentID, identity.EmailAddress)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot export document PDF", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.ExportDocumentPDFPayload{
|
||||
Data: fmt.Sprintf("data:application/pdf;base64,%s", base64.StdEncoding.EncodeToString(pdf)),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ExportReportPDF is the resolver for the exportReportPDF field.
|
||||
func (r *mutationResolver) ExportReportPDF(ctx context.Context, input types.ExportReportPDFInput) (*types.ExportReportPDFPayload, error) {
|
||||
trustService := r.TrustService(ctx, input.ReportID.TenantID())
|
||||
|
||||
trustCenter := compliancepage.CompliancePageFromContext(ctx)
|
||||
|
||||
audit, err := trustService.Audits.GetByReportID(ctx, input.ReportID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot load audit", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
if audit.TrustCenterVisibility == coredata.TrustCenterVisibilityPublic {
|
||||
pdf, err := trustService.Reports.ExportPDFWithoutWatermark(ctx, input.ReportID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot export report PDF", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.ExportReportPDFPayload{
|
||||
Data: fmt.Sprintf("data:application/pdf;base64,%s", base64.StdEncoding.EncodeToString(pdf)),
|
||||
}, nil
|
||||
}
|
||||
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
if identity == nil {
|
||||
return nil, gqlutils.Unauthenticatedf(ctx, "unauthenticated")
|
||||
}
|
||||
|
||||
reportAccess, err := trustService.TrustCenterAccesses.GetReportAccess(
|
||||
ctx,
|
||||
trustCenter.ID,
|
||||
identity.ID,
|
||||
input.ReportID,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if reportAccess.Status != coredata.TrustCenterDocumentAccessStatusGranted {
|
||||
return nil, gqlutils.Forbiddenf(ctx, "access denied: no permission to access this report")
|
||||
}
|
||||
|
||||
pdf, err := trustService.Reports.ExportPDF(ctx, input.ReportID, identity.EmailAddress)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot export report PDF", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.ExportReportPDFPayload{
|
||||
Data: fmt.Sprintf("data:application/pdf;base64,%s", base64.StdEncoding.EncodeToString(pdf)),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ExportTrustCenterFile is the resolver for the exportTrustCenterFile field.
|
||||
func (r *mutationResolver) ExportTrustCenterFile(ctx context.Context, input types.ExportTrustCenterFileInput) (*types.ExportTrustCenterFilePayload, error) {
|
||||
trustCenter := compliancepage.CompliancePageFromContext(ctx)
|
||||
trustService := r.TrustService(ctx, trustCenter.ID.TenantID())
|
||||
|
||||
trustCenterFile, err := trustService.TrustCenterFiles.Get(ctx, trustCenter.OrganizationID, input.TrustCenterFileID)
|
||||
if err != nil {
|
||||
if errors.Is(err, trust.ErrTrustCenterFileNotFound) || errors.Is(err, trust.ErrTrustCenterFileNotVisible) {
|
||||
return nil, gqlutils.NotFoundf(ctx, "trust center file %q not found", input.TrustCenterFileID)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot load trust center file", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
if trustCenterFile.TrustCenterVisibility == coredata.TrustCenterVisibilityPublic {
|
||||
fileData, mimeType, err := trustService.TrustCenterFiles.ExportFileWithoutWatermark(ctx, input.TrustCenterFileID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot export trust center file", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.ExportTrustCenterFilePayload{
|
||||
Data: fmt.Sprintf("data:%s;base64,%s", mimeType, base64.StdEncoding.EncodeToString(fileData)),
|
||||
}, nil
|
||||
}
|
||||
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
if identity == nil {
|
||||
return nil, gqlutils.Unauthenticatedf(ctx, "unauthenticated")
|
||||
}
|
||||
|
||||
fileAccess, err := trustService.TrustCenterAccesses.GetTrustCenterFileAccess(ctx,
|
||||
trustCenter.ID,
|
||||
identity.ID,
|
||||
input.TrustCenterFileID,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if fileAccess.Status != coredata.TrustCenterDocumentAccessStatusGranted {
|
||||
return nil, gqlutils.Forbiddenf(ctx, "access denied: no permission to access this file")
|
||||
}
|
||||
|
||||
fileData, mimeType, err := trustService.TrustCenterFiles.ExportFile(ctx, input.TrustCenterFileID, identity.EmailAddress)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot export trust center file", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.ExportTrustCenterFilePayload{
|
||||
Data: fmt.Sprintf("data:%s;base64,%s", mimeType, base64.StdEncoding.EncodeToString(fileData)),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// RequestDocumentAccess is the resolver for the requestDocumentAccess field.
|
||||
func (r *mutationResolver) RequestDocumentAccess(ctx context.Context, input types.RequestDocumentAccessInput) (*types.RequestDocumentAccessPayload, error) {
|
||||
trustCenter := compliancepage.CompliancePageFromContext(ctx)
|
||||
trustService := r.TrustService(ctx, trustCenter.ID.TenantID())
|
||||
|
||||
document, err := trustService.Documents.Get(ctx, trustCenter.OrganizationID, input.DocumentID)
|
||||
if err != nil {
|
||||
if errors.Is(err, trust.ErrDocumentNotFound) || errors.Is(err, trust.ErrDocumentNotVisible) || errors.Is(err, coredata.ErrResourceNotFound) {
|
||||
return nil, gqlutils.NotFoundf(ctx, "document %q not found", input.DocumentID)
|
||||
}
|
||||
if _, ok := errors.AsType[*trust.ErrDocumentArchived](err); ok {
|
||||
return nil, gqlutils.NotFoundf(ctx, "document %q not found", input.DocumentID)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot load document", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
if document.TrustCenterVisibility == coredata.TrustCenterVisibilityPublic {
|
||||
return nil, gqlutils.Invalidf(
|
||||
ctx,
|
||||
"document is publicly available and does not require access request",
|
||||
)
|
||||
}
|
||||
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
if identity == nil {
|
||||
return nil, gqlutils.Unauthenticatedf(ctx, "authentication is required to request access")
|
||||
}
|
||||
|
||||
if _, err := trustService.TrustCenterAccesses.Request(
|
||||
ctx,
|
||||
&trust.TrustCenterAccessRequest{
|
||||
TrustCenterID: trustCenter.ID,
|
||||
IdentityID: identity.ID,
|
||||
DocumentIDs: []gid.GID{input.DocumentID},
|
||||
ReportIDs: []gid.GID{},
|
||||
TrustCenterFileIDs: []gid.GID{},
|
||||
},
|
||||
); err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot request document access", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.RequestDocumentAccessPayload{
|
||||
Document: types.NewDocument(document),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// RequestReportAccess is the resolver for the requestReportAccess field.
|
||||
func (r *mutationResolver) RequestReportAccess(ctx context.Context, input types.RequestReportAccessInput) (*types.RequestReportAccessPayload, error) {
|
||||
trustCenter := compliancepage.CompliancePageFromContext(ctx)
|
||||
trustService := r.TrustService(ctx, trustCenter.ID.TenantID())
|
||||
|
||||
audit, err := trustService.Audits.GetByReportID(ctx, input.ReportID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot load audit", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
if audit.TrustCenterVisibility == coredata.TrustCenterVisibilityPublic {
|
||||
return nil, gqlutils.Invalidf(
|
||||
ctx,
|
||||
"report is publicly available and does not require access request",
|
||||
)
|
||||
}
|
||||
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
if identity == nil {
|
||||
return nil, gqlutils.Unauthenticatedf(ctx, "authentication is required to request access")
|
||||
}
|
||||
|
||||
if _, err := trustService.TrustCenterAccesses.Request(
|
||||
ctx,
|
||||
&trust.TrustCenterAccessRequest{
|
||||
TrustCenterID: trustCenter.ID,
|
||||
IdentityID: identity.ID,
|
||||
DocumentIDs: []gid.GID{},
|
||||
ReportIDs: []gid.GID{input.ReportID},
|
||||
TrustCenterFileIDs: []gid.GID{},
|
||||
},
|
||||
); err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot request report access", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.RequestReportAccessPayload{
|
||||
Audit: types.NewAudit(audit),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// RequestTrustCenterFileAccess is the resolver for the requestTrustCenterFileAccess field.
|
||||
func (r *mutationResolver) RequestTrustCenterFileAccess(ctx context.Context, input types.RequestTrustCenterFileAccessInput) (*types.RequestFileAccessPayload, error) {
|
||||
trustCenter := compliancepage.CompliancePageFromContext(ctx)
|
||||
trustService := r.TrustService(ctx, trustCenter.ID.TenantID())
|
||||
|
||||
trustCenterFile, err := trustService.TrustCenterFiles.Get(ctx, trustCenter.OrganizationID, input.TrustCenterFileID)
|
||||
if err != nil {
|
||||
if errors.Is(err, trust.ErrTrustCenterFileNotFound) || errors.Is(err, trust.ErrTrustCenterFileNotVisible) {
|
||||
return nil, gqlutils.NotFoundf(ctx, "trust center file %q not found", input.TrustCenterFileID)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot load trust center file", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
if trustCenterFile.TrustCenterVisibility == coredata.TrustCenterVisibilityPublic {
|
||||
return nil, gqlutils.Invalidf(
|
||||
ctx,
|
||||
"trust center file is publicly available and does not require access request",
|
||||
)
|
||||
}
|
||||
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
if identity == nil {
|
||||
return nil, gqlutils.Unauthenticatedf(ctx, "authentication is required to request access")
|
||||
}
|
||||
|
||||
if _, err := trustService.TrustCenterAccesses.Request(
|
||||
ctx,
|
||||
&trust.TrustCenterAccessRequest{
|
||||
TrustCenterID: trustCenter.ID,
|
||||
IdentityID: identity.ID,
|
||||
DocumentIDs: []gid.GID{},
|
||||
ReportIDs: []gid.GID{},
|
||||
TrustCenterFileIDs: []gid.GID{input.TrustCenterFileID},
|
||||
},
|
||||
); err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot request trust center file access", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.RequestFileAccessPayload{
|
||||
File: types.NewTrustCenterFile(trustCenterFile),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// IsUserAuthorized is the resolver for the isUserAuthorized field.
|
||||
func (r *reportResolver) IsUserAuthorized(ctx context.Context, obj *types.Report) (bool, error) {
|
||||
trustService := r.TrustService(ctx, obj.ID.TenantID())
|
||||
|
||||
trustCenter := compliancepage.CompliancePageFromContext(ctx)
|
||||
|
||||
audit, err := trustService.Audits.GetByReportID(ctx, obj.ID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot load document", log.Error(err))
|
||||
return false, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
if audit.TrustCenterVisibility == coredata.TrustCenterVisibilityPublic {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
if identity == nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
reportAccess, err := trustService.TrustCenterAccesses.GetReportAccess(ctx,
|
||||
trustCenter.ID,
|
||||
identity.ID,
|
||||
obj.ID,
|
||||
)
|
||||
if err != nil {
|
||||
if errors.Is(err, trust.ErrMembershipNotFound) ||
|
||||
errors.Is(err, trust.ErrUserNotFound) ||
|
||||
errors.Is(err, trust.ErrUserInactive) ||
|
||||
errors.Is(err, trust.ErrDocumentAccessNotFound) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot check report access", log.Error(err))
|
||||
return false, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return reportAccess.Status == coredata.TrustCenterDocumentAccessStatusGranted, nil
|
||||
}
|
||||
|
||||
// Access is the resolver for the access field.
|
||||
func (r *reportResolver) Access(ctx context.Context, obj *types.Report) (*types.DocumentAccess, error) {
|
||||
trustService := r.TrustService(ctx, obj.ID.TenantID())
|
||||
trustCenter := compliancepage.CompliancePageFromContext(ctx)
|
||||
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
if identity == nil {
|
||||
return nil, nil // User is not authenticated, so no access requested
|
||||
}
|
||||
|
||||
access, err := trustService.TrustCenterAccesses.GetReportAccess(
|
||||
ctx,
|
||||
trustCenter.ID,
|
||||
identity.ID,
|
||||
obj.ID,
|
||||
)
|
||||
if err != nil {
|
||||
if errors.Is(err, trust.ErrMembershipNotFound) ||
|
||||
errors.Is(err, trust.ErrUserNotFound) ||
|
||||
errors.Is(err, trust.ErrDocumentAccessNotFound) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if errors.Is(err, trust.ErrUserInactive) {
|
||||
return nil, gqlutils.Forbidden(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get audit report access", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DocumentAccess{
|
||||
ID: access.ID,
|
||||
Status: access.Status,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// TotalCount is the resolver for the totalCount field.
|
||||
func (r *subprocessorConnectionResolver) TotalCount(ctx context.Context, obj *types.SubprocessorConnection) (int, error) {
|
||||
trustService := r.TrustService(ctx, obj.ParentID.TenantID())
|
||||
|
||||
switch obj.Resolver.(type) {
|
||||
case *trustCenterResolver:
|
||||
count, err := trustService.Vendors.CountForTrustCenterId(ctx, obj.ParentID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count subprocessors", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "not implemented: TotalCount for parent type")
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
// IsUserAuthorized is the resolver for the isUserAuthorized field.
|
||||
func (r *trustCenterFileResolver) IsUserAuthorized(ctx context.Context, obj *types.TrustCenterFile) (bool, error) {
|
||||
trustService := r.TrustService(ctx, obj.ID.TenantID())
|
||||
|
||||
trustCenter := compliancepage.CompliancePageFromContext(ctx)
|
||||
|
||||
trustCenterFile, err := trustService.TrustCenterFiles.Get(ctx, trustCenter.OrganizationID, obj.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, trust.ErrTrustCenterFileNotFound) || errors.Is(err, trust.ErrTrustCenterFileNotVisible) {
|
||||
return false, gqlutils.NotFoundf(ctx, "trust center file %q not found", obj.ID)
|
||||
}
|
||||
r.logger.ErrorCtx(ctx, "cannot load trust center file", log.Error(err))
|
||||
return false, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
if trustCenterFile.TrustCenterVisibility == coredata.TrustCenterVisibilityPublic {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
if identity == nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
fileAccess, err := trustService.TrustCenterAccesses.GetTrustCenterFileAccess(ctx,
|
||||
trustCenter.ID,
|
||||
identity.ID,
|
||||
obj.ID,
|
||||
)
|
||||
if err != nil {
|
||||
if errors.Is(err, trust.ErrMembershipNotFound) ||
|
||||
errors.Is(err, trust.ErrUserNotFound) ||
|
||||
errors.Is(err, trust.ErrUserInactive) ||
|
||||
errors.Is(err, trust.ErrDocumentAccessNotFound) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot check trust center file access", log.Error(err))
|
||||
return false, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return fileAccess.Status == coredata.TrustCenterDocumentAccessStatusGranted, nil
|
||||
}
|
||||
|
||||
// Access is the resolver for the access field.
|
||||
func (r *trustCenterFileResolver) Access(ctx context.Context, obj *types.TrustCenterFile) (*types.DocumentAccess, error) {
|
||||
trustService := r.TrustService(ctx, obj.ID.TenantID())
|
||||
trustCenter := compliancepage.CompliancePageFromContext(ctx)
|
||||
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
if identity == nil {
|
||||
return nil, nil // User is not authenticated, so no access requested
|
||||
}
|
||||
|
||||
access, err := trustService.TrustCenterAccesses.GetTrustCenterFileAccess(
|
||||
ctx,
|
||||
trustCenter.ID,
|
||||
identity.ID,
|
||||
obj.ID,
|
||||
)
|
||||
if err != nil {
|
||||
if errors.Is(err, trust.ErrMembershipNotFound) ||
|
||||
errors.Is(err, trust.ErrUserNotFound) ||
|
||||
errors.Is(err, trust.ErrDocumentAccessNotFound) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if errors.Is(err, trust.ErrUserInactive) {
|
||||
return nil, gqlutils.Forbidden(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get file access", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DocumentAccess{
|
||||
ID: access.ID,
|
||||
Status: access.Status,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// LogoURL is the resolver for the logoUrl field.
|
||||
func (r *trustCenterReferenceResolver) LogoURL(ctx context.Context, obj *types.TrustCenterReference) (string, error) {
|
||||
trustService := r.TrustService(ctx, obj.ID.TenantID())
|
||||
|
||||
logoURL, err := trustService.TrustCenterReferences.GenerateLogoURL(ctx, obj.ID, 1*time.Hour)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot generate logo URL", log.Error(err))
|
||||
return "", gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return logoURL, nil
|
||||
}
|
||||
|
||||
// Audit returns schema.AuditResolver implementation.
|
||||
func (r *Resolver) Audit() schema.AuditResolver { return &auditResolver{r} }
|
||||
|
||||
// ComplianceFramework returns schema.ComplianceFrameworkResolver implementation.
|
||||
func (r *Resolver) ComplianceFramework() schema.ComplianceFrameworkResolver {
|
||||
return &complianceFrameworkResolver{r}
|
||||
}
|
||||
|
||||
// Document returns schema.DocumentResolver implementation.
|
||||
func (r *Resolver) Document() schema.DocumentResolver { return &documentResolver{r} }
|
||||
|
||||
// Framework returns schema.FrameworkResolver implementation.
|
||||
func (r *Resolver) Framework() schema.FrameworkResolver { return &frameworkResolver{r} }
|
||||
|
||||
// Report returns schema.ReportResolver implementation.
|
||||
func (r *Resolver) Report() schema.ReportResolver { return &reportResolver{r} }
|
||||
|
||||
// SubprocessorConnection returns schema.SubprocessorConnectionResolver implementation.
|
||||
func (r *Resolver) SubprocessorConnection() schema.SubprocessorConnectionResolver {
|
||||
return &subprocessorConnectionResolver{r}
|
||||
}
|
||||
|
||||
// TrustCenterFile returns schema.TrustCenterFileResolver implementation.
|
||||
func (r *Resolver) TrustCenterFile() schema.TrustCenterFileResolver {
|
||||
return &trustCenterFileResolver{r}
|
||||
}
|
||||
|
||||
// TrustCenterReference returns schema.TrustCenterReferenceResolver implementation.
|
||||
func (r *Resolver) TrustCenterReference() schema.TrustCenterReferenceResolver {
|
||||
return &trustCenterReferenceResolver{r}
|
||||
}
|
||||
|
||||
type auditResolver struct{ *Resolver }
|
||||
type complianceFrameworkResolver struct{ *Resolver }
|
||||
type documentResolver struct{ *Resolver }
|
||||
type frameworkResolver struct{ *Resolver }
|
||||
type reportResolver struct{ *Resolver }
|
||||
type subprocessorConnectionResolver struct{ *Resolver }
|
||||
type trustCenterFileResolver struct{ *Resolver }
|
||||
type trustCenterReferenceResolver struct{ *Resolver }
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,8 @@
|
||||
},
|
||||
"projects": {
|
||||
"core": {
|
||||
"schema": "pkg/server/api/console/v1/schema.graphql",
|
||||
"schema": "pkg/server/api/console/v1/graphql/base.graphql",
|
||||
"schemaExtensions": ["pkg/server/api/console/v1/graphql"],
|
||||
"language": "typescript",
|
||||
"noFutureProofEnums": true,
|
||||
"output": "apps/console/src/__generated__/core",
|
||||
@@ -22,7 +23,8 @@
|
||||
}
|
||||
},
|
||||
"iam": {
|
||||
"schema": "pkg/server/api/connect/v1/schema.graphql",
|
||||
"schema": "pkg/server/api/connect/v1/graphql/base.graphql",
|
||||
"schemaExtensions": ["pkg/server/api/connect/v1/graphql"],
|
||||
"language": "typescript",
|
||||
"noFutureProofEnums": true,
|
||||
"output": "apps/console/src/__generated__/iam",
|
||||
@@ -37,7 +39,8 @@
|
||||
}
|
||||
},
|
||||
"trust": {
|
||||
"schema": "pkg/server/api/trust/v1/schema.graphql",
|
||||
"schema": "pkg/server/api/trust/v1/graphql/base.graphql",
|
||||
"schemaExtensions": ["pkg/server/api/trust/v1/graphql"],
|
||||
"language": "typescript",
|
||||
"noFutureProofEnums": true,
|
||||
"customScalarTypes": {
|
||||
|
||||
Reference in New Issue
Block a user