Add finding console GraphQL API
Replace nonconformity and continual improvement GraphQL types with a unified Finding type supporting kind, status, priority, and audit associations. Update schema, resolver, and type mappings. Add mutations for createFinding, updateFinding, deleteFinding, linkFindingToAudit, and unlinkFindingFromAudit. Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
@@ -163,19 +163,63 @@ enum TrustCenterDocumentAccessStatus
|
||||
)
|
||||
}
|
||||
|
||||
enum NonconformityStatus
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.NonconformityStatus") {
|
||||
enum FindingKind
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.FindingKind") {
|
||||
NONCONFORMITY
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingKindNonconformity"
|
||||
)
|
||||
OBSERVATION
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingKindObservation"
|
||||
)
|
||||
EXCEPTION
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingKindException"
|
||||
)
|
||||
}
|
||||
|
||||
enum FindingStatus
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.FindingStatus") {
|
||||
OPEN
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.NonconformityStatusOpen"
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingStatusOpen"
|
||||
)
|
||||
IN_PROGRESS
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.NonconformityStatusInProgress"
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingStatusInProgress"
|
||||
)
|
||||
CLOSED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.NonconformityStatusClosed"
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingStatusClosed"
|
||||
)
|
||||
RISK_ACCEPTED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingStatusRiskAccepted"
|
||||
)
|
||||
MITIGATED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingStatusMitigated"
|
||||
)
|
||||
FALSE_POSITIVE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingStatusFalsePositive"
|
||||
)
|
||||
}
|
||||
|
||||
enum FindingPriority
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.FindingPriority") {
|
||||
LOW
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingPriorityLow"
|
||||
)
|
||||
MEDIUM
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingPriorityMedium"
|
||||
)
|
||||
HIGH
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingPriorityHigh"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -204,42 +248,6 @@ enum ObligationType
|
||||
)
|
||||
}
|
||||
|
||||
enum ContinualImprovementStatus
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.ContinualImprovementStatus"
|
||||
) {
|
||||
OPEN
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ContinualImprovementStatusOpen"
|
||||
)
|
||||
IN_PROGRESS
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ContinualImprovementStatusInProgress"
|
||||
)
|
||||
CLOSED
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ContinualImprovementStatusClosed"
|
||||
)
|
||||
}
|
||||
|
||||
enum ContinualImprovementPriority
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.ContinualImprovementPriority"
|
||||
) {
|
||||
LOW
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ContinualImprovementPriorityLow"
|
||||
)
|
||||
MEDIUM
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ContinualImprovementPriorityMedium"
|
||||
)
|
||||
HIGH
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ContinualImprovementPriorityHigh"
|
||||
)
|
||||
}
|
||||
|
||||
enum RightsRequestType
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.RightsRequestType") {
|
||||
ACCESS
|
||||
@@ -1050,27 +1058,35 @@ enum AuditOrderField
|
||||
STATE @goEnum(value: "go.probo.inc/probo/pkg/coredata.AuditOrderFieldState")
|
||||
}
|
||||
|
||||
enum NonconformityOrderField
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.NonconformityOrderField") {
|
||||
enum FindingOrderField
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.FindingOrderField") {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.NonconformityOrderFieldCreatedAt"
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingOrderFieldCreatedAt"
|
||||
)
|
||||
REFERENCE_ID
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.NonconformityOrderFieldReferenceId"
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingOrderFieldReferenceId"
|
||||
)
|
||||
DATE_IDENTIFIED
|
||||
IDENTIFIED_ON
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.NonconformityOrderFieldDateIdentified"
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingOrderFieldIdentifiedOn"
|
||||
)
|
||||
DUE_DATE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.NonconformityOrderFieldDueDate"
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingOrderFieldDueDate"
|
||||
)
|
||||
STATUS
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.NonconformityOrderFieldStatus"
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingOrderFieldStatus"
|
||||
)
|
||||
PRIORITY
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingOrderFieldPriority"
|
||||
)
|
||||
KIND
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.FindingOrderFieldKind"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1094,32 +1110,6 @@ enum ObligationOrderField
|
||||
)
|
||||
}
|
||||
|
||||
enum ContinualImprovementOrderField
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/coredata.ContinualImprovementOrderField"
|
||||
) {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ContinualImprovementOrderFieldCreatedAt"
|
||||
)
|
||||
REFERENCE_ID
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ContinualImprovementOrderFieldReferenceId"
|
||||
)
|
||||
TARGET_DATE
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ContinualImprovementOrderFieldTargetDate"
|
||||
)
|
||||
STATUS
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ContinualImprovementOrderFieldStatus"
|
||||
)
|
||||
PRIORITY
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.ContinualImprovementOrderFieldPriority"
|
||||
)
|
||||
}
|
||||
|
||||
enum RightsRequestOrderField
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.RightsRequestOrderField") {
|
||||
CREATED_AT
|
||||
@@ -1297,18 +1287,14 @@ enum SnapshotsType
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.SnapshotsTypeVendors")
|
||||
ASSETS @goEnum(value: "go.probo.inc/probo/pkg/coredata.SnapshotsTypeAssets")
|
||||
DATA @goEnum(value: "go.probo.inc/probo/pkg/coredata.SnapshotsTypeData")
|
||||
NONCONFORMITIES
|
||||
FINDINGS
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.SnapshotsTypeNonconformities"
|
||||
value: "go.probo.inc/probo/pkg/coredata.SnapshotsTypeFindings"
|
||||
)
|
||||
OBLIGATIONS
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.SnapshotsTypeObligations"
|
||||
)
|
||||
CONTINUAL_IMPROVEMENTS
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.SnapshotsTypeContinualImprovements"
|
||||
)
|
||||
PROCESSING_ACTIVITIES
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.SnapshotsTypeProcessingActivities"
|
||||
@@ -1420,12 +1406,9 @@ input AuditOrder
|
||||
field: AuditOrderField!
|
||||
}
|
||||
|
||||
input NonconformityOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.NonconformityOrderBy"
|
||||
) {
|
||||
input FindingOrder {
|
||||
field: FindingOrderField!
|
||||
direction: OrderDirection!
|
||||
field: NonconformityOrderField!
|
||||
}
|
||||
|
||||
input ObligationOrder
|
||||
@@ -1436,13 +1419,6 @@ input ObligationOrder
|
||||
field: ObligationOrderField!
|
||||
}
|
||||
|
||||
input ContinualImprovementOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.ContinualImprovementOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: ContinualImprovementOrderField!
|
||||
}
|
||||
|
||||
input RightsRequestOrder
|
||||
@goModel(
|
||||
@@ -1615,17 +1591,18 @@ input StateOfApplicabilityFilter {
|
||||
snapshotId: ID
|
||||
}
|
||||
|
||||
input NonconformityFilter {
|
||||
input FindingFilter {
|
||||
snapshotId: ID
|
||||
kind: FindingKind
|
||||
status: FindingStatus
|
||||
priority: FindingPriority
|
||||
ownerId: ID
|
||||
}
|
||||
|
||||
input ObligationFilter {
|
||||
snapshotId: ID
|
||||
}
|
||||
|
||||
input ContinualImprovementFilter {
|
||||
snapshotId: ID
|
||||
}
|
||||
|
||||
input ProcessingActivityFilter {
|
||||
snapshotId: ID
|
||||
@@ -1932,14 +1909,14 @@ type Organization implements Node {
|
||||
orderBy: AuditOrder
|
||||
): AuditConnection! @goField(forceResolver: true)
|
||||
|
||||
nonconformities(
|
||||
findings(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: NonconformityOrder
|
||||
filter: NonconformityFilter = { snapshotId: null }
|
||||
): NonconformityConnection! @goField(forceResolver: true)
|
||||
orderBy: FindingOrder
|
||||
filter: FindingFilter = { snapshotId: null }
|
||||
): FindingConnection @goField(forceResolver: true)
|
||||
|
||||
obligations(
|
||||
first: Int
|
||||
@@ -1950,15 +1927,6 @@ type Organization implements Node {
|
||||
filter: ObligationFilter = { snapshotId: null }
|
||||
): ObligationConnection! @goField(forceResolver: true)
|
||||
|
||||
continualImprovements(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: ContinualImprovementOrder
|
||||
filter: ContinualImprovementFilter = { snapshotId: null }
|
||||
): ContinualImprovementConnection! @goField(forceResolver: true)
|
||||
|
||||
rightsRequests(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
@@ -2683,8 +2651,8 @@ type Risk implements Node {
|
||||
type Audit implements Node {
|
||||
id: ID!
|
||||
name: String
|
||||
organization: Organization! @goField(forceResolver: true)
|
||||
framework: Framework! @goField(forceResolver: true)
|
||||
organization: Organization @goField(forceResolver: true)
|
||||
framework: Framework @goField(forceResolver: true)
|
||||
validFrom: Datetime
|
||||
validUntil: Datetime
|
||||
report: Report @goField(forceResolver: true)
|
||||
@@ -2698,7 +2666,16 @@ type Audit implements Node {
|
||||
before: CursorKey
|
||||
orderBy: ControlOrder
|
||||
filter: ControlFilter
|
||||
): ControlConnection! @goField(forceResolver: true)
|
||||
): ControlConnection @goField(forceResolver: true)
|
||||
|
||||
findings(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: FindingOrder
|
||||
filter: FindingFilter = { snapshotId: null }
|
||||
): FindingConnection @goField(forceResolver: true)
|
||||
|
||||
trustCenterVisibility: TrustCenterVisibility!
|
||||
createdAt: Datetime!
|
||||
@@ -2707,23 +2684,32 @@ type Audit implements Node {
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type Nonconformity implements Node {
|
||||
type Finding implements Node {
|
||||
id: ID!
|
||||
snapshotId: ID
|
||||
organization: Organization! @goField(forceResolver: true)
|
||||
organization: Organization @goField(forceResolver: true)
|
||||
kind: FindingKind!
|
||||
referenceId: String!
|
||||
description: String
|
||||
audit: Audit @goField(forceResolver: true)
|
||||
dateIdentified: Datetime
|
||||
rootCause: String!
|
||||
source: String
|
||||
audits(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: AuditOrder
|
||||
): AuditConnection @goField(forceResolver: true)
|
||||
identifiedOn: Datetime
|
||||
rootCause: String
|
||||
correctiveAction: String
|
||||
owner: Profile! @goField(forceResolver: true)
|
||||
owner: Profile @goField(forceResolver: true)
|
||||
dueDate: Datetime
|
||||
status: NonconformityStatus!
|
||||
status: FindingStatus!
|
||||
priority: FindingPriority!
|
||||
risk: Risk @goField(forceResolver: true)
|
||||
effectivenessCheck: String
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
@@ -2748,23 +2734,6 @@ type Obligation implements Node {
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type ContinualImprovement implements Node {
|
||||
id: ID!
|
||||
snapshotId: ID
|
||||
sourceId: ID
|
||||
organization: Organization! @goField(forceResolver: true)
|
||||
referenceId: String!
|
||||
description: String
|
||||
source: String
|
||||
owner: Profile! @goField(forceResolver: true)
|
||||
targetDate: Datetime
|
||||
status: ContinualImprovementStatus!
|
||||
priority: ContinualImprovementPriority!
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
permission(action: String!): Boolean! @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
type RightsRequest implements Node {
|
||||
id: ID!
|
||||
@@ -3327,18 +3296,21 @@ type AuditEdge {
|
||||
node: Audit!
|
||||
}
|
||||
|
||||
type NonconformityConnection
|
||||
type FindingConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.NonconformityConnection"
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.FindingConnection"
|
||||
) {
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
edges: [NonconformityEdge!]!
|
||||
edges: [FindingEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type NonconformityEdge {
|
||||
type FindingEdge
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.FindingEdge"
|
||||
) {
|
||||
cursor: CursorKey!
|
||||
node: Nonconformity!
|
||||
node: Finding!
|
||||
}
|
||||
type ObligationConnection
|
||||
@goModel(
|
||||
@@ -3354,19 +3326,6 @@ type ObligationEdge {
|
||||
node: Obligation!
|
||||
}
|
||||
|
||||
type ContinualImprovementConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.ContinualImprovementConnection"
|
||||
) {
|
||||
totalCount: Int! @goField(forceResolver: true)
|
||||
edges: [ContinualImprovementEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type ContinualImprovementEdge {
|
||||
cursor: CursorKey!
|
||||
node: ContinualImprovement!
|
||||
}
|
||||
|
||||
type RightsRequestConnection
|
||||
@goModel(
|
||||
@@ -3605,10 +3564,10 @@ type Mutation {
|
||||
): DeleteApplicabilityStatementPayload!
|
||||
createControlAuditMapping(
|
||||
input: CreateControlAuditMappingInput!
|
||||
): CreateControlAuditMappingPayload!
|
||||
): CreateControlAuditMappingPayload
|
||||
deleteControlAuditMapping(
|
||||
input: DeleteControlAuditMappingInput!
|
||||
): DeleteControlAuditMappingPayload!
|
||||
): DeleteControlAuditMappingPayload
|
||||
createControlObligationMapping(
|
||||
input: CreateControlObligationMappingInput!
|
||||
): CreateControlObligationMappingPayload!
|
||||
@@ -3771,36 +3730,25 @@ type Mutation {
|
||||
createDatum(input: CreateDatumInput!): CreateDatumPayload!
|
||||
updateDatum(input: UpdateDatumInput!): UpdateDatumPayload!
|
||||
deleteDatum(input: DeleteDatumInput!): DeleteDatumPayload!
|
||||
createAudit(input: CreateAuditInput!): CreateAuditPayload!
|
||||
updateAudit(input: UpdateAuditInput!): UpdateAuditPayload!
|
||||
deleteAudit(input: DeleteAuditInput!): DeleteAuditPayload!
|
||||
uploadAuditReport(input: UploadAuditReportInput!): UploadAuditReportPayload!
|
||||
deleteAuditReport(input: DeleteAuditReportInput!): DeleteAuditReportPayload!
|
||||
# Nonconformity mutations
|
||||
createNonconformity(
|
||||
input: CreateNonconformityInput!
|
||||
): CreateNonconformityPayload!
|
||||
updateNonconformity(
|
||||
input: UpdateNonconformityInput!
|
||||
): UpdateNonconformityPayload!
|
||||
deleteNonconformity(
|
||||
input: DeleteNonconformityInput!
|
||||
): DeleteNonconformityPayload!
|
||||
createAudit(input: CreateAuditInput!): CreateAuditPayload
|
||||
updateAudit(input: UpdateAuditInput!): UpdateAuditPayload
|
||||
deleteAudit(input: DeleteAuditInput!): DeleteAuditPayload
|
||||
uploadAuditReport(input: UploadAuditReportInput!): UploadAuditReportPayload
|
||||
deleteAuditReport(input: DeleteAuditReportInput!): DeleteAuditReportPayload
|
||||
# Finding mutations
|
||||
createFinding(input: CreateFindingInput!): CreateFindingPayload
|
||||
updateFinding(input: UpdateFindingInput!): UpdateFindingPayload
|
||||
deleteFinding(input: DeleteFindingInput!): DeleteFindingPayload
|
||||
createFindingAuditMapping(
|
||||
input: CreateFindingAuditMappingInput!
|
||||
): CreateFindingAuditMappingPayload
|
||||
deleteFindingAuditMapping(
|
||||
input: DeleteFindingAuditMappingInput!
|
||||
): DeleteFindingAuditMappingPayload
|
||||
# Obligation mutations
|
||||
createObligation(input: CreateObligationInput!): CreateObligationPayload!
|
||||
updateObligation(input: UpdateObligationInput!): UpdateObligationPayload!
|
||||
deleteObligation(input: DeleteObligationInput!): DeleteObligationPayload!
|
||||
# Continual Improvement mutations
|
||||
createContinualImprovement(
|
||||
input: CreateContinualImprovementInput!
|
||||
): CreateContinualImprovementPayload!
|
||||
updateContinualImprovement(
|
||||
input: UpdateContinualImprovementInput!
|
||||
): UpdateContinualImprovementPayload!
|
||||
deleteContinualImprovement(
|
||||
input: DeleteContinualImprovementInput!
|
||||
): DeleteContinualImprovementPayload!
|
||||
|
||||
# Rights Request mutations
|
||||
createRightsRequest(
|
||||
input: CreateRightsRequestInput!
|
||||
@@ -4535,37 +4483,51 @@ input DeleteAuditReportInput {
|
||||
auditId: ID!
|
||||
}
|
||||
|
||||
# Nonconformity input types
|
||||
input CreateNonconformityInput {
|
||||
# Finding input types
|
||||
input CreateFindingInput {
|
||||
organizationId: ID!
|
||||
referenceId: String!
|
||||
kind: FindingKind!
|
||||
description: String
|
||||
auditId: ID
|
||||
dateIdentified: Datetime
|
||||
rootCause: String!
|
||||
source: String
|
||||
identifiedOn: Datetime
|
||||
rootCause: String
|
||||
correctiveAction: String
|
||||
ownerId: ID!
|
||||
ownerId: ID
|
||||
dueDate: Datetime
|
||||
status: NonconformityStatus!
|
||||
status: FindingStatus!
|
||||
priority: FindingPriority!
|
||||
riskId: ID
|
||||
effectivenessCheck: String
|
||||
}
|
||||
|
||||
input UpdateNonconformityInput {
|
||||
input UpdateFindingInput {
|
||||
id: ID!
|
||||
referenceId: String
|
||||
description: String @goField(omittable: true)
|
||||
dateIdentified: Datetime @goField(omittable: true)
|
||||
rootCause: String
|
||||
source: String @goField(omittable: true)
|
||||
identifiedOn: Datetime @goField(omittable: true)
|
||||
rootCause: String @goField(omittable: true)
|
||||
correctiveAction: String @goField(omittable: true)
|
||||
ownerId: ID
|
||||
auditId: ID @goField(omittable: true)
|
||||
dueDate: Datetime @goField(omittable: true)
|
||||
status: NonconformityStatus
|
||||
status: FindingStatus
|
||||
priority: FindingPriority
|
||||
riskId: ID @goField(omittable: true)
|
||||
effectivenessCheck: String @goField(omittable: true)
|
||||
}
|
||||
|
||||
input DeleteNonconformityInput {
|
||||
nonconformityId: ID!
|
||||
input DeleteFindingInput {
|
||||
findingId: ID!
|
||||
}
|
||||
|
||||
input CreateFindingAuditMappingInput {
|
||||
findingId: ID!
|
||||
auditId: ID!
|
||||
referenceId: String!
|
||||
}
|
||||
|
||||
input DeleteFindingAuditMappingInput {
|
||||
findingId: ID!
|
||||
auditId: ID!
|
||||
}
|
||||
|
||||
input CreateObligationInput {
|
||||
@@ -4600,31 +4562,6 @@ input DeleteObligationInput {
|
||||
obligationId: ID!
|
||||
}
|
||||
|
||||
input CreateContinualImprovementInput {
|
||||
organizationId: ID!
|
||||
referenceId: String!
|
||||
description: String
|
||||
source: String
|
||||
ownerId: ID!
|
||||
targetDate: Datetime
|
||||
status: ContinualImprovementStatus!
|
||||
priority: ContinualImprovementPriority!
|
||||
}
|
||||
|
||||
input UpdateContinualImprovementInput {
|
||||
id: ID!
|
||||
referenceId: String
|
||||
description: String @goField(omittable: true)
|
||||
source: String @goField(omittable: true)
|
||||
ownerId: ID
|
||||
targetDate: Datetime @goField(omittable: true)
|
||||
status: ContinualImprovementStatus
|
||||
priority: ContinualImprovementPriority
|
||||
}
|
||||
|
||||
input DeleteContinualImprovementInput {
|
||||
continualImprovementId: ID!
|
||||
}
|
||||
|
||||
input CreateRightsRequestInput {
|
||||
organizationId: ID!
|
||||
@@ -4996,13 +4933,13 @@ type DeleteApplicabilityStatementPayload {
|
||||
}
|
||||
|
||||
type CreateControlAuditMappingPayload {
|
||||
controlEdge: ControlEdge!
|
||||
auditEdge: AuditEdge!
|
||||
controlEdge: ControlEdge
|
||||
auditEdge: AuditEdge
|
||||
}
|
||||
|
||||
type DeleteControlAuditMappingPayload {
|
||||
deletedControlId: ID!
|
||||
deletedAuditId: ID!
|
||||
deletedControlId: ID
|
||||
deletedAuditId: ID
|
||||
}
|
||||
|
||||
type CreateControlObligationMappingPayload {
|
||||
@@ -5616,36 +5553,46 @@ type DeleteDatumPayload {
|
||||
}
|
||||
|
||||
type CreateAuditPayload {
|
||||
auditEdge: AuditEdge!
|
||||
auditEdge: AuditEdge
|
||||
}
|
||||
|
||||
type UpdateAuditPayload {
|
||||
audit: Audit!
|
||||
audit: Audit
|
||||
}
|
||||
|
||||
type DeleteAuditPayload {
|
||||
deletedAuditId: ID!
|
||||
deletedAuditId: ID
|
||||
}
|
||||
|
||||
type UploadAuditReportPayload {
|
||||
audit: Audit!
|
||||
audit: Audit
|
||||
}
|
||||
|
||||
type DeleteAuditReportPayload {
|
||||
audit: Audit!
|
||||
audit: Audit
|
||||
}
|
||||
|
||||
# Nonconformity payload types
|
||||
type CreateNonconformityPayload {
|
||||
nonconformityEdge: NonconformityEdge!
|
||||
# Finding payload types
|
||||
type CreateFindingPayload {
|
||||
findingEdge: FindingEdge
|
||||
}
|
||||
|
||||
type UpdateNonconformityPayload {
|
||||
nonconformity: Nonconformity!
|
||||
type UpdateFindingPayload {
|
||||
finding: Finding
|
||||
}
|
||||
|
||||
type DeleteNonconformityPayload {
|
||||
deletedNonconformityId: ID!
|
||||
type DeleteFindingPayload {
|
||||
deletedFindingId: ID
|
||||
}
|
||||
|
||||
type CreateFindingAuditMappingPayload {
|
||||
findingEdge: FindingEdge
|
||||
auditEdge: AuditEdge
|
||||
}
|
||||
|
||||
type DeleteFindingAuditMappingPayload {
|
||||
deletedFindingId: ID
|
||||
deletedAuditId: ID
|
||||
}
|
||||
|
||||
type CreateObligationPayload {
|
||||
@@ -5660,17 +5607,6 @@ type DeleteObligationPayload {
|
||||
deletedObligationId: ID!
|
||||
}
|
||||
|
||||
type CreateContinualImprovementPayload {
|
||||
continualImprovementEdge: ContinualImprovementEdge!
|
||||
}
|
||||
|
||||
type UpdateContinualImprovementPayload {
|
||||
continualImprovement: ContinualImprovement!
|
||||
}
|
||||
|
||||
type DeleteContinualImprovementPayload {
|
||||
deletedContinualImprovementId: ID!
|
||||
}
|
||||
|
||||
type CreateRightsRequestPayload {
|
||||
rightsRequestEdge: RightsRequestEdge!
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
// 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 (
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
)
|
||||
|
||||
type (
|
||||
ContinualImprovementOrderBy OrderBy[coredata.ContinualImprovementOrderField]
|
||||
|
||||
ContinualImprovementConnection struct {
|
||||
TotalCount int
|
||||
Edges []*ContinualImprovementEdge
|
||||
PageInfo PageInfo
|
||||
|
||||
Resolver any
|
||||
ParentID gid.GID
|
||||
Filter *ContinualImprovementFilter
|
||||
}
|
||||
)
|
||||
|
||||
func NewContinualImprovementConnection(
|
||||
p *page.Page[*coredata.ContinualImprovement, coredata.ContinualImprovementOrderField],
|
||||
parentType any,
|
||||
parentID gid.GID,
|
||||
filter *ContinualImprovementFilter,
|
||||
) *ContinualImprovementConnection {
|
||||
edges := make([]*ContinualImprovementEdge, len(p.Data))
|
||||
for i, improvement := range p.Data {
|
||||
edges[i] = NewContinualImprovementEdge(improvement, p.Cursor.OrderBy.Field)
|
||||
}
|
||||
|
||||
return &ContinualImprovementConnection{
|
||||
Edges: edges,
|
||||
PageInfo: *NewPageInfo(p),
|
||||
|
||||
Resolver: parentType,
|
||||
ParentID: parentID,
|
||||
Filter: filter,
|
||||
}
|
||||
}
|
||||
|
||||
func NewContinualImprovementEdge(ci *coredata.ContinualImprovement, orderField coredata.ContinualImprovementOrderField) *ContinualImprovementEdge {
|
||||
return &ContinualImprovementEdge{
|
||||
Node: NewContinualImprovement(ci),
|
||||
Cursor: ci.CursorKey(orderField),
|
||||
}
|
||||
}
|
||||
|
||||
func NewContinualImprovement(ci *coredata.ContinualImprovement) *ContinualImprovement {
|
||||
return &ContinualImprovement{
|
||||
ID: ci.ID,
|
||||
SnapshotID: ci.SnapshotID,
|
||||
Organization: &Organization{
|
||||
ID: ci.OrganizationID,
|
||||
},
|
||||
Owner: &Profile{
|
||||
ID: ci.OwnerID,
|
||||
},
|
||||
SourceID: ci.SourceID,
|
||||
ReferenceID: ci.ReferenceID,
|
||||
Description: ci.Description,
|
||||
Source: ci.Source,
|
||||
TargetDate: ci.TargetDate,
|
||||
Status: ci.Status,
|
||||
Priority: ci.Priority,
|
||||
CreatedAt: ci.CreatedAt,
|
||||
UpdatedAt: ci.UpdatedAt,
|
||||
}
|
||||
}
|
||||
103
pkg/server/api/console/v1/types/finding.go
Normal file
103
pkg/server/api/console/v1/types/finding.go
Normal file
@@ -0,0 +1,103 @@
|
||||
// Copyright (c) 2026 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 (
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
)
|
||||
|
||||
type (
|
||||
FindingEdge struct {
|
||||
Cursor page.CursorKey `json:"cursor"`
|
||||
Node *Finding `json:"node"`
|
||||
}
|
||||
|
||||
FindingConnection struct {
|
||||
TotalCount int
|
||||
Edges []*FindingEdge
|
||||
PageInfo PageInfo
|
||||
|
||||
Resolver any
|
||||
ParentID gid.GID
|
||||
Filter *FindingFilter
|
||||
}
|
||||
)
|
||||
|
||||
func NewFindingConnection(
|
||||
p *page.Page[*coredata.Finding, coredata.FindingOrderField],
|
||||
parentType any,
|
||||
parentID gid.GID,
|
||||
filter *FindingFilter,
|
||||
) *FindingConnection {
|
||||
edges := make([]*FindingEdge, len(p.Data))
|
||||
for i, finding := range p.Data {
|
||||
edges[i] = NewFindingEdge(finding, p.Cursor.OrderBy.Field)
|
||||
}
|
||||
|
||||
return &FindingConnection{
|
||||
Edges: edges,
|
||||
PageInfo: *NewPageInfo(p),
|
||||
|
||||
Resolver: parentType,
|
||||
ParentID: parentID,
|
||||
Filter: filter,
|
||||
}
|
||||
}
|
||||
|
||||
func NewFindingEdge(f *coredata.Finding, orderField coredata.FindingOrderField) *FindingEdge {
|
||||
return &FindingEdge{
|
||||
Node: NewFinding(f),
|
||||
Cursor: f.CursorKey(orderField),
|
||||
}
|
||||
}
|
||||
|
||||
func NewFinding(f *coredata.Finding) *Finding {
|
||||
finding := &Finding{
|
||||
ID: f.ID,
|
||||
SnapshotID: f.SnapshotID,
|
||||
Organization: &Organization{
|
||||
ID: f.OrganizationID,
|
||||
},
|
||||
Kind: f.Kind,
|
||||
ReferenceID: f.ReferenceID,
|
||||
Description: f.Description,
|
||||
Source: f.Source,
|
||||
IdentifiedOn: f.IdentifiedOn,
|
||||
RootCause: f.RootCause,
|
||||
CorrectiveAction: f.CorrectiveAction,
|
||||
DueDate: f.DueDate,
|
||||
Status: f.Status,
|
||||
Priority: f.Priority,
|
||||
EffectivenessCheck: f.EffectivenessCheck,
|
||||
CreatedAt: f.CreatedAt,
|
||||
UpdatedAt: f.UpdatedAt,
|
||||
}
|
||||
|
||||
if f.OwnerID != nil {
|
||||
finding.Owner = &Profile{
|
||||
ID: *f.OwnerID,
|
||||
}
|
||||
}
|
||||
|
||||
if f.RiskID != nil {
|
||||
finding.Risk = &Risk{
|
||||
ID: *f.RiskID,
|
||||
}
|
||||
}
|
||||
|
||||
return finding
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
// 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 (
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
)
|
||||
|
||||
type (
|
||||
NonconformityOrderBy OrderBy[coredata.NonconformityOrderField]
|
||||
|
||||
NonconformityConnection struct {
|
||||
TotalCount int
|
||||
Edges []*NonconformityEdge
|
||||
PageInfo PageInfo
|
||||
|
||||
Resolver any
|
||||
ParentID gid.GID
|
||||
Filter *NonconformityFilter
|
||||
}
|
||||
)
|
||||
|
||||
func NewNonconformityConnection(
|
||||
p *page.Page[*coredata.Nonconformity, coredata.NonconformityOrderField],
|
||||
parentType any,
|
||||
parentID gid.GID,
|
||||
filter *NonconformityFilter,
|
||||
) *NonconformityConnection {
|
||||
edges := make([]*NonconformityEdge, len(p.Data))
|
||||
for i, nonconformity := range p.Data {
|
||||
edges[i] = NewNonconformityEdge(nonconformity, p.Cursor.OrderBy.Field)
|
||||
}
|
||||
|
||||
return &NonconformityConnection{
|
||||
Edges: edges,
|
||||
PageInfo: *NewPageInfo(p),
|
||||
|
||||
Resolver: parentType,
|
||||
ParentID: parentID,
|
||||
Filter: filter,
|
||||
}
|
||||
}
|
||||
|
||||
func NewNonconformityEdge(nr *coredata.Nonconformity, orderField coredata.NonconformityOrderField) *NonconformityEdge {
|
||||
return &NonconformityEdge{
|
||||
Node: NewNonconformity(nr),
|
||||
Cursor: nr.CursorKey(orderField),
|
||||
}
|
||||
}
|
||||
|
||||
func NewNonconformity(nr *coredata.Nonconformity) *Nonconformity {
|
||||
nc := &Nonconformity{
|
||||
ID: nr.ID,
|
||||
Organization: &Organization{
|
||||
ID: nr.OrganizationID,
|
||||
},
|
||||
Owner: &Profile{
|
||||
ID: nr.OwnerID,
|
||||
},
|
||||
ReferenceID: nr.ReferenceID,
|
||||
SnapshotID: nr.SnapshotID,
|
||||
Description: nr.Description,
|
||||
DateIdentified: nr.DateIdentified,
|
||||
RootCause: nr.RootCause,
|
||||
CorrectiveAction: nr.CorrectiveAction,
|
||||
DueDate: nr.DueDate,
|
||||
Status: nr.Status,
|
||||
EffectivenessCheck: nr.EffectivenessCheck,
|
||||
CreatedAt: nr.CreatedAt,
|
||||
UpdatedAt: nr.UpdatedAt,
|
||||
}
|
||||
|
||||
if nr.AuditID != nil {
|
||||
nc.Audit = &Audit{
|
||||
ID: *nr.AuditID,
|
||||
}
|
||||
}
|
||||
|
||||
return nc
|
||||
}
|
||||
@@ -304,6 +304,54 @@ func (r *auditResolver) Controls(ctx context.Context, obj *types.Audit, first *i
|
||||
return types.NewControlConnection(page, r, obj.ID, controlFilter), nil
|
||||
}
|
||||
|
||||
// Findings is the resolver for the findings field.
|
||||
func (r *auditResolver) Findings(ctx context.Context, obj *types.Audit, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.FindingOrder, filter *types.FindingFilter) (*types.FindingConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionFindingList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.FindingOrderField]{
|
||||
Field: coredata.FindingOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.FindingOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
var (
|
||||
kind *coredata.FindingKind
|
||||
status *coredata.FindingStatus
|
||||
priority *coredata.FindingPriority
|
||||
ownerID *gid.GID
|
||||
)
|
||||
if filter != nil {
|
||||
kind = filter.Kind
|
||||
status = filter.Status
|
||||
priority = filter.Priority
|
||||
ownerID = filter.OwnerID
|
||||
}
|
||||
|
||||
findingFilter := coredata.NewFindingFilter(nil, kind, status, priority, ownerID)
|
||||
if filter != nil {
|
||||
findingFilter = coredata.NewFindingFilter(&filter.SnapshotID, kind, status, priority, ownerID)
|
||||
}
|
||||
|
||||
p, err := prb.Findings.ListForAuditID(ctx, obj.ID, cursor, findingFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list audit findings", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewFindingConnection(p, r, obj.ID, filter), nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *auditResolver) Permission(ctx context.Context, obj *types.Audit, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
@@ -315,15 +363,34 @@ func (r *auditConnectionResolver) TotalCount(ctx context.Context, obj *types.Aud
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// TODO missing switch case
|
||||
|
||||
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
||||
|
||||
count, err := prb.Audits.CountForOrganizationID(ctx, obj.ParentID)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("cannot count audits: %w", err))
|
||||
switch obj.Resolver.(type) {
|
||||
case *organizationResolver:
|
||||
count, err := prb.Audits.CountForOrganizationID(ctx, obj.ParentID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count audits", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
case *findingResolver:
|
||||
count, err := prb.Audits.CountForFindingID(ctx, obj.ParentID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count audits", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
case *controlResolver:
|
||||
count, err := prb.Audits.CountForControlID(ctx, obj.ParentID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count audits", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
default:
|
||||
r.logger.ErrorCtx(ctx, "unsupported resolver", log.Any("resolver", obj.Resolver))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
@@ -348,75 +415,6 @@ func (r *complianceFrameworkResolver) Framework(ctx context.Context, obj *types.
|
||||
return types.NewFramework(framework), nil
|
||||
}
|
||||
|
||||
// Organization is the resolver for the organization field.
|
||||
func (r *continualImprovementResolver) Organization(ctx context.Context, obj *types.ContinualImprovement) (*types.Organization, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
organization, err := prb.Organizations.Get(ctx, obj.Organization.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
panic(fmt.Errorf("cannot get continual improvement organization: %w", err))
|
||||
}
|
||||
|
||||
return types.NewOrganization(organization), nil
|
||||
}
|
||||
|
||||
// Owner is the resolver for the owner field.
|
||||
func (r *continualImprovementResolver) Owner(ctx context.Context, obj *types.ContinualImprovement) (*types.Profile, error) {
|
||||
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
owner, err := r.iam.OrganizationService.GetProfile(ctx, obj.Owner.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
panic(fmt.Errorf("cannot get continual improvement owner: %w", err))
|
||||
}
|
||||
|
||||
return types.NewProfile(owner), nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *continualImprovementResolver) Permission(ctx context.Context, obj *types.ContinualImprovement, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// TotalCount is the resolver for the totalCount field.
|
||||
func (r *continualImprovementConnectionResolver) TotalCount(ctx context.Context, obj *types.ContinualImprovementConnection) (int, error) {
|
||||
if err := r.authorize(ctx, obj.ParentID, probo.ActionContinualImprovementList); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
||||
|
||||
switch obj.Resolver.(type) {
|
||||
case *organizationResolver:
|
||||
continualImprovementFilter := coredata.NewContinualImprovementFilter(nil)
|
||||
if obj.Filter != nil {
|
||||
continualImprovementFilter = coredata.NewContinualImprovementFilter(&obj.Filter.SnapshotID)
|
||||
}
|
||||
|
||||
count, err := prb.ContinualImprovements.CountByOrganizationID(ctx, obj.ParentID, continualImprovementFilter)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("cannot count continual improvements: %w", err))
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// TODO no panic use gqlutils.InternalError
|
||||
panic(fmt.Errorf("unsupported resolver: %T", obj.Resolver))
|
||||
}
|
||||
|
||||
// Organization is the resolver for the organization field.
|
||||
func (r *controlResolver) Organization(ctx context.Context, obj *types.Control) (*types.Organization, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
||||
@@ -1421,6 +1419,157 @@ func (r *fileResolver) DownloadURL(ctx context.Context, obj *types.File) (string
|
||||
return downloadUrl, nil
|
||||
}
|
||||
|
||||
// Organization is the resolver for the organization field.
|
||||
func (r *findingResolver) Organization(ctx context.Context, obj *types.Finding) (*types.Organization, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
organization, err := prb.Organizations.Get(ctx, obj.Organization.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get finding organization", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewOrganization(organization), nil
|
||||
}
|
||||
|
||||
// Audits is the resolver for the audits field.
|
||||
func (r *findingResolver) Audits(ctx context.Context, obj *types.Finding, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.AuditOrderBy) (*types.AuditConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionAuditList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.AuditOrderField]{
|
||||
Field: coredata.AuditOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.AuditOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
p, err := prb.Audits.ListForFindingID(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list finding audits", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewAuditConnection(p, r, obj.ID), nil
|
||||
}
|
||||
|
||||
// Owner is the resolver for the owner field.
|
||||
func (r *findingResolver) Owner(ctx context.Context, obj *types.Finding) (*types.Profile, error) {
|
||||
if obj.Owner == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
owner, err := r.iam.OrganizationService.GetProfile(ctx, obj.Owner.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get finding owner", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewProfile(owner), nil
|
||||
}
|
||||
|
||||
// Risk is the resolver for the risk field.
|
||||
func (r *findingResolver) Risk(ctx context.Context, obj *types.Finding) (*types.Risk, error) {
|
||||
if obj.Risk == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionRiskGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
risk, err := prb.Risks.Get(ctx, obj.Risk.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot get finding risk", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewRisk(risk), nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *findingResolver) Permission(ctx context.Context, obj *types.Finding, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// TotalCount is the resolver for the totalCount field.
|
||||
func (r *findingConnectionResolver) TotalCount(ctx context.Context, obj *types.FindingConnection) (int, error) {
|
||||
if err := r.authorize(ctx, obj.ParentID, probo.ActionFindingList); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
||||
|
||||
var (
|
||||
kind *coredata.FindingKind
|
||||
status *coredata.FindingStatus
|
||||
priority *coredata.FindingPriority
|
||||
ownerID *gid.GID
|
||||
)
|
||||
if obj.Filter != nil {
|
||||
kind = obj.Filter.Kind
|
||||
status = obj.Filter.Status
|
||||
priority = obj.Filter.Priority
|
||||
ownerID = obj.Filter.OwnerID
|
||||
}
|
||||
|
||||
findingFilter := coredata.NewFindingFilter(nil, kind, status, priority, ownerID)
|
||||
if obj.Filter != nil {
|
||||
findingFilter = coredata.NewFindingFilter(&obj.Filter.SnapshotID, kind, status, priority, ownerID)
|
||||
}
|
||||
|
||||
switch obj.Resolver.(type) {
|
||||
case *organizationResolver:
|
||||
count, err := prb.Findings.CountForOrganizationID(ctx, obj.ParentID, findingFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count findings", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
case *auditResolver:
|
||||
count, err := prb.Findings.CountForAuditID(ctx, obj.ParentID, findingFilter)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count findings", log.Error(err))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "unsupported resolver", log.Any("resolver", obj.Resolver))
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
// Organization is the resolver for the organization field.
|
||||
func (r *frameworkResolver) Organization(ctx context.Context, obj *types.Framework) (*types.Organization, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
||||
@@ -3302,8 +3451,8 @@ func (r *mutationResolver) DeleteControlAuditMapping(ctx context.Context, input
|
||||
}
|
||||
|
||||
return &types.DeleteControlAuditMappingPayload{
|
||||
DeletedControlID: control.ID,
|
||||
DeletedAuditID: audit.ID,
|
||||
DeletedControlID: &control.ID,
|
||||
DeletedAuditID: &audit.ID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -5027,7 +5176,7 @@ func (r *mutationResolver) DeleteAudit(ctx context.Context, input types.DeleteAu
|
||||
}
|
||||
|
||||
return &types.DeleteAuditPayload{
|
||||
DeletedAuditID: input.AuditID,
|
||||
DeletedAuditID: &input.AuditID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -5079,88 +5228,131 @@ func (r *mutationResolver) DeleteAuditReport(ctx context.Context, input types.De
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreateNonconformity is the resolver for the createNonconformity field.
|
||||
func (r *mutationResolver) CreateNonconformity(ctx context.Context, input types.CreateNonconformityInput) (*types.CreateNonconformityPayload, error) {
|
||||
if err := r.authorize(ctx, input.OrganizationID, probo.ActionNonconformityCreate); err != nil {
|
||||
// CreateFinding is the resolver for the createFinding field.
|
||||
func (r *mutationResolver) CreateFinding(ctx context.Context, input types.CreateFindingInput) (*types.CreateFindingPayload, error) {
|
||||
if err := r.authorize(ctx, input.OrganizationID, probo.ActionFindingCreate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
||||
|
||||
req := probo.CreateNonconformityRequest{
|
||||
req := probo.CreateFindingRequest{
|
||||
OrganizationID: input.OrganizationID,
|
||||
ReferenceID: input.ReferenceID,
|
||||
Kind: input.Kind,
|
||||
Description: input.Description,
|
||||
AuditID: input.AuditID,
|
||||
DateIdentified: input.DateIdentified,
|
||||
Source: input.Source,
|
||||
IdentifiedOn: input.IdentifiedOn,
|
||||
RootCause: input.RootCause,
|
||||
CorrectiveAction: input.CorrectiveAction,
|
||||
OwnerID: input.OwnerID,
|
||||
DueDate: input.DueDate,
|
||||
Status: &input.Status,
|
||||
Priority: &input.Priority,
|
||||
RiskID: input.RiskID,
|
||||
EffectivenessCheck: input.EffectivenessCheck,
|
||||
}
|
||||
|
||||
nonconformity, err := prb.Nonconformities.Create(ctx, &req)
|
||||
finding, err := prb.Findings.Create(ctx, &req)
|
||||
if err != nil {
|
||||
// TODO no panic use gqlutils.InternalError
|
||||
panic(fmt.Errorf("cannot create nonconformity: %w", err))
|
||||
r.logger.ErrorCtx(ctx, "cannot create finding", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.CreateNonconformityPayload{
|
||||
NonconformityEdge: types.NewNonconformityEdge(nonconformity, coredata.NonconformityOrderFieldCreatedAt),
|
||||
return &types.CreateFindingPayload{
|
||||
FindingEdge: types.NewFindingEdge(finding, coredata.FindingOrderFieldCreatedAt),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateNonconformity is the resolver for the updateNonconformity field.
|
||||
func (r *mutationResolver) UpdateNonconformity(ctx context.Context, input types.UpdateNonconformityInput) (*types.UpdateNonconformityPayload, error) {
|
||||
if err := r.authorize(ctx, input.ID, probo.ActionNonconformityUpdate); err != nil {
|
||||
// UpdateFinding is the resolver for the updateFinding field.
|
||||
func (r *mutationResolver) UpdateFinding(ctx context.Context, input types.UpdateFindingInput) (*types.UpdateFindingPayload, error) {
|
||||
if err := r.authorize(ctx, input.ID, probo.ActionFindingUpdate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.ID.TenantID())
|
||||
|
||||
req := probo.UpdateNonconformityRequest{
|
||||
req := probo.UpdateFindingRequest{
|
||||
ID: input.ID,
|
||||
ReferenceID: input.ReferenceID,
|
||||
Description: gqlutils.UnwrapOmittable(input.Description),
|
||||
DateIdentified: gqlutils.UnwrapOmittable(input.DateIdentified),
|
||||
RootCause: input.RootCause,
|
||||
Source: gqlutils.UnwrapOmittable(input.Source),
|
||||
IdentifiedOn: gqlutils.UnwrapOmittable(input.IdentifiedOn),
|
||||
RootCause: gqlutils.UnwrapOmittable(input.RootCause),
|
||||
CorrectiveAction: gqlutils.UnwrapOmittable(input.CorrectiveAction),
|
||||
OwnerID: input.OwnerID,
|
||||
AuditID: gqlutils.UnwrapOmittable(input.AuditID),
|
||||
DueDate: gqlutils.UnwrapOmittable(input.DueDate),
|
||||
Status: input.Status,
|
||||
Priority: input.Priority,
|
||||
RiskID: gqlutils.UnwrapOmittable(input.RiskID),
|
||||
EffectivenessCheck: gqlutils.UnwrapOmittable(input.EffectivenessCheck),
|
||||
}
|
||||
|
||||
nonconformity, err := prb.Nonconformities.Update(ctx, &req)
|
||||
finding, err := prb.Findings.Update(ctx, &req)
|
||||
if err != nil {
|
||||
// TODO no panic use gqlutils.InternalError
|
||||
panic(fmt.Errorf("cannot update nonconformity: %w", err))
|
||||
r.logger.ErrorCtx(ctx, "cannot update finding", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.UpdateNonconformityPayload{
|
||||
Nonconformity: types.NewNonconformity(nonconformity),
|
||||
return &types.UpdateFindingPayload{
|
||||
Finding: types.NewFinding(finding),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteNonconformity is the resolver for the deleteNonconformity field.
|
||||
func (r *mutationResolver) DeleteNonconformity(ctx context.Context, input types.DeleteNonconformityInput) (*types.DeleteNonconformityPayload, error) {
|
||||
if err := r.authorize(ctx, input.NonconformityID, probo.ActionNonconformityDelete); err != nil {
|
||||
// DeleteFinding is the resolver for the deleteFinding field.
|
||||
func (r *mutationResolver) DeleteFinding(ctx context.Context, input types.DeleteFindingInput) (*types.DeleteFindingPayload, error) {
|
||||
if err := r.authorize(ctx, input.FindingID, probo.ActionFindingDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.NonconformityID.TenantID())
|
||||
prb := r.ProboService(ctx, input.FindingID.TenantID())
|
||||
|
||||
err := prb.Nonconformities.Delete(ctx, input.NonconformityID)
|
||||
err := prb.Findings.Delete(ctx, input.FindingID)
|
||||
if err != nil {
|
||||
// TODO no panic use gqlutils.InternalError
|
||||
panic(fmt.Errorf("cannot delete nonconformity: %w", err))
|
||||
r.logger.ErrorCtx(ctx, "cannot delete finding", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DeleteNonconformityPayload{
|
||||
DeletedNonconformityID: input.NonconformityID,
|
||||
return &types.DeleteFindingPayload{
|
||||
DeletedFindingID: &input.FindingID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreateFindingAuditMapping is the resolver for the createFindingAuditMapping field.
|
||||
func (r *mutationResolver) CreateFindingAuditMapping(ctx context.Context, input types.CreateFindingAuditMappingInput) (*types.CreateFindingAuditMappingPayload, error) {
|
||||
if err := r.authorize(ctx, input.FindingID, probo.ActionFindingAuditMappingCreate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.FindingID.TenantID())
|
||||
|
||||
finding, audit, err := prb.Findings.CreateAuditMapping(ctx, input.FindingID, input.AuditID, input.ReferenceID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot create finding audit mapping", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.CreateFindingAuditMappingPayload{
|
||||
FindingEdge: types.NewFindingEdge(finding, coredata.FindingOrderFieldCreatedAt),
|
||||
AuditEdge: types.NewAuditEdge(audit, coredata.AuditOrderFieldCreatedAt),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteFindingAuditMapping is the resolver for the deleteFindingAuditMapping field.
|
||||
func (r *mutationResolver) DeleteFindingAuditMapping(ctx context.Context, input types.DeleteFindingAuditMappingInput) (*types.DeleteFindingAuditMappingPayload, error) {
|
||||
if err := r.authorize(ctx, input.FindingID, probo.ActionFindingAuditMappingDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.FindingID.TenantID())
|
||||
|
||||
finding, audit, err := prb.Findings.DeleteAuditMapping(ctx, input.FindingID, input.AuditID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot delete finding audit mapping", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DeleteFindingAuditMappingPayload{
|
||||
DeletedFindingID: &finding.ID,
|
||||
DeletedAuditID: &audit.ID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -5249,85 +5441,6 @@ func (r *mutationResolver) DeleteObligation(ctx context.Context, input types.Del
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreateContinualImprovement is the resolver for the createContinualImprovement field.
|
||||
func (r *mutationResolver) CreateContinualImprovement(ctx context.Context, input types.CreateContinualImprovementInput) (*types.CreateContinualImprovementPayload, error) {
|
||||
if err := r.authorize(ctx, input.OrganizationID, probo.ActionContinualImprovementCreate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
||||
|
||||
req := probo.CreateContinualImprovementRequest{
|
||||
OrganizationID: input.OrganizationID,
|
||||
ReferenceID: input.ReferenceID,
|
||||
Description: input.Description,
|
||||
Source: input.Source,
|
||||
OwnerID: input.OwnerID,
|
||||
TargetDate: input.TargetDate,
|
||||
Status: &input.Status,
|
||||
Priority: &input.Priority,
|
||||
}
|
||||
|
||||
continualImprovement, err := prb.ContinualImprovements.Create(ctx, &req)
|
||||
if err != nil {
|
||||
// TODO no panic use gqlutils.InternalError
|
||||
panic(fmt.Errorf("cannot create continual improvement: %w", err))
|
||||
}
|
||||
|
||||
return &types.CreateContinualImprovementPayload{
|
||||
ContinualImprovementEdge: types.NewContinualImprovementEdge(continualImprovement, coredata.ContinualImprovementOrderFieldCreatedAt),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateContinualImprovement is the resolver for the updateContinualImprovement field.
|
||||
func (r *mutationResolver) UpdateContinualImprovement(ctx context.Context, input types.UpdateContinualImprovementInput) (*types.UpdateContinualImprovementPayload, error) {
|
||||
if err := r.authorize(ctx, input.ID, probo.ActionContinualImprovementUpdate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.ID.TenantID())
|
||||
|
||||
req := probo.UpdateContinualImprovementRequest{
|
||||
ID: input.ID,
|
||||
ReferenceID: input.ReferenceID,
|
||||
Description: gqlutils.UnwrapOmittable(input.Description),
|
||||
Source: gqlutils.UnwrapOmittable(input.Source),
|
||||
OwnerID: input.OwnerID,
|
||||
TargetDate: gqlutils.UnwrapOmittable(input.TargetDate),
|
||||
Status: input.Status,
|
||||
Priority: input.Priority,
|
||||
}
|
||||
|
||||
continualImprovement, err := prb.ContinualImprovements.Update(ctx, &req)
|
||||
if err != nil {
|
||||
// TODO no panic use gqlutils.InternalError
|
||||
panic(fmt.Errorf("cannot update continual improvement: %w", err))
|
||||
}
|
||||
|
||||
return &types.UpdateContinualImprovementPayload{
|
||||
ContinualImprovement: types.NewContinualImprovement(continualImprovement),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteContinualImprovement is the resolver for the deleteContinualImprovement field.
|
||||
func (r *mutationResolver) DeleteContinualImprovement(ctx context.Context, input types.DeleteContinualImprovementInput) (*types.DeleteContinualImprovementPayload, error) {
|
||||
if err := r.authorize(ctx, input.ContinualImprovementID, probo.ActionContinualImprovementDelete); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.ContinualImprovementID.TenantID())
|
||||
|
||||
err := prb.ContinualImprovements.Delete(ctx, input.ContinualImprovementID)
|
||||
if err != nil {
|
||||
// TODO no panic use gqlutils.InternalError
|
||||
panic(fmt.Errorf("cannot delete continual improvement: %w", err))
|
||||
}
|
||||
|
||||
return &types.DeleteContinualImprovementPayload{
|
||||
DeletedContinualImprovementID: input.ContinualImprovementID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreateRightsRequest is the resolver for the createRightsRequest field.
|
||||
func (r *mutationResolver) CreateRightsRequest(ctx context.Context, input types.CreateRightsRequestInput) (*types.CreateRightsRequestPayload, error) {
|
||||
if err := r.authorize(ctx, input.OrganizationID, probo.ActionRightsRequestCreate); err != nil {
|
||||
@@ -5763,102 +5876,6 @@ func (r *mutationResolver) DeleteCustomDomain(ctx context.Context, input types.D
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Organization is the resolver for the organization field.
|
||||
func (r *nonconformityResolver) Organization(ctx context.Context, obj *types.Nonconformity) (*types.Organization, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
organization, err := prb.Organizations.Get(ctx, obj.Organization.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
// TODO no panic use gqlutils.InternalError
|
||||
panic(fmt.Errorf("cannot get nonconformity organization: %w", err))
|
||||
}
|
||||
|
||||
return types.NewOrganization(organization), nil
|
||||
}
|
||||
|
||||
// Audit is the resolver for the audit field.
|
||||
func (r *nonconformityResolver) Audit(ctx context.Context, obj *types.Nonconformity) (*types.Audit, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionAuditGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
if obj.Audit == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
audit, err := prb.Audits.Get(ctx, obj.Audit.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
// TODO no panic use gqlutils.InternalError
|
||||
panic(fmt.Errorf("cannot get nonconformity audit: %w", err))
|
||||
}
|
||||
|
||||
return types.NewAudit(audit), nil
|
||||
}
|
||||
|
||||
// Owner is the resolver for the owner field.
|
||||
func (r *nonconformityResolver) Owner(ctx context.Context, obj *types.Nonconformity) (*types.Profile, error) {
|
||||
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileGet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
owner, err := r.iam.OrganizationService.GetProfile(ctx, obj.Owner.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
// TODO no panic use gqlutils.InternalError
|
||||
panic(fmt.Errorf("cannot get nonconformity owner: %w", err))
|
||||
}
|
||||
|
||||
return types.NewProfile(owner), nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *nonconformityResolver) Permission(ctx context.Context, obj *types.Nonconformity, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
}
|
||||
|
||||
// TotalCount is the resolver for the totalCount field.
|
||||
func (r *nonconformityConnectionResolver) TotalCount(ctx context.Context, obj *types.NonconformityConnection) (int, error) {
|
||||
if err := r.authorize(ctx, obj.ParentID, probo.ActionNonconformityList); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
||||
switch obj.Resolver.(type) {
|
||||
case *organizationResolver:
|
||||
nonconformityFilter := coredata.NewNonconformityFilter(nil)
|
||||
if obj.Filter != nil {
|
||||
nonconformityFilter = coredata.NewNonconformityFilter(&obj.Filter.SnapshotID)
|
||||
}
|
||||
|
||||
count, err := prb.Nonconformities.CountForOrganizationID(ctx, obj.ParentID, nonconformityFilter)
|
||||
if err != nil {
|
||||
// TODO no panic use gqlutils.InternalError
|
||||
panic(fmt.Errorf("cannot count nonconformities: %w", err))
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// TODO no panic use gqlutils.InternalError
|
||||
panic(fmt.Errorf("unsupported resolver: %T", obj.Resolver))
|
||||
}
|
||||
|
||||
// Organization is the resolver for the organization field.
|
||||
func (r *obligationResolver) Organization(ctx context.Context, obj *types.Obligation) (*types.Organization, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
||||
@@ -6458,21 +6475,21 @@ func (r *organizationResolver) Audits(ctx context.Context, obj *types.Organizati
|
||||
return types.NewAuditConnection(page, r, obj.ID), nil
|
||||
}
|
||||
|
||||
// Nonconformities is the resolver for the nonconformities field.
|
||||
func (r *organizationResolver) Nonconformities(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.NonconformityOrderBy, filter *types.NonconformityFilter) (*types.NonconformityConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionNonconformityList); err != nil {
|
||||
// Findings is the resolver for the findings field.
|
||||
func (r *organizationResolver) Findings(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.FindingOrder, filter *types.FindingFilter) (*types.FindingConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionFindingList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.NonconformityOrderField]{
|
||||
Field: coredata.NonconformityOrderFieldCreatedAt,
|
||||
pageOrderBy := page.OrderBy[coredata.FindingOrderField]{
|
||||
Field: coredata.FindingOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.NonconformityOrderField]{
|
||||
pageOrderBy = page.OrderBy[coredata.FindingOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
@@ -6480,18 +6497,31 @@ func (r *organizationResolver) Nonconformities(ctx context.Context, obj *types.O
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
nonconformityFilter := coredata.NewNonconformityFilter(nil)
|
||||
var (
|
||||
kind *coredata.FindingKind
|
||||
status *coredata.FindingStatus
|
||||
priority *coredata.FindingPriority
|
||||
ownerID *gid.GID
|
||||
)
|
||||
if filter != nil {
|
||||
nonconformityFilter = coredata.NewNonconformityFilter(&filter.SnapshotID)
|
||||
kind = filter.Kind
|
||||
status = filter.Status
|
||||
priority = filter.Priority
|
||||
ownerID = filter.OwnerID
|
||||
}
|
||||
|
||||
page, err := prb.Nonconformities.ListForOrganizationID(ctx, obj.ID, cursor, nonconformityFilter)
|
||||
findingFilter := coredata.NewFindingFilter(nil, kind, status, priority, ownerID)
|
||||
if filter != nil {
|
||||
findingFilter = coredata.NewFindingFilter(&filter.SnapshotID, kind, status, priority, ownerID)
|
||||
}
|
||||
|
||||
page, err := prb.Findings.ListForOrganizationID(ctx, obj.ID, cursor, findingFilter)
|
||||
if err != nil {
|
||||
// TODO no panic use gqlutils.InternalError
|
||||
panic(fmt.Errorf("cannot list organization nonconformities: %w", err))
|
||||
r.logger.ErrorCtx(ctx, "cannot list organization findings", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewNonconformityConnection(page, r, obj.ID, filter), nil
|
||||
return types.NewFindingConnection(page, r, obj.ID, filter), nil
|
||||
}
|
||||
|
||||
// Obligations is the resolver for the obligations field.
|
||||
@@ -6530,42 +6560,6 @@ func (r *organizationResolver) Obligations(ctx context.Context, obj *types.Organ
|
||||
return types.NewObligationConnection(page, r, obj.ID, filter), nil
|
||||
}
|
||||
|
||||
// ContinualImprovements is the resolver for the continualImprovements field.
|
||||
func (r *organizationResolver) ContinualImprovements(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ContinualImprovementOrderBy, filter *types.ContinualImprovementFilter) (*types.ContinualImprovementConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionContinualImprovementList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.ContinualImprovementOrderField]{
|
||||
Field: coredata.ContinualImprovementOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.ContinualImprovementOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
continualImprovementFilter := coredata.NewContinualImprovementFilter(nil)
|
||||
if filter != nil {
|
||||
continualImprovementFilter = coredata.NewContinualImprovementFilter(&filter.SnapshotID)
|
||||
}
|
||||
|
||||
page, err := prb.ContinualImprovements.ListForOrganizationID(ctx, obj.ID, cursor, continualImprovementFilter)
|
||||
if err != nil {
|
||||
// TODO no panic use gqlutils.InternalError
|
||||
panic(fmt.Errorf("cannot list organization continual improvements: %w", err))
|
||||
}
|
||||
|
||||
return types.NewContinualImprovementConnection(page, r, obj.ID, filter), nil
|
||||
}
|
||||
|
||||
// RightsRequests is the resolver for the rightsRequests field.
|
||||
func (r *organizationResolver) RightsRequests(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.RightsRequestOrderBy) (*types.RightsRequestConnection, error) {
|
||||
if err := r.authorize(ctx, obj.ID, probo.ActionRightsRequestList); err != nil {
|
||||
@@ -7173,14 +7167,14 @@ func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error
|
||||
}
|
||||
return types.NewAudit(audit), nil
|
||||
}
|
||||
case coredata.NonconformityEntityType:
|
||||
action = probo.ActionNonconformityList
|
||||
case coredata.FindingEntityType:
|
||||
action = probo.ActionFindingList
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
nonconformity, err := prb.Nonconformities.Get(ctx, id)
|
||||
finding, err := prb.Findings.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewNonconformity(nonconformity), nil
|
||||
return types.NewFinding(finding), nil
|
||||
}
|
||||
case coredata.ObligationEntityType:
|
||||
action = probo.ActionObligationList
|
||||
@@ -7191,15 +7185,6 @@ func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error
|
||||
}
|
||||
return types.NewObligation(obligation), nil
|
||||
}
|
||||
case coredata.ContinualImprovementEntityType:
|
||||
action = probo.ActionContinualImprovementList
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
continualImprovement, err := prb.ContinualImprovements.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewContinualImprovement(continualImprovement), nil
|
||||
}
|
||||
case coredata.ReportEntityType:
|
||||
action = probo.ActionReportGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
@@ -9266,16 +9251,6 @@ func (r *Resolver) ComplianceFramework() schema.ComplianceFrameworkResolver {
|
||||
return &complianceFrameworkResolver{r}
|
||||
}
|
||||
|
||||
// ContinualImprovement returns schema.ContinualImprovementResolver implementation.
|
||||
func (r *Resolver) ContinualImprovement() schema.ContinualImprovementResolver {
|
||||
return &continualImprovementResolver{r}
|
||||
}
|
||||
|
||||
// ContinualImprovementConnection returns schema.ContinualImprovementConnectionResolver implementation.
|
||||
func (r *Resolver) ContinualImprovementConnection() schema.ContinualImprovementConnectionResolver {
|
||||
return &continualImprovementConnectionResolver{r}
|
||||
}
|
||||
|
||||
// Control returns schema.ControlResolver implementation.
|
||||
func (r *Resolver) Control() schema.ControlResolver { return &controlResolver{r} }
|
||||
|
||||
@@ -9349,6 +9324,14 @@ func (r *Resolver) EvidenceConnection() schema.EvidenceConnectionResolver {
|
||||
// File returns schema.FileResolver implementation.
|
||||
func (r *Resolver) File() schema.FileResolver { return &fileResolver{r} }
|
||||
|
||||
// Finding returns schema.FindingResolver implementation.
|
||||
func (r *Resolver) Finding() schema.FindingResolver { return &findingResolver{r} }
|
||||
|
||||
// FindingConnection returns schema.FindingConnectionResolver implementation.
|
||||
func (r *Resolver) FindingConnection() schema.FindingConnectionResolver {
|
||||
return &findingConnectionResolver{r}
|
||||
}
|
||||
|
||||
// Framework returns schema.FrameworkResolver implementation.
|
||||
func (r *Resolver) Framework() schema.FrameworkResolver { return &frameworkResolver{r} }
|
||||
|
||||
@@ -9389,14 +9372,6 @@ func (r *Resolver) MeetingConnection() schema.MeetingConnectionResolver {
|
||||
// Mutation returns schema.MutationResolver implementation.
|
||||
func (r *Resolver) Mutation() schema.MutationResolver { return &mutationResolver{r} }
|
||||
|
||||
// Nonconformity returns schema.NonconformityResolver implementation.
|
||||
func (r *Resolver) Nonconformity() schema.NonconformityResolver { return &nonconformityResolver{r} }
|
||||
|
||||
// NonconformityConnection returns schema.NonconformityConnectionResolver implementation.
|
||||
func (r *Resolver) NonconformityConnection() schema.NonconformityConnectionResolver {
|
||||
return &nonconformityConnectionResolver{r}
|
||||
}
|
||||
|
||||
// Obligation returns schema.ObligationResolver implementation.
|
||||
func (r *Resolver) Obligation() schema.ObligationResolver { return &obligationResolver{r} }
|
||||
|
||||
@@ -9583,8 +9558,6 @@ type auditResolver struct{ *Resolver }
|
||||
type auditConnectionResolver struct{ *Resolver }
|
||||
type complianceExternalURLResolver struct{ *Resolver }
|
||||
type complianceFrameworkResolver struct{ *Resolver }
|
||||
type continualImprovementResolver struct{ *Resolver }
|
||||
type continualImprovementConnectionResolver struct{ *Resolver }
|
||||
type controlResolver struct{ *Resolver }
|
||||
type controlConnectionResolver struct{ *Resolver }
|
||||
type customDomainResolver struct{ *Resolver }
|
||||
@@ -9602,6 +9575,8 @@ type electronicSignatureResolver struct{ *Resolver }
|
||||
type evidenceResolver struct{ *Resolver }
|
||||
type evidenceConnectionResolver struct{ *Resolver }
|
||||
type fileResolver struct{ *Resolver }
|
||||
type findingResolver struct{ *Resolver }
|
||||
type findingConnectionResolver struct{ *Resolver }
|
||||
type frameworkResolver struct{ *Resolver }
|
||||
type frameworkConnectionResolver struct{ *Resolver }
|
||||
type mailingListResolver struct{ *Resolver }
|
||||
@@ -9612,8 +9587,6 @@ type measureConnectionResolver struct{ *Resolver }
|
||||
type meetingResolver struct{ *Resolver }
|
||||
type meetingConnectionResolver struct{ *Resolver }
|
||||
type mutationResolver struct{ *Resolver }
|
||||
type nonconformityResolver struct{ *Resolver }
|
||||
type nonconformityConnectionResolver struct{ *Resolver }
|
||||
type obligationResolver struct{ *Resolver }
|
||||
type obligationConnectionResolver struct{ *Resolver }
|
||||
type organizationResolver struct{ *Resolver }
|
||||
|
||||
Reference in New Issue
Block a user