[ACS-3217] initial project scaffold for the Folder Rules (#2566)

* initial project scaffold

* visibility rules placeholders

* custom scope for rules evaluators

* unit tests and minor improvements

* update e2e

* add write permission check

* update e2e

* update e2e

* enable the env variable

* fix tests

* update e2e

* fix e2e
This commit is contained in:
Denys Vuika 2022-07-08 10:53:53 +01:00 committed by GitHub
parent 838f5f2ec2
commit 8312bf8d84
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 644 additions and 2 deletions

View File

@ -34,6 +34,7 @@ ENV APP_CONFIG_OAUTH2_REDIRECT_SILENT_IFRAME_URI="{protocol}//{hostname}{:port}/
ENV APP_CONFIG_OAUTH2_REDIRECT_LOGIN="/"
ENV APP_CONFIG_OAUTH2_REDIRECT_LOGOUT="/"
ENV APP_CONFIG_PLUGIN_AOS=true
ENV APP_CONFIG_PLUGIN_FOLDER_RULES=true
ENV APP_CONFIG_PLUGIN_CONTENT_SERVICE=true
COPY docker/default.conf.template /etc/nginx/templates/

View File

@ -89,6 +89,16 @@
"glob": "settings.plugin.json",
"input": "projects/aca-settings/assets",
"output": "./assets/plugins"
},
{
"glob": "folder-rules.plugin.json",
"input": "projects/aca-folder-rules/assets",
"output": "./assets/plugins"
},
{
"glob": "**/*",
"input": "projects/aca-folder-rules/assets",
"output": "./assets/aca-folder-rules"
}
],
"styles": [
@ -484,6 +494,46 @@
}
}
}
},
"aca-folder-rules": {
"projectType": "library",
"root": "projects/aca-folder-rules",
"sourceRoot": "projects/aca-folder-rules/src",
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"tsConfig": "projects/aca-folder-rules/tsconfig.lib.json",
"project": "projects/aca-folder-rules/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "projects/aca-folder-rules/tsconfig.lib.prod.json"
}
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "projects/aca-folder-rules/src/test.ts",
"tsConfig": "projects/aca-folder-rules/tsconfig.spec.json",
"karmaConfig": "projects/aca-folder-rules/karma.conf.js"
}
},
"lint": {
"builder": "@angular-eslint/builder:lint",
"options": {
"lintFilePatterns": [
"projects/aca-folder-rules/**/*.ts",
"projects/aca-folder-rules/**/*.html"
],
"cache": true,
"cacheLocation": ".eslintcache",
"ignorePath": ".eslintignore"
}
}
}
}
},
"defaultProject": "content-ce",

View File

@ -27,9 +27,15 @@ import { NgModule } from '@angular/core';
import { AosExtensionModule } from '@alfresco/adf-office-services-ext';
import { AcaAboutModule } from '@alfresco/aca-about';
import { AcaSettingsModule } from '@alfresco/aca-settings';
import { AcaFolderRulesModule } from '@alfresco/aca-folder-rules';
import { environment } from '../environments/environment';
@NgModule({
imports: [AosExtensionModule, ...(environment.devTools ? [AcaSettingsModule] : []), AcaAboutModule.forRoot(environment.production)]
imports: [
AosExtensionModule,
...(environment.devTools ? [AcaSettingsModule] : []),
AcaAboutModule.forRoot(environment.production),
AcaFolderRulesModule
]
})
export class AppExtensionsModule {}

View File

