diff --git a/frontend/src/app/modules/analytics/compare-policy/compare-policy.component.ts b/frontend/src/app/modules/analytics/compare-policy/compare-policy.component.ts index d370144a32..382064f0d2 100644 --- a/frontend/src/app/modules/analytics/compare-policy/compare-policy.component.ts +++ b/frontend/src/app/modules/analytics/compare-policy/compare-policy.component.ts @@ -48,6 +48,7 @@ export class ComparePolicyComponent implements OnInit { "aggregateDocumentBlock": "calendar_month", "reassigningBlock": "content_copy", "revokeBlock": "restart_alt", + "revocationBlock": "restart_alt", "setRelationshipsBlock": "settings", "splitBlock": "content_cut", "filtersAddon": "filter_alt", diff --git a/frontend/src/app/modules/policy-engine/policy-configuration/common-properties/common-properties.component.html b/frontend/src/app/modules/policy-engine/policy-configuration/common-properties/common-properties.component.html index 628e80d74c..00ca665b31 100644 --- a/frontend/src/app/modules/policy-engine/policy-configuration/common-properties/common-properties.component.html +++ b/frontend/src/app/modules/policy-engine/policy-configuration/common-properties/common-properties.component.html @@ -63,6 +63,13 @@ {{about.children}} + + + Deprecated + + {{about.deprecated?'Yes':'No'}} + + @@ -169,11 +176,11 @@
diff --git a/frontend/src/app/modules/policy-engine/policy-configuration/policy-configuration/policy-configuration.component.ts b/frontend/src/app/modules/policy-engine/policy-configuration/policy-configuration/policy-configuration.component.ts index bc53b11756..f7060a6ce5 100644 --- a/frontend/src/app/modules/policy-engine/policy-configuration/policy-configuration/policy-configuration.component.ts +++ b/frontend/src/app/modules/policy-engine/policy-configuration/policy-configuration/policy-configuration.component.ts @@ -479,7 +479,10 @@ export class PolicyConfigurationComponent implements OnInit { this.componentsList.unGrouped = []; const search = this.search ? this.search.toLowerCase() : null; for (const block of all) { - if (search && block.search.indexOf(search) === -1) { + if ( + (search && block.search.indexOf(search) === -1) || + block?.deprecated + ) { continue; } if (block.header === 'UI Components') { diff --git a/frontend/src/app/modules/policy-engine/policy-configuration/policy-tree/policy-tree.component.css b/frontend/src/app/modules/policy-engine/policy-configuration/policy-tree/policy-tree.component.css index 98e8e80568..0917757c0a 100644 --- a/frontend/src/app/modules/policy-engine/policy-configuration/policy-tree/policy-tree.component.css +++ b/frontend/src/app/modules/policy-engine/policy-configuration/policy-tree/policy-tree.component.css @@ -455,6 +455,23 @@ grid-template-columns: auto 1px !important; } +.block-container[deprecated="true"] .block-item { + background-color: lightgray !important; + border-color: lightgray !important; +} + +.block-container[deprecated="true"] .block-item::after { + content: ""; + width: 110%; + height: 3px; + background-color: black; + position: absolute; + left: -5%; +} + +.block-container[selected="true"][deprecated="true"] .block-item { + border-color: #5161e1 !important; +} .cdk-drag-animating { transition: transform 50ms cubic-bezier(0, 0, 0.2, 1); diff --git a/frontend/src/app/modules/policy-engine/policy-configuration/policy-tree/policy-tree.component.html b/frontend/src/app/modules/policy-engine/policy-configuration/policy-tree/policy-tree.component.html index d15020c441..6c4730d866 100644 --- a/frontend/src/app/modules/policy-engine/policy-configuration/policy-tree/policy-tree.component.html +++ b/frontend/src/app/modules/policy-engine/policy-configuration/policy-tree/policy-tree.component.html @@ -15,7 +15,7 @@ [attr.collapsed]="item.collapsed" [attr.selected]="isSelect(item)" [attr.error]="item.error" [attr.root]="item.root" [attr.block-id]="item.id" [attr.block-instance]="item.node.tag" [attr.block-type]="item.type" [style.paddingLeft]="item.offset" cdkDrag [cdkDragData]="item.level" - [cdkDragDisabled]="item.root"> + [cdkDragDisabled]="item.root" [attr.deprecated]="item.deprecated">
arrow_drop_down
diff --git a/frontend/src/app/modules/policy-engine/policy-configuration/policy-tree/policy-tree.component.ts b/frontend/src/app/modules/policy-engine/policy-configuration/policy-tree/policy-tree.component.ts index c8af82de9f..543c260282 100644 --- a/frontend/src/app/modules/policy-engine/policy-configuration/policy-tree/policy-tree.component.ts +++ b/frontend/src/app/modules/policy-engine/policy-configuration/policy-tree/policy-tree.component.ts @@ -220,6 +220,7 @@ export class PolicyTreeComponent implements OnInit { node.level = level; node.root = block === this.root; node.expandable = block.expandable && !node.root; + node.deprecated = this.registeredService.getDeprecated(block.blockType); node.about = this.registeredService.getAbout(block, this.module); node.icon = this.registeredService.getIcon(block.blockType); node.type = this.registeredService.getHeader(block.blockType); diff --git a/frontend/src/app/modules/policy-engine/services/blocks-information.ts b/frontend/src/app/modules/policy-engine/services/blocks-information.ts index 0f09a517ec..ad2ae8a9ec 100644 --- a/frontend/src/app/modules/policy-engine/services/blocks-information.ts +++ b/frontend/src/app/modules/policy-engine/services/blocks-information.ts @@ -82,6 +82,7 @@ const Container: IBlockSetting = { { type: BlockType.CustomLogicBlock }, { type: BlockType.Report }, { type: BlockType.RevokeBlock }, + { type: BlockType.RevocationBlock }, { type: BlockType.SetRelationshipsBlock }, { type: BlockType.ButtonBlock }, { type: BlockType.TokenActionBlock }, @@ -124,6 +125,7 @@ const Step: IBlockSetting = { { type: BlockType.CustomLogicBlock }, { type: BlockType.Report }, { type: BlockType.RevokeBlock }, + { type: BlockType.RevocationBlock }, { type: BlockType.SetRelationshipsBlock }, { type: BlockType.ButtonBlock }, { type: BlockType.TokenActionBlock }, @@ -378,6 +380,15 @@ const RevokeBlock: IBlockSetting = { property: RevokeConfigComponent, } +const RevocationBlock: IBlockSetting = { + type: BlockType.RevocationBlock, + icon: 'restart_alt', + group: BlockGroup.Documents, + header: BlockHeaders.ServerBlocks, + factory: null, + property: null, +} + const SetRelationshipsBlock: IBlockSetting = { type: BlockType.SetRelationshipsBlock, icon: 'settings', @@ -625,6 +636,7 @@ export default [ AggregateDocument, ReassigningBlock, RevokeBlock, + RevocationBlock, SetRelationshipsBlock, SplitBlock, FiltersAddon, diff --git a/frontend/src/app/modules/policy-engine/services/module-information.ts b/frontend/src/app/modules/policy-engine/services/module-information.ts index c39f5dd42b..39a9e5ec61 100644 --- a/frontend/src/app/modules/policy-engine/services/module-information.ts +++ b/frontend/src/app/modules/policy-engine/services/module-information.ts @@ -43,6 +43,7 @@ const Module: IBlockSetting = { { type: BlockType.CustomLogicBlock }, { type: BlockType.Report }, { type: BlockType.RevokeBlock }, + { type: BlockType.RevocationBlock }, { type: BlockType.SetRelationshipsBlock }, { type: BlockType.ButtonBlock }, { type: BlockType.TokenActionBlock }, diff --git a/frontend/src/app/modules/policy-engine/services/registered.service.ts b/frontend/src/app/modules/policy-engine/services/registered.service.ts index 2fbbafa5f4..657e414a77 100644 --- a/frontend/src/app/modules/policy-engine/services/registered.service.ts +++ b/frontend/src/app/modules/policy-engine/services/registered.service.ts @@ -19,6 +19,7 @@ export class RegisteredService { private blockName: { [type: string]: string }; private blockTitle: { [type: string]: string }; + private blockDeprecation: { [type: string]: boolean }; private blockAbout: { [type: string]: BlockAbout }; private blockProperties: { [type: string]: BlockAbout }; @@ -38,6 +39,7 @@ export class RegisteredService { this.blockTitle = {}; this.blockAbout = {}; this.blockProperties = {}; + this.blockDeprecation = {}; this.defaultAbout = new BlockAbout({ post: false, get: false, @@ -45,7 +47,8 @@ export class RegisteredService { output: null, children: ChildrenType.None, control: ControlType.None, - defaultEvent: false + defaultEvent: false, + deprecated: false, }) for (const config of blocks) { @@ -103,6 +106,7 @@ export class RegisteredService { this.blockTitle[type] = setting.title; this.blockAbout[type] = new BlockAbout(setting, this.about[type]); this.blockProperties[type] = setting.properties; + this.blockDeprecation[type] = !!setting.deprecated; } this.update(); } @@ -119,7 +123,8 @@ export class RegisteredService { group: this.group[type], header: this.header[type], title: this.blockTitle[type], - data: `new:${type}` + data: `new:${type}`, + deprecated: this.blockDeprecation[type], }); } this.list = this.list.sort((a, b) => a.name > b.name ? 1 : -1); @@ -181,4 +186,8 @@ export class RegisteredService { public getHeader(blockType: string): string { return this.header[blockType] || ''; } -} + + public getDeprecated(blockType: string): boolean { + return this.blockDeprecation[blockType]; + } + } diff --git a/frontend/src/app/modules/policy-engine/structures/interfaces/block-about-config.interface.ts b/frontend/src/app/modules/policy-engine/structures/interfaces/block-about-config.interface.ts index 6972e856fd..7425d0aa5c 100644 --- a/frontend/src/app/modules/policy-engine/structures/interfaces/block-about-config.interface.ts +++ b/frontend/src/app/modules/policy-engine/structures/interfaces/block-about-config.interface.ts @@ -9,4 +9,5 @@ export interface IBlockAboutConfig { children: ChildrenType; control: ControlType; defaultEvent: boolean; + deprecated?: boolean; } diff --git a/frontend/src/app/modules/policy-engine/structures/interfaces/block-about.interface.ts b/frontend/src/app/modules/policy-engine/structures/interfaces/block-about.interface.ts index 603bd52ef8..d6447ace7d 100644 --- a/frontend/src/app/modules/policy-engine/structures/interfaces/block-about.interface.ts +++ b/frontend/src/app/modules/policy-engine/structures/interfaces/block-about.interface.ts @@ -11,4 +11,5 @@ export interface IBlockAbout { defaultEvent: boolean; prev?: IBlockAbout; next?: boolean; + deprecated?: boolean; } diff --git a/frontend/src/app/modules/policy-engine/structures/interfaces/block-dynamic-about-config.interface.ts b/frontend/src/app/modules/policy-engine/structures/interfaces/block-dynamic-about-config.interface.ts index d17bd066ac..0898109522 100644 --- a/frontend/src/app/modules/policy-engine/structures/interfaces/block-dynamic-about-config.interface.ts +++ b/frontend/src/app/modules/policy-engine/structures/interfaces/block-dynamic-about-config.interface.ts @@ -14,4 +14,5 @@ export interface IBlockDynamicAboutConfig { children?: ConfigFunction; control?: ConfigFunction; defaultEvent?: ConfigFunction; + deprecated?: ConfigFunction; } diff --git a/frontend/src/app/modules/policy-engine/structures/policy-models/block-about.ts b/frontend/src/app/modules/policy-engine/structures/policy-models/block-about.ts index fabc5ebdbb..9d14971731 100644 --- a/frontend/src/app/modules/policy-engine/structures/policy-models/block-about.ts +++ b/frontend/src/app/modules/policy-engine/structures/policy-models/block-about.ts @@ -34,6 +34,7 @@ export class BlockAbout { this._setProp(about, dynamic, 'children'); this._setProp(about, dynamic, 'control'); this._setProp(about, dynamic, 'defaultEvent'); + this._setProp(about, dynamic, 'deprecated'); } public getAbout( @@ -48,6 +49,7 @@ export class BlockAbout { children: this._propFunc.children(this._propVal.children, block, module), control: this._propFunc.control(this._propVal.control, block, module), defaultEvent: this._propFunc.defaultEvent(this._propVal.defaultEvent, block, module), + deprecated: this._propFunc.deprecated(this._propVal.deprecated, block, module), }; } @@ -81,6 +83,9 @@ export class BlockAbout { get defaultEvent() { return this._func.defaultEvent(this._val.defaultEvent, this._block, this._module); }, + get deprecated() { + return this._func.defaultEvent(this._val.deprecated, this._block, this._module); + }, set module(value: PolicyModel | PolicyModuleModel) { this._module = value; }, diff --git a/frontend/src/app/modules/policy-engine/structures/tree-model/block-node.ts b/frontend/src/app/modules/policy-engine/structures/tree-model/block-node.ts index 77759a5626..711763b09f 100644 --- a/frontend/src/app/modules/policy-engine/structures/tree-model/block-node.ts +++ b/frontend/src/app/modules/policy-engine/structures/tree-model/block-node.ts @@ -18,6 +18,7 @@ export class FlatBlockNode { public parentNode!: FlatBlockNode; public data!: any; public error!: boolean; + public deprecated!: boolean; constructor(node: PolicyBlockModel) { this.node = node; diff --git a/frontend/src/app/modules/policy-engine/themes/default.ts b/frontend/src/app/modules/policy-engine/themes/default.ts index 281b32be67..5e0a787faf 100644 --- a/frontend/src/app/modules/policy-engine/themes/default.ts +++ b/frontend/src/app/modules/policy-engine/themes/default.ts @@ -48,6 +48,7 @@ export const defaultTheme = { 'reassigningBlock', 'httpRequestBlock', 'revokeBlock', + 'revocationBlock', 'sendToGuardianBlock', 'setRelationshipsBlock', 'splitBlock', diff --git a/guardian-service/src/policy-engine/block-about.ts b/guardian-service/src/policy-engine/block-about.ts index 893b7ebbf8..63e2890945 100644 --- a/guardian-service/src/policy-engine/block-about.ts +++ b/guardian-service/src/policy-engine/block-about.ts @@ -494,6 +494,23 @@ export const BlockAbout = { 'revokeBlock': { 'label': 'Revoke Document', 'title': 'Add \'Revoke\' Block', + 'post': true, + 'get': true, + 'children': 'None', + 'control': 'Server', + 'input': [ + 'RunEvent' + ], + 'output': [ + 'RunEvent', + 'ErrorEvent' + ], + 'defaultEvent': true, + 'deprecated': true, + }, + 'revocationBlock': { + 'label': 'Revocation', + 'title': 'Add \'Revocation\' Block', 'post': false, 'get': false, 'children': 'None', @@ -505,7 +522,23 @@ export const BlockAbout = { 'RunEvent', 'ErrorEvent' ], - 'defaultEvent': true + 'defaultEvent': true, + 'properties': [ + { + 'name': 'updatePrevDoc', + 'label': 'Update previous document status', + 'title': 'Update previous document status', + 'type': 'Checkbox', + 'default': false + }, + { + 'name': 'prevDocStatus', + 'label': 'Status value', + 'title': 'Status value', + 'type': 'Input', + 'default': '' + }, + ], }, 'setRelationshipsBlock': { 'label': 'Set Relationships', diff --git a/guardian-service/src/policy-engine/block-validators/block-validator.ts b/guardian-service/src/policy-engine/block-validators/block-validator.ts index d019ff5db1..a418bfaa28 100644 --- a/guardian-service/src/policy-engine/block-validators/block-validator.ts +++ b/guardian-service/src/policy-engine/block-validators/block-validator.ts @@ -31,6 +31,7 @@ import { ReportItemBlock } from './blocks/report-item-block'; import { RequestVcDocumentBlock } from './blocks/request-vc-document-block'; import { RetirementBlock } from './blocks/retirement-block'; import { RevokeBlock } from './blocks/revoke-block'; +import { RevocationBlock } from './blocks/revocation-block'; import { SelectiveAttributes } from './blocks/selective-attributes-addon'; import { SendToGuardianBlock } from './blocks/send-to-guardian-block'; import { SetRelationshipsBlock } from './blocks/set-relationships-block'; @@ -75,6 +76,7 @@ export const validators = [ RequestVcDocumentBlock, RetirementBlock, RevokeBlock, + RevocationBlock, SelectiveAttributes, SendToGuardianBlock, SetRelationshipsBlock, diff --git a/guardian-service/src/policy-engine/block-validators/blocks/revocation-block.ts b/guardian-service/src/policy-engine/block-validators/blocks/revocation-block.ts new file mode 100644 index 0000000000..28a0cefb94 --- /dev/null +++ b/guardian-service/src/policy-engine/block-validators/blocks/revocation-block.ts @@ -0,0 +1,31 @@ +import { BlockValidator, IBlockProp } from '@policy-engine/block-validators'; + +/** + * Revoke document action with UI + */ +export class RevocationBlock { + /** + * Block type + */ + public static readonly blockType: string = 'revocationBlock'; + + /** + * Validate block options + * @param validator + * @param config + */ + public static async validate( + validator: BlockValidator, + ref: IBlockProp + ): Promise { + try { + if (ref.options.updatePrevDoc && !ref.options.prevDocStatus) { + validator.addError('Option "Status Value" is not set'); + } + } catch (error) { + validator.addError( + `Unhandled exception ${validator.getErrorMessage(error)}` + ); + } + } +} diff --git a/guardian-service/src/policy-engine/policy-converter-utils.ts b/guardian-service/src/policy-engine/policy-converter-utils.ts index 9b4dcb35de..cff57e20c9 100644 --- a/guardian-service/src/policy-engine/policy-converter-utils.ts +++ b/guardian-service/src/policy-engine/policy-converter-utils.ts @@ -1,6 +1,6 @@ import { Policy } from '@guardian/common'; -import { GenerateUUIDv4, UserType } from '@guardian/interfaces'; -import { EventActor, EventConfig, PolicyInputEventType, PolicyOutputEventType } from './interfaces'; +import { BlockType, GenerateUUIDv4, UserType } from '@guardian/interfaces'; +import { EventConfig, PolicyInputEventType, PolicyOutputEventType, EventActor } from './interfaces'; /** * Policy converter utils @@ -390,7 +390,7 @@ export class PolicyConverterUtils { const currentBlock = stack.pop(); if ( currentBlock?.blockType === - 'interfaceDocumentsSourceBlock' && + BlockType.DocumentsViewer && Array.isArray(currentBlock.uiMetaData?.fields) ) { currentBlock.uiMetaData.fields = @@ -404,6 +404,10 @@ export class PolicyConverterUtils { } }; clearOldRevokeColumns(root, block.tag); + block.blockType = BlockType.RevocationBlock; + block.updatePrevDoc = block.uiMetaData.updatePrevDoc; + block.prevDocStatus = block.uiMetaData.prevDocStatus; + delete block.uiMetaData; return block; } } diff --git a/interfaces/src/type/block.type.ts b/interfaces/src/type/block.type.ts index 2f3aff3394..dbc005e50f 100644 --- a/interfaces/src/type/block.type.ts +++ b/interfaces/src/type/block.type.ts @@ -27,6 +27,7 @@ export enum BlockType { CustomLogicBlock = 'customLogicBlock', Switch = 'switchBlock', RevokeBlock = 'revokeBlock', + RevocationBlock = 'revocationBlock', SetRelationshipsBlock = 'setRelationshipsBlock', ButtonBlock = 'buttonBlock', TokenActionBlock = 'tokenActionBlock', diff --git a/policy-service/src/policy-engine/block-tree-generator.ts b/policy-service/src/policy-engine/block-tree-generator.ts index fb6aae33a1..b16699fc20 100644 --- a/policy-service/src/policy-engine/block-tree-generator.ts +++ b/policy-service/src/policy-engine/block-tree-generator.ts @@ -179,6 +179,11 @@ export class BlockTreeGenerator extends NatsService { const block = PolicyComponentsUtils.GetBlockByTag(policyId, tag); if (block && (await block.isAvailable(userFull))) { + if (typeof block.getData !== 'function') { + throw new Error( + 'Block is not supporting get data functions' + ); + } const data = await block.getData(userFull, block.uuid, null); return new MessageResponse(data); } else { @@ -194,6 +199,11 @@ export class BlockTreeGenerator extends NatsService { const block = PolicyComponentsUtils.GetBlockByUUID(blockId); if (block && (await block.isAvailable(userFull))) { + if (typeof block.setData !== 'function') { + throw new Error( + 'Block is not supporting set data functions' + ); + } const result = await block.setData(userFull, data); return new MessageResponse(result); } else { diff --git a/policy-service/src/policy-engine/block-validators/block-validator.ts b/policy-service/src/policy-engine/block-validators/block-validator.ts index d019ff5db1..a418bfaa28 100644 --- a/policy-service/src/policy-engine/block-validators/block-validator.ts +++ b/policy-service/src/policy-engine/block-validators/block-validator.ts @@ -31,6 +31,7 @@ import { ReportItemBlock } from './blocks/report-item-block'; import { RequestVcDocumentBlock } from './blocks/request-vc-document-block'; import { RetirementBlock } from './blocks/retirement-block'; import { RevokeBlock } from './blocks/revoke-block'; +import { RevocationBlock } from './blocks/revocation-block'; import { SelectiveAttributes } from './blocks/selective-attributes-addon'; import { SendToGuardianBlock } from './blocks/send-to-guardian-block'; import { SetRelationshipsBlock } from './blocks/set-relationships-block'; @@ -75,6 +76,7 @@ export const validators = [ RequestVcDocumentBlock, RetirementBlock, RevokeBlock, + RevocationBlock, SelectiveAttributes, SendToGuardianBlock, SetRelationshipsBlock, diff --git a/policy-service/src/policy-engine/block-validators/blocks/revocation-block.ts b/policy-service/src/policy-engine/block-validators/blocks/revocation-block.ts new file mode 100644 index 0000000000..28a0cefb94 --- /dev/null +++ b/policy-service/src/policy-engine/block-validators/blocks/revocation-block.ts @@ -0,0 +1,31 @@ +import { BlockValidator, IBlockProp } from '@policy-engine/block-validators'; + +/** + * Revoke document action with UI + */ +export class RevocationBlock { + /** + * Block type + */ + public static readonly blockType: string = 'revocationBlock'; + + /** + * Validate block options + * @param validator + * @param config + */ + public static async validate( + validator: BlockValidator, + ref: IBlockProp + ): Promise { + try { + if (ref.options.updatePrevDoc && !ref.options.prevDocStatus) { + validator.addError('Option "Status Value" is not set'); + } + } catch (error) { + validator.addError( + `Unhandled exception ${validator.getErrorMessage(error)}` + ); + } + } +} diff --git a/policy-service/src/policy-engine/blocks/index.ts b/policy-service/src/policy-engine/blocks/index.ts index 3c37a8f89d..7f723692f4 100644 --- a/policy-service/src/policy-engine/blocks/index.ts +++ b/policy-service/src/policy-engine/blocks/index.ts @@ -24,6 +24,7 @@ export { SendToGuardianBlock } from './send-to-guardian-block'; export { SwitchBlock } from './switch-block'; export { TimerBlock } from './timer-block'; export { RevokeBlock } from './revoke-block'; +export { RevocationBlock } from './revocation-block'; export { SetRelationshipsBlock } from './set-relationships-block'; export { ButtonBlock } from './button-block'; export { TokenActionBlock } from './token-action-block'; diff --git a/policy-service/src/policy-engine/blocks/revocation-block.ts b/policy-service/src/policy-engine/blocks/revocation-block.ts new file mode 100644 index 0000000000..ff5dd4bbd6 --- /dev/null +++ b/policy-service/src/policy-engine/blocks/revocation-block.ts @@ -0,0 +1,272 @@ +import { ActionCallback, BasicBlock } from '@policy-engine/helpers/decorators'; +import { PolicyComponentsUtils } from '@policy-engine/policy-components-utils'; +import { + AnyBlockType, + IPolicyEventState, + IPolicyInterfaceBlock, +} from '@policy-engine/policy-engine.interface'; +import { Message, MessageServer } from '@guardian/common'; +import { PolicyUtils } from '@policy-engine/helpers/utils'; +import { + IPolicyEvent, + PolicyInputEventType, + PolicyOutputEventType, +} from '@policy-engine/interfaces'; +import { + ChildrenType, + ControlType, + PropertyType, +} from '@policy-engine/interfaces/block-about'; +import { CatchErrors } from '@policy-engine/helpers/decorators/catch-errors'; +import { + ExternalDocuments, + ExternalEvent, + ExternalEventType, +} from '@policy-engine/interfaces/external-event'; + +export const RevokedStatus = 'Revoked'; + +/** + * Revocation block + */ +@BasicBlock({ + blockType: 'revocationBlock', + about: { + label: 'Revocation', + title: `Add 'Revocation' Block`, + post: false, + get: false, + children: ChildrenType.None, + control: ControlType.Server, + input: [PolicyInputEventType.RunEvent], + output: [ + PolicyOutputEventType.RunEvent, + PolicyOutputEventType.ErrorEvent, + ], + defaultEvent: true, + properties: [ + { + name: 'updatePrevDoc', + label: 'Update previous document status', + title: 'Update previous document status', + type: PropertyType.Checkbox, + default: false, + }, + { + name: 'prevDocStatus', + label: 'Status value', + title: 'Status value', + type: PropertyType.Input, + default: '', + }, + ], + }, +}) +export class RevocationBlock { + /** + * Send to hedera + * @param message + * @param messageServer + * @param ref + * @param revokeMessage + * @param parentId + */ + async sendToHedera( + message: Message, + messageServer: MessageServer, + ref: AnyBlockType, + revokeMessage: string, + parentId?: string[] + ) { + const topic = await PolicyUtils.getPolicyTopic(ref, message.topicId); + message.revoke(revokeMessage, parentId); + await messageServer.setTopicObject(topic).sendMessage(message, false); + } + + /** + * Find related message Ids + * @param topicMessage + * @param topicMessages + * @param relatedMessageIds + * @param parentId + */ + async findRelatedMessageIds( + topicMessage: any, + topicMessages: any[], + relatedMessageIds: any[] = [], + parentId?: string + ): Promise { + if (!topicMessage) { + throw new Error('Topic message to find related messages is empty'); + } + const relatedMessages = topicMessages.filter( + (message: any) => + message.relationships && + message.relationships.includes(topicMessage.id) + ); + for (const relatedMessage of relatedMessages) { + await this.findRelatedMessageIds( + relatedMessage, + topicMessages, + relatedMessageIds, + topicMessage.id + ); + } + const relatedMessageId = relatedMessageIds.find( + (item) => item.id === topicMessage.id + ); + if (!relatedMessageId) { + relatedMessageIds.push({ + parentIds: parentId ? [parentId] : undefined, + id: topicMessage.id, + }); + } else if ( + relatedMessageId.parentIds && + !relatedMessageId.parentIds.includes(parentId) + ) { + relatedMessageId.parentIds.push(parentId); + } + return relatedMessageIds; + } + + /** + * Find document by message ids + * @param messageIds + */ + async findDocumentByMessageIds(messageIds: string[]): Promise { + const ref = + PolicyComponentsUtils.GetBlockRef(this); + const filters: any = { + messageId: { $in: messageIds }, + }; + const otherOptions = { + orderBy: { + messageId: 'ASC', + }, + }; + const vcDocuments: any[] = (await ref.databaseServer.getVcDocuments( + filters, + otherOptions + )) as any[]; + const vpDocuments: any[] = (await ref.databaseServer.getVpDocuments( + filters, + otherOptions + )) as any[]; + const didDocuments: any[] = (await ref.databaseServer.getDidDocuments( + filters, + otherOptions + )) as any[]; + return vcDocuments.concat(vpDocuments).concat(didDocuments); + } + + /** + * Run block action + * @param event + */ + @ActionCallback({ + output: [ + PolicyOutputEventType.RunEvent, + PolicyOutputEventType.ErrorEvent, + ], + }) + @CatchErrors() + async runAction(event: IPolicyEvent): Promise { + const ref = + PolicyComponentsUtils.GetBlockRef(this); + const data = event.data.data; + const doc = Array.isArray(data) ? data[0] : data; + + const hederaAccount = await PolicyUtils.getHederaAccount( + ref, + event.user.did + ); + const messageServer = new MessageServer( + hederaAccount.hederaAccountId, + hederaAccount.hederaAccountKey, + ref.dryRun + ); + const policyTopics = await ref.databaseServer.getTopics({ + policyId: ref.policyId, + }); + + const policyTopicsMessages = []; + for (const topic of policyTopics) { + const topicMessages = await messageServer.getMessages( + topic.topicId + ); + policyTopicsMessages.push(...topicMessages); + } + const messagesToFind = policyTopicsMessages.filter( + (item) => !item.isRevoked() + ); + + const topicMessage = policyTopicsMessages.find( + (item) => item.id === doc.messageId + ); + + const relatedMessages = await this.findRelatedMessageIds( + topicMessage, + messagesToFind + ); + for (const policyTopicMessage of policyTopicsMessages) { + const relatedMessage = relatedMessages.find( + (item) => item.id === policyTopicMessage.id + ); + if (relatedMessage) { + await this.sendToHedera( + policyTopicMessage, + messageServer, + ref, + doc.comment, + relatedMessage.parentIds + ); + } + } + + const documents = await this.findDocumentByMessageIds( + relatedMessages.map((item) => item.id) + ); + for (const item of documents) { + item.option = item.option || {}; + item.option.status = RevokedStatus; + item.comment = doc.option.comment; + if (Array.isArray(item.comment)) { + item.comment = item.comment[item.comment.length - 1]; + } + if (item.option.comment) { + if (Array.isArray(item.option.comment)) { + item.option.comment.push(item.comment); + } + } else { + item.option.comment = [item.comment]; + } + } + + if (ref.options.updatePrevDoc && doc.relationships) { + const prevDocs = await this.findDocumentByMessageIds( + doc.relationships + ); + const prevDocument = prevDocs[prevDocs.length - 1]; + if (prevDocument) { + prevDocument.option.status = ref.options.prevDocStatus; + await ref.databaseServer.updateVC(prevDocument); + await ref.databaseServer.saveDocumentState({ + documentId: prevDocument.id, + document: prevDocument, + }); + } + } + + const state: IPolicyEventState = { + data: documents, + }; + ref.triggerEvents(PolicyOutputEventType.RunEvent, event.user, state); + ref.triggerEvents(PolicyOutputEventType.ReleaseEvent, event.user, null); + + PolicyComponentsUtils.ExternalEventFn( + new ExternalEvent(ExternalEventType.Run, ref, event?.user, { + documents: ExternalDocuments(documents), + }) + ); + } +} diff --git a/policy-service/src/policy-engine/blocks/revoke-block.ts b/policy-service/src/policy-engine/blocks/revoke-block.ts index 68bb031ff6..b89f6b24b5 100644 --- a/policy-service/src/policy-engine/blocks/revoke-block.ts +++ b/policy-service/src/policy-engine/blocks/revoke-block.ts @@ -1,4 +1,4 @@ -import { ActionCallback, BasicBlock } from '@policy-engine/helpers/decorators'; +import { ActionCallback, EventBlock } from '@policy-engine/helpers/decorators'; import { PolicyComponentsUtils } from '@policy-engine/policy-components-utils'; import { AnyBlockType, IPolicyEventState, IPolicyInterfaceBlock } from '@policy-engine/policy-engine.interface'; import { Message, MessageServer } from '@guardian/common'; @@ -13,13 +13,13 @@ export const RevokedStatus = 'Revoked'; /** * Revoke document action with UI */ -@BasicBlock({ +@EventBlock({ blockType: 'revokeBlock', about: { label: 'Revoke Document', title: `Add 'Revoke' Block`, - post: false, - get: false, + post: true, + get: true, children: ChildrenType.None, control: ControlType.Server, input: [ diff --git a/policy-service/src/policy-engine/helpers/decorators/basic-block.ts b/policy-service/src/policy-engine/helpers/decorators/basic-block.ts index 9ebb7dcdfb..40a6e26cb1 100644 --- a/policy-service/src/policy-engine/helpers/decorators/basic-block.ts +++ b/policy-service/src/policy-engine/helpers/decorators/basic-block.ts @@ -248,28 +248,6 @@ export function BasicBlock(options: Partial) { } } - /** - * Get block data - * @param args - */ - async getData(...args) { - if (typeof super.getData === 'function') { - return await super.getData(...args); - } - return {}; - } - - /** - * Set block data - * @param args - */ - async setData(...args) { - if (typeof super.getData === 'function') { - return await super.setData(...args); - } - return {}; - } - /** * Get child by UUID * @param uuid