From d312baeee787974e5bf68cbd1e42d40c49f73f76 Mon Sep 17 00:00:00 2001 From: Stepan Kiryakov Date: Thu, 19 Dec 2024 19:07:20 +0400 Subject: [PATCH] update Signed-off-by: Stepan Kiryakov --- common/src/import-export/policy-label.ts | 3 + .../policy-label-document-view.component.html | 1 + .../policy-label-document-view.component.scss | 18 ++++ .../policy-label-document-view.component.ts | 2 + .../src/api/helpers/policy-labels-helpers.ts | 101 ++++++++++++++++-- .../api/helpers/policy-statistics-helpers.ts | 13 ++- .../src/api/helpers/schema-publish-helper.ts | 31 ++++-- .../src/api/policy-labels.service.ts | 31 ++++-- .../src/interface/policy-label.interface.ts | 4 +- .../label-validator/item-group-validator.ts | 29 ++++- .../label-validator/item-label-validator.ts | 29 ++++- .../label-validator/item-node-validator.ts | 1 + .../label-validator/item-rule-validator.ts | 17 ++- .../item-statistic-validator.ts | 13 +++ .../label-validator/label-validator.ts | 4 + 15 files changed, 257 insertions(+), 40 deletions(-) diff --git a/common/src/import-export/policy-label.ts b/common/src/import-export/policy-label.ts index 3b50011002..0948f70943 100644 --- a/common/src/import-export/policy-label.ts +++ b/common/src/import-export/policy-label.ts @@ -99,6 +99,7 @@ export class PolicyLabelImportExport { const config: IPolicyLabelConfig = { imports: PolicyLabelImportExport.validateImports(data?.imports), children: PolicyLabelImportExport.validateChildren(data?.children), + schemaId: PolicyLabelImportExport.validateString(data?.schemaId), } return config; } @@ -153,6 +154,7 @@ export class PolicyLabelImportExport { title: PolicyLabelImportExport.validateString(data.title), tag: PolicyLabelImportExport.validateTag(data.tag), rule: PolicyLabelImportExport.validateString(data.rule) as any, + schemaId: PolicyLabelImportExport.validateString(data.schemaId), children: PolicyLabelImportExport.validateChildren(data.children), }; return child; @@ -166,6 +168,7 @@ export class PolicyLabelImportExport { tag: PolicyLabelImportExport.validateTag(data.tag), description: PolicyLabelImportExport.validateString(data.description), owner: PolicyLabelImportExport.validateString(data.owner), + schemaId: PolicyLabelImportExport.validateString(data.schemaId), messageId: PolicyLabelImportExport.validateString(data.messageId), config: PolicyLabelImportExport.validateConfig(data.config), }; diff --git a/frontend/src/app/modules/statistics/policy-labels/policy-label-document-view/policy-label-document-view.component.html b/frontend/src/app/modules/statistics/policy-labels/policy-label-document-view/policy-label-document-view.component.html index cbed43f9e2..715a800eb2 100644 --- a/frontend/src/app/modules/statistics/policy-labels/policy-label-document-view/policy-label-document-view.component.html +++ b/frontend/src/app/modules/statistics/policy-labels/policy-label-document-view/policy-label-document-view.component.html @@ -130,6 +130,7 @@
+ {{current.prefix}} {{current.title}}
diff --git a/frontend/src/app/modules/statistics/policy-labels/policy-label-document-view/policy-label-document-view.component.scss b/frontend/src/app/modules/statistics/policy-labels/policy-label-document-view/policy-label-document-view.component.scss index 00e9807f99..d91f5b729e 100644 --- a/frontend/src/app/modules/statistics/policy-labels/policy-label-document-view/policy-label-document-view.component.scss +++ b/frontend/src/app/modules/statistics/policy-labels/policy-label-document-view/policy-label-document-view.component.scss @@ -113,6 +113,24 @@ margin-bottom: 4px; } + .node-status { + width: 8px; + height: 8px; + overflow: hidden; + border-radius: 50%; + background: #AAB7C4; + display: inline-block; + margin: 3px 12px 3px 0px; + + &[status="true"] { + background: #19BE47; + } + + &[status="false"] { + background: #FF432A; + } + } + .node-body { padding-top: 12px; padding-bottom: 16px; diff --git a/frontend/src/app/modules/statistics/policy-labels/policy-label-document-view/policy-label-document-view.component.ts b/frontend/src/app/modules/statistics/policy-labels/policy-label-document-view/policy-label-document-view.component.ts index 256a360f75..ddb52ffe08 100644 --- a/frontend/src/app/modules/statistics/policy-labels/policy-label-document-view/policy-label-document-view.component.ts +++ b/frontend/src/app/modules/statistics/policy-labels/policy-label-document-view/policy-label-document-view.component.ts @@ -153,6 +153,8 @@ export class PolicyLabelDocumentViewComponent implements OnInit { this.steps = this.validator.getDocument(); this.validator.setData(this.relationships); this.validator.setVp(this.document); + // this.steps.shift(); + console.log( this.steps ) // this.schemasMap = new Map(); diff --git a/guardian-service/src/api/helpers/policy-labels-helpers.ts b/guardian-service/src/api/helpers/policy-labels-helpers.ts index 7e2c4c60a2..31f9280c09 100644 --- a/guardian-service/src/api/helpers/policy-labels-helpers.ts +++ b/guardian-service/src/api/helpers/policy-labels-helpers.ts @@ -9,6 +9,7 @@ import { Schema as SchemaCollection, VcDocument as VcDocumentCollection, VpDocument as VpDocumentCollection, + SchemaConverterUtils, } from '@guardian/common'; import { GenerateUUIDv4, @@ -21,10 +22,13 @@ import { NavItemType, PolicyType, Schema, + SchemaCategory, SchemaHelper, + SchemaStatus, TopicType } from '@guardian/interfaces'; import { generateSchema as generateStatisticSchema } from './policy-statistics-helpers.js'; +import { generateSchemaContext } from './schema-publish-helper.js'; export function publishLabelConfig(data?: IPolicyLabelConfig): IPolicyLabelConfig { return data; @@ -69,18 +73,29 @@ export async function generateSchema( node: any, schema: SchemaCollection }[]> { - console.log('generateSchema') - const items = convertConfigToList([], config?.children); - console.log('items', items.length); - const nodes = items - .filter((e) => e.type === NavItemType.Statistic || e.type === NavItemType.Rules) as (IRulesItemConfig | IStatisticItemConfig)[]; - console.log('nodes', nodes.length); + if (!config) { + return []; + } + const items = convertConfigToList([], config.children); const schemas: any[] = []; - for (const node of nodes) { - const schema = await generateStatisticSchema(topicId, node.config, owner); - schemas.push({ node, schema }); + const groupSchema = await generateGroupSchema(topicId, 'Group', owner); + schemas.push({ node: config, schema: groupSchema }); + for (const node of items) { + if (node.type === NavItemType.Statistic) { + const schema = await generateStatisticSchema(topicId, node.config, owner, false); + schemas.push({ node, schema }); + } + if (node.type === NavItemType.Rules) { + const schema = await generateStatisticSchema(topicId, node.config, owner, true); + schemas.push({ node, schema }); + } + if (node.type === NavItemType.Group) { + schemas.push({ node, schema: groupSchema }); + } + if (node.type === NavItemType.Label) { + schemas.push({ node, schema: groupSchema }); + } } - console.log('schemas', schemas.length); return schemas; } @@ -186,4 +201,68 @@ export async function generateVcDocument( const vcObject = await vcHelper.createVerifiableCredential(document, didDocument, null, null); return vcObject; -} \ No newline at end of file +} + +export async function generateGroupSchema(topicId: string, type: string, owner: IOwner) { + const uuid = type; + const document: any = { + $id: `#${uuid}`, + $comment: `{ "term": "${uuid}", "@id": "#${uuid}" }`, + title: `${uuid}`, + description: `${uuid}`, + type: 'object', + properties: { + '@context': { + oneOf: [{ + type: 'string' + }, { + type: 'array', + items: { + type: 'string' + } + }], + readOnly: true + }, + type: { + oneOf: [{ + type: 'string' + }, { + type: 'array', + items: { + type: 'string' + } + }], + readOnly: true + }, + id: { + type: 'string', + readOnly: true + }, + status: { + type: 'boolean', + readOnly: true + } + }, + required: [], + additionalProperties: false + } + const newSchema: any = {}; + newSchema.category = SchemaCategory.STATISTIC; + newSchema.readonly = true; + newSchema.system = false; + newSchema.uuid = uuid + newSchema.status = SchemaStatus.PUBLISHED; + newSchema.document = document; + newSchema.context = generateSchemaContext(newSchema); + newSchema.iri = `${uuid}`; + newSchema.codeVersion = SchemaConverterUtils.VERSION; + newSchema.documentURL = `schema:${uuid}`; + newSchema.contextURL = `schema:${uuid}`; + newSchema.topicId = topicId; + newSchema.creator = owner.creator; + newSchema.owner = owner.owner; + const schemaObject = DatabaseServer.createSchema(newSchema); + SchemaHelper.setVersion(schemaObject, '1.0.0', null); + SchemaHelper.updateIRI(schemaObject); + return schemaObject; +} diff --git a/guardian-service/src/api/helpers/policy-statistics-helpers.ts b/guardian-service/src/api/helpers/policy-statistics-helpers.ts index ff5c80274f..67fdfb070a 100644 --- a/guardian-service/src/api/helpers/policy-statistics-helpers.ts +++ b/guardian-service/src/api/helpers/policy-statistics-helpers.ts @@ -59,9 +59,10 @@ export async function findRelationships( } export async function generateSchema( - topicId: string, - config: IStatisticConfig, - owner: IOwner + topicId: string, + config: IStatisticConfig, + owner: IOwner, + rules: boolean = false ) { const uuid = GenerateUUIDv4(); const variables = config?.variables || []; @@ -116,6 +117,12 @@ export async function generateSchema( readOnly: false } } + if (rules) { + properties.status = { + type: 'boolean', + readOnly: true + } + } const document: any = { $id: `#${uuid}`, $comment: `{ "term": "${uuid}", "@id": "#${uuid}" }`, diff --git a/guardian-service/src/api/helpers/schema-publish-helper.ts b/guardian-service/src/api/helpers/schema-publish-helper.ts index 40234f7add..7f74dccb2f 100644 --- a/guardian-service/src/api/helpers/schema-publish-helper.ts +++ b/guardian-service/src/api/helpers/schema-publish-helper.ts @@ -112,23 +112,38 @@ export async function publishSchema( } /** - * Publish system schemas - * @param systemSchemas + * Publish schemas + * @param schemas * @param messageServer - * @param user + * @param owner * @param notifier */ export async function publishSchemas( - schemas: SchemaCollection[], - user: IOwner, + schemas: Iterable, + owner: IOwner, messageServer: MessageServer, type: MessageAction -): Promise { +): Promise { const tasks = []; for (const schema of schemas) { - tasks.push(publishSchema(schema, user, messageServer, type)); + tasks.push(publishSchema(schema, owner, messageServer, type)); + } + await Promise.all(tasks); +} + +/** + * Save schemas + * @param schemas + * @param messageServer + * @param owner + * @param notifier + */ +export async function saveSchemas( + schemas: Iterable +): Promise { + for (const schema of schemas) { + await DatabaseServer.createAndSaveSchema(schema); } - return await Promise.all(tasks); } /** diff --git a/guardian-service/src/api/policy-labels.service.ts b/guardian-service/src/api/policy-labels.service.ts index 70e88205b8..3b3f9f590a 100644 --- a/guardian-service/src/api/policy-labels.service.ts +++ b/guardian-service/src/api/policy-labels.service.ts @@ -1,8 +1,23 @@ import { ApiResponse } from './helpers/api-response.js'; -import { BinaryMessageResponse, DatabaseServer, LabelDocumentMessage, LabelMessage, MessageAction, MessageError, MessageResponse, MessageServer, PinoLogger, PolicyImportExport, PolicyLabel, PolicyLabelImportExport, Users } from '@guardian/common'; +import { + BinaryMessageResponse, + DatabaseServer, + LabelDocumentMessage, + LabelMessage, + MessageAction, + MessageError, + MessageResponse, + MessageServer, + PinoLogger, + PolicyImportExport, + PolicyLabel, + PolicyLabelImportExport, + Users, + Schema as SchemaCollection, +} from '@guardian/common'; import { EntityStatus, IOwner, LabelValidators, MessageAPI, PolicyType, Schema, SchemaStatus } from '@guardian/interfaces'; import { findRelationships, generateSchema, generateVpDocument, getOrCreateTopic, publishLabelConfig } from './helpers/policy-labels-helpers.js'; -import { publishSchema } from './helpers/index.js'; +import { publishSchemas, saveSchemas } from './helpers/index.js'; /** * Connect to the message broker methods of working with policy labels. @@ -155,9 +170,12 @@ export async function policyLabelsAPI(logger: PinoLogger): Promise { .concat(schemas, toolSchemas) .filter((s) => s.status === SchemaStatus.PUBLISHED && s.entity !== 'EVC'); + const documentsSchemas = await DatabaseServer.getSchemas({ topicId: item.topicId }); + return new MessageResponse({ policy, policySchemas: all, + documentsSchemas }); } catch (error) { await logger.error(error, ['GUARDIAN_SERVICE']); @@ -265,13 +283,13 @@ export async function policyLabelsAPI(logger: PinoLogger): Promise { messageServer.setTopicObject(topic); const schemas = await generateSchema(topic.topicId, item.config, owner); - const tasks = []; + const schemaList = new Set(); for (const { schema } of schemas) { - tasks.push(publishSchema(schema, owner, messageServer, MessageAction.PublishSchema)); + schemaList.add(schema); } - await Promise.all(tasks); + await publishSchemas(schemaList, owner, messageServer, MessageAction.PublishSchema); + await saveSchemas(schemaList); for (const { node, schema } of schemas) { - await DatabaseServer.createAndSaveSchema(schema); node.schemaId = schema.iri; } @@ -614,7 +632,6 @@ export async function policyLabelsAPI(logger: PinoLogger): Promise { const status = validator.validate(); if (!status.valid) { - console.log(JSON.stringify(status, null, 4)) return new MessageError('Invalid item.'); } diff --git a/interfaces/src/interface/policy-label.interface.ts b/interfaces/src/interface/policy-label.interface.ts index ea8bcc3a7e..8048fd505d 100644 --- a/interfaces/src/interface/policy-label.interface.ts +++ b/interfaces/src/interface/policy-label.interface.ts @@ -20,6 +20,7 @@ export interface IItemConfig { name?: string; description?: string; owner?: string; + schemaId?:string; } export interface IGroupItemConfig extends IItemConfig { @@ -36,13 +37,11 @@ export interface ILabelItemConfig extends IItemConfig { export interface IRulesItemConfig extends IItemConfig { type: NavItemType.Rules; - schemaId?:string; config?: IStatisticConfig; } export interface IStatisticItemConfig extends IItemConfig { type: NavItemType.Statistic; - schemaId?:string; messageId?: string; config?: IStatisticConfig; } @@ -73,6 +72,7 @@ export interface INavLabelImportConfig { export type INavImportsConfig = INavStatisticImportConfig | INavLabelImportConfig export interface IPolicyLabelConfig { + schemaId?:string; imports?: INavImportsConfig[]; children?: INavItemConfig[]; } diff --git a/interfaces/src/validators/label-validator/item-group-validator.ts b/interfaces/src/validators/label-validator/item-group-validator.ts index 81d7dc742f..dc4fe0a264 100644 --- a/interfaces/src/validators/label-validator/item-group-validator.ts +++ b/interfaces/src/validators/label-validator/item-group-validator.ts @@ -17,6 +17,9 @@ export class GroupItemValidator { public readonly children: IValidator[]; public readonly steps: number = 0; public readonly rule: GroupType; + public readonly schema: string; + + public isRoot: boolean; private namespace: ValidateNamespace; private scope: ValidateScore; @@ -29,8 +32,10 @@ export class GroupItemValidator { this.name = item.name || ''; this.title = item.title || ''; this.tag = item.tag || ''; + this.schema = item.schemaId || ''; this.rule = item.rule || GroupType.Every; this.children = NodeItemValidator.fromArray(item.children); + this.isRoot = false; } public get status(): boolean | undefined { @@ -106,8 +111,19 @@ export class GroupItemValidator { } } - public setResult(result: any): void { - return; + public setResult(document: any): void { + if (!document) { + this.valid = { + id: this.id, + valid: false, + error: 'Invalid document' + }; + return; + } + this.valid = { + id: this.id, + valid: !!document.status + }; } public clear(): void { @@ -115,10 +131,15 @@ export class GroupItemValidator { } public getVC(): IStepDocument | null { - return null; + return { + id: this.id, + schema: this.schema, + document: this.getResult() + }; } public setVC(vc: any): boolean { - return false; + this.setResult(vc); + return true; } } diff --git a/interfaces/src/validators/label-validator/item-label-validator.ts b/interfaces/src/validators/label-validator/item-label-validator.ts index f4d03504b0..a8a000c33f 100644 --- a/interfaces/src/validators/label-validator/item-label-validator.ts +++ b/interfaces/src/validators/label-validator/item-label-validator.ts @@ -15,6 +15,9 @@ export class LabelItemValidator { public readonly tag: string; public readonly steps: number = 0; public readonly root: GroupItemValidator; + public readonly schema: string; + + public isRoot: boolean; private namespace: ValidateNamespace; private scope: ValidateScore; @@ -32,18 +35,22 @@ export class LabelItemValidator { this.name = item.name || ''; this.title = item.title || ''; this.tag = item.tag || ''; + this.isRoot = false; const label: IPolicyLabelConfig = item.config || {}; this.imports = label.imports || []; this.children = label.children || []; + this.schema = item.schemaId || label.schemaId || ''; this.root = new GroupItemValidator({ id: item.id, type: NavItemType.Group, name: item.name, + schemaId: this.schema, rule: GroupType.Every, children: this.children }); + this.root.isRoot = true; } public get status(): boolean | undefined { @@ -93,8 +100,17 @@ export class LabelItemValidator { } } - public setResult(result: any): void { - return; + public setResult(document: any): void { + if (!document) { + this.valid = { + id: this.id, + valid: false, + error: 'Invalid document' + }; + return; + } + this.root.setResult(document); + this.valid = this.root.getStatus(); } public clear(): void { @@ -102,10 +118,15 @@ export class LabelItemValidator { } public getVC(): IStepDocument | null { - return null; + return { + id: this.id, + schema: this.schema, + document: this.getResult() + }; } public setVC(vc: any): boolean { - return false; + this.setResult(vc); + return true; } } diff --git a/interfaces/src/validators/label-validator/item-node-validator.ts b/interfaces/src/validators/label-validator/item-node-validator.ts index ce62c3252b..1963cdb257 100644 --- a/interfaces/src/validators/label-validator/item-node-validator.ts +++ b/interfaces/src/validators/label-validator/item-node-validator.ts @@ -19,6 +19,7 @@ export class NodeItemValidator { public readonly title: string; public readonly tag: string; public readonly steps: number = 0; + public readonly isRoot: boolean = false; private namespace: ValidateNamespace; private scope: ValidateScore; diff --git a/interfaces/src/validators/label-validator/item-rule-validator.ts b/interfaces/src/validators/label-validator/item-rule-validator.ts index 90b1dd144a..74a6f677e7 100644 --- a/interfaces/src/validators/label-validator/item-rule-validator.ts +++ b/interfaces/src/validators/label-validator/item-rule-validator.ts @@ -21,6 +21,7 @@ export class RuleItemValidator { public readonly tag: string; public readonly steps: number = 3; public readonly schema: string; + public readonly isRoot: boolean = false; private namespace: ValidateNamespace; private scope: ValidateScore; @@ -300,7 +301,9 @@ export class RuleItemValidator { } public getResult(): any { - const document: any = {}; + const document: any = { + status: this.status + }; for (const field of this.variables) { if (field.value !== undefined) { document[field.id] = field.getValue(); @@ -316,6 +319,14 @@ export class RuleItemValidator { } public setResult(document: any): void { + if(!document) { + this.valid = { + id: this.id, + valid: false, + error: 'Invalid document' + }; + return; + } for (const field of this.variables) { field.setValue(document[field.id]); } @@ -325,6 +336,10 @@ export class RuleItemValidator { for (const formula of this.formulas) { formula.setValue(document[formula.id]); } + this.valid = { + id: this.id, + valid: !!document.status + }; } public clear(): void { diff --git a/interfaces/src/validators/label-validator/item-statistic-validator.ts b/interfaces/src/validators/label-validator/item-statistic-validator.ts index fcc1e86bb0..d79f860341 100644 --- a/interfaces/src/validators/label-validator/item-statistic-validator.ts +++ b/interfaces/src/validators/label-validator/item-statistic-validator.ts @@ -19,6 +19,7 @@ export class StatisticItemValidator { public readonly tag: string; public readonly steps: number = 3; public readonly schema: string; + public readonly isRoot: boolean = false; private namespace: ValidateNamespace; private scope: ValidateScore; @@ -297,6 +298,14 @@ export class StatisticItemValidator { } public setResult(document: any): void { + if (!document) { + this.valid = { + id: this.id, + valid: false, + error: 'Invalid document' + }; + return; + } for (const field of this.variables) { field.setValue(document[field.id]); } @@ -306,6 +315,10 @@ export class StatisticItemValidator { for (const formula of this.formulas) { formula.setValue(document[formula.id]); } + this.valid = { + id: this.id, + valid: true, + }; } public clear(): void { diff --git a/interfaces/src/validators/label-validator/label-validator.ts b/interfaces/src/validators/label-validator/label-validator.ts index 468f80ce30..2e6cf78e15 100644 --- a/interfaces/src/validators/label-validator/label-validator.ts +++ b/interfaces/src/validators/label-validator/label-validator.ts @@ -31,6 +31,7 @@ export class LabelValidators { title: label.name, config }); + this.root.isRoot = true; this.tree = this.createTree(this.root); this.steps = this.createSteps(this.root, []); this.list = this.createList(this.root, []); @@ -96,6 +97,9 @@ export class LabelValidators { } private addDocument(node: IValidator, result: IValidatorStep[]): IValidatorStep[] { + if (node.isRoot) { + return result; + } const steps = node.getSteps(); steps.unshift(steps.pop()); for (const step of steps) {