@ -0,0 +1,120 @@
{
"extends": "../../.eslintrc.json",
"ignorePatterns": [
"!**/*"
],
"overrides": [
{
"files": [
"*.ts"
],
"parserOptions": {
"project": [
"projects/aca-folder-rules/tsconfig.lib.json",
"projects/aca-folder-rules/tsconfig.spec.json"
],
"createDefaultProgram": true
},
"plugins": [
"eslint-plugin-rxjs",
"eslint-plugin-unicorn"
],
"rules": {
"@angular-eslint/component-selector": [
"error",
{
"type": "element",
"prefix": [
"lib",
"aca",
"app",
"adf"
],
"style": "kebab-case"
}
],
"@angular-eslint/directive-selector": [
"error",
{
"type": "attribute",
"prefix": [
"lib",
"aca",
"app",
"adf"
],
"style": "camelCase"
}
],
"@angular-eslint/no-host-metadata-property": "off",
"@typescript-eslint/consistent-type-definitions": "error",
"@typescript-eslint/dot-notation": "off",
"@typescript-eslint/explicit-member-accessibility": [
"off",
{
"accessibility": "explicit"
}
],
"@typescript-eslint/member-delimiter-style": [
"off",
{
"multiline": {
"delimiter": "none",
"requireLast": true
},
"singleline": {
"delimiter": "semi",
"requireLast": false
}
}
],
"@typescript-eslint/semi": [
"off",
null
],
"@typescript-eslint/type-annotation-spacing": "off",
"arrow-parens": [
"off",
"always"
],
"brace-style": [
"off",
"off"
],
"eol-last": "off",
"id-blacklist": "off",
"id-match": "off",
"linebreak-style": "off",
"max-len": "off",
"new-parens": "off",
"newline-per-chained-call": "off",
"no-duplicate-imports": "error",
"no-extra-semi": "off",
"no-irregular-whitespace": "off",
"no-return-await": "error",
"no-underscore-dangle": "off",
"quote-props": "off",
"rxjs/no-create": "error",
"rxjs/no-subject-unsubscribe": "error",
"rxjs/no-subject-value": "error",
"rxjs/no-unsafe-takeuntil": "error",
"space-before-function-paren": "off",
"space-in-parens": [
"off",
"never"
],
"unicorn/filename-case": "error"
}
},
{
"files": [
"*.html"
],
"rules": {
"@angular-eslint/template/no-autofocus": "error",
"@angular-eslint/template/no-negated-async": "off",
"@angular-eslint/template/no-positive-tabindex": "error"
}
}
]
}

View File

@ -0,0 +1,9 @@
# Folder Rules
## Build
Run `ng build aca-folder-rules` to build the project. The build artifacts will be stored in the `dist/` directory.
## Running unit tests
Run `ng test aca-folder-rules` to execute the unit tests via [Karma](https://karma-runner.github.io).

View File

@ -0,0 +1,71 @@
{
"$schema": "../../../extension.schema.json",
"$id": "0455ca6c-cc7a-43ae-bbf7-35795413d2dd",
"$name": "Folder Rules Plugin",
"$version": "0.0.1",
"$vendor": "Alfresco Software, Ltd.",
"$license": "LGPL-3.0",
"features": {
"toolbar": [
{
"id": "app.toolbar.more",
"children": [
{
"id": "app.toolbar.rules.separator",
"type": "separator",
"rules": {
"visible": "app.selection.folder"
}
},
{
"id": "app.toolbar.rules.create",
"title": "ACA_FOLDER_RULES.MENU.CREATE_RULES",
"description": "ACA_FOLDER_RULES.MENU.CREATE_RULES_DESC",
"icon": "add",
"rules": {
"visible": "rules.canCreateFolderRule"
}
},
{
"id": "app.toolbar.rules.link",
"title": "ACA_FOLDER_RULES.MENU.LINK_RULES",
"description": "ACA_FOLDER_RULES.MENU.LINK_RULES_DESC",
"icon": "link",
"rules": {
"visible": "rules.canLinkFolderRule"
}
}
]
}
],
"contextMenu": [
{
"id": "app.toolbar.rules.separator",
"type": "separator",
"rules": {
"visible": "app.selection.folder"
}
},
{
"id": "app.toolbar.rules.create",
"title": "ACA_FOLDER_RULES.MENU.CREATE_RULES",
"description": "ACA_FOLDER_RULES.MENU.CREATE_RULES_DESC",
"icon": "add",
"rules": {
"visible": "rules.canCreateFolderRule"
}
},
{
"id": "app.toolbar.rules.link",
"title": "ACA_FOLDER_RULES.MENU.LINK_RULES",
"description": "ACA_FOLDER_RULES.MENU.LINK_RULES_DESC",
"icon": "link",
"rules": {
"visible": "rules.canLinkFolderRule"
}
}
]
}
}

View File

@ -0,0 +1,10 @@
{
"ACA_FOLDER_RULES": {
"MENU": {
"CREATE_RULES": "Create rules",
"CREATE_RULES_DESC": "[tbd] Creates new rules",
"LINK_RULES": "Link to rules set",
"LINK_RULES_DESC": "[tbd] Link to existing rules"
}
}
}

View File

@ -0,0 +1,32 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('@angular-devkit/build-angular/plugins/karma')
],
client: {
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
coverageIstanbulReporter: {
dir: require('path').join(__dirname, '../../coverage/aca-folder-rules'),
reports: ['html', 'lcovonly', 'text-summary'],
fixWebpackSourcePaths: true
},
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false,
restartOnFileChange: true
});
};

