Embded frontend inside go binary
This will simplify the self hosting of the platform. Signed-off-by: gearnode <bryan@frimin.fr>
This commit is contained in:
215
pkg/server/api/console/v1/auth_handlers.go
Normal file
215
pkg/server/api/console/v1/auth_handlers.go
Normal file
@@ -0,0 +1,215 @@
|
||||
package console_v1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/getprobo/probo/pkg/gid"
|
||||
"github.com/getprobo/probo/pkg/usrmgr"
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
type (
|
||||
// RegisterRequest represents the request body for user registration
|
||||
RegisterRequest struct {
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password"`
|
||||
FullName string `json:"fullName"`
|
||||
}
|
||||
|
||||
// LoginRequest represents the request body for user login
|
||||
LoginRequest struct {
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
// AuthResponse represents the response for successful authentication
|
||||
AuthResponse struct {
|
||||
User UserResponse `json:"user"`
|
||||
Session SessionResponse `json:"session"`
|
||||
}
|
||||
|
||||
// UserResponse represents user data in the authentication response
|
||||
UserResponse struct {
|
||||
ID gid.GID `json:"id"`
|
||||
Email string `json:"email"`
|
||||
FullName string `json:"fullName"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
// SessionResponse represents session data in the authentication response
|
||||
SessionResponse struct {
|
||||
ID gid.GID `json:"id"`
|
||||
ExpiresAt time.Time `json:"expiresAt"`
|
||||
}
|
||||
)
|
||||
|
||||
// RegisterHandler handles user registration
|
||||
func RegisterHandler(usrmgrSvc *usrmgr.Service, authCfg AuthConfig) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
// Parse request body
|
||||
var req RegisterRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
http.Error(w, "Invalid request body", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Validate request
|
||||
if req.Email == "" || req.Password == "" {
|
||||
http.Error(w, "Email and password are required", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Register the user
|
||||
user, err := usrmgrSvc.RegisterUser(
|
||||
r.Context(),
|
||||
usrmgr.RegisterUserParams{
|
||||
Email: req.Email,
|
||||
Password: req.Password,
|
||||
FullName: req.FullName,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Failed to register user: %v", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Log the user in
|
||||
session, err := usrmgrSvc.Login(r.Context(), req.Email, req.Password)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Failed to login after registration: %v", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Set the session cookie
|
||||
setSessionCookie(w, session.ID.String(), authCfg)
|
||||
|
||||
// Return response
|
||||
resp := AuthResponse{
|
||||
User: UserResponse{
|
||||
ID: user.ID,
|
||||
Email: user.EmailAddress,
|
||||
FullName: user.FullName,
|
||||
CreatedAt: user.CreatedAt,
|
||||
UpdatedAt: user.UpdatedAt,
|
||||
},
|
||||
Session: SessionResponse{
|
||||
ID: session.ID,
|
||||
ExpiresAt: session.ExpiredAt,
|
||||
},
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if err := json.NewEncoder(w).Encode(resp); err != nil {
|
||||
http.Error(w, "Failed to encode response", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// LoginHandler handles user login
|
||||
func LoginHandler(usrmgrSvc *usrmgr.Service, authCfg AuthConfig) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
// Parse request body
|
||||
var req LoginRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
http.Error(w, "Invalid request body", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Validate request
|
||||
if req.Email == "" || req.Password == "" {
|
||||
http.Error(w, "Email and password are required", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Login the user
|
||||
session, err := usrmgrSvc.Login(r.Context(), req.Email, req.Password)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Failed to login: %v", err), http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
// Get the user
|
||||
user, err := usrmgrSvc.GetUserBySession(r.Context(), session.ID)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Failed to get user: %v", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Set the session cookie
|
||||
setSessionCookie(w, session.ID.String(), authCfg)
|
||||
|
||||
// Return response
|
||||
resp := AuthResponse{
|
||||
User: UserResponse{
|
||||
ID: user.ID,
|
||||
Email: user.EmailAddress,
|
||||
FullName: user.FullName,
|
||||
CreatedAt: user.CreatedAt,
|
||||
UpdatedAt: user.UpdatedAt,
|
||||
},
|
||||
Session: SessionResponse{
|
||||
ID: session.ID,
|
||||
ExpiresAt: session.ExpiredAt,
|
||||
},
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if err := json.NewEncoder(w).Encode(resp); err != nil {
|
||||
http.Error(w, "Failed to encode response", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// LogoutHandler handles user logout
|
||||
func LogoutHandler(usrmgrSvc *usrmgr.Service, authCfg AuthConfig) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
// Get session from cookie
|
||||
cookie, err := r.Cookie(authCfg.CookieName)
|
||||
if err != nil || cookie.Value == "" {
|
||||
http.Error(w, "No active session", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Verify the cookie signature
|
||||
originalValue, err := verifyCookieValue(cookie.Value, authCfg.CookieSecret)
|
||||
if err != nil {
|
||||
http.Error(w, "Invalid session cookie", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Parse the session ID
|
||||
sessionID, err := gid.ParseGID(originalValue)
|
||||
if err != nil {
|
||||
http.Error(w, "Invalid session ID", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Logout the user
|
||||
err = usrmgrSvc.Logout(r.Context(), sessionID)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Failed to logout: %v", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Clear the session cookie
|
||||
clearSessionCookie(w, authCfg)
|
||||
|
||||
// Return success response
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(map[string]bool{"success": true})
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterAuthRoutes registers the authentication routes
|
||||
func RegisterAuthRoutes(r chi.Router, usrmgrSvc *usrmgr.Service, authCfg AuthConfig) {
|
||||
r.Post("/auth/register", RegisterHandler(usrmgrSvc, authCfg))
|
||||
r.Post("/auth/login", LoginHandler(usrmgrSvc, authCfg))
|
||||
r.Post("/auth/logout", LogoutHandler(usrmgrSvc, authCfg))
|
||||
}
|
||||
38
pkg/server/api/console/v1/cookie.go
Normal file
38
pkg/server/api/console/v1/cookie.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package console_v1
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// setSessionCookie sets a session cookie in the response
|
||||
func setSessionCookie(w http.ResponseWriter, sessionID string, cfg AuthConfig) {
|
||||
// Sign the session ID
|
||||
signedValue := signCookieValue(sessionID, cfg.CookieSecret)
|
||||
|
||||
cookie := &http.Cookie{
|
||||
Name: cfg.CookieName,
|
||||
Value: signedValue,
|
||||
Path: cfg.CookiePath,
|
||||
Domain: cfg.CookieDomain,
|
||||
Secure: cfg.CookieSecure,
|
||||
HttpOnly: cfg.CookieHTTPOnly,
|
||||
MaxAge: int(cfg.SessionDuration.Seconds()),
|
||||
SameSite: http.SameSiteLaxMode,
|
||||
}
|
||||
http.SetCookie(w, cookie)
|
||||
}
|
||||
|
||||
// clearSessionCookie clears the session cookie
|
||||
func clearSessionCookie(w http.ResponseWriter, cfg AuthConfig) {
|
||||
cookie := &http.Cookie{
|
||||
Name: cfg.CookieName,
|
||||
Value: "",
|
||||
Path: cfg.CookiePath,
|
||||
Domain: cfg.CookieDomain,
|
||||
Secure: cfg.CookieSecure,
|
||||
HttpOnly: cfg.CookieHTTPOnly,
|
||||
MaxAge: -1,
|
||||
SameSite: http.SameSiteLaxMode,
|
||||
}
|
||||
http.SetCookie(w, cookie)
|
||||
}
|
||||
50
pkg/server/api/console/v1/cookie_signer.go
Normal file
50
pkg/server/api/console/v1/cookie_signer.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package console_v1
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func signCookieValue(value string, secret string) string {
|
||||
if secret == "" {
|
||||
panic(fmt.Errorf("cookie secret is not set"))
|
||||
}
|
||||
|
||||
h := hmac.New(sha256.New, []byte(secret))
|
||||
|
||||
h.Write([]byte(value))
|
||||
|
||||
signature := base64.URLEncoding.EncodeToString(h.Sum(nil))
|
||||
|
||||
return fmt.Sprintf("%s.%s", value, signature)
|
||||
}
|
||||
|
||||
func verifyCookieValue(signedValue string, secret string) (string, error) {
|
||||
if secret == "" {
|
||||
panic(fmt.Errorf("cookie secret is not set"))
|
||||
}
|
||||
|
||||
parts := strings.Split(signedValue, ".")
|
||||
if len(parts) != 2 {
|
||||
return "", fmt.Errorf("invalid signed cookie format")
|
||||
}
|
||||
|
||||
value, signature := parts[0], parts[1]
|
||||
|
||||
expectedSignedValue := signCookieValue(value, secret)
|
||||
expectedParts := strings.Split(expectedSignedValue, ".")
|
||||
if len(expectedParts) != 2 {
|
||||
return "", fmt.Errorf("error computing signature")
|
||||
}
|
||||
|
||||
expectedSignature := expectedParts[1]
|
||||
|
||||
if signature != expectedSignature {
|
||||
return "", fmt.Errorf("cookie signature verification failed")
|
||||
}
|
||||
|
||||
return value, nil
|
||||
}
|
||||
30
pkg/server/api/console/v1/gqlgen.yaml
Normal file
30
pkg/server/api/console/v1/gqlgen.yaml
Normal file
@@ -0,0 +1,30 @@
|
||||
schema: ["schema.graphql"]
|
||||
|
||||
exec:
|
||||
filename: "schema/schema.go"
|
||||
package: "schema"
|
||||
|
||||
model:
|
||||
filename: "types/types.go"
|
||||
package: "types"
|
||||
|
||||
resolver:
|
||||
layout: "follow-schema"
|
||||
dir: "."
|
||||
package: "console_v1"
|
||||
filename_template: "v1_resolver.go"
|
||||
|
||||
autobind: []
|
||||
omit_panic_handler: true
|
||||
call_argument_directives_with_null: true
|
||||
|
||||
models:
|
||||
ID:
|
||||
model:
|
||||
- "github.com/getprobo/probo/pkg/server/api/console/v1/types.GIDScalar"
|
||||
Datetime:
|
||||
model:
|
||||
- "github.com/99designs/gqlgen/graphql.Time"
|
||||
CursorKey:
|
||||
model:
|
||||
- "github.com/getprobo/probo/pkg/server/api/console/v1/types.CursorKeyScalar"
|
||||
178
pkg/server/api/console/v1/resolver.go
Normal file
178
pkg/server/api/console/v1/resolver.go
Normal file
@@ -0,0 +1,178 @@
|
||||
//go:generate go run github.com/99designs/gqlgen generate
|
||||
|
||||
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package console_v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
"github.com/99designs/gqlgen/graphql/handler"
|
||||
"github.com/99designs/gqlgen/graphql/handler/extension"
|
||||
"github.com/99designs/gqlgen/graphql/handler/transport"
|
||||
"github.com/99designs/gqlgen/graphql/playground"
|
||||
"github.com/getprobo/probo/pkg/gid"
|
||||
"github.com/getprobo/probo/pkg/probo"
|
||||
"github.com/getprobo/probo/pkg/server/api/console/v1/schema"
|
||||
"github.com/getprobo/probo/pkg/usrmgr"
|
||||
"github.com/getprobo/probo/pkg/usrmgr/coredata"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
)
|
||||
|
||||
type (
|
||||
AuthConfig struct {
|
||||
CookieName string
|
||||
CookieSecure bool
|
||||
CookieHTTPOnly bool
|
||||
CookieDomain string
|
||||
CookiePath string
|
||||
SessionDuration time.Duration
|
||||
CookieSecret string
|
||||
}
|
||||
|
||||
Resolver struct {
|
||||
proboSvc *probo.Service
|
||||
usrmgrSvc *usrmgr.Service
|
||||
authCfg AuthConfig
|
||||
}
|
||||
|
||||
contextKey string
|
||||
|
||||
httpContext struct {
|
||||
ResponseWriter http.ResponseWriter
|
||||
Request *http.Request
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
sessionContextKey contextKey = "session"
|
||||
userContextKey contextKey = "user"
|
||||
httpContextKey contextKey = "http"
|
||||
)
|
||||
|
||||
// SessionFromContext retrieves the session from the context
|
||||
func SessionFromContext(ctx context.Context) *coredata.Session {
|
||||
session, _ := ctx.Value(sessionContextKey).(*coredata.Session)
|
||||
return session
|
||||
}
|
||||
|
||||
// UserFromContext retrieves the user from the context
|
||||
func UserFromContext(ctx context.Context) *coredata.User {
|
||||
user, _ := ctx.Value(userContextKey).(*coredata.User)
|
||||
return user
|
||||
}
|
||||
|
||||
func NewMux(proboSvc *probo.Service, usrmgrSvc *usrmgr.Service, authCfg AuthConfig) *chi.Mux {
|
||||
r := chi.NewMux()
|
||||
|
||||
// Register authentication routes
|
||||
RegisterAuthRoutes(r, usrmgrSvc, authCfg)
|
||||
|
||||
// GraphQL playground and query endpoint
|
||||
r.Get("/", playground.Handler("GraphQL", "/console/v1/query"))
|
||||
r.Post("/query", graphqlHandler(proboSvc, usrmgrSvc, authCfg))
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func graphqlHandler(proboSvc *probo.Service, usrmgrSvc *usrmgr.Service, authCfg AuthConfig) http.HandlerFunc {
|
||||
var mb int64 = 1 << 20
|
||||
|
||||
es := schema.NewExecutableSchema(
|
||||
schema.Config{
|
||||
Resolvers: &Resolver{
|
||||
proboSvc: proboSvc,
|
||||
usrmgrSvc: usrmgrSvc,
|
||||
authCfg: authCfg,
|
||||
},
|
||||
},
|
||||
)
|
||||
srv := handler.New(es)
|
||||
srv.AddTransport(transport.POST{})
|
||||
srv.AddTransport(transport.MultipartForm{
|
||||
MaxMemory: 32 * mb,
|
||||
MaxUploadSize: 50 * mb,
|
||||
})
|
||||
srv.Use(extension.Introspection{})
|
||||
|
||||
// Add operation middleware for authentication
|
||||
srv.AroundOperations(func(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler {
|
||||
// Skip authentication for introspection queries
|
||||
if op := graphql.GetOperationContext(ctx); op.OperationName == "IntrospectionQuery" {
|
||||
return next(ctx)
|
||||
}
|
||||
|
||||
// Get the user from context
|
||||
user := UserFromContext(ctx)
|
||||
if user == nil {
|
||||
return func(ctx context.Context) *graphql.Response {
|
||||
return &graphql.Response{
|
||||
Errors: gqlerror.List{gqlerror.Errorf("authentication required")},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Continue with the operation
|
||||
return next(ctx)
|
||||
})
|
||||
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
// Create HTTP context
|
||||
httpCtx := &httpContext{
|
||||
ResponseWriter: w,
|
||||
Request: r,
|
||||
}
|
||||
ctx := context.WithValue(r.Context(), httpContextKey, httpCtx)
|
||||
|
||||
// Extract session from cookie
|
||||
cookie, err := r.Cookie(authCfg.CookieName)
|
||||
if err == nil && cookie.Value != "" {
|
||||
// Verify the cookie signature
|
||||
originalValue, err := verifyCookieValue(cookie.Value, authCfg.CookieSecret)
|
||||
if err == nil {
|
||||
// Parse the session ID
|
||||
sessionID, err := gid.ParseGID(originalValue)
|
||||
if err == nil {
|
||||
// Get the session
|
||||
session, err := usrmgrSvc.GetSession(r.Context(), sessionID)
|
||||
if err == nil {
|
||||
// Add session to context
|
||||
ctx = context.WithValue(ctx, sessionContextKey, session)
|
||||
|
||||
// Get the user
|
||||
user, err := usrmgrSvc.GetUserBySession(r.Context(), sessionID)
|
||||
if err == nil {
|
||||
// Add user to context
|
||||
ctx = context.WithValue(ctx, userContextKey, user)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
srv.ServeHTTP(w, r.WithContext(ctx))
|
||||
|
||||
if session := SessionFromContext(r.Context()); session != nil {
|
||||
if err := usrmgrSvc.UpdateSession(r.Context(), session); err != nil {
|
||||
panic(fmt.Errorf("failed to update session: %w", err))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
702
pkg/server/api/console/v1/schema.graphql
Normal file
702
pkg/server/api/console/v1/schema.graphql
Normal file
@@ -0,0 +1,702 @@
|
||||
directive @goField(
|
||||
forceResolver: Boolean
|
||||
name: String
|
||||
omittable: Boolean
|
||||
) on INPUT_FIELD_DEFINITION | FIELD_DEFINITION
|
||||
|
||||
directive @goModel(
|
||||
model: String
|
||||
models: [String!]
|
||||
) on OBJECT | INPUT_OBJECT | SCALAR | ENUM | INTERFACE | UNION
|
||||
|
||||
directive @goEnum(value: String) on ENUM_VALUE
|
||||
|
||||
scalar CursorKey
|
||||
scalar Void
|
||||
scalar Datetime
|
||||
scalar Upload
|
||||
|
||||
interface Node {
|
||||
id: ID!
|
||||
}
|
||||
|
||||
enum ControlState
|
||||
@goModel(model: "github.com/getprobo/probo/pkg/probo/coredata.ControlState") {
|
||||
NOT_STARTED
|
||||
@goEnum(
|
||||
value: "github.com/getprobo/probo/pkg/probo/coredata.ControlStateNotStarted"
|
||||
)
|
||||
IN_PROGRESS
|
||||
@goEnum(
|
||||
value: "github.com/getprobo/probo/pkg/probo/coredata.ControlStateInProgress"
|
||||
)
|
||||
NOT_APPLICABLE
|
||||
@goEnum(
|
||||
value: "github.com/getprobo/probo/pkg/probo/coredata.ControlStateNotApplicable"
|
||||
)
|
||||
IMPLEMENTED
|
||||
@goEnum(
|
||||
value: "github.com/getprobo/probo/pkg/probo/coredata.ControlStateImplemented"
|
||||
)
|
||||
}
|
||||
|
||||
enum TaskState
|
||||
@goModel(model: "github.com/getprobo/probo/pkg/probo/coredata.TaskState") {
|
||||
TODO
|
||||
@goEnum(value: "github.com/getprobo/probo/pkg/probo/coredata.TaskStateTodo")
|
||||
DONE
|
||||
@goEnum(value: "github.com/getprobo/probo/pkg/probo/coredata.TaskStateDone")
|
||||
}
|
||||
|
||||
enum EvidenceState
|
||||
@goModel(
|
||||
model: "github.com/getprobo/probo/pkg/probo/coredata.EvidenceState"
|
||||
) {
|
||||
VALID
|
||||
@goEnum(
|
||||
value: "github.com/getprobo/probo/pkg/probo/coredata.EvidenceStateValid"
|
||||
)
|
||||
INVALID
|
||||
@goEnum(
|
||||
value: "github.com/getprobo/probo/pkg/probo/coredata.EvidenceStateInvalid"
|
||||
)
|
||||
EXPIRED
|
||||
@goEnum(
|
||||
value: "github.com/getprobo/probo/pkg/probo/coredata.EvidenceStateExpired"
|
||||
)
|
||||
}
|
||||
|
||||
enum PeopleKind
|
||||
@goModel(model: "github.com/getprobo/probo/pkg/probo/coredata.PeopleKind") {
|
||||
EMPLOYEE
|
||||
@goEnum(
|
||||
value: "github.com/getprobo/probo/pkg/probo/coredata.PeopleKindEmployee"
|
||||
)
|
||||
CONTRACTOR
|
||||
@goEnum(
|
||||
value: "github.com/getprobo/probo/pkg/probo/coredata.PeopleKindContractor"
|
||||
)
|
||||
}
|
||||
|
||||
type PageInfo {
|
||||
hasNextPage: Boolean!
|
||||
hasPreviousPage: Boolean!
|
||||
startCursor: CursorKey
|
||||
endCursor: CursorKey
|
||||
}
|
||||
|
||||
type OrganizationConnection {
|
||||
edges: [OrganizationEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type OrganizationEdge {
|
||||
cursor: CursorKey!
|
||||
node: Organization!
|
||||
}
|
||||
|
||||
type Organization implements Node {
|
||||
id: ID!
|
||||
name: String!
|
||||
logoUrl: String!
|
||||
|
||||
frameworks(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
): FrameworkConnection! @goField(forceResolver: true)
|
||||
|
||||
vendors(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
): VendorConnection! @goField(forceResolver: true)
|
||||
|
||||
peoples(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
): PeopleConnection! @goField(forceResolver: true)
|
||||
|
||||
policies(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
): PolicyConnection! @goField(forceResolver: true)
|
||||
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
}
|
||||
|
||||
type PeopleConnection {
|
||||
edges: [PeopleEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type PeopleEdge {
|
||||
cursor: CursorKey!
|
||||
node: People!
|
||||
}
|
||||
|
||||
type People implements Node {
|
||||
id: ID!
|
||||
fullName: String!
|
||||
primaryEmailAddress: String!
|
||||
additionalEmailAddresses: [String!]!
|
||||
kind: PeopleKind!
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
version: Int!
|
||||
}
|
||||
|
||||
type VendorConnection {
|
||||
edges: [VendorEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type VendorEdge {
|
||||
cursor: CursorKey!
|
||||
node: Vendor!
|
||||
}
|
||||
|
||||
type Vendor implements Node {
|
||||
id: ID!
|
||||
name: String!
|
||||
description: String!
|
||||
serviceStartAt: Datetime!
|
||||
serviceTerminationAt: Datetime
|
||||
serviceCriticality: ServiceCriticality!
|
||||
riskTier: RiskTier!
|
||||
statusPageUrl: String
|
||||
termsOfServiceUrl: String
|
||||
privacyPolicyUrl: String
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
version: Int!
|
||||
}
|
||||
|
||||
type FrameworkConnection {
|
||||
edges: [FrameworkEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type FrameworkEdge {
|
||||
cursor: CursorKey!
|
||||
node: Framework!
|
||||
}
|
||||
|
||||
type Framework implements Node {
|
||||
id: ID!
|
||||
version: Int!
|
||||
|
||||
name: String!
|
||||
description: String!
|
||||
|
||||
controls(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
): ControlConnection! @goField(forceResolver: true)
|
||||
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
}
|
||||
|
||||
type ControlConnection {
|
||||
edges: [ControlEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type ControlEdge {
|
||||
cursor: CursorKey!
|
||||
node: Control!
|
||||
}
|
||||
|
||||
type Control implements Node {
|
||||
id: ID!
|
||||
version: Int!
|
||||
category: String!
|
||||
name: String!
|
||||
description: String!
|
||||
state: ControlState!
|
||||
|
||||
stateTransisions(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
): ControlStateTransitionConnection! @goField(forceResolver: true)
|
||||
|
||||
tasks(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
): TaskConnection! @goField(forceResolver: true)
|
||||
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
}
|
||||
|
||||
type ControlStateTransitionConnection {
|
||||
edges: [ControlStateTransitionEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type ControlStateTransitionEdge {
|
||||
cursor: CursorKey!
|
||||
node: ControlStateTransition!
|
||||
}
|
||||
|
||||
type ControlStateTransition {
|
||||
id: ID!
|
||||
fromState: ControlState
|
||||
toState: ControlState!
|
||||
reason: String
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
}
|
||||
|
||||
type TaskConnection {
|
||||
edges: [TaskEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type TaskEdge {
|
||||
cursor: CursorKey!
|
||||
node: Task!
|
||||
}
|
||||
|
||||
type Task implements Node {
|
||||
id: ID!
|
||||
name: String!
|
||||
description: String!
|
||||
state: TaskState!
|
||||
|
||||
stateTransisions(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
): TaskStateTransitionConnection! @goField(forceResolver: true)
|
||||
|
||||
evidences(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
): EvidenceConnection! @goField(forceResolver: true)
|
||||
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
}
|
||||
|
||||
type TaskStateTransitionConnection {
|
||||
edges: [TaskStateTransitionEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type TaskStateTransitionEdge {
|
||||
cursor: CursorKey!
|
||||
node: TaskStateTransition!
|
||||
}
|
||||
|
||||
type TaskStateTransition {
|
||||
id: ID!
|
||||
fromState: TaskState
|
||||
toState: TaskState!
|
||||
reason: String
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
}
|
||||
|
||||
type EvidenceConnection {
|
||||
edges: [EvidenceEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type EvidenceEdge {
|
||||
cursor: CursorKey!
|
||||
node: Evidence!
|
||||
}
|
||||
|
||||
type Evidence implements Node {
|
||||
id: ID!
|
||||
fileUrl: String! @goField(forceResolver: true)
|
||||
mimeType: String!
|
||||
size: Int!
|
||||
state: EvidenceState!
|
||||
filename: String!
|
||||
|
||||
stateTransisions(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
): EvidenceStateTransitionConnection! @goField(forceResolver: true)
|
||||
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
}
|
||||
|
||||
type EvidenceStateTransitionConnection {
|
||||
edges: [EvidenceStateTransitionEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type EvidenceStateTransitionEdge {
|
||||
cursor: CursorKey!
|
||||
node: EvidenceStateTransition!
|
||||
}
|
||||
|
||||
type EvidenceStateTransition {
|
||||
id: ID!
|
||||
fromState: EvidenceState
|
||||
toState: EvidenceState!
|
||||
reason: String
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
}
|
||||
|
||||
type User implements Node {
|
||||
id: ID!
|
||||
fullName: String!
|
||||
email: String!
|
||||
|
||||
organizations(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
): OrganizationConnection! @goField(forceResolver: true)
|
||||
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
}
|
||||
|
||||
type Session {
|
||||
id: ID!
|
||||
expiresAt: Datetime!
|
||||
}
|
||||
|
||||
type Query {
|
||||
node(id: ID!): Node!
|
||||
viewer: User!
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
createVendor(input: CreateVendorInput!): CreateVendorPayload!
|
||||
updateVendor(input: UpdateVendorInput!): UpdateVendorPayload!
|
||||
deleteVendor(input: DeleteVendorInput!): DeleteVendorPayload!
|
||||
createPeople(input: CreatePeopleInput!): CreatePeoplePayload!
|
||||
updatePeople(input: UpdatePeopleInput!): UpdatePeoplePayload!
|
||||
deletePeople(input: DeletePeopleInput!): DeletePeoplePayload!
|
||||
createOrganization(
|
||||
input: CreateOrganizationInput!
|
||||
): CreateOrganizationPayload!
|
||||
deleteOrganization(
|
||||
input: DeleteOrganizationInput!
|
||||
): DeleteOrganizationPayload!
|
||||
updateTaskState(input: UpdateTaskStateInput!): UpdateTaskStatePayload!
|
||||
createTask(input: CreateTaskInput!): CreateTaskPayload!
|
||||
deleteTask(input: DeleteTaskInput!): DeleteTaskPayload!
|
||||
createFramework(input: CreateFrameworkInput!): CreateFrameworkPayload!
|
||||
createControl(input: CreateControlInput!): CreateControlPayload!
|
||||
updateFramework(input: UpdateFrameworkInput!): UpdateFrameworkPayload!
|
||||
updateControl(input: UpdateControlInput!): UpdateControlPayload!
|
||||
uploadEvidence(input: UploadEvidenceInput!): UploadEvidencePayload!
|
||||
deleteEvidence(input: DeleteEvidenceInput!): DeleteEvidencePayload!
|
||||
createPolicy(input: CreatePolicyInput!): CreatePolicyPayload!
|
||||
updatePolicy(input: UpdatePolicyInput!): UpdatePolicyPayload!
|
||||
deletePolicy(input: DeletePolicyInput!): DeletePolicyPayload!
|
||||
}
|
||||
|
||||
input CreateVendorInput {
|
||||
organizationId: ID!
|
||||
name: String!
|
||||
description: String!
|
||||
serviceStartAt: Datetime!
|
||||
serviceTerminationAt: Datetime
|
||||
serviceCriticality: ServiceCriticality!
|
||||
riskTier: RiskTier!
|
||||
statusPageUrl: String
|
||||
termsOfServiceUrl: String
|
||||
privacyPolicyUrl: String
|
||||
}
|
||||
|
||||
input DeleteVendorInput {
|
||||
vendorId: ID!
|
||||
}
|
||||
|
||||
input DeletePeopleInput {
|
||||
peopleId: ID!
|
||||
}
|
||||
|
||||
input CreatePeopleInput {
|
||||
organizationId: ID!
|
||||
fullName: String!
|
||||
primaryEmailAddress: String!
|
||||
additionalEmailAddresses: [String!]
|
||||
kind: PeopleKind!
|
||||
}
|
||||
|
||||
input UpdatePeopleInput {
|
||||
id: ID!
|
||||
expectedVersion: Int!
|
||||
fullName: String
|
||||
primaryEmailAddress: String
|
||||
additionalEmailAddresses: [String!]
|
||||
kind: PeopleKind
|
||||
}
|
||||
|
||||
enum ServiceCriticality
|
||||
@goModel(
|
||||
model: "github.com/getprobo/probo/pkg/probo/coredata.ServiceCriticality"
|
||||
) {
|
||||
LOW
|
||||
@goEnum(
|
||||
value: "github.com/getprobo/probo/pkg/probo/coredata.ServiceCriticalityLow"
|
||||
)
|
||||
MEDIUM
|
||||
@goEnum(
|
||||
value: "github.com/getprobo/probo/pkg/probo/coredata.ServiceCriticalityMedium"
|
||||
)
|
||||
HIGH
|
||||
@goEnum(
|
||||
value: "github.com/getprobo/probo/pkg/probo/coredata.ServiceCriticalityHigh"
|
||||
)
|
||||
}
|
||||
|
||||
enum RiskTier
|
||||
@goModel(model: "github.com/getprobo/probo/pkg/probo/coredata.RiskTier") {
|
||||
CRITICAL
|
||||
@goEnum(
|
||||
value: "github.com/getprobo/probo/pkg/probo/coredata.RiskTierCritical"
|
||||
)
|
||||
SIGNIFICANT
|
||||
@goEnum(
|
||||
value: "github.com/getprobo/probo/pkg/probo/coredata.RiskTierSignificant"
|
||||
)
|
||||
GENERAL
|
||||
@goEnum(
|
||||
value: "github.com/getprobo/probo/pkg/probo/coredata.RiskTierGeneral"
|
||||
)
|
||||
}
|
||||
|
||||
input UpdateVendorInput {
|
||||
id: ID!
|
||||
expectedVersion: Int!
|
||||
name: String
|
||||
description: String
|
||||
serviceStartAt: Datetime
|
||||
serviceTerminationAt: Datetime
|
||||
serviceCriticality: ServiceCriticality
|
||||
riskTier: RiskTier
|
||||
statusPageUrl: String
|
||||
termsOfServiceUrl: String
|
||||
privacyPolicyUrl: String
|
||||
}
|
||||
|
||||
type CreatePeoplePayload {
|
||||
peopleEdge: PeopleEdge!
|
||||
}
|
||||
|
||||
type CreateVendorPayload {
|
||||
vendorEdge: VendorEdge!
|
||||
}
|
||||
|
||||
type DeleteVendorPayload {
|
||||
deletedVendorId: ID!
|
||||
}
|
||||
|
||||
type DeletePeoplePayload {
|
||||
deletedPeopleId: ID!
|
||||
}
|
||||
|
||||
input CreateOrganizationInput {
|
||||
name: String!
|
||||
}
|
||||
|
||||
input DeleteOrganizationInput {
|
||||
organizationId: ID!
|
||||
}
|
||||
|
||||
type CreateOrganizationPayload {
|
||||
organizationEdge: OrganizationEdge!
|
||||
}
|
||||
|
||||
type DeleteOrganizationPayload {
|
||||
deletedOrganizationId: ID!
|
||||
}
|
||||
|
||||
input UpdateTaskStateInput {
|
||||
taskId: ID!
|
||||
state: TaskState!
|
||||
}
|
||||
|
||||
type UpdateTaskStatePayload {
|
||||
task: Task!
|
||||
}
|
||||
|
||||
input CreateTaskInput {
|
||||
controlId: ID!
|
||||
name: String!
|
||||
description: String!
|
||||
}
|
||||
|
||||
type CreateTaskPayload {
|
||||
taskEdge: TaskEdge!
|
||||
}
|
||||
|
||||
input DeleteTaskInput {
|
||||
taskId: ID!
|
||||
}
|
||||
|
||||
type DeleteTaskPayload {
|
||||
deletedTaskId: ID!
|
||||
}
|
||||
|
||||
input CreateFrameworkInput {
|
||||
organizationId: ID!
|
||||
name: String!
|
||||
description: String!
|
||||
}
|
||||
|
||||
input UpdateFrameworkInput {
|
||||
id: ID!
|
||||
expectedVersion: Int!
|
||||
name: String
|
||||
description: String
|
||||
}
|
||||
|
||||
type CreateFrameworkPayload {
|
||||
frameworkEdge: FrameworkEdge!
|
||||
}
|
||||
|
||||
input CreateControlInput {
|
||||
frameworkId: ID!
|
||||
name: String!
|
||||
description: String!
|
||||
category: String!
|
||||
}
|
||||
|
||||
type CreateControlPayload {
|
||||
controlEdge: ControlEdge!
|
||||
}
|
||||
|
||||
type UpdateFrameworkPayload {
|
||||
framework: Framework!
|
||||
}
|
||||
|
||||
type UpdateVendorPayload {
|
||||
vendor: Vendor!
|
||||
}
|
||||
|
||||
type UpdatePeoplePayload {
|
||||
people: People!
|
||||
}
|
||||
|
||||
input UpdateControlInput {
|
||||
id: ID!
|
||||
expectedVersion: Int!
|
||||
name: String
|
||||
description: String
|
||||
category: String
|
||||
state: ControlState
|
||||
}
|
||||
|
||||
type UpdateControlPayload {
|
||||
control: Control!
|
||||
}
|
||||
|
||||
input UploadEvidenceInput {
|
||||
taskId: ID!
|
||||
name: String!
|
||||
file: Upload!
|
||||
}
|
||||
|
||||
type UploadEvidencePayload {
|
||||
evidenceEdge: EvidenceEdge!
|
||||
}
|
||||
|
||||
input DeleteEvidenceInput {
|
||||
evidenceId: ID!
|
||||
}
|
||||
|
||||
type DeleteEvidencePayload {
|
||||
deletedEvidenceId: ID!
|
||||
}
|
||||
|
||||
enum PolicyStatus
|
||||
@goModel(model: "github.com/getprobo/probo/pkg/probo/coredata.PolicyStatus") {
|
||||
DRAFT
|
||||
@goEnum(
|
||||
value: "github.com/getprobo/probo/pkg/probo/coredata.PolicyStatusDraft"
|
||||
)
|
||||
ACTIVE
|
||||
@goEnum(
|
||||
value: "github.com/getprobo/probo/pkg/probo/coredata.PolicyStatusActive"
|
||||
)
|
||||
}
|
||||
|
||||
input CreatePolicyInput {
|
||||
organizationId: ID!
|
||||
name: String!
|
||||
content: String!
|
||||
status: PolicyStatus!
|
||||
reviewDate: Datetime
|
||||
ownerId: ID!
|
||||
}
|
||||
|
||||
input UpdatePolicyInput {
|
||||
id: ID!
|
||||
expectedVersion: Int!
|
||||
name: String
|
||||
content: String
|
||||
status: PolicyStatus
|
||||
reviewDate: Datetime
|
||||
ownerId: ID
|
||||
}
|
||||
|
||||
input DeletePolicyInput {
|
||||
policyId: ID!
|
||||
}
|
||||
|
||||
type CreatePolicyPayload {
|
||||
policyEdge: PolicyEdge!
|
||||
}
|
||||
|
||||
type UpdatePolicyPayload {
|
||||
policy: Policy!
|
||||
}
|
||||
|
||||
type DeletePolicyPayload {
|
||||
deletedPolicyId: ID!
|
||||
}
|
||||
|
||||
type Policy implements Node {
|
||||
id: ID!
|
||||
version: Int!
|
||||
name: String!
|
||||
status: PolicyStatus!
|
||||
content: String!
|
||||
reviewDate: Datetime
|
||||
owner: People! @goField(forceResolver: true)
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
}
|
||||
|
||||
type PolicyConnection {
|
||||
edges: [PolicyEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type PolicyEdge {
|
||||
cursor: CursorKey!
|
||||
node: Policy!
|
||||
}
|
||||
20868
pkg/server/api/console/v1/schema/schema.go
Normal file
20868
pkg/server/api/console/v1/schema/schema.go
Normal file
File diff suppressed because it is too large
Load Diff
53
pkg/server/api/console/v1/types/control.go
Normal file
53
pkg/server/api/console/v1/types/control.go
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"github.com/getprobo/probo/pkg/page"
|
||||
"github.com/getprobo/probo/pkg/probo/coredata"
|
||||
)
|
||||
|
||||
func NewControlConnection(p *page.Page[*coredata.Control]) *ControlConnection {
|
||||
var edges = make([]*ControlEdge, len(p.Data))
|
||||
|
||||
for i := range edges {
|
||||
edges[i] = NewControlEdge(p.Data[i])
|
||||
}
|
||||
|
||||
return &ControlConnection{
|
||||
Edges: edges,
|
||||
PageInfo: NewPageInfo(p),
|
||||
}
|
||||
}
|
||||
|
||||
func NewControlEdge(c *coredata.Control) *ControlEdge {
|
||||
return &ControlEdge{
|
||||
Cursor: c.CursorKey(),
|
||||
Node: NewControl(c),
|
||||
}
|
||||
}
|
||||
|
||||
func NewControl(c *coredata.Control) *Control {
|
||||
return &Control{
|
||||
ID: c.ID,
|
||||
Version: c.Version,
|
||||
Category: c.Category,
|
||||
Name: c.Name,
|
||||
Description: c.Description,
|
||||
State: c.State,
|
||||
CreatedAt: c.CreatedAt,
|
||||
UpdatedAt: c.UpdatedAt,
|
||||
}
|
||||
}
|
||||
58
pkg/server/api/console/v1/types/control_state_transition.go
Normal file
58
pkg/server/api/console/v1/types/control_state_transition.go
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"github.com/getprobo/probo/pkg/page"
|
||||
"github.com/getprobo/probo/pkg/probo/coredata"
|
||||
)
|
||||
|
||||
func NewControlStateTransitionConnection(
|
||||
p *page.Page[*coredata.ControlStateTransition],
|
||||
) *ControlStateTransitionConnection {
|
||||
var edges = make([]*ControlStateTransitionEdge, len(p.Data))
|
||||
|
||||
for i := range edges {
|
||||
edges[i] = NewControlStateTransitionEdge(p.Data[i])
|
||||
}
|
||||
|
||||
return &ControlStateTransitionConnection{
|
||||
Edges: edges,
|
||||
PageInfo: NewPageInfo(p),
|
||||
}
|
||||
}
|
||||
|
||||
func NewControlStateTransitionEdge(cst *coredata.ControlStateTransition) *ControlStateTransitionEdge {
|
||||
return &ControlStateTransitionEdge{
|
||||
Cursor: cst.CursorKey(),
|
||||
Node: NewControlStateTransition(cst),
|
||||
}
|
||||
}
|
||||
|
||||
func NewControlStateTransition(cst *coredata.ControlStateTransition) *ControlStateTransition {
|
||||
var fromState *coredata.ControlState
|
||||
if cst.FromState != nil {
|
||||
fromState = cst.FromState
|
||||
}
|
||||
|
||||
return &ControlStateTransition{
|
||||
ID: cst.ID,
|
||||
FromState: fromState,
|
||||
ToState: cst.ToState,
|
||||
Reason: cst.Reason,
|
||||
CreatedAt: cst.CreatedAt,
|
||||
UpdatedAt: cst.UpdatedAt,
|
||||
}
|
||||
}
|
||||
69
pkg/server/api/console/v1/types/cursorkey.go
Normal file
69
pkg/server/api/console/v1/types/cursorkey.go
Normal file
@@ -0,0 +1,69 @@
|
||||
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"strconv"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
"github.com/getprobo/probo/pkg/page"
|
||||
)
|
||||
|
||||
func NewCursor(
|
||||
first *int,
|
||||
after *page.CursorKey,
|
||||
last *int,
|
||||
before *page.CursorKey,
|
||||
) *page.Cursor {
|
||||
var (
|
||||
size int
|
||||
from *page.CursorKey
|
||||
direction = page.Head
|
||||
)
|
||||
|
||||
if first != nil {
|
||||
size = *first
|
||||
direction = page.Head
|
||||
from = after
|
||||
} else if last != nil {
|
||||
size = *last
|
||||
direction = page.Tail
|
||||
from = before
|
||||
}
|
||||
|
||||
return page.NewCursor(size, from, direction)
|
||||
}
|
||||
|
||||
func MarshalCursorKeyScalar(ck page.CursorKey) graphql.Marshaler {
|
||||
return graphql.WriterFunc(func(w io.Writer) {
|
||||
_, _ = w.Write([]byte(strconv.Quote(ck.String())))
|
||||
})
|
||||
}
|
||||
|
||||
func UnmarshalCursorKeyScalar(v interface{}) (page.CursorKey, error) {
|
||||
s, ok := v.(string)
|
||||
if !ok {
|
||||
return page.CursorKeyNil, errors.New("must be a string")
|
||||
}
|
||||
|
||||
ck, err := page.ParseCursorKey(s)
|
||||
if err != nil {
|
||||
return page.CursorKeyNil, err
|
||||
}
|
||||
|
||||
return ck, nil
|
||||
}
|
||||
53
pkg/server/api/console/v1/types/evidence.go
Normal file
53
pkg/server/api/console/v1/types/evidence.go
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"github.com/getprobo/probo/pkg/page"
|
||||
"github.com/getprobo/probo/pkg/probo/coredata"
|
||||
)
|
||||
|
||||
func NewEvidenceConnection(p *page.Page[*coredata.Evidence]) *EvidenceConnection {
|
||||
var edges = make([]*EvidenceEdge, len(p.Data))
|
||||
|
||||
for i := range edges {
|
||||
edges[i] = NewEvidenceEdge(p.Data[i])
|
||||
}
|
||||
|
||||
return &EvidenceConnection{
|
||||
Edges: edges,
|
||||
PageInfo: NewPageInfo(p),
|
||||
}
|
||||
}
|
||||
|
||||
func NewEvidenceEdge(e *coredata.Evidence) *EvidenceEdge {
|
||||
return &EvidenceEdge{
|
||||
Cursor: e.CursorKey(),
|
||||
Node: NewEvidence(e),
|
||||
}
|
||||
}
|
||||
|
||||
func NewEvidence(e *coredata.Evidence) *Evidence {
|
||||
return &Evidence{
|
||||
ID: e.ID,
|
||||
State: e.State,
|
||||
FileURL: "",
|
||||
Filename: e.Filename,
|
||||
MimeType: e.MimeType,
|
||||
Size: int(e.Size),
|
||||
CreatedAt: e.CreatedAt,
|
||||
UpdatedAt: e.UpdatedAt,
|
||||
}
|
||||
}
|
||||
58
pkg/server/api/console/v1/types/evidence_state_transition.go
Normal file
58
pkg/server/api/console/v1/types/evidence_state_transition.go
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"github.com/getprobo/probo/pkg/page"
|
||||
"github.com/getprobo/probo/pkg/probo/coredata"
|
||||
)
|
||||
|
||||
func NewEvidenceStateTransitionConnection(
|
||||
p *page.Page[*coredata.EvidenceStateTransition],
|
||||
) *EvidenceStateTransitionConnection {
|
||||
var edges = make([]*EvidenceStateTransitionEdge, len(p.Data))
|
||||
|
||||
for i := range edges {
|
||||
edges[i] = NewEvidenceStateTransitionEdge(p.Data[i])
|
||||
}
|
||||
|
||||
return &EvidenceStateTransitionConnection{
|
||||
Edges: edges,
|
||||
PageInfo: NewPageInfo(p),
|
||||
}
|
||||
}
|
||||
|
||||
func NewEvidenceStateTransitionEdge(est *coredata.EvidenceStateTransition) *EvidenceStateTransitionEdge {
|
||||
return &EvidenceStateTransitionEdge{
|
||||
Cursor: est.CursorKey(),
|
||||
Node: NewEvidenceStateTransition(est),
|
||||
}
|
||||
}
|
||||
|
||||
func NewEvidenceStateTransition(est *coredata.EvidenceStateTransition) *EvidenceStateTransition {
|
||||
var fromState *coredata.EvidenceState
|
||||
if est.FromState != nil {
|
||||
fromState = est.FromState
|
||||
}
|
||||
|
||||
return &EvidenceStateTransition{
|
||||
ID: est.ID,
|
||||
FromState: fromState,
|
||||
ToState: est.ToState,
|
||||
Reason: est.Reason,
|
||||
CreatedAt: est.CreatedAt,
|
||||
UpdatedAt: est.UpdatedAt,
|
||||
}
|
||||
}
|
||||
51
pkg/server/api/console/v1/types/framework.go
Normal file
51
pkg/server/api/console/v1/types/framework.go
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"github.com/getprobo/probo/pkg/page"
|
||||
"github.com/getprobo/probo/pkg/probo/coredata"
|
||||
)
|
||||
|
||||
func NewFrameworkConnection(p *page.Page[*coredata.Framework]) *FrameworkConnection {
|
||||
var edges = make([]*FrameworkEdge, len(p.Data))
|
||||
|
||||
for i := range edges {
|
||||
edges[i] = NewFrameworkEdge(p.Data[i])
|
||||
}
|
||||
|
||||
return &FrameworkConnection{
|
||||
Edges: edges,
|
||||
PageInfo: NewPageInfo(p),
|
||||
}
|
||||
}
|
||||
|
||||
func NewFrameworkEdge(f *coredata.Framework) *FrameworkEdge {
|
||||
return &FrameworkEdge{
|
||||
Cursor: f.CursorKey(),
|
||||
Node: NewFramework(f),
|
||||
}
|
||||
}
|
||||
|
||||
func NewFramework(f *coredata.Framework) *Framework {
|
||||
return &Framework{
|
||||
ID: f.ID,
|
||||
Version: f.Version,
|
||||
Name: f.Name,
|
||||
Description: f.Description,
|
||||
CreatedAt: f.CreatedAt,
|
||||
UpdatedAt: f.UpdatedAt,
|
||||
}
|
||||
}
|
||||
44
pkg/server/api/console/v1/types/gid.go
Normal file
44
pkg/server/api/console/v1/types/gid.go
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"strconv"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
"github.com/getprobo/probo/pkg/gid"
|
||||
)
|
||||
|
||||
func MarshalGIDScalar(id gid.GID) graphql.Marshaler {
|
||||
return graphql.WriterFunc(func(w io.Writer) {
|
||||
w.Write([]byte(strconv.Quote(id.String())))
|
||||
})
|
||||
}
|
||||
|
||||
func UnmarshalGIDScalar(v interface{}) (gid.GID, error) {
|
||||
s, ok := v.(string)
|
||||
if !ok {
|
||||
return gid.Nil, errors.New("must be a string")
|
||||
}
|
||||
|
||||
id, err := gid.ParseGID(s)
|
||||
if err != nil {
|
||||
return gid.Nil, err
|
||||
}
|
||||
|
||||
return id, nil
|
||||
}
|
||||
35
pkg/server/api/console/v1/types/organization.go
Normal file
35
pkg/server/api/console/v1/types/organization.go
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"github.com/getprobo/probo/pkg/probo/coredata"
|
||||
)
|
||||
|
||||
func NewOrganization(o *coredata.Organization) *Organization {
|
||||
return &Organization{
|
||||
ID: o.ID,
|
||||
Name: o.Name,
|
||||
LogoURL: o.LogoURL,
|
||||
CreatedAt: o.CreatedAt,
|
||||
UpdatedAt: o.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
func NewOrganizationEdge(o *coredata.Organization) *OrganizationEdge {
|
||||
return &OrganizationEdge{
|
||||
Node: NewOrganization(o),
|
||||
}
|
||||
}
|
||||
39
pkg/server/api/console/v1/types/pageinfo.go
Normal file
39
pkg/server/api/console/v1/types/pageinfo.go
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"gearno.de/ref"
|
||||
"github.com/getprobo/probo/pkg/page"
|
||||
)
|
||||
|
||||
func NewPageInfo[T page.Paginable](p *page.Page[T]) *PageInfo {
|
||||
var (
|
||||
startCursor *page.CursorKey
|
||||
endCursor *page.CursorKey
|
||||
)
|
||||
|
||||
if len(p.Data) > 0 {
|
||||
startCursor = ref.Ref(p.First().CursorKey())
|
||||
endCursor = ref.Ref(p.Last().CursorKey())
|
||||
}
|
||||
|
||||
return &PageInfo{
|
||||
HasNextPage: p.Info.HasNext,
|
||||
HasPreviousPage: p.Info.HasPrev,
|
||||
StartCursor: startCursor,
|
||||
EndCursor: endCursor,
|
||||
}
|
||||
}
|
||||
53
pkg/server/api/console/v1/types/people.go
Normal file
53
pkg/server/api/console/v1/types/people.go
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"github.com/getprobo/probo/pkg/page"
|
||||
"github.com/getprobo/probo/pkg/probo/coredata"
|
||||
)
|
||||
|
||||
func NewPeopleConnection(p *page.Page[*coredata.People]) *PeopleConnection {
|
||||
var edges = make([]*PeopleEdge, len(p.Data))
|
||||
|
||||
for i := range edges {
|
||||
edges[i] = NewPeopleEdge(p.Data[i])
|
||||
}
|
||||
|
||||
return &PeopleConnection{
|
||||
Edges: edges,
|
||||
PageInfo: NewPageInfo(p),
|
||||
}
|
||||
}
|
||||
|
||||
func NewPeopleEdge(p *coredata.People) *PeopleEdge {
|
||||
return &PeopleEdge{
|
||||
Cursor: p.CursorKey(),
|
||||
Node: NewPeople(p),
|
||||
}
|
||||
}
|
||||
|
||||
func NewPeople(p *coredata.People) *People {
|
||||
return &People{
|
||||
ID: p.ID,
|
||||
FullName: p.FullName,
|
||||
PrimaryEmailAddress: p.PrimaryEmailAddress,
|
||||
AdditionalEmailAddresses: p.AdditionalEmailAddresses,
|
||||
Kind: p.Kind,
|
||||
CreatedAt: p.CreatedAt,
|
||||
UpdatedAt: p.UpdatedAt,
|
||||
Version: p.Version,
|
||||
}
|
||||
}
|
||||
52
pkg/server/api/console/v1/types/policy.go
Normal file
52
pkg/server/api/console/v1/types/policy.go
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"github.com/getprobo/probo/pkg/page"
|
||||
"github.com/getprobo/probo/pkg/probo/coredata"
|
||||
)
|
||||
|
||||
func NewPolicy(policy *coredata.Policy) *Policy {
|
||||
return &Policy{
|
||||
ID: policy.ID,
|
||||
Version: policy.Version,
|
||||
Name: policy.Name,
|
||||
Content: policy.Content,
|
||||
CreatedAt: policy.CreatedAt,
|
||||
UpdatedAt: policy.UpdatedAt,
|
||||
Status: policy.Status,
|
||||
ReviewDate: policy.ReviewDate,
|
||||
}
|
||||
}
|
||||
|
||||
func NewPolicyEdge(policy *coredata.Policy) *PolicyEdge {
|
||||
return &PolicyEdge{
|
||||
Cursor: policy.CursorKey(),
|
||||
Node: NewPolicy(policy),
|
||||
}
|
||||
}
|
||||
|
||||
func NewPolicyConnection(page *page.Page[*coredata.Policy]) *PolicyConnection {
|
||||
edges := make([]*PolicyEdge, len(page.Data))
|
||||
for i, policy := range page.Data {
|
||||
edges[i] = NewPolicyEdge(policy)
|
||||
}
|
||||
|
||||
return &PolicyConnection{
|
||||
Edges: edges,
|
||||
PageInfo: NewPageInfo(page),
|
||||
}
|
||||
}
|
||||
51
pkg/server/api/console/v1/types/task.go
Normal file
51
pkg/server/api/console/v1/types/task.go
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"github.com/getprobo/probo/pkg/page"
|
||||
"github.com/getprobo/probo/pkg/probo/coredata"
|
||||
)
|
||||
|
||||
func NewTaskConnection(p *page.Page[*coredata.Task]) *TaskConnection {
|
||||
var edges = make([]*TaskEdge, len(p.Data))
|
||||
|
||||
for i := range edges {
|
||||
edges[i] = NewTaskEdge(p.Data[i])
|
||||
}
|
||||
|
||||
return &TaskConnection{
|
||||
Edges: edges,
|
||||
PageInfo: NewPageInfo(p),
|
||||
}
|
||||
}
|
||||
|
||||
func NewTaskEdge(t *coredata.Task) *TaskEdge {
|
||||
return &TaskEdge{
|
||||
Cursor: t.CursorKey(),
|
||||
Node: NewTask(t),
|
||||
}
|
||||
}
|
||||
|
||||
func NewTask(t *coredata.Task) *Task {
|
||||
return &Task{
|
||||
ID: t.ID,
|
||||
Name: t.Name,
|
||||
Description: t.Description,
|
||||
State: t.State,
|
||||
CreatedAt: t.CreatedAt,
|
||||
UpdatedAt: t.UpdatedAt,
|
||||
}
|
||||
}
|
||||
58
pkg/server/api/console/v1/types/task_state_transition.go
Normal file
58
pkg/server/api/console/v1/types/task_state_transition.go
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"github.com/getprobo/probo/pkg/page"
|
||||
"github.com/getprobo/probo/pkg/probo/coredata"
|
||||
)
|
||||
|
||||
func NewTaskStateTransitionConnection(
|
||||
p *page.Page[*coredata.TaskStateTransition],
|
||||
) *TaskStateTransitionConnection {
|
||||
var edges = make([]*TaskStateTransitionEdge, len(p.Data))
|
||||
|
||||
for i := range edges {
|
||||
edges[i] = NewTaskStateTransitionEdge(p.Data[i])
|
||||
}
|
||||
|
||||
return &TaskStateTransitionConnection{
|
||||
Edges: edges,
|
||||
PageInfo: NewPageInfo(p),
|
||||
}
|
||||
}
|
||||
|
||||
func NewTaskStateTransitionEdge(tst *coredata.TaskStateTransition) *TaskStateTransitionEdge {
|
||||
return &TaskStateTransitionEdge{
|
||||
Cursor: tst.CursorKey(),
|
||||
Node: NewTaskStateTransition(tst),
|
||||
}
|
||||
}
|
||||
|
||||
func NewTaskStateTransition(tst *coredata.TaskStateTransition) *TaskStateTransition {
|
||||
var fromState *coredata.TaskState
|
||||
if tst.FromState != nil {
|
||||
fromState = tst.FromState
|
||||
}
|
||||
|
||||
return &TaskStateTransition{
|
||||
ID: tst.ID,
|
||||
FromState: fromState,
|
||||
ToState: tst.ToState,
|
||||
Reason: tst.Reason,
|
||||
CreatedAt: tst.CreatedAt,
|
||||
UpdatedAt: tst.UpdatedAt,
|
||||
}
|
||||
}
|
||||
522
pkg/server/api/console/v1/types/types.go
Normal file
522
pkg/server/api/console/v1/types/types.go
Normal file
@@ -0,0 +1,522 @@
|
||||
// Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
"github.com/getprobo/probo/pkg/gid"
|
||||
"github.com/getprobo/probo/pkg/page"
|
||||
"github.com/getprobo/probo/pkg/probo/coredata"
|
||||
)
|
||||
|
||||
type Node interface {
|
||||
IsNode()
|
||||
GetID() gid.GID
|
||||
}
|
||||
|
||||
type Control struct {
|
||||
ID gid.GID `json:"id"`
|
||||
Version int `json:"version"`
|
||||
Category string `json:"category"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
State coredata.ControlState `json:"state"`
|
||||
StateTransisions *ControlStateTransitionConnection `json:"stateTransisions"`
|
||||
Tasks *TaskConnection `json:"tasks"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
func (Control) IsNode() {}
|
||||
func (this Control) GetID() gid.GID { return this.ID }
|
||||
|
||||
type ControlConnection struct {
|
||||
Edges []*ControlEdge `json:"edges"`
|
||||
PageInfo *PageInfo `json:"pageInfo"`
|
||||
}
|
||||
|
||||
type ControlEdge struct {
|
||||
Cursor page.CursorKey `json:"cursor"`
|
||||
Node *Control `json:"node"`
|
||||
}
|
||||
|
||||
type ControlStateTransition struct {
|
||||
ID gid.GID `json:"id"`
|
||||
FromState *coredata.ControlState `json:"fromState,omitempty"`
|
||||
ToState coredata.ControlState `json:"toState"`
|
||||
Reason *string `json:"reason,omitempty"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
type ControlStateTransitionConnection struct {
|
||||
Edges []*ControlStateTransitionEdge `json:"edges"`
|
||||
PageInfo *PageInfo `json:"pageInfo"`
|
||||
}
|
||||
|
||||
type ControlStateTransitionEdge struct {
|
||||
Cursor page.CursorKey `json:"cursor"`
|
||||
Node *ControlStateTransition `json:"node"`
|
||||
}
|
||||
|
||||
type CreateControlInput struct {
|
||||
FrameworkID gid.GID `json:"frameworkId"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Category string `json:"category"`
|
||||
}
|
||||
|
||||
type CreateControlPayload struct {
|
||||
ControlEdge *ControlEdge `json:"controlEdge"`
|
||||
}
|
||||
|
||||
type CreateFrameworkInput struct {
|
||||
OrganizationID gid.GID `json:"organizationId"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type CreateFrameworkPayload struct {
|
||||
FrameworkEdge *FrameworkEdge `json:"frameworkEdge"`
|
||||
}
|
||||
|
||||
type CreateOrganizationInput struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type CreateOrganizationPayload struct {
|
||||
OrganizationEdge *OrganizationEdge `json:"organizationEdge"`
|
||||
}
|
||||
|
||||
type CreatePeopleInput struct {
|
||||
OrganizationID gid.GID `json:"organizationId"`
|
||||
FullName string `json:"fullName"`
|
||||
PrimaryEmailAddress string `json:"primaryEmailAddress"`
|
||||
AdditionalEmailAddresses []string `json:"additionalEmailAddresses,omitempty"`
|
||||
Kind coredata.PeopleKind `json:"kind"`
|
||||
}
|
||||
|
||||
type CreatePeoplePayload struct {
|
||||
PeopleEdge *PeopleEdge `json:"peopleEdge"`
|
||||
}
|
||||
|
||||
type CreatePolicyInput struct {
|
||||
OrganizationID gid.GID `json:"organizationId"`
|
||||
Name string `json:"name"`
|
||||
Content string `json:"content"`
|
||||
Status coredata.PolicyStatus `json:"status"`
|
||||
ReviewDate *time.Time `json:"reviewDate,omitempty"`
|
||||
OwnerID gid.GID `json:"ownerId"`
|
||||
}
|
||||
|
||||
type CreatePolicyPayload struct {
|
||||
PolicyEdge *PolicyEdge `json:"policyEdge"`
|
||||
}
|
||||
|
||||
type CreateTaskInput struct {
|
||||
ControlID gid.GID `json:"controlId"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type CreateTaskPayload struct {
|
||||
TaskEdge *TaskEdge `json:"taskEdge"`
|
||||
}
|
||||
|
||||
type CreateVendorInput struct {
|
||||
OrganizationID gid.GID `json:"organizationId"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
ServiceStartAt time.Time `json:"serviceStartAt"`
|
||||
ServiceTerminationAt *time.Time `json:"serviceTerminationAt,omitempty"`
|
||||
ServiceCriticality coredata.ServiceCriticality `json:"serviceCriticality"`
|
||||
RiskTier coredata.RiskTier `json:"riskTier"`
|
||||
StatusPageURL *string `json:"statusPageUrl,omitempty"`
|
||||
TermsOfServiceURL *string `json:"termsOfServiceUrl,omitempty"`
|
||||
PrivacyPolicyURL *string `json:"privacyPolicyUrl,omitempty"`
|
||||
}
|
||||
|
||||
type CreateVendorPayload struct {
|
||||
VendorEdge *VendorEdge `json:"vendorEdge"`
|
||||
}
|
||||
|
||||
type DeleteEvidenceInput struct {
|
||||
EvidenceID gid.GID `json:"evidenceId"`
|
||||
}
|
||||
|
||||
type DeleteEvidencePayload struct {
|
||||
DeletedEvidenceID gid.GID `json:"deletedEvidenceId"`
|
||||
}
|
||||
|
||||
type DeleteOrganizationInput struct {
|
||||
OrganizationID gid.GID `json:"organizationId"`
|
||||
}
|
||||
|
||||
type DeleteOrganizationPayload struct {
|
||||
DeletedOrganizationID gid.GID `json:"deletedOrganizationId"`
|
||||
}
|
||||
|
||||
type DeletePeopleInput struct {
|
||||
PeopleID gid.GID `json:"peopleId"`
|
||||
}
|
||||
|
||||
type DeletePeoplePayload struct {
|
||||
DeletedPeopleID gid.GID `json:"deletedPeopleId"`
|
||||
}
|
||||
|
||||
type DeletePolicyInput struct {
|
||||
PolicyID gid.GID `json:"policyId"`
|
||||
}
|
||||
|
||||
type DeletePolicyPayload struct {
|
||||
DeletedPolicyID gid.GID `json:"deletedPolicyId"`
|
||||
}
|
||||
|
||||
type DeleteTaskInput struct {
|
||||
TaskID gid.GID `json:"taskId"`
|
||||
}
|
||||
|
||||
type DeleteTaskPayload struct {
|
||||
DeletedTaskID gid.GID `json:"deletedTaskId"`
|
||||
}
|
||||
|
||||
type DeleteVendorInput struct {
|
||||
VendorID gid.GID `json:"vendorId"`
|
||||
}
|
||||
|
||||
type DeleteVendorPayload struct {
|
||||
DeletedVendorID gid.GID `json:"deletedVendorId"`
|
||||
}
|
||||
|
||||
type Evidence struct {
|
||||
ID gid.GID `json:"id"`
|
||||
FileURL string `json:"fileUrl"`
|
||||
MimeType string `json:"mimeType"`
|
||||
Size int `json:"size"`
|
||||
State coredata.EvidenceState `json:"state"`
|
||||
Filename string `json:"filename"`
|
||||
StateTransisions *EvidenceStateTransitionConnection `json:"stateTransisions"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
func (Evidence) IsNode() {}
|
||||
func (this Evidence) GetID() gid.GID { return this.ID }
|
||||
|
||||
type EvidenceConnection struct {
|
||||
Edges []*EvidenceEdge `json:"edges"`
|
||||
PageInfo *PageInfo `json:"pageInfo"`
|
||||
}
|
||||
|
||||
type EvidenceEdge struct {
|
||||
Cursor page.CursorKey `json:"cursor"`
|
||||
Node *Evidence `json:"node"`
|
||||
}
|
||||
|
||||
type EvidenceStateTransition struct {
|
||||
ID gid.GID `json:"id"`
|
||||
FromState *coredata.EvidenceState `json:"fromState,omitempty"`
|
||||
ToState coredata.EvidenceState `json:"toState"`
|
||||
Reason *string `json:"reason,omitempty"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
type EvidenceStateTransitionConnection struct {
|
||||
Edges []*EvidenceStateTransitionEdge `json:"edges"`
|
||||
PageInfo *PageInfo `json:"pageInfo"`
|
||||
}
|
||||
|
||||
type EvidenceStateTransitionEdge struct {
|
||||
Cursor page.CursorKey `json:"cursor"`
|
||||
Node *EvidenceStateTransition `json:"node"`
|
||||
}
|
||||
|
||||
type Framework struct {
|
||||
ID gid.GID `json:"id"`
|
||||
Version int `json:"version"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Controls *ControlConnection `json:"controls"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
func (Framework) IsNode() {}
|
||||
func (this Framework) GetID() gid.GID { return this.ID }
|
||||
|
||||
type FrameworkConnection struct {
|
||||
Edges []*FrameworkEdge `json:"edges"`
|
||||
PageInfo *PageInfo `json:"pageInfo"`
|
||||
}
|
||||
|
||||
type FrameworkEdge struct {
|
||||
Cursor page.CursorKey `json:"cursor"`
|
||||
Node *Framework `json:"node"`
|
||||
}
|
||||
|
||||
type Mutation struct {
|
||||
}
|
||||
|
||||
type Organization struct {
|
||||
ID gid.GID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
LogoURL string `json:"logoUrl"`
|
||||
Frameworks *FrameworkConnection `json:"frameworks"`
|
||||
Vendors *VendorConnection `json:"vendors"`
|
||||
Peoples *PeopleConnection `json:"peoples"`
|
||||
Policies *PolicyConnection `json:"policies"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
func (Organization) IsNode() {}
|
||||
func (this Organization) GetID() gid.GID { return this.ID }
|
||||
|
||||
type OrganizationConnection struct {
|
||||
Edges []*OrganizationEdge `json:"edges"`
|
||||
PageInfo *PageInfo `json:"pageInfo"`
|
||||
}
|
||||
|
||||
type OrganizationEdge struct {
|
||||
Cursor page.CursorKey `json:"cursor"`
|
||||
Node *Organization `json:"node"`
|
||||
}
|
||||
|
||||
type PageInfo struct {
|
||||
HasNextPage bool `json:"hasNextPage"`
|
||||
HasPreviousPage bool `json:"hasPreviousPage"`
|
||||
StartCursor *page.CursorKey `json:"startCursor,omitempty"`
|
||||
EndCursor *page.CursorKey `json:"endCursor,omitempty"`
|
||||
}
|
||||
|
||||
type People struct {
|
||||
ID gid.GID `json:"id"`
|
||||
FullName string `json:"fullName"`
|
||||
PrimaryEmailAddress string `json:"primaryEmailAddress"`
|
||||
AdditionalEmailAddresses []string `json:"additionalEmailAddresses"`
|
||||
Kind coredata.PeopleKind `json:"kind"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
Version int `json:"version"`
|
||||
}
|
||||
|
||||
func (People) IsNode() {}
|
||||
func (this People) GetID() gid.GID { return this.ID }
|
||||
|
||||
type PeopleConnection struct {
|
||||
Edges []*PeopleEdge `json:"edges"`
|
||||
PageInfo *PageInfo `json:"pageInfo"`
|
||||
}
|
||||
|
||||
type PeopleEdge struct {
|
||||
Cursor page.CursorKey `json:"cursor"`
|
||||
Node *People `json:"node"`
|
||||
}
|
||||
|
||||
type Policy struct {
|
||||
ID gid.GID `json:"id"`
|
||||
Version int `json:"version"`
|
||||
Name string `json:"name"`
|
||||
Status coredata.PolicyStatus `json:"status"`
|
||||
Content string `json:"content"`
|
||||
ReviewDate *time.Time `json:"reviewDate,omitempty"`
|
||||
Owner *People `json:"owner"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
func (Policy) IsNode() {}
|
||||
func (this Policy) GetID() gid.GID { return this.ID }
|
||||
|
||||
type PolicyConnection struct {
|
||||
Edges []*PolicyEdge `json:"edges"`
|
||||
PageInfo *PageInfo `json:"pageInfo"`
|
||||
}
|
||||
|
||||
type PolicyEdge struct {
|
||||
Cursor page.CursorKey `json:"cursor"`
|
||||
Node *Policy `json:"node"`
|
||||
}
|
||||
|
||||
type Query struct {
|
||||
}
|
||||
|
||||
type Session struct {
|
||||
ID gid.GID `json:"id"`
|
||||
ExpiresAt time.Time `json:"expiresAt"`
|
||||
}
|
||||
|
||||
type Task struct {
|
||||
ID gid.GID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
State coredata.TaskState `json:"state"`
|
||||
StateTransisions *TaskStateTransitionConnection `json:"stateTransisions"`
|
||||
Evidences *EvidenceConnection `json:"evidences"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
func (Task) IsNode() {}
|
||||
func (this Task) GetID() gid.GID { return this.ID }
|
||||
|
||||
type TaskConnection struct {
|
||||
Edges []*TaskEdge `json:"edges"`
|
||||
PageInfo *PageInfo `json:"pageInfo"`
|
||||
}
|
||||
|
||||
type TaskEdge struct {
|
||||
Cursor page.CursorKey `json:"cursor"`
|
||||
Node *Task `json:"node"`
|
||||
}
|
||||
|
||||
type TaskStateTransition struct {
|
||||
ID gid.GID `json:"id"`
|
||||
FromState *coredata.TaskState `json:"fromState,omitempty"`
|
||||
ToState coredata.TaskState `json:"toState"`
|
||||
Reason *string `json:"reason,omitempty"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
type TaskStateTransitionConnection struct {
|
||||
Edges []*TaskStateTransitionEdge `json:"edges"`
|
||||
PageInfo *PageInfo `json:"pageInfo"`
|
||||
}
|
||||
|
||||
type TaskStateTransitionEdge struct {
|
||||
Cursor page.CursorKey `json:"cursor"`
|
||||
Node *TaskStateTransition `json:"node"`
|
||||
}
|
||||
|
||||
type UpdateControlInput struct {
|
||||
ID gid.GID `json:"id"`
|
||||
ExpectedVersion int `json:"expectedVersion"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
Category *string `json:"category,omitempty"`
|
||||
State *coredata.ControlState `json:"state,omitempty"`
|
||||
}
|
||||
|
||||
type UpdateControlPayload struct {
|
||||
Control *Control `json:"control"`
|
||||
}
|
||||
|
||||
type UpdateFrameworkInput struct {
|
||||
ID gid.GID `json:"id"`
|
||||
ExpectedVersion int `json:"expectedVersion"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
type UpdateFrameworkPayload struct {
|
||||
Framework *Framework `json:"framework"`
|
||||
}
|
||||
|
||||
type UpdatePeopleInput struct {
|
||||
ID gid.GID `json:"id"`
|
||||
ExpectedVersion int `json:"expectedVersion"`
|
||||
FullName *string `json:"fullName,omitempty"`
|
||||
PrimaryEmailAddress *string `json:"primaryEmailAddress,omitempty"`
|
||||
AdditionalEmailAddresses []string `json:"additionalEmailAddresses,omitempty"`
|
||||
Kind *coredata.PeopleKind `json:"kind,omitempty"`
|
||||
}
|
||||
|
||||
type UpdatePeoplePayload struct {
|
||||
People *People `json:"people"`
|
||||
}
|
||||
|
||||
type UpdatePolicyInput struct {
|
||||
ID gid.GID `json:"id"`
|
||||
ExpectedVersion int `json:"expectedVersion"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
Content *string `json:"content,omitempty"`
|
||||
Status *coredata.PolicyStatus `json:"status,omitempty"`
|
||||
ReviewDate *time.Time `json:"reviewDate,omitempty"`
|
||||
OwnerID *gid.GID `json:"ownerId,omitempty"`
|
||||
}
|
||||
|
||||
type UpdatePolicyPayload struct {
|
||||
Policy *Policy `json:"policy"`
|
||||
}
|
||||
|
||||
type UpdateTaskStateInput struct {
|
||||
TaskID gid.GID `json:"taskId"`
|
||||
State coredata.TaskState `json:"state"`
|
||||
}
|
||||
|
||||
type UpdateTaskStatePayload struct {
|
||||
Task *Task `json:"task"`
|
||||
}
|
||||
|
||||
type UpdateVendorInput struct {
|
||||
ID gid.GID `json:"id"`
|
||||
ExpectedVersion int `json:"expectedVersion"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
ServiceStartAt *time.Time `json:"serviceStartAt,omitempty"`
|
||||
ServiceTerminationAt *time.Time `json:"serviceTerminationAt,omitempty"`
|
||||
ServiceCriticality *coredata.ServiceCriticality `json:"serviceCriticality,omitempty"`
|
||||
RiskTier *coredata.RiskTier `json:"riskTier,omitempty"`
|
||||
StatusPageURL *string `json:"statusPageUrl,omitempty"`
|
||||
TermsOfServiceURL *string `json:"termsOfServiceUrl,omitempty"`
|
||||
PrivacyPolicyURL *string `json:"privacyPolicyUrl,omitempty"`
|
||||
}
|
||||
|
||||
type UpdateVendorPayload struct {
|
||||
Vendor *Vendor `json:"vendor"`
|
||||
}
|
||||
|
||||
type UploadEvidenceInput struct {
|
||||
TaskID gid.GID `json:"taskId"`
|
||||
Name string `json:"name"`
|
||||
File graphql.Upload `json:"file"`
|
||||
}
|
||||
|
||||
type UploadEvidencePayload struct {
|
||||
EvidenceEdge *EvidenceEdge `json:"evidenceEdge"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
ID gid.GID `json:"id"`
|
||||
FullName string `json:"fullName"`
|
||||
Email string `json:"email"`
|
||||
Organizations *OrganizationConnection `json:"organizations"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
func (User) IsNode() {}
|
||||
func (this User) GetID() gid.GID { return this.ID }
|
||||
|
||||
type Vendor struct {
|
||||
ID gid.GID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
ServiceStartAt time.Time `json:"serviceStartAt"`
|
||||
ServiceTerminationAt *time.Time `json:"serviceTerminationAt,omitempty"`
|
||||
ServiceCriticality coredata.ServiceCriticality `json:"serviceCriticality"`
|
||||
RiskTier coredata.RiskTier `json:"riskTier"`
|
||||
StatusPageURL *string `json:"statusPageUrl,omitempty"`
|
||||
TermsOfServiceURL *string `json:"termsOfServiceUrl,omitempty"`
|
||||
PrivacyPolicyURL *string `json:"privacyPolicyUrl,omitempty"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
Version int `json:"version"`
|
||||
}
|
||||
|
||||
func (Vendor) IsNode() {}
|
||||
func (this Vendor) GetID() gid.GID { return this.ID }
|
||||
|
||||
type VendorConnection struct {
|
||||
Edges []*VendorEdge `json:"edges"`
|
||||
PageInfo *PageInfo `json:"pageInfo"`
|
||||
}
|
||||
|
||||
type VendorEdge struct {
|
||||
Cursor page.CursorKey `json:"cursor"`
|
||||
Node *Vendor `json:"node"`
|
||||
}
|
||||
29
pkg/server/api/console/v1/types/user.go
Normal file
29
pkg/server/api/console/v1/types/user.go
Normal file
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"github.com/getprobo/probo/pkg/usrmgr/coredata"
|
||||
)
|
||||
|
||||
func NewUser(u *coredata.User) *User {
|
||||
return &User{
|
||||
ID: u.ID,
|
||||
Email: u.EmailAddress,
|
||||
FullName: u.FullName,
|
||||
CreatedAt: u.CreatedAt,
|
||||
UpdatedAt: u.UpdatedAt,
|
||||
}
|
||||
}
|
||||
58
pkg/server/api/console/v1/types/vendor.go
Normal file
58
pkg/server/api/console/v1/types/vendor.go
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"github.com/getprobo/probo/pkg/page"
|
||||
"github.com/getprobo/probo/pkg/probo/coredata"
|
||||
)
|
||||
|
||||
func NewVendorConnection(p *page.Page[*coredata.Vendor]) *VendorConnection {
|
||||
var edges = make([]*VendorEdge, len(p.Data))
|
||||
|
||||
for i := range edges {
|
||||
edges[i] = NewVendorEdge(p.Data[i])
|
||||
}
|
||||
|
||||
return &VendorConnection{
|
||||
Edges: edges,
|
||||
PageInfo: NewPageInfo(p),
|
||||
}
|
||||
}
|
||||
|
||||
func NewVendorEdge(v *coredata.Vendor) *VendorEdge {
|
||||
return &VendorEdge{
|
||||
Cursor: v.CursorKey(),
|
||||
Node: NewVendor(v),
|
||||
}
|
||||
}
|
||||
|
||||
func NewVendor(v *coredata.Vendor) *Vendor {
|
||||
return &Vendor{
|
||||
ID: v.ID,
|
||||
Name: v.Name,
|
||||
Description: v.Description,
|
||||
CreatedAt: v.CreatedAt,
|
||||
UpdatedAt: v.UpdatedAt,
|
||||
ServiceStartAt: v.ServiceStartAt,
|
||||
ServiceTerminationAt: v.ServiceTerminationAt,
|
||||
ServiceCriticality: v.ServiceCriticality,
|
||||
RiskTier: v.RiskTier,
|
||||
StatusPageURL: v.StatusPageURL,
|
||||
TermsOfServiceURL: v.TermsOfServiceURL,
|
||||
PrivacyPolicyURL: v.PrivacyPolicyURL,
|
||||
Version: v.Version,
|
||||
}
|
||||
}
|
||||
654
pkg/server/api/console/v1/v1_resolver.go
Normal file
654
pkg/server/api/console/v1/v1_resolver.go
Normal file
@@ -0,0 +1,654 @@
|
||||
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.63
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/getprobo/probo/pkg/gid"
|
||||
"github.com/getprobo/probo/pkg/page"
|
||||
"github.com/getprobo/probo/pkg/probo"
|
||||
"github.com/getprobo/probo/pkg/probo/coredata"
|
||||
"github.com/getprobo/probo/pkg/server/api/console/v1/schema"
|
||||
"github.com/getprobo/probo/pkg/server/api/console/v1/types"
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
)
|
||||
|
||||
// StateTransisions is the resolver for the stateTransisions field.
|
||||
func (r *controlResolver) StateTransisions(ctx context.Context, obj *types.Control, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.ControlStateTransitionConnection, error) {
|
||||
cursor := types.NewCursor(first, after, last, before)
|
||||
|
||||
page, err := r.proboSvc.ListControlStateTransitions(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot list control tasks: %w", err)
|
||||
}
|
||||
|
||||
return types.NewControlStateTransitionConnection(page), nil
|
||||
}
|
||||
|
||||
// Tasks is the resolver for the tasks field.
|
||||
func (r *controlResolver) Tasks(ctx context.Context, obj *types.Control, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.TaskConnection, error) {
|
||||
cursor := types.NewCursor(first, after, last, before)
|
||||
|
||||
page, err := r.proboSvc.ListControlTasks(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot list control tasks: %w", err)
|
||||
}
|
||||
|
||||
return types.NewTaskConnection(page), nil
|
||||
}
|
||||
|
||||
// FileURL is the resolver for the fileUrl field.
|
||||
func (r *evidenceResolver) FileURL(ctx context.Context, obj *types.Evidence) (string, error) {
|
||||
fileURL, err := r.proboSvc.GetEvidenceFileURL(ctx, obj.ID, 15*time.Minute)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("cannot generate file URL: %w", err)
|
||||
}
|
||||
|
||||
return *fileURL, nil
|
||||
}
|
||||
|
||||
// StateTransisions is the resolver for the stateTransisions field.
|
||||
func (r *evidenceResolver) StateTransisions(ctx context.Context, obj *types.Evidence, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.EvidenceStateTransitionConnection, error) {
|
||||
cursor := types.NewCursor(first, after, last, before)
|
||||
|
||||
page, err := r.proboSvc.ListEvidenceStateTransitions(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot list evidence state transitions: %w", err)
|
||||
}
|
||||
|
||||
return types.NewEvidenceStateTransitionConnection(page), nil
|
||||
}
|
||||
|
||||
// Controls is the resolver for the controls field.
|
||||
func (r *frameworkResolver) Controls(ctx context.Context, obj *types.Framework, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.ControlConnection, error) {
|
||||
cursor := types.NewCursor(first, after, last, before)
|
||||
|
||||
page, err := r.proboSvc.ListFrameworkControls(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot list framework controls: %w", err)
|
||||
}
|
||||
|
||||
return types.NewControlConnection(page), nil
|
||||
}
|
||||
|
||||
// CreateVendor is the resolver for the createVendor field.
|
||||
func (r *mutationResolver) CreateVendor(ctx context.Context, input types.CreateVendorInput) (*types.CreateVendorPayload, error) {
|
||||
vendor, err := r.proboSvc.CreateVendor(ctx, probo.CreateVendorRequest{
|
||||
OrganizationID: input.OrganizationID,
|
||||
Name: input.Name,
|
||||
Description: input.Description,
|
||||
ServiceStartAt: input.ServiceStartAt,
|
||||
ServiceTerminationAt: input.ServiceTerminationAt,
|
||||
ServiceCriticality: input.ServiceCriticality,
|
||||
RiskTier: input.RiskTier,
|
||||
StatusPageURL: input.StatusPageURL,
|
||||
TermsOfServiceURL: input.TermsOfServiceURL,
|
||||
PrivacyPolicyURL: input.PrivacyPolicyURL,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot create vendor: %w", err)
|
||||
}
|
||||
return &types.CreateVendorPayload{
|
||||
VendorEdge: types.NewVendorEdge(vendor),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateVendor is the resolver for the updateVendor field.
|
||||
func (r *mutationResolver) UpdateVendor(ctx context.Context, input types.UpdateVendorInput) (*types.UpdateVendorPayload, error) {
|
||||
vendor, err := r.proboSvc.UpdateVendor(ctx, probo.UpdateVendorRequest{
|
||||
ID: input.ID,
|
||||
ExpectedVersion: input.ExpectedVersion,
|
||||
Name: input.Name,
|
||||
Description: input.Description,
|
||||
ServiceStartAt: input.ServiceStartAt,
|
||||
ServiceTerminationAt: input.ServiceTerminationAt,
|
||||
ServiceCriticality: input.ServiceCriticality,
|
||||
RiskTier: input.RiskTier,
|
||||
StatusPageURL: input.StatusPageURL,
|
||||
TermsOfServiceURL: input.TermsOfServiceURL,
|
||||
PrivacyPolicyURL: input.PrivacyPolicyURL,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot update vendor: %w", err)
|
||||
}
|
||||
|
||||
return &types.UpdateVendorPayload{
|
||||
Vendor: types.NewVendor(vendor),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteVendor is the resolver for the deleteVendor field.
|
||||
func (r *mutationResolver) DeleteVendor(ctx context.Context, input types.DeleteVendorInput) (*types.DeleteVendorPayload, error) {
|
||||
err := r.proboSvc.DeleteVendor(ctx, input.VendorID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot delete vendor: %w", err)
|
||||
}
|
||||
|
||||
return &types.DeleteVendorPayload{
|
||||
DeletedVendorID: input.VendorID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreatePeople is the resolver for the createPeople field.
|
||||
func (r *mutationResolver) CreatePeople(ctx context.Context, input types.CreatePeopleInput) (*types.CreatePeoplePayload, error) {
|
||||
people, err := r.proboSvc.CreatePeople(ctx, probo.CreatePeopleRequest{
|
||||
OrganizationID: input.OrganizationID,
|
||||
FullName: input.FullName,
|
||||
PrimaryEmailAddress: input.PrimaryEmailAddress,
|
||||
AdditionalEmailAddresses: []string{},
|
||||
Kind: input.Kind,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot create people: %w", err)
|
||||
}
|
||||
|
||||
return &types.CreatePeoplePayload{
|
||||
PeopleEdge: types.NewPeopleEdge(people),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdatePeople is the resolver for the updatePeople field.
|
||||
func (r *mutationResolver) UpdatePeople(ctx context.Context, input types.UpdatePeopleInput) (*types.UpdatePeoplePayload, error) {
|
||||
people, err := r.proboSvc.UpdatePeople(ctx, probo.UpdatePeopleRequest{
|
||||
ID: input.ID,
|
||||
ExpectedVersion: input.ExpectedVersion,
|
||||
FullName: input.FullName,
|
||||
PrimaryEmailAddress: input.PrimaryEmailAddress,
|
||||
AdditionalEmailAddresses: &input.AdditionalEmailAddresses,
|
||||
Kind: input.Kind,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot update people: %w", err)
|
||||
}
|
||||
|
||||
return &types.UpdatePeoplePayload{
|
||||
People: types.NewPeople(people),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeletePeople is the resolver for the deletePeople field.
|
||||
func (r *mutationResolver) DeletePeople(ctx context.Context, input types.DeletePeopleInput) (*types.DeletePeoplePayload, error) {
|
||||
err := r.proboSvc.DeletePeople(ctx, input.PeopleID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot delete people: %w", err)
|
||||
}
|
||||
|
||||
return &types.DeletePeoplePayload{
|
||||
DeletedPeopleID: input.PeopleID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreateOrganization is the resolver for the createOrganization field.
|
||||
func (r *mutationResolver) CreateOrganization(ctx context.Context, input types.CreateOrganizationInput) (*types.CreateOrganizationPayload, error) {
|
||||
organization, err := r.proboSvc.CreateOrganization(ctx, probo.CreateOrganizationRequest{
|
||||
Name: input.Name,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot create organization: %w", err)
|
||||
}
|
||||
|
||||
err = r.usrmgrSvc.AddUserToOrganization(ctx, UserFromContext(ctx).ID, organization.ID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot add user to organization: %w", err)
|
||||
}
|
||||
|
||||
return &types.CreateOrganizationPayload{
|
||||
OrganizationEdge: types.NewOrganizationEdge(organization),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteOrganization is the resolver for the deleteOrganization field.
|
||||
func (r *mutationResolver) DeleteOrganization(ctx context.Context, input types.DeleteOrganizationInput) (*types.DeleteOrganizationPayload, error) {
|
||||
panic(fmt.Errorf("not implemented: DeleteOrganization - deleteOrganization"))
|
||||
}
|
||||
|
||||
// UpdateTaskState is the resolver for the updateTaskState field.
|
||||
func (r *mutationResolver) UpdateTaskState(ctx context.Context, input types.UpdateTaskStateInput) (*types.UpdateTaskStatePayload, error) {
|
||||
task, err := r.proboSvc.UpdateTaskState(ctx, probo.UpdateTaskStateRequest{
|
||||
TaskID: input.TaskID,
|
||||
State: input.State,
|
||||
Reason: nil,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot update task state: %w", err)
|
||||
}
|
||||
|
||||
return &types.UpdateTaskStatePayload{
|
||||
Task: types.NewTask(task),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreateTask is the resolver for the createTask field.
|
||||
func (r *mutationResolver) CreateTask(ctx context.Context, input types.CreateTaskInput) (*types.CreateTaskPayload, error) {
|
||||
task, err := r.proboSvc.CreateTask(ctx, probo.CreateTaskRequest{
|
||||
ControlID: input.ControlID,
|
||||
Name: input.Name,
|
||||
Description: input.Description,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot create task: %w", err)
|
||||
}
|
||||
|
||||
return &types.CreateTaskPayload{
|
||||
TaskEdge: types.NewTaskEdge(task),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteTask is the resolver for the deleteTask field.
|
||||
func (r *mutationResolver) DeleteTask(ctx context.Context, input types.DeleteTaskInput) (*types.DeleteTaskPayload, error) {
|
||||
err := r.proboSvc.DeleteTask(ctx, input.TaskID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot delete task: %w", err)
|
||||
}
|
||||
|
||||
return &types.DeleteTaskPayload{
|
||||
DeletedTaskID: input.TaskID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreateFramework is the resolver for the createFramework field.
|
||||
func (r *mutationResolver) CreateFramework(ctx context.Context, input types.CreateFrameworkInput) (*types.CreateFrameworkPayload, error) {
|
||||
framework, err := r.proboSvc.CreateFramework(ctx, probo.CreateFrameworkRequest{
|
||||
OrganizationID: input.OrganizationID,
|
||||
Name: input.Name,
|
||||
Description: input.Description,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot create framework: %w", err)
|
||||
}
|
||||
|
||||
return &types.CreateFrameworkPayload{
|
||||
FrameworkEdge: types.NewFrameworkEdge(framework),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreateControl is the resolver for the createControl field.
|
||||
func (r *mutationResolver) CreateControl(ctx context.Context, input types.CreateControlInput) (*types.CreateControlPayload, error) {
|
||||
control, err := r.proboSvc.CreateControl(ctx, probo.CreateControlRequest{
|
||||
FrameworkID: input.FrameworkID,
|
||||
Name: input.Name,
|
||||
Description: input.Description,
|
||||
Category: input.Category,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot create control: %w", err)
|
||||
}
|
||||
|
||||
return &types.CreateControlPayload{
|
||||
ControlEdge: types.NewControlEdge(control),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateFramework is the resolver for the updateFramework field.
|
||||
func (r *mutationResolver) UpdateFramework(ctx context.Context, input types.UpdateFrameworkInput) (*types.UpdateFrameworkPayload, error) {
|
||||
var name, description *string
|
||||
if input.Name != nil {
|
||||
name = input.Name
|
||||
}
|
||||
if input.Description != nil {
|
||||
description = input.Description
|
||||
}
|
||||
|
||||
framework, err := r.proboSvc.UpdateFramework(ctx, probo.UpdateFrameworkRequest{
|
||||
ID: input.ID,
|
||||
ExpectedVersion: input.ExpectedVersion,
|
||||
Name: name,
|
||||
Description: description,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot update framework: %w", err)
|
||||
}
|
||||
|
||||
return &types.UpdateFrameworkPayload{
|
||||
Framework: types.NewFramework(framework),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateControl is the resolver for the updateControl field.
|
||||
func (r *mutationResolver) UpdateControl(ctx context.Context, input types.UpdateControlInput) (*types.UpdateControlPayload, error) {
|
||||
var name, description, category *string
|
||||
var state *coredata.ControlState
|
||||
|
||||
if input.Name != nil {
|
||||
name = input.Name
|
||||
}
|
||||
if input.Description != nil {
|
||||
description = input.Description
|
||||
}
|
||||
if input.Category != nil {
|
||||
category = input.Category
|
||||
}
|
||||
if input.State != nil {
|
||||
state = input.State
|
||||
}
|
||||
|
||||
control, err := r.proboSvc.UpdateControl(ctx, probo.UpdateControlRequest{
|
||||
ID: input.ID,
|
||||
ExpectedVersion: input.ExpectedVersion,
|
||||
Name: name,
|
||||
Description: description,
|
||||
Category: category,
|
||||
State: state,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot update control: %w", err)
|
||||
}
|
||||
|
||||
return &types.UpdateControlPayload{
|
||||
Control: types.NewControl(control),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UploadEvidence is the resolver for the uploadEvidence field.
|
||||
func (r *mutationResolver) UploadEvidence(ctx context.Context, input types.UploadEvidenceInput) (*types.UploadEvidencePayload, error) {
|
||||
req := probo.CreateEvidenceRequest{
|
||||
TaskID: input.TaskID,
|
||||
Name: input.Name,
|
||||
File: input.File.File,
|
||||
}
|
||||
|
||||
evidence, err := r.proboSvc.CreateEvidence(ctx, req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create evidence: %w", err)
|
||||
}
|
||||
|
||||
return &types.UploadEvidencePayload{
|
||||
EvidenceEdge: types.NewEvidenceEdge(evidence),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteEvidence is the resolver for the deleteEvidence field.
|
||||
func (r *mutationResolver) DeleteEvidence(ctx context.Context, input types.DeleteEvidenceInput) (*types.DeleteEvidencePayload, error) {
|
||||
err := r.proboSvc.DeleteEvidence(ctx, input.EvidenceID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to delete evidence: %w", err)
|
||||
}
|
||||
|
||||
return &types.DeleteEvidencePayload{
|
||||
DeletedEvidenceID: input.EvidenceID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreatePolicy is the resolver for the createPolicy field.
|
||||
func (r *mutationResolver) CreatePolicy(ctx context.Context, input types.CreatePolicyInput) (*types.CreatePolicyPayload, error) {
|
||||
policy, err := r.proboSvc.Policies.Create(ctx, probo.CreatePolicyRequest{
|
||||
OrganizationID: input.OrganizationID,
|
||||
Name: input.Name,
|
||||
Content: input.Content,
|
||||
Status: input.Status,
|
||||
ReviewDate: input.ReviewDate,
|
||||
OwnerID: input.OwnerID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot create policy: %w", err)
|
||||
}
|
||||
|
||||
return &types.CreatePolicyPayload{
|
||||
PolicyEdge: types.NewPolicyEdge(policy),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdatePolicy is the resolver for the updatePolicy field.
|
||||
func (r *mutationResolver) UpdatePolicy(ctx context.Context, input types.UpdatePolicyInput) (*types.UpdatePolicyPayload, error) {
|
||||
policy, err := r.proboSvc.Policies.Update(ctx, probo.UpdatePolicyRequest{
|
||||
ID: input.ID,
|
||||
ExpectedVersion: input.ExpectedVersion,
|
||||
Name: input.Name,
|
||||
Content: input.Content,
|
||||
Status: input.Status,
|
||||
ReviewDate: input.ReviewDate,
|
||||
OwnerID: input.OwnerID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot update policy: %w", err)
|
||||
}
|
||||
|
||||
return &types.UpdatePolicyPayload{
|
||||
Policy: types.NewPolicy(policy),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeletePolicy is the resolver for the deletePolicy field.
|
||||
func (r *mutationResolver) DeletePolicy(ctx context.Context, input types.DeletePolicyInput) (*types.DeletePolicyPayload, error) {
|
||||
err := r.proboSvc.Policies.Delete(ctx, input.PolicyID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot delete policy: %w", err)
|
||||
}
|
||||
|
||||
return &types.DeletePolicyPayload{
|
||||
DeletedPolicyID: input.PolicyID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Frameworks is the resolver for the frameworks field.
|
||||
func (r *organizationResolver) Frameworks(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.FrameworkConnection, error) {
|
||||
cursor := types.NewCursor(first, after, last, before)
|
||||
|
||||
page, err := r.proboSvc.ListOrganizationFrameworks(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot list organization frameworks: %w", err)
|
||||
}
|
||||
|
||||
return types.NewFrameworkConnection(page), nil
|
||||
}
|
||||
|
||||
// Vendors is the resolver for the vendors field.
|
||||
func (r *organizationResolver) Vendors(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.VendorConnection, error) {
|
||||
cursor := types.NewCursor(first, after, last, before)
|
||||
|
||||
page, err := r.proboSvc.ListOrganizationVendors(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot list organization vendors: %w", err)
|
||||
}
|
||||
|
||||
return types.NewVendorConnection(page), nil
|
||||
}
|
||||
|
||||
// Peoples is the resolver for the peoples field.
|
||||
func (r *organizationResolver) Peoples(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.PeopleConnection, error) {
|
||||
cursor := types.NewCursor(first, after, last, before)
|
||||
|
||||
page, err := r.proboSvc.ListOrganizationPeoples(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot list organization peoples: %w", err)
|
||||
}
|
||||
|
||||
return types.NewPeopleConnection(page), nil
|
||||
}
|
||||
|
||||
// Policies is the resolver for the policies field.
|
||||
func (r *organizationResolver) Policies(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.PolicyConnection, error) {
|
||||
cursor := types.NewCursor(first, after, last, before)
|
||||
|
||||
page, err := r.proboSvc.Policies.ListByOrganization(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot list organization policies: %w", err)
|
||||
}
|
||||
|
||||
return types.NewPolicyConnection(page), nil
|
||||
}
|
||||
|
||||
// Owner is the resolver for the owner field.
|
||||
func (r *policyResolver) Owner(ctx context.Context, obj *types.Policy) (*types.People, error) {
|
||||
policy, err := r.proboSvc.Policies.Get(ctx, obj.ID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot get policy: %w", err)
|
||||
}
|
||||
|
||||
// Get the owner
|
||||
owner, err := r.proboSvc.GetPeople(ctx, policy.OwnerID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot get owner: %w", err)
|
||||
}
|
||||
|
||||
return types.NewPeople(owner), nil
|
||||
}
|
||||
|
||||
// Node is the resolver for the node field.
|
||||
func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
switch id.EntityType() {
|
||||
case coredata.OrganizationEntityType:
|
||||
organization, err := r.proboSvc.GetOrganization(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return types.NewOrganization(organization), nil
|
||||
case coredata.PeopleEntityType:
|
||||
people, err := r.proboSvc.GetPeople(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return types.NewPeople(people), nil
|
||||
case coredata.VendorEntityType:
|
||||
vendor, err := r.proboSvc.GetVendor(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return types.NewVendor(vendor), nil
|
||||
case coredata.FrameworkEntityType:
|
||||
framework, err := r.proboSvc.GetFramework(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return types.NewFramework(framework), nil
|
||||
case coredata.ControlEntityType:
|
||||
control, err := r.proboSvc.GetControl(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return types.NewControl(control), nil
|
||||
case coredata.TaskEntityType:
|
||||
task, err := r.proboSvc.GetTask(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return types.NewTask(task), nil
|
||||
case coredata.EvidenceEntityType:
|
||||
evidence, err := r.proboSvc.GetEvidence(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return types.NewEvidence(evidence), nil
|
||||
case coredata.PolicyEntityType:
|
||||
policy, err := r.proboSvc.Policies.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewPolicy(policy), nil
|
||||
default:
|
||||
}
|
||||
|
||||
return nil, gqlerror.Errorf("node %q not found", id)
|
||||
}
|
||||
|
||||
// Viewer is the resolver for the viewer field.
|
||||
func (r *queryResolver) Viewer(ctx context.Context) (*types.User, error) {
|
||||
user := UserFromContext(ctx)
|
||||
return types.NewUser(user), nil
|
||||
}
|
||||
|
||||
// StateTransisions is the resolver for the stateTransisions field.
|
||||
func (r *taskResolver) StateTransisions(ctx context.Context, obj *types.Task, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.TaskStateTransitionConnection, error) {
|
||||
cursor := types.NewCursor(first, after, last, before)
|
||||
|
||||
page, err := r.proboSvc.ListTaskStateTransitions(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot list control tasks: %w", err)
|
||||
}
|
||||
|
||||
return types.NewTaskStateTransitionConnection(page), nil
|
||||
}
|
||||
|
||||
// Evidences is the resolver for the evidences field.
|
||||
func (r *taskResolver) Evidences(ctx context.Context, obj *types.Task, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.EvidenceConnection, error) {
|
||||
cursor := types.NewCursor(first, after, last, before)
|
||||
|
||||
page, err := r.proboSvc.ListTaskEvidences(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot list organization frameworks: %w", err)
|
||||
}
|
||||
|
||||
return types.NewEvidenceConnection(page), nil
|
||||
}
|
||||
|
||||
// Organizations is the resolver for the organizations field.
|
||||
func (r *userResolver) Organizations(ctx context.Context, obj *types.User, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.OrganizationConnection, error) {
|
||||
// Get the user's organization IDs
|
||||
organizationIDs, err := r.usrmgrSvc.GetUserOrganizations(ctx, obj.ID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get user organizations: %w", err)
|
||||
}
|
||||
|
||||
// If the user doesn't have any organizations, return an empty connection
|
||||
if len(organizationIDs) == 0 {
|
||||
return &types.OrganizationConnection{
|
||||
Edges: []*types.OrganizationEdge{},
|
||||
PageInfo: &types.PageInfo{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Get the organization details for each organization ID
|
||||
var edges []*types.OrganizationEdge
|
||||
for _, organizationID := range organizationIDs {
|
||||
organization, err := r.proboSvc.GetOrganization(ctx, organizationID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get organization details: %w", err)
|
||||
}
|
||||
edges = append(edges, types.NewOrganizationEdge(organization))
|
||||
}
|
||||
|
||||
return &types.OrganizationConnection{
|
||||
Edges: edges,
|
||||
PageInfo: &types.PageInfo{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Control returns schema.ControlResolver implementation.
|
||||
func (r *Resolver) Control() schema.ControlResolver { return &controlResolver{r} }
|
||||
|
||||
// Evidence returns schema.EvidenceResolver implementation.
|
||||
func (r *Resolver) Evidence() schema.EvidenceResolver { return &evidenceResolver{r} }
|
||||
|
||||
// Framework returns schema.FrameworkResolver implementation.
|
||||
func (r *Resolver) Framework() schema.FrameworkResolver { return &frameworkResolver{r} }
|
||||
|
||||
// Mutation returns schema.MutationResolver implementation.
|
||||
func (r *Resolver) Mutation() schema.MutationResolver { return &mutationResolver{r} }
|
||||
|
||||
// Organization returns schema.OrganizationResolver implementation.
|
||||
func (r *Resolver) Organization() schema.OrganizationResolver { return &organizationResolver{r} }
|
||||
|
||||
// Policy returns schema.PolicyResolver implementation.
|
||||
func (r *Resolver) Policy() schema.PolicyResolver { return &policyResolver{r} }
|
||||
|
||||
// Query returns schema.QueryResolver implementation.
|
||||
func (r *Resolver) Query() schema.QueryResolver { return &queryResolver{r} }
|
||||
|
||||
// Task returns schema.TaskResolver implementation.
|
||||
func (r *Resolver) Task() schema.TaskResolver { return &taskResolver{r} }
|
||||
|
||||
// User returns schema.UserResolver implementation.
|
||||
func (r *Resolver) User() schema.UserResolver { return &userResolver{r} }
|
||||
|
||||
type controlResolver struct{ *Resolver }
|
||||
type evidenceResolver struct{ *Resolver }
|
||||
type frameworkResolver struct{ *Resolver }
|
||||
type mutationResolver struct{ *Resolver }
|
||||
type organizationResolver struct{ *Resolver }
|
||||
type policyResolver struct{ *Resolver }
|
||||
type queryResolver struct{ *Resolver }
|
||||
type taskResolver struct{ *Resolver }
|
||||
type userResolver struct{ *Resolver }
|
||||
Reference in New Issue
Block a user