Slim base.graphql to directives, scalars, Query, Node, and Mutation
Move Identity, Organization, Viewer, PageInfo, OrderDirection, CountryCode, OIDCProviderInfo, File, and ReauthenticationReason out of base.graphql into their own dedicated files across all three APIs. base.graphql now only contains directives, scalars, Node interface, Query type, and an empty Mutation type (required by Relay schemaExtensions). Entity files use extend type Mutation for their mutations. Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
@@ -12,628 +12,17 @@ import (
|
||||
"strings"
|
||||
|
||||
"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/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
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// Node is the resolver for the node field.
|
||||
func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
var (
|
||||
@@ -843,15 +232,11 @@ 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} }
|
||||
|
||||
// Query returns schema.QueryResolver implementation.
|
||||
func (r *Resolver) Query() schema.QueryResolver { return &queryResolver{r} }
|
||||
|
||||
type identityResolver struct{ *Resolver }
|
||||
type mutationResolver struct{ *Resolver }
|
||||
type queryResolver struct{ *Resolver }
|
||||
|
||||
@@ -16,34 +16,10 @@ 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)
|
||||
@@ -58,69 +34,4 @@ type Query {
|
||||
@session(required: OPTIONAL)
|
||||
}
|
||||
|
||||
type Identity implements Node {
|
||||
id: ID!
|
||||
email: EmailAddr!
|
||||
fullName: String!
|
||||
emailVerified: Boolean!
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
profiles(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: ProfileOrder
|
||||
filter: ProfileFilter
|
||||
): ProfileConnection @goField(forceResolver: true)
|
||||
|
||||
sessions(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: SessionOrder
|
||||
): SessionConnection @goField(forceResolver: true)
|
||||
|
||||
personalAPIKeys(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
): PersonalAPIKeyConnection @goField(forceResolver: true)
|
||||
|
||||
ssoLoginURL: String
|
||||
@goField(forceResolver: true)
|
||||
@session(required: PRESENT)
|
||||
|
||||
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)
|
||||
}
|
||||
type Mutation
|
||||
|
||||
40
pkg/server/api/connect/v1/graphql/identity.graphql
Normal file
40
pkg/server/api/connect/v1/graphql/identity.graphql
Normal file
@@ -0,0 +1,40 @@
|
||||
type Identity implements Node {
|
||||
id: ID!
|
||||
email: EmailAddr!
|
||||
fullName: String!
|
||||
emailVerified: Boolean!
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
profiles(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: ProfileOrder
|
||||
filter: ProfileFilter
|
||||
): ProfileConnection @goField(forceResolver: true)
|
||||
|
||||
sessions(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: SessionOrder
|
||||
): SessionConnection @goField(forceResolver: true)
|
||||
|
||||
personalAPIKeys(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
): PersonalAPIKeyConnection @goField(forceResolver: true)
|
||||
|
||||
ssoLoginURL: String
|
||||
@goField(forceResolver: true)
|
||||
@session(required: PRESENT)
|
||||
|
||||
permission(action: String!): Boolean!
|
||||
@goField(forceResolver: true)
|
||||
@session(required: PRESENT)
|
||||
}
|
||||
4
pkg/server/api/connect/v1/graphql/oidc.graphql
Normal file
4
pkg/server/api/connect/v1/graphql/oidc.graphql
Normal file
@@ -0,0 +1,4 @@
|
||||
type OIDCProviderInfo {
|
||||
name: String!
|
||||
loginURL: String!
|
||||
}
|
||||
12
pkg/server/api/connect/v1/graphql/pagination.graphql
Normal file
12
pkg/server/api/connect/v1/graphql/pagination.graphql
Normal file
@@ -0,0 +1,12 @@
|
||||
type PageInfo {
|
||||
hasNextPage: Boolean!
|
||||
hasPreviousPage: Boolean!
|
||||
startCursor: CursorKey
|
||||
endCursor: CursorKey
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
@@ -1,3 +1,35 @@
|
||||
enum ReauthenticationReason {
|
||||
SESSION_EXPIRED
|
||||
SENSITIVE_ACTION
|
||||
POLICY_REQUIREMENT
|
||||
}
|
||||
|
||||
extend 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)
|
||||
}
|
||||
|
||||
enum SessionOrderField
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.SessionOrderField") {
|
||||
CREATED_AT
|
||||
|
||||
185
pkg/server/api/connect/v1/identity.resolvers.go
Normal file
185
pkg/server/api/connect/v1/identity.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"
|
||||
"fmt"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
"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
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// Identity returns schema.IdentityResolver implementation.
|
||||
func (r *Resolver) Identity() schema.IdentityResolver { return &identityResolver{r} }
|
||||
|
||||
type identityResolver struct{ *Resolver }
|
||||
@@ -7,13 +7,467 @@ package connect_v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
"go.gearno.de/kit/log"
|
||||
"go.probo.inc/probo/pkg/iam"
|
||||
"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"
|
||||
)
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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) {
|
||||
|
||||
@@ -9,13 +9,11 @@ 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"
|
||||
@@ -24,23 +22,6 @@ import (
|
||||
"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 {
|
||||
@@ -431,177 +412,11 @@ func (r *queryResolver) Viewer(ctx context.Context) (*types.Viewer, error) {
|
||||
return &types.Viewer{ID: viewerID}, nil
|
||||
}
|
||||
|
||||
// SignableDocuments is the resolver for the signableDocuments field.
|
||||
func (r *viewerResolver) SignableDocuments(ctx context.Context, obj *types.Viewer, organizationID gid.GID, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentOrderBy) (*types.EmployeeDocumentConnection, error) {
|
||||
if err := r.authorize(ctx, organizationID, probo.ActionEmployeeDocumentList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, organizationID.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)
|
||||
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
|
||||
documentFilter := coredata.NewDocumentFilter(nil).WithEmployeeIdentityID(&identity.ID, coredata.EmployeeFilterModeSignature)
|
||||
|
||||
documentsPage, err := prb.Documents.ListByOrganizationID(ctx, organizationID, cursor, documentFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list organization signable documents", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
employeeDocuments := make([]*types.EmployeeDocument, len(documentsPage.Data))
|
||||
for i, doc := range documentsPage.Data {
|
||||
employeeDocuments[i] = &types.EmployeeDocument{
|
||||
ID: doc.ID,
|
||||
Title: doc.Title,
|
||||
DocumentType: doc.DocumentType,
|
||||
CreatedAt: doc.CreatedAt,
|
||||
UpdatedAt: doc.UpdatedAt,
|
||||
FilterMode: types.EmployeeDocumentFilterModeSignature,
|
||||
}
|
||||
}
|
||||
|
||||
page := page.NewPage(employeeDocuments, documentsPage.Cursor)
|
||||
|
||||
return types.NewEmployeeDocumentConnection(page), nil
|
||||
}
|
||||
|
||||
// SignableDocument is the resolver for the signableDocument field.
|
||||
func (r *viewerResolver) SignableDocument(ctx context.Context, obj *types.Viewer, id gid.GID) (*types.EmployeeDocument, error) {
|
||||
if err := r.authorize(ctx, id, probo.ActionEmployeeDocumentGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, id.TenantID())
|
||||
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
|
||||
documentFilter := coredata.NewDocumentFilter(nil).WithEmployeeIdentityID(&identity.ID, coredata.EmployeeFilterModeSignature)
|
||||
document, err := prb.Documents.GetWithFilter(ctx, id, documentFilter)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get signable document", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.EmployeeDocument{
|
||||
ID: document.ID,
|
||||
Title: document.Title,
|
||||
DocumentType: document.DocumentType,
|
||||
CreatedAt: document.CreatedAt,
|
||||
UpdatedAt: document.UpdatedAt,
|
||||
FilterMode: types.EmployeeDocumentFilterModeSignature,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ApprovableDocuments is the resolver for the approvableDocuments field.
|
||||
func (r *viewerResolver) ApprovableDocuments(ctx context.Context, obj *types.Viewer, organizationID gid.GID, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentOrderBy) (*types.EmployeeDocumentConnection, error) {
|
||||
if err := r.authorize(ctx, organizationID, probo.ActionEmployeeDocumentList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, organizationID.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)
|
||||
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
|
||||
documentFilter := coredata.NewDocumentFilter(nil).WithEmployeeIdentityID(&identity.ID, coredata.EmployeeFilterModeApproval)
|
||||
|
||||
documentsPage, err := prb.Documents.ListByOrganizationID(ctx, organizationID, cursor, documentFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list organization approvable documents", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
employeeDocuments := make([]*types.EmployeeDocument, len(documentsPage.Data))
|
||||
for i, doc := range documentsPage.Data {
|
||||
employeeDocuments[i] = &types.EmployeeDocument{
|
||||
ID: doc.ID,
|
||||
Title: doc.Title,
|
||||
DocumentType: doc.DocumentType,
|
||||
CreatedAt: doc.CreatedAt,
|
||||
UpdatedAt: doc.UpdatedAt,
|
||||
FilterMode: types.EmployeeDocumentFilterModeApproval,
|
||||
}
|
||||
}
|
||||
|
||||
page := page.NewPage(employeeDocuments, documentsPage.Cursor)
|
||||
|
||||
return types.NewEmployeeDocumentConnection(page), nil
|
||||
}
|
||||
|
||||
// ApprovableDocument is the resolver for the approvableDocument field.
|
||||
func (r *viewerResolver) ApprovableDocument(ctx context.Context, obj *types.Viewer, id gid.GID) (*types.EmployeeDocument, error) {
|
||||
if err := r.authorize(ctx, id, probo.ActionEmployeeDocumentGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, id.TenantID())
|
||||
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
|
||||
documentFilter := coredata.NewDocumentFilter(nil).WithEmployeeIdentityID(&identity.ID, coredata.EmployeeFilterModeApproval)
|
||||
document, err := prb.Documents.GetWithFilter(ctx, id, documentFilter)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get approvable document", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.EmployeeDocument{
|
||||
ID: document.ID,
|
||||
Title: document.Title,
|
||||
DocumentType: document.DocumentType,
|
||||
CreatedAt: document.CreatedAt,
|
||||
UpdatedAt: document.UpdatedAt,
|
||||
FilterMode: types.EmployeeDocumentFilterModeApproval,
|
||||
}, 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} }
|
||||
|
||||
// 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 queryResolver struct{ *Resolver }
|
||||
type viewerResolver struct{ *Resolver }
|
||||
|
||||
39
pkg/server/api/console/v1/file.resolvers.go
Normal file
39
pkg/server/api/console/v1/file.resolvers.go
Normal file
@@ -0,0 +1,39 @@
|
||||
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"
|
||||
"time"
|
||||
|
||||
"go.gearno.de/kit/log"
|
||||
"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"
|
||||
)
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// File returns schema.FileResolver implementation.
|
||||
func (r *Resolver) File() schema.FileResolver { return &fileResolver{r} }
|
||||
|
||||
type fileResolver struct{ *Resolver }
|
||||
@@ -1,4 +1,3 @@
|
||||
# Directives
|
||||
directive @goField(
|
||||
forceResolver: Boolean
|
||||
name: String
|
||||
@@ -12,7 +11,6 @@ directive @goModel(
|
||||
|
||||
directive @goEnum(value: String) on ENUM_VALUE
|
||||
|
||||
# Scalars
|
||||
scalar CursorKey
|
||||
scalar Datetime
|
||||
scalar Upload
|
||||
@@ -20,321 +18,15 @@ 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!
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
updateOrganizationContext(
|
||||
input: UpdateOrganizationContextInput!
|
||||
|
||||
253
pkg/server/api/console/v1/graphql/country_code.graphql
Normal file
253
pkg/server/api/console/v1/graphql/country_code.graphql
Normal file
@@ -0,0 +1,253 @@
|
||||
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")
|
||||
}
|
||||
|
||||
9
pkg/server/api/console/v1/graphql/file.graphql
Normal file
9
pkg/server/api/console/v1/graphql/file.graphql
Normal file
@@ -0,0 +1,9 @@
|
||||
type File {
|
||||
id: ID!
|
||||
mimeType: String!
|
||||
fileName: String!
|
||||
size: BigInt!
|
||||
downloadUrl: String! @goField(forceResolver: true)
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
}
|
||||
12
pkg/server/api/console/v1/graphql/pagination.graphql
Normal file
12
pkg/server/api/console/v1/graphql/pagination.graphql
Normal file
@@ -0,0 +1,12 @@
|
||||
type PageInfo {
|
||||
hasNextPage: Boolean!
|
||||
hasPreviousPage: Boolean!
|
||||
startCursor: CursorKey
|
||||
endCursor: CursorKey
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
25
pkg/server/api/console/v1/graphql/viewer.graphql
Normal file
25
pkg/server/api/console/v1/graphql/viewer.graphql
Normal file
@@ -0,0 +1,25 @@
|
||||
type Viewer {
|
||||
id: ID!
|
||||
|
||||
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)
|
||||
}
|
||||
184
pkg/server/api/console/v1/viewer.resolvers.go
Normal file
184
pkg/server/api/console/v1/viewer.resolvers.go
Normal file
@@ -0,0 +1,184 @@
|
||||
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/gid"
|
||||
"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"
|
||||
)
|
||||
|
||||
// SignableDocuments is the resolver for the signableDocuments field.
|
||||
func (r *viewerResolver) SignableDocuments(ctx context.Context, obj *types.Viewer, organizationID gid.GID, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentOrderBy) (*types.EmployeeDocumentConnection, error) {
|
||||
if err := r.authorize(ctx, organizationID, probo.ActionEmployeeDocumentList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, organizationID.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)
|
||||
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
|
||||
documentFilter := coredata.NewDocumentFilter(nil).WithEmployeeIdentityID(&identity.ID, coredata.EmployeeFilterModeSignature)
|
||||
|
||||
documentsPage, err := prb.Documents.ListByOrganizationID(ctx, organizationID, cursor, documentFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list organization signable documents", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
employeeDocuments := make([]*types.EmployeeDocument, len(documentsPage.Data))
|
||||
for i, doc := range documentsPage.Data {
|
||||
employeeDocuments[i] = &types.EmployeeDocument{
|
||||
ID: doc.ID,
|
||||
Title: doc.Title,
|
||||
DocumentType: doc.DocumentType,
|
||||
CreatedAt: doc.CreatedAt,
|
||||
UpdatedAt: doc.UpdatedAt,
|
||||
FilterMode: types.EmployeeDocumentFilterModeSignature,
|
||||
}
|
||||
}
|
||||
|
||||
page := page.NewPage(employeeDocuments, documentsPage.Cursor)
|
||||
|
||||
return types.NewEmployeeDocumentConnection(page), nil
|
||||
}
|
||||
|
||||
// SignableDocument is the resolver for the signableDocument field.
|
||||
func (r *viewerResolver) SignableDocument(ctx context.Context, obj *types.Viewer, id gid.GID) (*types.EmployeeDocument, error) {
|
||||
if err := r.authorize(ctx, id, probo.ActionEmployeeDocumentGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, id.TenantID())
|
||||
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
|
||||
documentFilter := coredata.NewDocumentFilter(nil).WithEmployeeIdentityID(&identity.ID, coredata.EmployeeFilterModeSignature)
|
||||
document, err := prb.Documents.GetWithFilter(ctx, id, documentFilter)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get signable document", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.EmployeeDocument{
|
||||
ID: document.ID,
|
||||
Title: document.Title,
|
||||
DocumentType: document.DocumentType,
|
||||
CreatedAt: document.CreatedAt,
|
||||
UpdatedAt: document.UpdatedAt,
|
||||
FilterMode: types.EmployeeDocumentFilterModeSignature,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ApprovableDocuments is the resolver for the approvableDocuments field.
|
||||
func (r *viewerResolver) ApprovableDocuments(ctx context.Context, obj *types.Viewer, organizationID gid.GID, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentOrderBy) (*types.EmployeeDocumentConnection, error) {
|
||||
if err := r.authorize(ctx, organizationID, probo.ActionEmployeeDocumentList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, organizationID.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)
|
||||
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
|
||||
documentFilter := coredata.NewDocumentFilter(nil).WithEmployeeIdentityID(&identity.ID, coredata.EmployeeFilterModeApproval)
|
||||
|
||||
documentsPage, err := prb.Documents.ListByOrganizationID(ctx, organizationID, cursor, documentFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list organization approvable documents", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
employeeDocuments := make([]*types.EmployeeDocument, len(documentsPage.Data))
|
||||
for i, doc := range documentsPage.Data {
|
||||
employeeDocuments[i] = &types.EmployeeDocument{
|
||||
ID: doc.ID,
|
||||
Title: doc.Title,
|
||||
DocumentType: doc.DocumentType,
|
||||
CreatedAt: doc.CreatedAt,
|
||||
UpdatedAt: doc.UpdatedAt,
|
||||
FilterMode: types.EmployeeDocumentFilterModeApproval,
|
||||
}
|
||||
}
|
||||
|
||||
page := page.NewPage(employeeDocuments, documentsPage.Cursor)
|
||||
|
||||
return types.NewEmployeeDocumentConnection(page), nil
|
||||
}
|
||||
|
||||
// ApprovableDocument is the resolver for the approvableDocument field.
|
||||
func (r *viewerResolver) ApprovableDocument(ctx context.Context, obj *types.Viewer, id gid.GID) (*types.EmployeeDocument, error) {
|
||||
if err := r.authorize(ctx, id, probo.ActionEmployeeDocumentGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, id.TenantID())
|
||||
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
|
||||
documentFilter := coredata.NewDocumentFilter(nil).WithEmployeeIdentityID(&identity.ID, coredata.EmployeeFilterModeApproval)
|
||||
document, err := prb.Documents.GetWithFilter(ctx, id, documentFilter)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get approvable document", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.EmployeeDocument{
|
||||
ID: document.ID,
|
||||
Title: document.Title,
|
||||
DocumentType: document.DocumentType,
|
||||
CreatedAt: document.CreatedAt,
|
||||
UpdatedAt: document.UpdatedAt,
|
||||
FilterMode: types.EmployeeDocumentFilterModeApproval,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Viewer returns schema.ViewerResolver implementation.
|
||||
func (r *Resolver) Viewer() schema.ViewerResolver { return &viewerResolver{r} }
|
||||
|
||||
type viewerResolver struct{ *Resolver }
|
||||
179
pkg/server/api/trust/v1/auth.resolvers.go
Normal file
179
pkg/server/api/trust/v1/auth.resolvers.go
Normal file
@@ -0,0 +1,179 @@
|
||||
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/baseurl"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/iam"
|
||||
"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/types"
|
||||
"go.probo.inc/probo/pkg/server/gqlutils"
|
||||
)
|
||||
|
||||
// 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
|
||||
}
|
||||
@@ -9,14 +9,10 @@ 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/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"
|
||||
@@ -25,171 +21,6 @@ import (
|
||||
"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)
|
||||
@@ -352,12 +183,8 @@ func (r *queryResolver) OidcProviders(ctx context.Context) ([]*types.OIDCProvide
|
||||
// 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 mutationResolver struct{ *Resolver }
|
||||
type organizationResolver struct{ *Resolver }
|
||||
type queryResolver struct{ *Resolver }
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
extend type Mutation {
|
||||
sendMagicLink(input: SendMagicLinkInput!): SendMagicLinkPayload
|
||||
@session(required: OPTIONAL)
|
||||
verifyMagicLink(input: VerifyMagicLinkInput!): VerifyMagicLinkPayload
|
||||
@session(required: OPTIONAL)
|
||||
updateFullName(input: UpdateFullNameInput!): UpdateFullNamePayload
|
||||
@session(required: PRESENT)
|
||||
}
|
||||
|
||||
input SendMagicLinkInput {
|
||||
email: EmailAddr!
|
||||
continue: String
|
||||
|
||||
@@ -21,291 +21,6 @@ interface Node {
|
||||
id: ID!
|
||||
}
|
||||
|
||||
type PageInfo {
|
||||
hasNextPage: Boolean!
|
||||
hasPreviousPage: Boolean!
|
||||
startCursor: CursorKey
|
||||
endCursor: CursorKey
|
||||
}
|
||||
|
||||
type Identity implements Node {
|
||||
id: ID!
|
||||
email: EmailAddr!
|
||||
fullName: String!
|
||||
emailVerified: Boolean!
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
}
|
||||
|
||||
type Organization implements Node {
|
||||
id: ID!
|
||||
name: String!
|
||||
logoUrl: String @goField(forceResolver: true)
|
||||
|
||||
description: String
|
||||
websiteUrl: String
|
||||
email: String
|
||||
headquarterAddress: String
|
||||
}
|
||||
|
||||
type OIDCProviderInfo {
|
||||
name: String!
|
||||
loginURL: String!
|
||||
}
|
||||
|
||||
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 Query {
|
||||
viewer: Identity
|
||||
node(id: ID!): Node
|
||||
@@ -315,11 +30,4 @@ type Query {
|
||||
@session(required: OPTIONAL)
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
sendMagicLink(input: SendMagicLinkInput!): SendMagicLinkPayload
|
||||
@session(required: OPTIONAL)
|
||||
verifyMagicLink(input: VerifyMagicLinkInput!): VerifyMagicLinkPayload
|
||||
@session(required: OPTIONAL)
|
||||
updateFullName(input: UpdateFullNameInput!): UpdateFullNamePayload
|
||||
@session(required: PRESENT)
|
||||
}
|
||||
type Mutation
|
||||
|
||||
253
pkg/server/api/trust/v1/graphql/country_code.graphql
Normal file
253
pkg/server/api/trust/v1/graphql/country_code.graphql
Normal file
@@ -0,0 +1,253 @@
|
||||
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")
|
||||
}
|
||||
|
||||
8
pkg/server/api/trust/v1/graphql/identity.graphql
Normal file
8
pkg/server/api/trust/v1/graphql/identity.graphql
Normal file
@@ -0,0 +1,8 @@
|
||||
type Identity implements Node {
|
||||
id: ID!
|
||||
email: EmailAddr!
|
||||
fullName: String!
|
||||
emailVerified: Boolean!
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
}
|
||||
4
pkg/server/api/trust/v1/graphql/oidc.graphql
Normal file
4
pkg/server/api/trust/v1/graphql/oidc.graphql
Normal file
@@ -0,0 +1,4 @@
|
||||
type OIDCProviderInfo {
|
||||
name: String!
|
||||
loginURL: String!
|
||||
}
|
||||
10
pkg/server/api/trust/v1/graphql/organization.graphql
Normal file
10
pkg/server/api/trust/v1/graphql/organization.graphql
Normal file
@@ -0,0 +1,10 @@
|
||||
type Organization implements Node {
|
||||
id: ID!
|
||||
name: String!
|
||||
logoUrl: String @goField(forceResolver: true)
|
||||
|
||||
description: String
|
||||
websiteUrl: String
|
||||
email: String
|
||||
headquarterAddress: String
|
||||
}
|
||||
6
pkg/server/api/trust/v1/graphql/pagination.graphql
Normal file
6
pkg/server/api/trust/v1/graphql/pagination.graphql
Normal file
@@ -0,0 +1,6 @@
|
||||
type PageInfo {
|
||||
hasNextPage: Boolean!
|
||||
hasPreviousPage: Boolean!
|
||||
startCursor: CursorKey
|
||||
endCursor: CursorKey
|
||||
}
|
||||
26
pkg/server/api/trust/v1/organization.resolvers.go
Normal file
26
pkg/server/api/trust/v1/organization.resolvers.go
Normal file
@@ -0,0 +1,26 @@
|
||||
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"
|
||||
"time"
|
||||
|
||||
"go.probo.inc/probo/pkg/server/api/trust/v1/schema"
|
||||
"go.probo.inc/probo/pkg/server/api/trust/v1/types"
|
||||
)
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// Organization returns schema.OrganizationResolver implementation.
|
||||
func (r *Resolver) Organization() schema.OrganizationResolver { return &organizationResolver{r} }
|
||||
|
||||
type organizationResolver struct{ *Resolver }
|
||||
Reference in New Issue
Block a user