View File

@ -0,0 +1,7 @@
{
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
"dest": "../../dist/aca-folder-rules",
"lib": {
"entryFile": "src/public-api.ts"
}
}

View File

@ -0,0 +1,11 @@
{
"name": "@alfresco/aca-folder-rules",
"version": "0.0.1",
"peerDependencies": {
"@angular/common": "^10.2.4",
"@angular/core": "^10.2.4"
},
"dependencies": {
"tslib": "^2.0.0"
}
}

View File

@ -0,0 +1,43 @@
/*!
* @license
* Alfresco Example Content Application
*
* Copyright (C) 2005 - 2020 Alfresco Software Limited
*
* This file is part of the Alfresco Example Content Application.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
import { TranslationService } from '@alfresco/adf-core';
import { ExtensionService, provideExtensionConfig } from '@alfresco/adf-extensions';
import { NgModule } from '@angular/core';
import * as rules from './folder-rules.rules';
@NgModule({
providers: [provideExtensionConfig(['folder-rules.plugin.json'])]
})
export class AcaFolderRulesModule {
constructor(translation: TranslationService, extensions: ExtensionService) {
translation.addTranslationFolder('aca-folder-rules', 'assets/aca-folder-rules');
extensions.setEvaluators({
'rules.canCreateFolderRule': rules.canCreateFolderRule,
'rules.canLinkFolderRule': rules.canLinkFolderRule
});
}
}

View File

@ -0,0 +1,119 @@
/*!
* @license
* Alfresco Example Content Application
*
* Copyright (C) 2005 - 2020 Alfresco Software Limited
*
* This file is part of the Alfresco Example Content Application.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
import { AcaRuleContext } from '@alfresco/aca-shared/rules';
import { isFolderRulesEnabled, canCreateFolderRule, canLinkFolderRule } from './folder-rules.rules';
describe('Folder Rules', () => {
describe('isFolderRulesEnabled', () => {
it('should have the feature enabled', () => {
const context: any = {
appConfig: {
get: () => true
}
};
const result = isFolderRulesEnabled(context);
expect(result).toEqual(true);
});
it('should have the feature disabled', () => {
const context: any = {
appConfig: {
get: () => false
}
};
const result = isFolderRulesEnabled(context);
expect(result).toEqual(false);
});
});
describe('canCreateFolderRule', () => {
let context: AcaRuleContext;
beforeEach(() => {
context = {
appConfig: {
get: () => true
},
selection: {
folder: {} as any
},
navigation: {
url: '/personal-files'
},
permissions: {
check: () => true
}
} as any;
});
it('should allow creating a rule for the selected folder', () => {
const result = canCreateFolderRule(context);
expect(result).toEqual(true);
});
it('should not allow creating a rule if no folder selected', () => {
context.selection.folder = null;
const result = canCreateFolderRule(context);
expect(result).toEqual(false);
});
});
describe('canLinkFolderRule', () => {
let context: AcaRuleContext;
beforeEach(() => {
context = {
appConfig: {
get: () => true
},
selection: {
folder: {} as any
},
navigation: {
url: '/personal-files'
},
permissions: {
check: () => true
}
} as any;
});
it('should allow linking rule for the selected folder', () => {
const result = canLinkFolderRule(context);
expect(result).toEqual(true);
});
it('should not allow linking rule if no folder selected', () => {
context.selection.folder = null;
const result = canLinkFolderRule(context);
expect(result).toEqual(false);
});
});
});

View File

@ -0,0 +1,33 @@
/*!
* @license
* Alfresco Example Content Application
*
* Copyright (C) 2005 - 2020 Alfresco Software Limited
*
* This file is part of the Alfresco Example Content Application.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
import { AcaRuleContext, hasFolderSelected, canEditFolder } from '@alfresco/aca-shared/rules';
export const isFolderRulesEnabled = (context: AcaRuleContext) => context.appConfig.get<boolean>('plugins.folderRules', false);
export const isFolderRulesAllowed = (context: AcaRuleContext) =>
isFolderRulesEnabled(context) && canEditFolder(context) && hasFolderSelected(context);
export const canCreateFolderRule = (context: AcaRuleContext): boolean => isFolderRulesAllowed(context);
export const canLinkFolderRule = (context: AcaRuleContext): boolean => isFolderRulesAllowed(context);

View File

@ -0,0 +1,26 @@
/*!
* @license
* Alfresco Example Content Application
*
* Copyright (C) 2005 - 2020 Alfresco Software Limited
*
* This file is part of the Alfresco Example Content Application.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
export * from './lib/folder-rules.module';

View File

@ -0,0 +1,49 @@
/*!
* @license
* Alfresco Example Content Application
*
* Copyright (C) 2005 - 2020 Alfresco Software Limited
*
* This file is part of the Alfresco Example Content Application.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/dist/zone';
import 'zone.js/dist/zone-testing';
import { getTestBed } from '@angular/core/testing';
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
declare const require: {
context(
path: string,
deep?: boolean,
filter?: RegExp
): {
keys(): string[];
<T>(id: string): T;
};
};
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
// Then we find all the tests.
const context = require.context('./', true, /\.spec\.ts$/);
// And load the modules.
context.keys().map(context);

View File

@ -0,0 +1,25 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "../../out-tsc/lib",
"target": "es2015",
"declaration": true,
"declarationMap": true,
"inlineSources": true,
"types": [],
"lib": [
"dom",
"es2018"
]
},
"angularCompilerOptions": {
"skipTemplateCodegen": true,
"strictMetadataEmit": true,
"enableResourceInlining": true
},
"exclude": [
"src/test.ts",
"**/*.spec.ts"
]
}

