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)
|
# 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`
|
## Connection types and `@goModel`
|
||||||
|
|
||||||
@@ -40,14 +49,16 @@ enum VendorOrderField
|
|||||||
|
|
||||||
## Schema directives
|
## Schema directives
|
||||||
|
|
||||||
|
|
||||||
| Directive | Target | Purpose |
|
| Directive | Target | Purpose |
|
||||||
|-----------|--------|---------|
|
| ------------------------------- | ---------------------------------------------------------------- | ------------------------------------------------------------ |
|
||||||
| `@goModel(model: "...")` | `OBJECT`, `ENUM`, `INPUT_OBJECT`, `SCALAR`, `INTERFACE`, `UNION` | Map GraphQL type to existing Go type |
|
| `@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 |
|
| `@goEnum(value: "...")` | `ENUM_VALUE` | Map enum value to Go constant |
|
||||||
| `@goField(forceResolver: true)` | `FIELD_DEFINITION` | Force a resolver function instead of struct field |
|
| `@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(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 |
|
| `@goField(omittable: true)` | `INPUT_FIELD_DEFINITION` | Use `graphql.Omittable[T]` for distinguishing null vs absent |
|
||||||
|
|
||||||
|
|
||||||
## Cursor pagination schema types
|
## Cursor pagination schema types
|
||||||
|
|
||||||
Every paginated field uses shared base types plus entity-specific types:
|
Every paginated field uses shared base types plus entity-specific types:
|
||||||
@@ -158,7 +169,8 @@ Default page size is **25** when neither `first` nor `last` is provided.
|
|||||||
## Adding a new paginated field — checklist
|
## 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
|
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`
|
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)
|
4. **Resolver** — implement the resolver (authorize, build order, build cursor, call service, build connection)
|
||||||
5. **Codegen** — run `go generate` for the relevant API package
|
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:
|
Two Relay environments connect to two separate GraphQL APIs:
|
||||||
|
|
||||||
|
|
||||||
| Environment | Endpoint | Purpose |
|
| Environment | Endpoint | Purpose |
|
||||||
|-------------|----------|---------|
|
| ----------------- | ------------------------- | ------------------------- |
|
||||||
| `coreEnvironment` | `/api/console/v1/graphql` | Main application data |
|
| `coreEnvironment` | `/api/console/v1/graphql` | Main application data |
|
||||||
| `iamEnvironment` | `/api/connect/v1/graphql` | Authentication / identity |
|
| `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.
|
Configured in `apps/console/src/environments.ts`. Each has its own store with 1-minute query cache expiration.
|
||||||
|
|
||||||
## Relay compiler
|
## 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
|
```sh
|
||||||
npm run relay # clean + compile (from repo root)
|
npm run relay # clean + compile (from repo root)
|
||||||
@@ -381,7 +383,7 @@ return () => {
|
|||||||
|
|
||||||
## File organization
|
## 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/
|
pages/organizations/vendors/
|
||||||
|
|||||||
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:
|
||||||
- "schema.graphql"
|
- "graphql/*.graphql"
|
||||||
- "../../../gqlutils/directives/session/schema.graphql"
|
- "../../../gqlutils/directives/session/schema.graphql"
|
||||||
|
|
||||||
exec:
|
exec:
|
||||||
@@ -14,7 +14,7 @@ resolver:
|
|||||||
layout: "follow-schema"
|
layout: "follow-schema"
|
||||||
dir: "."
|
dir: "."
|
||||||
package: "connect_v1"
|
package: "connect_v1"
|
||||||
filename_template: "v1_resolver.go"
|
filename_template: "{name}.resolvers.go"
|
||||||
|
|
||||||
autobind: []
|
autobind: []
|
||||||
call_argument_directives_with_null: true
|
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 |
|
| 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 |
|
| `gqlgen.yaml` | Hand-written | Codegen config |
|
||||||
| `resolver.go` | Hand-written | Root `Resolver` struct and `NewMux` |
|
| `resolver.go` | Hand-written | Root `Resolver` struct and `NewMux` |
|
||||||
| `graphql_handler.go` | Hand-written | Handler setup |
|
| `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 |
|
| `schema/schema.go` | **Generated — DO NOT EDIT** | Executable schema |
|
||||||
| `types/types.go` | **Generated — DO NOT EDIT** | Type definitions |
|
| `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
|
## Important rules
|
||||||
|
|
||||||
- **Never edit generated files** (`schema/schema.go`, `types/types.go`). Only edit `schema.graphql` and resolver bodies.
|
- **Never edit generated files** (`schema/schema.go`, `types/types.go`). Only edit `graphql/*.graphql` and resolver bodies.
|
||||||
- **After any change to `schema.graphql`**, always run codegen:
|
- **After any change to `graphql/*.graphql`**, always run codegen:
|
||||||
|
|
||||||
```
|
```
|
||||||
go generate ./pkg/server/api/console/v1
|
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:
|
exec:
|
||||||
filename: "schema/schema.go"
|
filename: "schema/schema.go"
|
||||||
@@ -12,7 +13,7 @@ resolver:
|
|||||||
layout: "follow-schema"
|
layout: "follow-schema"
|
||||||
dir: "."
|
dir: "."
|
||||||
package: "console_v1"
|
package: "console_v1"
|
||||||
filename_template: "v1_resolver.go"
|
filename_template: "{name}.resolvers.go"
|
||||||
|
|
||||||
autobind: []
|
autobind: []
|
||||||
call_argument_directives_with_null: true
|
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:
|
||||||
- "schema.graphql"
|
- "graphql/*.graphql"
|
||||||
- "../../../gqlutils/directives/session/schema.graphql"
|
- "../../../gqlutils/directives/session/schema.graphql"
|
||||||
|
|
||||||
exec:
|
exec:
|
||||||
@@ -14,7 +14,7 @@ resolver:
|
|||||||
layout: "follow-schema"
|
layout: "follow-schema"
|
||||||
dir: "."
|
dir: "."
|
||||||
package: "trust_v1"
|
package: "trust_v1"
|
||||||
filename_template: "v1_resolver.go"
|
filename_template: "{name}.resolvers.go"
|
||||||
|
|
||||||
autobind: []
|
autobind: []
|
||||||
call_argument_directives_with_null: true
|
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(
|
directive @goField(
|
||||||
forceResolver: Boolean
|
forceResolver: Boolean
|
||||||
name: String
|
name: String
|
||||||
@@ -49,111 +48,9 @@ type Organization implements Node {
|
|||||||
headquarterAddress: String
|
headquarterAddress: String
|
||||||
}
|
}
|
||||||
|
|
||||||
enum DocumentType
|
type OIDCProviderInfo {
|
||||||
@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!
|
name: String!
|
||||||
lightLogoURL: String @goField(forceResolver: true)
|
loginURL: String!
|
||||||
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!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum CountryCode
|
enum CountryCode
|
||||||
@@ -409,141 +306,13 @@ enum CountryCode
|
|||||||
ZW @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeZW")
|
ZW @goEnum(value: "go.probo.inc/probo/pkg/coredata.CountryCodeZW")
|
||||||
}
|
}
|
||||||
|
|
||||||
enum SubprocessorCategory
|
type Query {
|
||||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.VendorCategory") {
|
viewer: Identity
|
||||||
ANALYTICS
|
node(id: ID!): Node
|
||||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.VendorCategoryAnalytics")
|
currentTrustCenter: TrustCenter
|
||||||
CLOUD_MONITORING
|
oidcProviders: [OIDCProviderInfo!]!
|
||||||
@goEnum(
|
@goField(forceResolver: true)
|
||||||
value: "go.probo.inc/probo/pkg/coredata.VendorCategoryCloudMonitoring"
|
@session(required: OPTIONAL)
|
||||||
)
|
|
||||||
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 TrustCenter implements Node {
|
type TrustCenter implements Node {
|
||||||
@@ -553,9 +322,6 @@ type TrustCenter implements Node {
|
|||||||
logoFileUrl: String @goField(forceResolver: true)
|
logoFileUrl: String @goField(forceResolver: true)
|
||||||
darkLogoFileUrl: String @goField(forceResolver: true)
|
darkLogoFileUrl: String @goField(forceResolver: true)
|
||||||
|
|
||||||
nonDisclosureAgreement: NonDisclosureAgreement @goField(forceResolver: true)
|
|
||||||
|
|
||||||
viewerSubscription: MailingListSubscriber @goField(forceResolver: true)
|
|
||||||
organization: Organization! @goField(forceResolver: true)
|
organization: Organization! @goField(forceResolver: true)
|
||||||
|
|
||||||
documents(
|
documents(
|
||||||
@@ -606,292 +372,6 @@ type TrustCenter implements Node {
|
|||||||
last: Int
|
last: Int
|
||||||
before: CursorKey
|
before: CursorKey
|
||||||
): ComplianceExternalURLConnection! @goField(forceResolver: true)
|
): 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 {
|
type Mutation {
|
||||||
@@ -901,74 +381,4 @@ type Mutation {
|
|||||||
@session(required: OPTIONAL)
|
@session(required: OPTIONAL)
|
||||||
updateFullName(input: UpdateFullNameInput!): UpdateFullNamePayload
|
updateFullName(input: UpdateFullNameInput!): UpdateFullNamePayload
|
||||||
@session(required: PRESENT)
|
@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": {
|
"projects": {
|
||||||
"core": {
|
"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",
|
"language": "typescript",
|
||||||
"noFutureProofEnums": true,
|
"noFutureProofEnums": true,
|
||||||
"output": "apps/console/src/__generated__/core",
|
"output": "apps/console/src/__generated__/core",
|
||||||
@@ -22,7 +23,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"iam": {
|
"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",
|
"language": "typescript",
|
||||||
"noFutureProofEnums": true,
|
"noFutureProofEnums": true,
|
||||||
"output": "apps/console/src/__generated__/iam",
|
"output": "apps/console/src/__generated__/iam",
|
||||||
@@ -37,7 +39,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"trust": {
|
"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",
|
"language": "typescript",
|
||||||
"noFutureProofEnums": true,
|
"noFutureProofEnums": true,
|
||||||
"customScalarTypes": {
|
"customScalarTypes": {
|
||||||
|
|||||||
Reference in New Issue
Block a user