View File

@ -0,0 +1,10 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "./tsconfig.lib.json",
"compilerOptions": {
"declarationMap": false
},
"angularCompilerOptions": {
"enableIvy": false
}
}

View File

@ -0,0 +1,17 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "../../out-tsc/spec",
"types": [
"jasmine"
]
},
"files": [
"src/test.ts"
],
"include": [
"**/*.spec.ts",
"**/*.d.ts"
]
}

View File

@ -23,6 +23,7 @@
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
import { AppConfigService } from '@alfresco/adf-core';
import { RuleContext } from '@alfresco/adf-extensions';
import * as navigation from './navigation.rules';
import * as repository from './repository.rules';
@ -30,6 +31,7 @@ import { isAdmin } from './user.rules';
export interface AcaRuleContext extends RuleContext {
withCredentials: boolean;
appConfig: AppConfigService;
}
/**

View File

@ -117,7 +117,7 @@ export class AppExtensionService implements RuleContext {
protected loader: ExtensionLoaderService,
protected extensions: ExtensionService,
public permissions: NodePermissionService,
protected appConfig: AppConfigService,
public appConfig: AppConfigService,
protected matIconRegistry: MatIconRegistry,
protected sanitizer: DomSanitizer,
protected logger: LogService

View File

@ -27,6 +27,7 @@
"@alfresco/aca-testing-shared": ["projects/aca-testing-shared"],
"@alfresco/aca-about": ["projects/aca-about/src/public-api.ts"],
"@alfresco/aca-settings": ["projects/aca-settings/src/public-api.ts"],
"@alfresco/aca-folder-rules": ["projects/aca-folder-rules/src/public-api.ts"],
"package.json": ["package.json"]
}
},